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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to