/* * 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 log_entry; unsigned int size = sizeof(log_entry); long status = 0xdeadbeef; int fatal; spin_lock(&log_lock); status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 0x500, irq, RTAS_INTERNAL_ERROR, 1, /* Time Critical */ __pa(&log_buf), size); log_entry = log_buf; spin_unlock(&log_lock); if ((status == 0) && (log_entry.severity >= SEVERITY_ERROR_SYNC)) fatal = 1; else fatal = 0; /* format and print the extended information */ log_error((char *)&log_entry, ERR_TYPE_RTAS_LOG, fatal); if (fatal) { udbg_printf("HW Error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), 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%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_WARNING "Warning: Recoverable hardware error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); } return IRQ_HANDLED; }
/* * 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; }
void udbg_init_scc(struct device_node *np) { u32 *reg; unsigned long addr; int i, x; if (np == NULL) np = of_find_node_by_name(NULL, "escc"); if (np == NULL || np->parent == NULL) return; udbg_printf("found SCC...\n"); /* Get address within mac-io ASIC */ reg = (u32 *)get_property(np, "reg", NULL); if (reg == NULL) return; addr = reg[0]; udbg_printf("local addr: %lx\n", addr); /* Get address of mac-io PCI itself */ reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); if (reg == NULL) return; addr += reg[2]; udbg_printf("final addr: %lx\n", addr); /* Setup for 57600 8N1 */ addr += 0x20; sccc = (volatile u8 *) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; sccc += addr & ~PAGE_MASK; sccd = sccc + 0x10; udbg_printf("ioremap result sccc: %p\n", sccc); mb(); for (i = 20000; i != 0; --i) x = *sccc; eieio(); *sccc = 9; eieio(); /* reset A or B side */ *sccc = 0xc0; eieio(); for (i = 0; i < sizeof(scc_inittab); ++i) { *sccc = scc_inittab[i]; eieio(); } ppc_md.udbg_putc = udbg_putc; ppc_md.udbg_getc = udbg_getc; ppc_md.udbg_getc_poll = udbg_getc_poll; udbg_puts("Hello World !\n"); }
/* * 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 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) { struct rtas_error_log log_entry; unsigned int size = sizeof(log_entry); long status = 0xdeadbeef; spin_lock(&log_lock); status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 0x500, irq, RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, 1, /* Time Critical */ __pa(&log_buf), size); log_entry = log_buf; spin_unlock(&log_lock); udbg_printf("EPOW <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_WARNING "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status); /* format and print the extended information */ log_error((char *)&log_entry, ERR_TYPE_RTAS_LOG, 0); return IRQ_HANDLED; }
void early_printk(const char *fmt, ...) { va_list args; va_start(args, fmt); udbg_printf (fmt, args); va_end(args); }
__openfirmware long rtas_call(int token, int nargs, int nret, unsigned long *outputs, ...) { va_list list; int i; unsigned long s; struct rtas_args *rtas_args = &(get_paca()->xRtas); PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; rtas_args->token = token; rtas_args->nargs = nargs; rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]); } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; #if 0 /* Gotta do something different here, use global lock for now... */ spin_lock_irqsave(&rtas_args->lock, s); #else spin_lock_irqsave(&rtas.lock, s); #endif PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args)); enter_rtas((void *)__pa((unsigned long)rtas_args)); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); #if 0 /* Gotta do something different here, use global lock for now... */ spin_unlock_irqrestore(&rtas_args->lock, s); #else spin_unlock_irqrestore(&rtas.lock, s); #endif ifppcdebug(PPCDBG_RTAS) { for(i=0; i < nret ;i++) udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; return (ulong)((nret > 0) ? rtas_args->rets[0] : 0); }
static void pSeriesLP_qirr_info(int n_cpu , u8 value) { unsigned long lpar_rc; lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu),value); if (lpar_rc != H_Success) { udbg_printf("pSeriesLP_qirr_info - plpar_ipi failed!!!!!!!! \n"); panic(" bad return code qirr -ipi - rc = %lx \n", lpar_rc); } }
/* * 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 void ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct rtas_error_log log_entry; unsigned int size = sizeof(log_entry); long status = 0xdeadbeef; status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 0x500, irq, INTERNAL_ERROR, 1, /* Time Critical */ __pa(&log_entry), size); if((status != 1) && (log_entry.severity >= SEVERITY_ERROR_SYNC)) { udbg_printf("HW Error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); #ifndef DEBUG /* Don't actually power off when debugging so we can test * without actually failing while injecting errors. */ ppc_md.power_off(); #endif } else { udbg_printf("Recoverable HW Error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_WARNING "Warning: Recoverable hardware error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); return; } }
/* * early console initialization * * PowerPC kernels support an early printk console, also known as udbg. * This function must be called via the ppc_md.init_early function pointer. * At this point, the device tree has been unflattened, so we can obtain the * byte channel handle for stdout. * * We only support displaying of characters (putc). We do not support * keyboard input. */ void __init udbg_init_ehv_bc(void) { unsigned int rx_count, tx_count; unsigned int ret; /* Verify the byte channel handle */ ret = ev_byte_channel_poll(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, &rx_count, &tx_count); if (ret) return; udbg_putc = ehv_bc_udbg_putc; register_early_udbg_console(); udbg_printf("ehv-bc: early console using byte channel handle %u\n", CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE); }
/* * Handle power subsystem events (EPOW). * * Presently we just log the event has occured. 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 void ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct rtas_error_log log_entry; unsigned int size = sizeof(log_entry); long status = 0xdeadbeef; status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 0x500, irq, EPOW_WARNING | POWERMGM_EVENTS, 1, /* Time Critical */ __pa(&log_entry), size); udbg_printf("EPOW <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_WARNING "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status); }
static void iommu_table_setparms(struct pci_controller *phb, struct device_node *dn, struct iommu_table *tbl) { struct device_node *node; const unsigned long *basep; const u32 *sizep; node = phb->dn; basep = of_get_property(node, "linux,tce-base", NULL); sizep = of_get_property(node, "linux,tce-size", NULL); if (basep == NULL || sizep == NULL) { printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has " "missing tce entries !\n", dn->full_name); return; } tbl->it_base = (unsigned long)__va(*basep); #ifndef CONFIG_CRASH_DUMP memset((void *)tbl->it_base, 0, *sizep); #endif tbl->it_busno = phb->bus->number; /* Units of tce entries */ tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT; /* Test if we are going over 2GB of DMA space */ if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); } phb->dma_window_base_cur += phb->dma_window_size; /* Set the tce table size - measured in entries */ tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT; tbl->it_index = 0; tbl->it_blocksize = 16; tbl->it_type = TCE_PCI; }
/********************************************************************************** * Dump the iSeries Temp Device Node *<4>buswalk [swapper : - DeviceNode: 0xC000000000634300 *<4>00. Device Node = 0xC000000000634300 *<4> - PciDev = 0x0000000000000000 *<4> - tDevice = 0x 17:01.00 0x1022 00 *<4> 4. Device Node = 0xC000000000634480 *<4> - PciDev = 0x0000000000000000 *<4> - Device = 0x 18:38.16 Irq:0xA7 Vendor:0x1014 Flags:0x00 *<4> - Devfn = 0xB0: 22.18 **********************************************************************************/ void dumpDevice_Node(struct iSeries_Device_Node* DevNode) { udbg_printf("Device Node = 0x%p\n",DevNode); udbg_printf(" - PciDev = 0x%p\n",DevNode->PciDev); udbg_printf(" - Device = 0x%4X:%02X.%02X (0x%02X)\n", ISERIES_BUS(DevNode), ISERIES_SUBBUS(DevNode), DevNode->AgentId, DevNode->DevFn); udbg_printf(" - LSlot = 0x%02X\n",DevNode->LogicalSlot); udbg_printf(" - TceTable = 0x%p\n ",DevNode->DevTceTable); udbg_printf(" - DSA = 0x%04X\n",ISERIES_DSA(DevNode)>>32 ); udbg_printf(" = Irq:0x%02X Vendor:0x%04X Flags:0x%02X\n", DevNode->Irq, DevNode->Vendor, DevNode->Flags ); udbg_printf(" - Location = %s\n",DevNode->CardLocation); }
void xics_init_IRQ( void ) { int i; unsigned long intr_size = 0; struct device_node *np; uint *ireg, ilen, indx=0; ibm_get_xive = rtas_token("ibm,get-xive"); ibm_set_xive = rtas_token("ibm,set-xive"); ibm_int_off = rtas_token("ibm,int-off"); np = find_type_devices("PowerPC-External-Interrupt-Presentation"); if (!np) { printk(KERN_WARNING "Can't find Interrupt Presentation\n"); udbg_printf("Can't find Interrupt Presentation\n"); while (1); } nextnode: ireg = (uint *)get_property(np, "ibm,interrupt-server-ranges", 0); if (ireg) { /* * set node starting index for this node */ indx = *ireg; } ireg = (uint *)get_property(np, "reg", &ilen); if (!ireg) { printk(KERN_WARNING "Can't find Interrupt Reg Property\n"); udbg_printf("Can't find Interrupt Reg Property\n"); while (1); } while (ilen) { inodes[indx].addr = (unsigned long long)*ireg++ << 32; ilen -= sizeof(uint); inodes[indx].addr |= *ireg++; ilen -= sizeof(uint); inodes[indx].size = (unsigned long long)*ireg++ << 32; ilen -= sizeof(uint); inodes[indx].size |= *ireg++; ilen -= sizeof(uint); indx++; if (indx >= NR_CPUS) break; } np = np->next; if ((indx < NR_CPUS) && np) goto nextnode; /* Find the server numbers for the boot cpu. */ for (np = find_type_devices("cpu"); np; np = np->next) { ireg = (uint *)get_property(np, "reg", &ilen); if (ireg && ireg[0] == hard_smp_processor_id()) { ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); i = ilen / sizeof(int); if (ireg && i > 0) { default_server = ireg[0]; default_distrib_server = ireg[i-1]; /* take last element */ } break; } } intr_base = inodes[0].addr; intr_size = (ulong)inodes[0].size; np = find_type_devices("interrupt-controller"); if (!np) { printk(KERN_WARNING "xics: no ISA Interrupt Controller\n"); xics_irq_8259_cascade = -1; } else { ireg = (uint *) get_property(np, "interrupts", 0); if (!ireg) { printk(KERN_WARNING "Can't find ISA Interrupts Property\n"); udbg_printf("Can't find ISA Interrupts Property\n"); while (1); } xics_irq_8259_cascade_real = *ireg; xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real); } if (naca->platform == PLATFORM_PSERIES) { #ifdef CONFIG_SMP for (i = 0; i < naca->processorCount; ++i) { xics_info.per_cpu[i] = __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE); } #else xics_info.per_cpu[0] = __ioremap((ulong)intr_base, intr_size, _PAGE_NO_CACHE); #endif /* CONFIG_SMP */ #ifdef CONFIG_PPC_PSERIES /* actually iSeries does not use any of xics...but it has link dependencies * for now, except this new one... */ } else if (naca->platform == PLATFORM_PSERIES_LPAR) { ops = &pSeriesLP_ops; #endif } xics_8259_pic.enable = i8259_pic.enable; xics_8259_pic.disable = i8259_pic.disable; for (i = 0; i < 16; ++i) irq_desc[i].handler = &xics_8259_pic; for (; i < NR_IRQS; ++i) irq_desc[i].handler = &xics_pic; ops->cppr_info(0, 0xff); iosync(); if (xics_irq_8259_cascade != -1) { if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action, 0, "8259 cascade", 0)) printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n"); i8259_init(); } #ifdef CONFIG_SMP real_irq_to_virt_map[XICS_IPI] = virt_irq_to_real_map[XICS_IPI] = XICS_IPI; request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0); irq_desc[XICS_IPI+XICS_IRQ_OFFSET].status |= IRQ_PER_CPU; #endif }
int rtas_call(int token, int nargs, int nret, int *outputs, ...) { va_list list; int i, logit = 0; unsigned long s; struct rtas_args *rtas_args; char * buff_copy = NULL; int ret; PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; /* Gotta do something different here, use global lock for now... */ spin_lock_irqsave(&rtas.lock, s); rtas_args = &rtas.args; rtas_args->token = token; rtas_args->nargs = nargs; rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { rtas_args->args[i] = va_arg(list, rtas_arg_t); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%x\n", i, rtas_args->args[i]); } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", __pa(rtas_args)); enter_rtas(__pa(rtas_args)); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (rtas_args->rets[0] == -1) logit = (__fetch_rtas_last_error() == 0); ifppcdebug(PPCDBG_RTAS) { for(i=0; i < nret ;i++) udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; ret = (nret > 0)? rtas_args->rets[0]: 0; /* Log the error in the unlikely case that there was one. */ if (unlikely(logit)) { buff_copy = rtas_err_buf; if (mem_init_done) { buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); if (buff_copy) memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); } } /* Gotta do something different here, use global lock for now... */ spin_unlock_irqrestore(&rtas.lock, s); if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); if (mem_init_done) kfree(buff_copy); } return ret; }
__openfirmware long rtas_call(int token, int nargs, int nret, unsigned long *outputs, ...) { va_list list; int i, logit = 0; unsigned long flags; struct rtas_args *rtas_args; char * buff_copy = NULL; unsigned long retval; PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; spin_lock_irqsave(&rtas.lock, flags); rtas_args = &(get_paca()->xRtas); rtas_args->token = token; rtas_args->nargs = nargs; rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]); } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args)); enter_rtas((void *)__pa((unsigned long)rtas_args)); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); /* A -1 return code indicates that the last command couldn't * be completed due to a hardware error. */ if (rtas_args->rets[0] == -1) logit = (__fetch_rtas_last_error() == 0); ifppcdebug(PPCDBG_RTAS) { for(i=0; i < nret ;i++) udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; retval = (ulong)((nret > 0) ? rtas_args->rets[0] : 0); /* Log the error in the unlikely case that there was one. */ if (unlikely(logit)) { /* Can't call kmalloc if VM subsystem is not yet up. */ if (slabpages>0) { buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); if (buff_copy) { memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); } } } spin_unlock_irqrestore(&rtas.lock, flags); if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); kfree(buff_copy); } return retval; }