/* * Handle power subsystem events (EPOW). * * Presently we just log the event has occurred. This should be fixed * to examine the type of power failure and take appropriate action where * the time horizon permits something useful to be done. */ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) { int status = 0xdeadbeef; int state = 0; int critical; status = rtas_call(ras_get_sensor_state_token, 2, 2, &state, EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX); if (state > 3) critical = 1; /* Time Critical */ else critical = 0; spin_lock(&ras_log_buf_lock); status = rtas_call(ras_check_exception_token, 6, 1, NULL, RAS_VECTOR_OFFSET, irq_map[irq].hwirq, RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, critical, __pa(&ras_log_buf), rtas_get_error_log_max()); udbg_printf("EPOW <0x%lx 0x%x 0x%x>\n", *((unsigned long *)&ras_log_buf), status, state); printk(KERN_WARNING "EPOW <0x%lx 0x%x 0x%x>\n", *((unsigned long *)&ras_log_buf), status, state); /* format and print the extended information */ log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); spin_unlock(&ras_log_buf_lock); return IRQ_HANDLED; }
/* Handle environmental and power warning (EPOW) interrupts. */ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id) { int status; int state; int critical; status = rtas_get_sensor_fast(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state); if (state > 3) critical = 1; /* Time Critical */ else critical = 0; spin_lock(&ras_log_buf_lock); status = rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, virq_to_hw(irq), RTAS_EPOW_WARNING, critical, __pa(&ras_log_buf), rtas_get_error_log_max()); log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); rtas_parse_epow_errlog((struct rtas_error_log *)ras_log_buf); spin_unlock(&ras_log_buf_lock); return IRQ_HANDLED; }
static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id) { struct pseries_errorlog *pseries_log; struct pseries_hp_errorlog *hp_elog; spin_lock(&ras_log_buf_lock); rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, virq_to_hw(irq), RTAS_HOTPLUG_EVENTS, 0, __pa(&ras_log_buf), rtas_get_error_log_max()); pseries_log = get_pseries_errorlog((struct rtas_error_log *)ras_log_buf, PSERIES_ELOG_SECT_ID_HOTPLUG); hp_elog = (struct pseries_hp_errorlog *)pseries_log->data; /* * Since PCI hotplug is not currently supported on pseries, put PCI * hotplug events on the ras_log_buf to be handled by rtas_errd. */ if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM || hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU || hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_PMEM) queue_hotplug_event(hp_elog); else log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); spin_unlock(&ras_log_buf_lock); return IRQ_HANDLED; }
/** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, * this routine must be called atomically with whatever produced * the error (i.e. with rtas.lock still held from the previous call). */ static int __fetch_rtas_last_error(void) { struct rtas_args err_args, save_args; u32 bufsz; bufsz = rtas_get_error_log_max(); err_args.token = rtas_token("rtas-last-error"); err_args.nargs = 2; err_args.nret = 1; err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); err_args.args[1] = bufsz; err_args.args[2] = 0; save_args = rtas.args; rtas.args = err_args; enter_rtas(__pa(&rtas.args)); err_args = rtas.args; rtas.args = save_args; return err_args.args[2]; }
/* * Handle hardware error interrupts. * * RTAS check-exception is called to collect data on the exception. If * the error is deemed recoverable, we log a warning and return. * For nonrecoverable errors, an error is logged and we stop all processing * as quickly as possible in order to prevent propagation of the failure. */ static irqreturn_t ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct rtas_error_log *rtas_elog; int status = 0xdeadbeef; int fatal; spin_lock(&ras_log_buf_lock); status = rtas_call(ras_check_exception_token, 6, 1, NULL, RAS_VECTOR_OFFSET, irq_map[irq].hwirq, RTAS_INTERNAL_ERROR, 1 /*Time Critical */, __pa(&ras_log_buf), rtas_get_error_log_max()); rtas_elog = (struct rtas_error_log *)ras_log_buf; if ((status == 0) && (rtas_elog->severity >= RTAS_SEVERITY_ERROR_SYNC)) fatal = 1; else fatal = 0; /* format and print the extended information */ log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal); if (fatal) { udbg_printf("Fatal HW Error <0x%lx 0x%x>\n", *((unsigned long *)&ras_log_buf), status); printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n", *((unsigned long *)&ras_log_buf), status); #ifndef DEBUG /* Don't actually power off when debugging so we can test * without actually failing while injecting errors. * Error data will not be logged to syslog. */ ppc_md.power_off(); #endif } else { udbg_printf("Recoverable HW Error <0x%lx 0x%x>\n", *((unsigned long *)&ras_log_buf), status); printk(KERN_WARNING "Warning: Recoverable hardware error <0x%lx 0x%x>\n", *((unsigned long *)&ras_log_buf), status); } spin_unlock(&ras_log_buf_lock); return IRQ_HANDLED; }
static int __init rtas_init(void) { struct proc_dir_entry *entry; if (!machine_is(pseries) && !machine_is(chrp)) return 0; /* No RTAS */ event_scan = rtas_token("event-scan"); if (event_scan == RTAS_UNKNOWN_SERVICE) { printk(KERN_INFO "rtasd: No event-scan on system\n"); return -ENODEV; } rtas_event_scan_rate = rtas_token("rtas-event-scan-rate"); if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) { printk(KERN_ERR "rtasd: no rtas-event-scan-rate on system\n"); return -ENODEV; } if (!rtas_event_scan_rate) { /* Broken firmware: take a rate of zero to mean don't scan */ printk(KERN_DEBUG "rtasd: scan rate is 0, not scanning\n"); return 0; } /* Make room for the sequence number */ rtas_error_log_max = rtas_get_error_log_max(); rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); if (!rtas_log_buf) { printk(KERN_ERR "rtasd: no memory\n"); return -ENOMEM; } entry = proc_create("powerpc/rtas/error_log", S_IRUSR, NULL, &proc_rtas_log_operations); if (!entry) printk(KERN_ERR "Failed to create error_log proc entry\n"); start_event_scan(); return 0; }
/** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, * this routine must be called atomically with whatever produced * the error (i.e. with rtas.lock still held from the previous call). */ static char *__fetch_rtas_last_error(char *altbuf) { struct rtas_args err_args, save_args; u32 bufsz; char *buf = NULL; if (rtas_last_error_token == -1) return NULL; bufsz = rtas_get_error_log_max(); err_args.token = cpu_to_be32(rtas_last_error_token); err_args.nargs = cpu_to_be32(2); err_args.nret = cpu_to_be32(1); err_args.args[0] = cpu_to_be32(__pa(rtas_err_buf)); err_args.args[1] = cpu_to_be32(bufsz); err_args.args[2] = 0; save_args = rtas.args; rtas.args = err_args; enter_rtas(__pa(&rtas.args)); err_args = rtas.args; rtas.args = save_args; /* Log the error in the unlikely case that there was one. */ if (unlikely(err_args.args[2] == 0)) { if (altbuf) { buf = altbuf; } else { buf = rtas_err_buf; if (mem_init_done) buf = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); } if (buf) memcpy(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX); } return buf; }
static int __init rtas_init(void) { struct proc_dir_entry *entry; if (!machine_is(pseries)) return 0; /* No RTAS */ event_scan = rtas_token("event-scan"); if (event_scan == RTAS_UNKNOWN_SERVICE) { printk(KERN_DEBUG "rtasd: no event-scan on system\n"); return -ENODEV; } rtas_event_scan_rate = rtas_token("rtas-event-scan-rate"); if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) { printk(KERN_ERR "rtasd: no rtas-event-scan-rate on system\n"); return -ENODEV; } /* Make room for the sequence number */ rtas_error_log_max = rtas_get_error_log_max(); rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); if (!rtas_log_buf) { printk(KERN_ERR "rtasd: no memory\n"); return -ENOMEM; } entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL); if (entry) entry->proc_fops = &proc_rtas_log_operations; else printk(KERN_ERR "Failed to create error_log proc entry\n"); if (kernel_thread(rtasd, NULL, CLONE_FS) < 0) printk(KERN_ERR "Failed to start RTAS daemon\n"); return 0; }
static int log_rtas_len(char * buf) { int len; struct rtas_error_log *err; /* rtas fixed header */ len = 8; err = (struct rtas_error_log *)buf; if (err->extended_log_length) { /* extended header */ len += err->extended_log_length; } if (rtas_error_log_max == 0) rtas_error_log_max = rtas_get_error_log_max(); if (len > rtas_error_log_max) len = rtas_error_log_max; return len; }
/* * Handle hardware error interrupts. * * RTAS check-exception is called to collect data on the exception. If * the error is deemed recoverable, we log a warning and return. * For nonrecoverable errors, an error is logged and we stop all processing * as quickly as possible in order to prevent propagation of the failure. */ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) { struct rtas_error_log *rtas_elog; int status; int fatal; spin_lock(&ras_log_buf_lock); status = rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, virq_to_hw(irq), RTAS_INTERNAL_ERROR, 1 /* Time Critical */, __pa(&ras_log_buf), rtas_get_error_log_max()); rtas_elog = (struct rtas_error_log *)ras_log_buf; if (status == 0 && rtas_error_severity(rtas_elog) >= RTAS_SEVERITY_ERROR_SYNC) fatal = 1; else fatal = 0; /* format and print the extended information */ log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal); if (fatal) { pr_emerg("Fatal hardware error reported by firmware"); pr_emerg("Check RTAS error log for details"); pr_emerg("Immediate power off"); emergency_sync(); kernel_power_off(); } else { pr_err("Recoverable hardware error reported by firmware"); } spin_unlock(&ras_log_buf_lock); return IRQ_HANDLED; }
static int __init rtas_event_scan_init(void) { if (!machine_is(pseries) && !machine_is(chrp)) return 0; /* No RTAS */ event_scan = rtas_token("event-scan"); if (event_scan == RTAS_UNKNOWN_SERVICE) { printk(KERN_INFO "rtasd: No event-scan on system\n"); return -ENODEV; } rtas_event_scan_rate = rtas_token("rtas-event-scan-rate"); if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) { printk(KERN_ERR "rtasd: no rtas-event-scan-rate on system\n"); return -ENODEV; } if (!rtas_event_scan_rate) { /* Broken firmware: take a rate of zero to mean don't scan */ printk(KERN_DEBUG "rtasd: scan rate is 0, not scanning\n"); return 0; } /* Make room for the sequence number */ rtas_error_log_max = rtas_get_error_log_max(); rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); if (!rtas_log_buf) { printk(KERN_ERR "rtasd: no memory\n"); return -ENOMEM; } start_event_scan(); return 0; }
static int get_eventscan_parms(void) { struct device_node *node; const int *ip; node = of_find_node_by_path("/rtas"); ip = get_property(node, "rtas-event-scan-rate", NULL); if (ip == NULL) { printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n"); of_node_put(node); return -1; } rtas_event_scan_rate = *ip; DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate); /* Make room for the sequence number */ rtas_error_log_max = rtas_get_error_log_max(); rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); of_node_put(node); return 0; }