lkml.org 
[lkml]   [2014]   [Mar]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [RFC PATCH] powerpc/le: enable RTAS events support
    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


    \
     
     \ /
      Last update: 2014-03-31 17:41    [W:2.287 / U:0.068 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site