This is the patch that I worked up at the same time as Greg, the biggest difference being that I took the approach of doing and's, and shifting as opposed to re-defining the bit fields for LE.
One other difference is that I left out defines for bits in the error log structures that we currently do not use. I did leave the comments in the structs describing the bit layout for future reference but did not feel we needed to provide a define for all of them. NOTE: This patch has not been tested. -Nathan --- arch/powerpc/include/asm/rtas.h | 92 +++++++++++++++++++--------- arch/powerpc/kernel/rtas.c | 24 ++++++-- arch/powerpc/kernel/rtasd.c | 11 ++-- arch/powerpc/platforms/pseries/mobility.c | 2 +- arch/powerpc/platforms/pseries/ras.c | 18 ++++-- 5 files changed, 97 insertions(+), 50 deletions(-) diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index a0e1add..6efa1b6 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -150,19 +150,45 @@ struct rtas_suspend_me_data { #define RTAS_VECTOR_EXTERNAL_INTERRUPT 0x500 struct rtas_error_log { - unsigned long version:8; /* Architectural version */ - unsigned long severity:3; /* Severity level of error */ - unsigned long disposition:2; /* Degree of recovery */ - unsigned long extended:1; /* extended log present? */ - unsigned long /* reserved */ :2; /* Reserved for future use */ - unsigned long initiator:4; /* Initiator of event */ - unsigned long target:4; /* Target of failed operation */ - unsigned long type:8; /* General event or error*/ - unsigned long extended_log_length:32; /* length in bytes */ - unsigned char buffer[1]; /* Start of extended log */ + /* Byte 0 */ + uint8_t version; /* Architectural version */ + + /* Byte 1 */ + uint8_t severity; + /* XXXXXXXX + * XXX 3: Severity level of error + * XX 2: Degree of recovery + * X 1: Extended log present? + * XX 2: Reserved + */ + + /* Byte 2 */ + uint8_t :8; + /* XXXXXXXX + * XXXX 4: Initiator of event + * XXXX 4: Target of failed operation + */ + uint8_t type; /* General event or error*/ + uint32_t extended_log_length; /* length in bytes */ + unsigned char buffer[1]; /* Start of extended log */ /* Variable length. */ }; +static inline uint8_t rtas_error_severity(struct rtas_error_log *elog) +{ + return (elog->severity & 0xE0) >> 5; +} + +static inline uint8_t rtas_error_disposition(struct rtas_error_log *elog) +{ + return (elog->severity & 0x18) >> 3; +} + +static inline uint8_t rtas_error_extended(struct rtas_error_log *elog) +{ + return elog->severity & 0x04; +} + #define RTAS_V6EXT_LOG_FORMAT_EVENT_LOG 14 #define RTAS_V6EXT_COMPANY_ID_IBM (('I' << 24) | ('B' << 16) | ('M' << 8)) @@ -172,34 +198,40 @@ struct rtas_error_log { */ struct rtas_ext_event_log_v6 { /* Byte 0 */ - uint32_t log_valid:1; /* 1:Log valid */ - uint32_t unrecoverable_error:1; /* 1:Unrecoverable error */ - uint32_t recoverable_error:1; /* 1:recoverable (correctable */ - /* or successfully retried) */ - uint32_t degraded_operation:1; /* 1:Unrecoverable err, bypassed*/ - /* - degraded operation (e.g. */ - /* CPU or mem taken off-line) */ - uint32_t predictive_error:1; - uint32_t new_log:1; /* 1:"New" log (Always 1 for */ - /* data returned from RTAS */ - uint32_t big_endian:1; /* 1: Big endian */ - uint32_t :1; /* reserved */ + uint8_t :8; + /* XXXXXXXX + * X 1: Log valid + * X 1: Unrecoverable error + * X 1: Recoverable (correctable or successfully retried) + * X 1: Unrecoverable err, bypassed - degraded operation + * (e.g. CPU or mem taken off-line) + * X 1: Preduictive error + * X 1: "New" log (Always 1 for data returned from RTAS) + * X 1: Big endian + * X 1: reserved + */ + /* Byte 1 */ - uint32_t :8; /* reserved */ + uint8_t :8; /* reserved */ /* Byte 2 */ - uint32_t powerpc_format:1; /* Set to 1 (indicating log is */ - /* in PowerPC format */ - uint32_t :3; /* reserved */ - uint32_t log_format:4; /* Log format indicator. Define */ - /* format used for byte 12-2047 */ + uint8_t format; + /* XXXXXXXX + * X 1: Set to 1 (indicating log is in PowerPC format) + * XXX 3: Reserved + * XXXX 4: Log format indicator. Define format used for + * byte 12-2047 + */ + /* Byte 3 */ - uint32_t :8; /* reserved */ + uint8_t :8; /* reserved */ /* Byte 4-11 */ uint8_t reserved[8]; /* reserved */ + /* Byte 12-15 */ - uint32_t company_id; /* Company ID of the company */ + char company_id[4]; /* Company ID of the company */ /* that defines the format for */ /* the vendor specific log type */ + /* Byte 16-end of log */ uint8_t vendor_log[1]; /* Start of vendor specific log */ /* Variable length. */ diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index f386296..314e3c9 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -979,6 +979,17 @@ int rtas_ibm_suspend_me(struct rtas_args *args) } #endif +const char *rtas_v6ext_company_id = "IBM"; +/** + * Validate the company_id specified in the rtas extended event log + */ +static int rtas_valid_extv6_company_id(struct rtas_ext_event_log_v6 *extlog) +{ + return (extlog->company_id[0] == 'I' && + extlog->company_id[1] == 'B' && + extlog->company_id[2] == 'M'); +} + /** * Find a specific pseries error log in an RTAS extended event log. * @log: RTAS error/event log @@ -993,21 +1004,22 @@ struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log, (struct rtas_ext_event_log_v6 *)log->buffer; struct pseries_errorlog *sect; unsigned char *p, *log_end; + uint32_t ext_log_length = be32_to_cpu(log->extended_log_length); /* Check that we understand the format */ - if (log->extended_log_length < sizeof(struct rtas_ext_event_log_v6) || - ext_log->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG || - ext_log->company_id != RTAS_V6EXT_COMPANY_ID_IBM) + if (ext_log_length < sizeof(struct rtas_ext_event_log_v6) || + (ext_log->format & 0x0f) != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG || + !rtas_valid_extv6_company_id(ext_log)) return NULL; - log_end = log->buffer + log->extended_log_length; + log_end = log->buffer + ext_log_length; p = ext_log->vendor_log; while (p < log_end) { sect = (struct pseries_errorlog *)p; - if (sect->id == section_id) + if (be16_to_cpu(sect->id) == section_id) return sect; - p += sect->length; + p += be16_to_cpu(sect->length); } return NULL; diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index 1130c53..6940e26 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -151,7 +151,7 @@ static void printk_log_rtas(char *buf, int len) printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n", error_log_cnt, rtas_event_type(errlog->type), - errlog->severity); + rtas_error_severity(errlog)); } } @@ -163,10 +163,10 @@ static int log_rtas_len(char * buf) /* rtas fixed header */ len = 8; err = (struct rtas_error_log *)buf; - if (err->extended && err->extended_log_length) { + if (rtas_error_extended(err) && err->extended_log_length) { /* extended header */ - len += err->extended_log_length; + len += be32_to_cpu(err->extended_log_length); } if (rtas_error_log_max == 0) @@ -293,12 +293,11 @@ void prrn_schedule_update(u32 scope) static void handle_rtas_event(const struct rtas_error_log *log) { - if (log->type == RTAS_TYPE_PRRN) { + if (log->type == RTAS_TYPE_PRRN && prrn_is_enabled()) { /* For PRRN Events the extended log length is used to denote * the scope for calling rtas update-nodes. */ - if (prrn_is_enabled()) - prrn_schedule_update(log->extended_log_length); + prrn_schedule_update(be32_to_cpu(log->extended_log_length)); } return; diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index bde7eba..ef08cda 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -46,7 +46,7 @@ static int mobility_rtas_call(int token, char *buf, s32 scope) spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE); - rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope); + rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, cpu_to_be32(scope)); memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 721c058..0940734 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -236,7 +236,8 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) rtas_elog = (struct rtas_error_log *)ras_log_buf; - if ((status == 0) && (rtas_elog->severity >= RTAS_SEVERITY_ERROR_SYNC)) + if ((status == 0) && + (rtas_error_severity(rtas_elog) >= RTAS_SEVERITY_ERROR_SYNC)) fatal = 1; else fatal = 0; @@ -300,13 +301,15 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) /* If it isn't an extended log we can use the per cpu 64bit buffer */ h = (struct rtas_error_log *)&savep[1]; - if (!h->extended) { + if (!rtas_error_extended(h)) { memcpy(&__get_cpu_var(mce_data_buf), h, sizeof(__u64)); errhdr = (struct rtas_error_log *)&__get_cpu_var(mce_data_buf); } else { - int len; + int len, error_log_length; + + error_log_length = 8 + be32_to_cpu(h->extended_log_length); + len = max_t(int, error_log_length, RTAS_ERROR_LOG_MAX); - len = max_t(int, 8+h->extended_log_length, RTAS_ERROR_LOG_MAX); memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX); memcpy(global_mce_data_buf, h, len); errhdr = (struct rtas_error_log *)global_mce_data_buf; @@ -350,23 +353,24 @@ int pSeries_system_reset_exception(struct pt_regs *regs) static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err) { int recovered = 0; + int disposition = rtas_error_disposition(err); if (!(regs->msr & MSR_RI)) { /* If MSR_RI isn't set, we cannot recover */ recovered = 0; - } else if (err->disposition == RTAS_DISP_FULLY_RECOVERED) { + } else if (disposition == RTAS_DISP_FULLY_RECOVERED) { /* Platform corrected itself */ recovered = 1; - } else if (err->disposition == RTAS_DISP_LIMITED_RECOVERY) { + } else if (disposition == RTAS_DISP_LIMITED_RECOVERY) { /* Platform corrected itself but could be degraded */ printk(KERN_ERR "MCE: limited recovery, system may " "be degraded\n"); recovered = 1; } else if (user_mode(regs) && !is_global_init(current) && - err->severity == RTAS_SEVERITY_ERROR_SYNC) { + rtas_error_severity(err) == RTAS_SEVERITY_ERROR_SYNC) { /* * If we received a synchronous error when in userspace _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev