linux/arch/powerpc/platforms/pseries/ras.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2001 Dave Engebretsen IBM Corporation
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  17 */
  18
  19#include <linux/sched.h>
  20#include <linux/interrupt.h>
  21#include <linux/irq.h>
  22#include <linux/of.h>
  23#include <linux/fs.h>
  24#include <linux/reboot.h>
  25
  26#include <asm/machdep.h>
  27#include <asm/rtas.h>
  28#include <asm/firmware.h>
  29
  30#include "pseries.h"
  31
  32static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
  33static DEFINE_SPINLOCK(ras_log_buf_lock);
  34
  35static char global_mce_data_buf[RTAS_ERROR_LOG_MAX];
  36static DEFINE_PER_CPU(__u64, mce_data_buf);
  37
  38static int ras_check_exception_token;
  39
  40#define EPOW_SENSOR_TOKEN       9
  41#define EPOW_SENSOR_INDEX       0
  42
  43/* EPOW events counter variable */
  44static int num_epow_events;
  45
  46static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id);
  47static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
  48static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
  49
  50
  51/*
  52 * Initialize handlers for the set of interrupts caused by hardware errors
  53 * and power system events.
  54 */
  55static int __init init_ras_IRQ(void)
  56{
  57        struct device_node *np;
  58
  59        ras_check_exception_token = rtas_token("check-exception");
  60
  61        /* Internal Errors */
  62        np = of_find_node_by_path("/event-sources/internal-errors");
  63        if (np != NULL) {
  64                request_event_sources_irqs(np, ras_error_interrupt,
  65                                           "RAS_ERROR");
  66                of_node_put(np);
  67        }
  68
  69        /* Hotplug Events */
  70        np = of_find_node_by_path("/event-sources/hot-plug-events");
  71        if (np != NULL) {
  72                request_event_sources_irqs(np, ras_hotplug_interrupt,
  73                                           "RAS_HOTPLUG");
  74                of_node_put(np);
  75        }
  76
  77        /* EPOW Events */
  78        np = of_find_node_by_path("/event-sources/epow-events");
  79        if (np != NULL) {
  80                request_event_sources_irqs(np, ras_epow_interrupt, "RAS_EPOW");
  81                of_node_put(np);
  82        }
  83
  84        return 0;
  85}
  86machine_subsys_initcall(pseries, init_ras_IRQ);
  87
  88#define EPOW_SHUTDOWN_NORMAL                            1
  89#define EPOW_SHUTDOWN_ON_UPS                            2
  90#define EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS        3
  91#define EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH      4
  92
  93static void handle_system_shutdown(char event_modifier)
  94{
  95        switch (event_modifier) {
  96        case EPOW_SHUTDOWN_NORMAL:
  97                pr_emerg("Power off requested\n");
  98                orderly_poweroff(true);
  99                break;
 100
 101        case EPOW_SHUTDOWN_ON_UPS:
 102                pr_emerg("Loss of system power detected. System is running on"
 103                         " UPS/battery. Check RTAS error log for details\n");
 104                orderly_poweroff(true);
 105                break;
 106
 107        case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS:
 108                pr_emerg("Loss of system critical functions detected. Check"
 109                         " RTAS error log for details\n");
 110                orderly_poweroff(true);
 111                break;
 112
 113        case EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH:
 114                pr_emerg("High ambient temperature detected. Check RTAS"
 115                         " error log for details\n");
 116                orderly_poweroff(true);
 117                break;
 118
 119        default:
 120                pr_err("Unknown power/cooling shutdown event (modifier = %d)\n",
 121                        event_modifier);
 122        }
 123}
 124
 125struct epow_errorlog {
 126        unsigned char sensor_value;
 127        unsigned char event_modifier;
 128        unsigned char extended_modifier;
 129        unsigned char reserved;
 130        unsigned char platform_reason;
 131};
 132
 133#define EPOW_RESET                      0
 134#define EPOW_WARN_COOLING               1
 135#define EPOW_WARN_POWER                 2
 136#define EPOW_SYSTEM_SHUTDOWN            3
 137#define EPOW_SYSTEM_HALT                4
 138#define EPOW_MAIN_ENCLOSURE             5
 139#define EPOW_POWER_OFF                  7
 140
 141static void rtas_parse_epow_errlog(struct rtas_error_log *log)
 142{
 143        struct pseries_errorlog *pseries_log;
 144        struct epow_errorlog *epow_log;
 145        char action_code;
 146        char modifier;
 147
 148        pseries_log = get_pseries_errorlog(log, PSERIES_ELOG_SECT_ID_EPOW);
 149        if (pseries_log == NULL)
 150                return;
 151
 152        epow_log = (struct epow_errorlog *)pseries_log->data;
 153        action_code = epow_log->sensor_value & 0xF;     /* bottom 4 bits */
 154        modifier = epow_log->event_modifier & 0xF;      /* bottom 4 bits */
 155
 156        switch (action_code) {
 157        case EPOW_RESET:
 158                if (num_epow_events) {
 159                        pr_info("Non critical power/cooling issue cleared\n");
 160                        num_epow_events--;
 161                }
 162                break;
 163
 164        case EPOW_WARN_COOLING:
 165                pr_info("Non-critical cooling issue detected. Check RTAS error"
 166                        " log for details\n");
 167                break;
 168
 169        case EPOW_WARN_POWER:
 170                pr_info("Non-critical power issue detected. Check RTAS error"
 171                        " log for details\n");
 172                break;
 173
 174        case EPOW_SYSTEM_SHUTDOWN:
 175                handle_system_shutdown(epow_log->event_modifier);
 176                break;
 177
 178        case EPOW_SYSTEM_HALT:
 179                pr_emerg("Critical power/cooling issue detected. Check RTAS"
 180                         " error log for details. Powering off.\n");
 181                orderly_poweroff(true);
 182                break;
 183
 184        case EPOW_MAIN_ENCLOSURE:
 185        case EPOW_POWER_OFF:
 186                pr_emerg("System about to lose power. Check RTAS error log "
 187                         " for details. Powering off immediately.\n");
 188                emergency_sync();
 189                kernel_power_off();
 190                break;
 191
 192        default:
 193                pr_err("Unknown power/cooling event (action code  = %d)\n",
 194                        action_code);
 195        }
 196
 197        /* Increment epow events counter variable */
 198        if (action_code != EPOW_RESET)
 199                num_epow_events++;
 200}
 201
 202static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id)
 203{
 204        struct pseries_errorlog *pseries_log;
 205        struct pseries_hp_errorlog *hp_elog;
 206
 207        spin_lock(&ras_log_buf_lock);
 208
 209        rtas_call(ras_check_exception_token, 6, 1, NULL,
 210                  RTAS_VECTOR_EXTERNAL_INTERRUPT, virq_to_hw(irq),
 211                  RTAS_HOTPLUG_EVENTS, 0, __pa(&ras_log_buf),
 212                  rtas_get_error_log_max());
 213
 214        pseries_log = get_pseries_errorlog((struct rtas_error_log *)ras_log_buf,
 215                                           PSERIES_ELOG_SECT_ID_HOTPLUG);
 216        hp_elog = (struct pseries_hp_errorlog *)pseries_log->data;
 217
 218        /*
 219         * Since PCI hotplug is not currently supported on pseries, put PCI
 220         * hotplug events on the ras_log_buf to be handled by rtas_errd.
 221         */
 222        if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM ||
 223            hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU)
 224                queue_hotplug_event(hp_elog, NULL, NULL);
 225        else
 226                log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);
 227
 228        spin_unlock(&ras_log_buf_lock);
 229        return IRQ_HANDLED;
 230}
 231
 232/* Handle environmental and power warning (EPOW) interrupts. */
 233static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
 234{
 235        int status;
 236        int state;
 237        int critical;
 238
 239        status = rtas_get_sensor_fast(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX,
 240                                      &state);
 241
 242        if (state > 3)
 243                critical = 1;           /* Time Critical */
 244        else
 245                critical = 0;
 246
 247        spin_lock(&ras_log_buf_lock);
 248
 249        status = rtas_call(ras_check_exception_token, 6, 1, NULL,
 250                           RTAS_VECTOR_EXTERNAL_INTERRUPT,
 251                           virq_to_hw(irq),
 252                           RTAS_EPOW_WARNING,
 253                           critical, __pa(&ras_log_buf),
 254                                rtas_get_error_log_max());
 255
 256        log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);
 257
 258        rtas_parse_epow_errlog((struct rtas_error_log *)ras_log_buf);
 259
 260        spin_unlock(&ras_log_buf_lock);
 261        return IRQ_HANDLED;
 262}
 263
 264/*
 265 * Handle hardware error interrupts.
 266 *
 267 * RTAS check-exception is called to collect data on the exception.  If
 268 * the error is deemed recoverable, we log a warning and return.
 269 * For nonrecoverable errors, an error is logged and we stop all processing
 270 * as quickly as possible in order to prevent propagation of the failure.
 271 */
 272static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
 273{
 274        struct rtas_error_log *rtas_elog;
 275        int status;
 276        int fatal;
 277
 278        spin_lock(&ras_log_buf_lock);
 279
 280        status = rtas_call(ras_check_exception_token, 6, 1, NULL,
 281                           RTAS_VECTOR_EXTERNAL_INTERRUPT,
 282                           virq_to_hw(irq),
 283                           RTAS_INTERNAL_ERROR, 1 /* Time Critical */,
 284                           __pa(&ras_log_buf),
 285                                rtas_get_error_log_max());
 286
 287        rtas_elog = (struct rtas_error_log *)ras_log_buf;
 288
 289        if (status == 0 &&
 290            rtas_error_severity(rtas_elog) >= RTAS_SEVERITY_ERROR_SYNC)
 291                fatal = 1;
 292        else
 293                fatal = 0;
 294
 295        /* format and print the extended information */
 296        log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);
 297
 298        if (fatal) {
 299                pr_emerg("Fatal hardware error detected. Check RTAS error"
 300                         " log for details. Powering off immediately\n");
 301                emergency_sync();
 302                kernel_power_off();
 303        } else {
 304                pr_err("Recoverable hardware error detected\n");
 305        }
 306
 307        spin_unlock(&ras_log_buf_lock);
 308        return IRQ_HANDLED;
 309}
 310
 311/*
 312 * Some versions of FWNMI place the buffer inside the 4kB page starting at
 313 * 0x7000. Other versions place it inside the rtas buffer. We check both.
 314 */
 315#define VALID_FWNMI_BUFFER(A) \
 316        ((((A) >= 0x7000) && ((A) < 0x7ff0)) || \
 317        (((A) >= rtas.base) && ((A) < (rtas.base + rtas.size - 16))))
 318
 319/*
 320 * Get the error information for errors coming through the
 321 * FWNMI vectors.  The pt_regs' r3 will be updated to reflect
 322 * the actual r3 if possible, and a ptr to the error log entry
 323 * will be returned if found.
 324 *
 325 * If the RTAS error is not of the extended type, then we put it in a per
 326 * cpu 64bit buffer. If it is the extended type we use global_mce_data_buf.
 327 *
 328 * The global_mce_data_buf does not have any locks or protection around it,
 329 * if a second machine check comes in, or a system reset is done
 330 * before we have logged the error, then we will get corruption in the
 331 * error log.  This is preferable over holding off on calling
 332 * ibm,nmi-interlock which would result in us checkstopping if a
 333 * second machine check did come in.
 334 */
 335static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
 336{
 337        unsigned long *savep;
 338        struct rtas_error_log *h, *errhdr = NULL;
 339
 340        /* Mask top two bits */
 341        regs->gpr[3] &= ~(0x3UL << 62);
 342
 343        if (!VALID_FWNMI_BUFFER(regs->gpr[3])) {
 344                printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
 345                return NULL;
 346        }
 347
 348        savep = __va(regs->gpr[3]);
 349        regs->gpr[3] = savep[0];        /* restore original r3 */
 350
 351        /* If it isn't an extended log we can use the per cpu 64bit buffer */
 352        h = (struct rtas_error_log *)&savep[1];
 353        if (!rtas_error_extended(h)) {
 354                memcpy(this_cpu_ptr(&mce_data_buf), h, sizeof(__u64));
 355                errhdr = (struct rtas_error_log *)this_cpu_ptr(&mce_data_buf);
 356        } else {
 357                int len, error_log_length;
 358
 359                error_log_length = 8 + rtas_error_extended_log_length(h);
 360                len = max_t(int, error_log_length, RTAS_ERROR_LOG_MAX);
 361                memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
 362                memcpy(global_mce_data_buf, h, len);
 363                errhdr = (struct rtas_error_log *)global_mce_data_buf;
 364        }
 365
 366        return errhdr;
 367}
 368
 369/* Call this when done with the data returned by FWNMI_get_errinfo.
 370 * It will release the saved data area for other CPUs in the
 371 * partition to receive FWNMI errors.
 372 */
 373static void fwnmi_release_errinfo(void)
 374{
 375        int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
 376        if (ret != 0)
 377                printk(KERN_ERR "FWNMI: nmi-interlock failed: %d\n", ret);
 378}
 379
 380int pSeries_system_reset_exception(struct pt_regs *regs)
 381{
 382        if (fwnmi_active) {
 383                struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
 384                if (errhdr) {
 385                        /* XXX Should look at FWNMI information */
 386                }
 387                fwnmi_release_errinfo();
 388        }
 389        return 0; /* need to perform reset */
 390}
 391
 392/*
 393 * See if we can recover from a machine check exception.
 394 * This is only called on power4 (or above) and only via
 395 * the Firmware Non-Maskable Interrupts (fwnmi) handler
 396 * which provides the error analysis for us.
 397 *
 398 * Return 1 if corrected (or delivered a signal).
 399 * Return 0 if there is nothing we can do.
 400 */
 401static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err)
 402{
 403        int recovered = 0;
 404        int disposition = rtas_error_disposition(err);
 405
 406        if (!(regs->msr & MSR_RI)) {
 407                /* If MSR_RI isn't set, we cannot recover */
 408                recovered = 0;
 409
 410        } else if (disposition == RTAS_DISP_FULLY_RECOVERED) {
 411                /* Platform corrected itself */
 412                recovered = 1;
 413
 414        } else if (disposition == RTAS_DISP_LIMITED_RECOVERY) {
 415                /* Platform corrected itself but could be degraded */
 416                printk(KERN_ERR "MCE: limited recovery, system may "
 417                       "be degraded\n");
 418                recovered = 1;
 419
 420        } else if (user_mode(regs) && !is_global_init(current) &&
 421                   rtas_error_severity(err) == RTAS_SEVERITY_ERROR_SYNC) {
 422
 423                /*
 424                 * If we received a synchronous error when in userspace
 425                 * kill the task. Firmware may report details of the fail
 426                 * asynchronously, so we can't rely on the target and type
 427                 * fields being valid here.
 428                 */
 429                printk(KERN_ERR "MCE: uncorrectable error, killing task "
 430                       "%s:%d\n", current->comm, current->pid);
 431
 432                _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
 433                recovered = 1;
 434        }
 435
 436        log_error((char *)err, ERR_TYPE_RTAS_LOG, 0);
 437
 438        return recovered;
 439}
 440
 441/*
 442 * Handle a machine check.
 443 *
 444 * Note that on Power 4 and beyond Firmware Non-Maskable Interrupts (fwnmi)
 445 * should be present.  If so the handler which called us tells us if the
 446 * error was recovered (never true if RI=0).
 447 *
 448 * On hardware prior to Power 4 these exceptions were asynchronous which
 449 * means we can't tell exactly where it occurred and so we can't recover.
 450 */
 451int pSeries_machine_check_exception(struct pt_regs *regs)
 452{
 453        struct rtas_error_log *errp;
 454
 455        if (fwnmi_active) {
 456                errp = fwnmi_get_errinfo(regs);
 457                fwnmi_release_errinfo();
 458                if (errp && recover_mce(regs, errp))
 459                        return 1;
 460        }
 461
 462        return 0;
 463}
 464