static void rtas_flash_firmware(int reboot_type) { unsigned long image_size; struct flash_block_list *f, *next, *flist; unsigned long rtas_block_list; int i, status, update_token; if (rtas_firmware_flash_list == NULL) return; /* nothing to do */ if (reboot_type != SYS_RESTART) { printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n"); printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n"); return; } update_token = rtas_token("ibm,update-flash-64-and-reboot"); if (update_token == RTAS_UNKNOWN_SERVICE) { printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot " "is not available -- not a service partition?\n"); printk(KERN_ALERT "FLASH: firmware will not be flashed\n"); return; } /* * Just before starting the firmware flash, cancel the event scan work * to avoid any soft lockup issues. */ rtas_cancel_event_scan(); /* * NOTE: the "first" block must be under 4GB, so we create * an entry with no data blocks in the reserved buffer in * the kernel data segment. */ spin_lock(&rtas_data_buf_lock); flist = (struct flash_block_list *)&rtas_data_buf[0]; flist->num_blocks = 0; flist->next = rtas_firmware_flash_list; rtas_block_list = virt_to_abs(flist); if (rtas_block_list >= 4UL*1024*1024*1024) { printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); spin_unlock(&rtas_data_buf_lock); return; } printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); /* Update the block_list in place. */ rtas_firmware_flash_list = NULL; /* too hard to backout on error */ image_size = 0; for (f = flist; f; f = next) { /* Translate data addrs to absolute */ for (i = 0; i < f->num_blocks; i++) { f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data); image_size += f->blocks[i].length; } next = f->next; /* Don't translate NULL pointer for last entry */ if (f->next) f->next = (struct flash_block_list *)virt_to_abs(f->next); else f->next = NULL; /* make num_blocks into the version/length field */ f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16); } printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); printk(KERN_ALERT "FLASH: performing flash and reboot\n"); rtas_progress("Flashing \n", 0x0); rtas_progress("Please Wait... ", 0x0); printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); switch (status) { /* should only get "bad" status */ case 0: printk(KERN_ALERT "FLASH: success\n"); break; case -1: printk(KERN_ALERT "FLASH: hardware error. Firmware may not be not flashed\n"); break; case -3: printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform. Firmware not flashed\n"); break; case -4: printk(KERN_ALERT "FLASH: flash failed when partially complete. System may not reboot\n"); break; default: printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); break; } spin_unlock(&rtas_data_buf_lock); }
static int __init rtas_flash_init(void) { int rc; if (rtas_token("ibm,update-flash-64-and-reboot") == RTAS_UNKNOWN_SERVICE) { printk(KERN_ERR "rtas_flash: no firmware flash support\n"); return 1; } firmware_flash_pde = create_flash_pde("powerpc/rtas/" FIRMWARE_FLASH_NAME, &rtas_flash_operations); if (firmware_flash_pde == NULL) { rc = -ENOMEM; goto cleanup; } rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot", sizeof(struct rtas_update_flash_t), firmware_flash_pde); if (rc != 0) goto cleanup; firmware_update_pde = create_flash_pde("powerpc/rtas/" FIRMWARE_UPDATE_NAME, &rtas_flash_operations); if (firmware_update_pde == NULL) { rc = -ENOMEM; goto cleanup; } rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot", sizeof(struct rtas_update_flash_t), firmware_update_pde); if (rc != 0) goto cleanup; validate_pde = create_flash_pde("powerpc/rtas/" VALIDATE_FLASH_NAME, &validate_flash_operations); if (validate_pde == NULL) { rc = -ENOMEM; goto cleanup; } rc = initialize_flash_pde_data("ibm,validate-flash-image", sizeof(struct rtas_validate_flash_t), validate_pde); if (rc != 0) goto cleanup; manage_pde = create_flash_pde("powerpc/rtas/" MANAGE_FLASH_NAME, &manage_flash_operations); if (manage_pde == NULL) { rc = -ENOMEM; goto cleanup; } rc = initialize_flash_pde_data("ibm,manage-flash-image", sizeof(struct rtas_manage_flash_t), manage_pde); if (rc != 0) goto cleanup; rtas_flash_term_hook = rtas_flash_firmware; flash_block_cache = kmem_cache_create("rtas_flash_cache", RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0, rtas_block_ctor); if (!flash_block_cache) { printk(KERN_ERR "%s: failed to create block cache\n", __func__); rc = -ENOMEM; goto cleanup; } return 0; cleanup: remove_flash_pde(firmware_flash_pde); remove_flash_pde(firmware_update_pde); remove_flash_pde(validate_pde); remove_flash_pde(manage_pde); return rc; }
int rtas_ibm_suspend_me(u64 handle, int *vasi_return) { long state; long rc; unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; struct rtas_suspend_me_data data; DECLARE_COMPLETION_ONSTACK(done); cpumask_var_t offline_mask; int cpuret; if (!rtas_service_present("ibm,suspend-me")) return -ENOSYS; /* Make sure the state is valid */ rc = plpar_hcall(H_VASI_STATE, retbuf, handle); state = retbuf[0]; if (rc) { printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc); return rc; } else if (state == H_VASI_ENABLED) { *vasi_return = RTAS_NOT_SUSPENDABLE; return 0; } else if (state != H_VASI_SUSPENDING) { printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned state %ld\n", state); *vasi_return = -1; return 0; } if (!alloc_cpumask_var(&offline_mask, GFP_TEMPORARY)) return -ENOMEM; atomic_set(&data.working, 0); atomic_set(&data.done, 0); atomic_set(&data.error, 0); data.token = rtas_token("ibm,suspend-me"); data.complete = &done; /* All present CPUs must be online */ cpumask_andnot(offline_mask, cpu_present_mask, cpu_online_mask); cpuret = rtas_online_cpus_mask(offline_mask); if (cpuret) { pr_err("%s: Could not bring present CPUs online.\n", __func__); atomic_set(&data.error, cpuret); goto out; } stop_topology_update(); /* Call function on all CPUs. One of us will make the * rtas call */ if (on_each_cpu(rtas_percpu_suspend_me, &data, 0)) atomic_set(&data.error, -EINVAL); wait_for_completion(&done); if (atomic_read(&data.error) != 0) printk(KERN_ERR "Error doing global join\n"); start_topology_update(); /* Take down CPUs not online prior to suspend */ cpuret = rtas_offline_cpus_mask(offline_mask); if (cpuret) pr_warn("%s: Could not restore CPUs to offline state.\n", __func__); out: free_cpumask_var(offline_mask); return atomic_read(&data.error); }
struct device_node *dlpar_configure_connector(u32 drc_index) { struct device_node *dn; struct device_node *first_dn = NULL; struct device_node *last_dn = NULL; struct property *property; struct property *last_property = NULL; struct cc_workarea *ccwa; int cc_token; int rc; cc_token = rtas_token("ibm,configure-connector"); if (cc_token == RTAS_UNKNOWN_SERVICE) return NULL; spin_lock(&rtas_data_buf_lock); ccwa = (struct cc_workarea *)&rtas_data_buf[0]; ccwa->drc_index = drc_index; ccwa->zero = 0; rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); while (rc) { switch (rc) { case NEXT_SIBLING: dn = dlpar_parse_cc_node(ccwa); if (!dn) goto cc_error; dn->parent = last_dn->parent; last_dn->sibling = dn; last_dn = dn; break; case NEXT_CHILD: dn = dlpar_parse_cc_node(ccwa); if (!dn) goto cc_error; if (!first_dn) first_dn = dn; else { dn->parent = last_dn; if (last_dn) last_dn->child = dn; } last_dn = dn; break; case NEXT_PROPERTY: property = dlpar_parse_cc_property(ccwa); if (!property) goto cc_error; if (!last_dn->properties) last_dn->properties = property; else last_property->next = property; last_property = property; break; case PREV_PARENT: last_dn = last_dn->parent; break; case CALL_AGAIN: break; case MORE_MEMORY: case ERR_CFG_USE: default: printk(KERN_ERR "Unexpected Error (%d) " "returned from configure-connector\n", rc); goto cc_error; } rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); } spin_unlock(&rtas_data_buf_lock); return first_dn; cc_error: if (first_dn) dlpar_free_cc_nodes(first_dn); spin_unlock(&rtas_data_buf_lock); return NULL; }
/* Check for an eeh failure at the given token address. * The given value has been read and it should be 1's (0xff, 0xffff or * 0xffffffff). * * Probe to determine if an error actually occurred. If not return val. * Otherwise panic. */ unsigned long eeh_check_failure(void *token, unsigned long val) { unsigned long addr; struct pci_dev *dev; struct device_node *dn; unsigned long ret, rets[2]; /* IO BAR access could get us here...or if we manually force EEH * operation on even if the hardware won't support it. */ if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) return val; /* Finding the phys addr + pci device is quite expensive. * However, the RTAS call is MUCH slower.... :( */ addr = eeh_token_to_phys((unsigned long)token); dev = pci_find_dev_by_addr(addr); if (!dev) { printk("EEH: no pci dev found for addr=0x%lx\n", addr); return val; } dn = pci_device_to_OF_node(dev); if (!dn) { printk("EEH: no pci dn found for addr=0x%lx\n", addr); return val; } /* Access to IO BARs might get this far and still not want checking. */ if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK) return val; /* Now test for an EEH failure. This is VERY expensive. * Note that the eeh_config_addr may be a parent device * in the case of a device behind a bridge, or it may be * function zero of a multi-function device. * In any case they must share a common PHB. */ if (dn->eeh_config_addr) { ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid)); if (ret == 0 && rets[1] == 1 && rets[0] >= 2) { unsigned char slot_err_buf[RTAS_ERROR_LOG_MAX]; unsigned long slot_err_ret; memset(slot_err_buf, 0, RTAS_ERROR_LOG_MAX); slot_err_ret = rtas_call(rtas_token("ibm,slot-error-detail"), 8, 1, dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid), NULL, 0, __pa(slot_err_buf), RTAS_ERROR_LOG_MAX, 2 /* Permanent Error */); if (slot_err_ret == 0) log_error(slot_err_buf, ERR_TYPE_RTAS_LOG, 1 /* Fatal */); panic("EEH: MMIO failure (%ld) on device:\n %s %s\n", rets[0], dev->slot_name, dev->name); } } eeh_false_positives++; return val; /* good case */ }
int rtas_service_present(const char *service) { return rtas_token(service) != RTAS_UNKNOWN_SERVICE; }
struct device_node *dlpar_configure_connector(__be32 drc_index, struct device_node *parent) { struct device_node *dn; struct device_node *first_dn = NULL; struct device_node *last_dn = NULL; struct property *property; struct property *last_property = NULL; struct cc_workarea *ccwa; char *data_buf; const char *parent_path = parent->full_name; int cc_token; int rc = -1; cc_token = rtas_token("ibm,configure-connector"); if (cc_token == RTAS_UNKNOWN_SERVICE) return NULL; data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); if (!data_buf) return NULL; ccwa = (struct cc_workarea *)&data_buf[0]; ccwa->drc_index = drc_index; ccwa->zero = 0; do { /* Since we release the rtas_data_buf lock between configure * connector calls we want to re-populate the rtas_data_buffer * with the contents of the previous call. */ spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE); rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); switch (rc) { case COMPLETE: break; case NEXT_SIBLING: dn = dlpar_parse_cc_node(ccwa, parent_path); if (!dn) goto cc_error; dn->parent = last_dn->parent; last_dn->sibling = dn; last_dn = dn; break; case NEXT_CHILD: if (first_dn) parent_path = last_dn->full_name; dn = dlpar_parse_cc_node(ccwa, parent_path); if (!dn) goto cc_error; if (!first_dn) { dn->parent = parent; first_dn = dn; } else { dn->parent = last_dn; if (last_dn) last_dn->child = dn; } last_dn = dn; break; case NEXT_PROPERTY: property = dlpar_parse_cc_property(ccwa); if (!property) goto cc_error; if (!last_dn->properties) last_dn->properties = property; else last_property->next = property; last_property = property; break; case PREV_PARENT: last_dn = last_dn->parent; parent_path = last_dn->parent->full_name; break; case CALL_AGAIN: break; case MORE_MEMORY: case ERR_CFG_USE: default: printk(KERN_ERR "Unexpected Error (%d) " "returned from configure-connector\n", rc); goto cc_error; } } while (rc); cc_error: kfree(data_buf); if (rc) { if (first_dn) dlpar_free_cc_nodes(first_dn); return NULL; } return first_dn; }
/* Call this when done with the data returned by FWNMI_get_errinfo. * It will release the saved data area for other CPUs in the * partition to receive FWNMI errors. */ static void fwnmi_release_errinfo(void) { int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL); if (ret != 0) printk(KERN_ERR "FWNMI: nmi-interlock failed: %d\n", ret); }
static int rtasd(void *unused) { unsigned int err_type; int cpu = 0; int event_scan = rtas_token("event-scan"); cpumask_t all = CPU_MASK_ALL; int rc; daemonize("rtasd"); if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1) goto error; rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); if (!rtas_log_buf) { printk(KERN_ERR "rtasd: no memory\n"); goto error; } /* We can use rtas_log_buf now */ no_more_logging = 0; printk(KERN_ERR "RTAS daemon started\n"); DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2); /* See if we have any error stored in NVRAM */ memset(logdata, 0, rtas_error_log_max); rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type); if (!rc) { if (err_type != ERR_FLAG_ALREADY_LOGGED) { pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0); } } /* First pass. */ lock_cpu_hotplug(); for_each_online_cpu(cpu) { DEBUG("scheduling on %d\n", cpu); set_cpus_allowed(current, cpumask_of_cpu(cpu)); DEBUG("watchdog scheduled on cpu %d\n", smp_processor_id()); do_event_scan(event_scan); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } unlock_cpu_hotplug(); if (surveillance_timeout != -1) { DEBUG("enabling surveillance\n"); enable_surveillance(surveillance_timeout); DEBUG("surveillance enabled\n"); } lock_cpu_hotplug(); cpu = first_cpu_const(mk_cpumask_const(cpu_online_map)); for (;;) { set_cpus_allowed(current, cpumask_of_cpu(cpu)); do_event_scan(event_scan); set_cpus_allowed(current, all); /* Drop hotplug lock, and sleep for a bit (at least * one second since some machines have problems if we * call event-scan too quickly). */ unlock_cpu_hotplug(); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout((HZ*60/rtas_event_scan_rate) / 2); lock_cpu_hotplug(); cpu = next_cpu_const(cpu, mk_cpumask_const(cpu_online_map)); if (cpu == NR_CPUS) cpu = first_cpu_const(mk_cpumask_const(cpu_online_map)); } error: /* Should delete proc entries */ return -EINVAL; }
static int update_dt_node(__be32 phandle, s32 scope) { struct update_props_workarea *upwa; struct device_node *dn; struct property *prop = NULL; int i, rc, rtas_rc; char *prop_data; char *rtas_buf; int update_properties_token; u32 nprops; u32 vd; update_properties_token = rtas_token("ibm,update-properties"); if (update_properties_token == RTAS_UNKNOWN_SERVICE) return -EINVAL; rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); if (!rtas_buf) return -ENOMEM; dn = of_find_node_by_phandle(be32_to_cpu(phandle)); if (!dn) { kfree(rtas_buf); return -ENOENT; } upwa = (struct update_props_workarea *)&rtas_buf[0]; upwa->phandle = phandle; do { rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf, scope); if (rtas_rc < 0) break; prop_data = rtas_buf + sizeof(*upwa); nprops = be32_to_cpu(upwa->nprops); /* On the first call to ibm,update-properties for a node the * the first property value descriptor contains an empty * property name, the property value length encoded as u32, * and the property value is the node path being updated. */ if (*prop_data == 0) { prop_data++; vd = be32_to_cpu(*(__be32 *)prop_data); prop_data += vd + sizeof(vd); nprops--; } for (i = 0; i < nprops; i++) { char *prop_name; prop_name = prop_data; prop_data += strlen(prop_name) + 1; vd = be32_to_cpu(*(__be32 *)prop_data); prop_data += sizeof(vd); switch (vd) { case 0x00000000: /* name only property, nothing to do */ break; case 0x80000000: prop = of_find_property(dn, prop_name, NULL); of_remove_property(dn, prop); prop = NULL; break; default: rc = update_dt_property(dn, &prop, prop_name, vd, prop_data); if (rc) { printk(KERN_ERR "Could not update %s" " property\n", prop_name); } prop_data += vd; } } } while (rtas_rc == 1); of_node_put(dn); kfree(rtas_buf); return 0; }
static int update_dt_node(u32 phandle) { struct update_props_workarea *upwa; struct device_node *dn; struct property *prop = NULL; int i, rc; char *prop_data; char *rtas_buf; int update_properties_token; update_properties_token = rtas_token("ibm,update-properties"); if (update_properties_token == RTAS_UNKNOWN_SERVICE) return -EINVAL; rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); if (!rtas_buf) return -ENOMEM; dn = of_find_node_by_phandle(phandle); if (!dn) { kfree(rtas_buf); return -ENOENT; } upwa = (struct update_props_workarea *)&rtas_buf[0]; upwa->phandle = phandle; do { rc = mobility_rtas_call(update_properties_token, rtas_buf); if (rc < 0) break; prop_data = rtas_buf + sizeof(*upwa); for (i = 0; i < upwa->nprops; i++) { char *prop_name; u32 vd; prop_name = prop_data + 1; prop_data += strlen(prop_name) + 1; vd = *prop_data++; switch (vd) { case 0x00000000: /* name only property, nothing to do */ break; case 0x80000000: prop = of_find_property(dn, prop_name, NULL); prom_remove_property(dn, prop); prop = NULL; break; default: rc = update_dt_property(dn, &prop, prop_name, vd, prop_data); if (rc) { printk(KERN_ERR "Could not update %s" " property\n", prop_name); } prop_data += vd; } } } while (rc == 1); of_node_put(dn); kfree(rtas_buf); return 0; }
void xics_init_IRQ( void ) { int i; unsigned long intr_size = 0; struct device_node *np; uint *ireg, ilen, indx=0; ppc64_boot_msg(0x20, "XICS Init"); ibm_get_xive = rtas_token("ibm,get-xive"); ibm_set_xive = rtas_token("ibm,set-xive"); ibm_int_on = rtas_token("ibm,int-on"); 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_real = -1; 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 (systemcfg->platform == PLATFORM_PSERIES) { #ifdef CONFIG_SMP for (i = 0; i < systemcfg->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 (systemcfg->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 ppc64_boot_msg(0x21, "XICS Done"); }
static int rtasd(void *unused) { int cpu = 0; int error; int first_pass = 1; int event_scan = rtas_token("event-scan"); if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1) goto error; rtas_log_buf = vmalloc(rtas_error_log_max*LOG_NUMBER); if (!rtas_log_buf) { printk(KERN_ERR "rtasd: no memory\n"); goto error; } DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2); daemonize("rtasd"); #if 0 /* Rusty unreal time task */ current->policy = SCHED_FIFO; current->nice = sys_sched_get_priority_max(SCHED_FIFO) + 1; #endif repeat: for (cpu = 0; cpu < NR_CPUS; cpu++) { if (!cpu_online(cpu)) continue; DEBUG("scheduling on %d\n", cpu); set_cpus_allowed(current, cpumask_of_cpu(cpu)); DEBUG("watchdog scheduled on cpu %d\n", smp_processor_id()); do { memset(logdata, 0, rtas_error_log_max); error = rtas_call(event_scan, 4, 1, NULL, EVENT_SCAN_ALL_EVENTS, 0, __pa(logdata), rtas_error_log_max); if (error == -1) { printk(KERN_ERR "event-scan failed\n"); break; } if (error == 0) log_rtas(logdata); } while(error == 0); /* * Check all cpus for pending events quickly, sleeping for * at least one second since some machines have problems * if we call event-scan too quickly */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(first_pass ? HZ : (HZ*60/rtas_event_scan_rate) / 2); } if (first_pass && surveillance_requested) { DEBUG("enabling surveillance\n"); if (enable_surveillance()) goto error_vfree; DEBUG("surveillance enabled\n"); } first_pass = 0; goto repeat; error_vfree: vfree(rtas_log_buf); error: /* Should delete proc entries */ return -EINVAL; }
/* Call this when done with the data returned by FWNMI_get_errinfo. * It will release the saved data area for other CPUs in the * partition to receive FWNMI errors. */ static void FWNMI_release_errinfo(void) { unsigned long ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL); if (ret != 0) printk("FWNMI: nmi-interlock failed: %ld\n", ret); }
static int rtasd(void *unused) { int cpu = 0; int error; int first_pass = 1; int event_scan = rtas_token("event-scan"); if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1) goto error; rtas_log_buf = vmalloc(rtas_error_log_max*LOG_NUMBER); if (!rtas_log_buf) { printk(KERN_ERR "rtasd: no memory\n"); goto error; } DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2); daemonize(); sigfillset(¤t->blocked); sprintf(current->comm, "rtasd"); /* Rusty unreal time task */ current->policy = SCHED_FIFO; current->nice = sys_sched_get_priority_max(SCHED_FIFO) + 1; cpu = 0; current->cpus_allowed = 1UL << cpu_logical_map(cpu); schedule(); while(1) { do { memset(logdata, 0, rtas_error_log_max); error = rtas_call(event_scan, 4, 1, NULL, EVENT_SCAN_ALL_EVENTS, 0, __pa(logdata), rtas_error_log_max); if (error == -1) { printk(KERN_ERR "event-scan failed\n"); break; } if (error == 0) log_rtas(logdata); } while(error == 0); DEBUG("watchdog scheduled on cpu %d\n", smp_processor_id()); cpu++; if (cpu >= smp_num_cpus) { if (first_pass && surveillance_requested) { DEBUG("enabling surveillance\n"); if (enable_surveillance()) goto error_vfree; DEBUG("surveillance enabled\n"); } first_pass = 0; cpu = 0; } current->cpus_allowed = 1UL << cpu_logical_map(cpu); /* Check all cpus for pending events before sleeping*/ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(first_pass ? HZ : (HZ*60/rtas_event_scan_rate) / 2); } error_vfree: vfree(rtas_log_buf); error: /* Should delete proc entries */ return -EINVAL; }
void rtas_power_off(void) { int ret = rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1); printf("RTAS power-off returned %d\n", ret); }
void rtas_progress(char *s, unsigned short hex) { struct device_node *root; int width; const __be32 *p; char *os; static int display_character, set_indicator; static int display_width, display_lines, form_feed; static const int *row_width; static DEFINE_SPINLOCK(progress_lock); static int current_line; static int pending_newline = 0; /* did last write end with unprinted newline? */ if (!rtas.base) return; if (display_width == 0) { display_width = 0x10; if ((root = of_find_node_by_path("/rtas"))) { if ((p = of_get_property(root, "ibm,display-line-length", NULL))) display_width = be32_to_cpu(*p); if ((p = of_get_property(root, "ibm,form-feed", NULL))) form_feed = be32_to_cpu(*p); if ((p = of_get_property(root, "ibm,display-number-of-lines", NULL))) display_lines = be32_to_cpu(*p); row_width = of_get_property(root, "ibm,display-truncation-length", NULL); of_node_put(root); } display_character = rtas_token("display-character"); set_indicator = rtas_token("set-indicator"); } if (display_character == RTAS_UNKNOWN_SERVICE) { /* use hex display if available */ if (set_indicator != RTAS_UNKNOWN_SERVICE) rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); return; } spin_lock(&progress_lock); /* * Last write ended with newline, but we didn't print it since * it would just clear the bottom line of output. Print it now * instead. * * If no newline is pending and form feed is supported, clear the * display with a form feed; otherwise, print a CR to start output * at the beginning of the line. */ if (pending_newline) { rtas_call(display_character, 1, 1, NULL, '\r'); rtas_call(display_character, 1, 1, NULL, '\n'); pending_newline = 0; } else { current_line = 0; if (form_feed) rtas_call(display_character, 1, 1, NULL, (char)form_feed); else rtas_call(display_character, 1, 1, NULL, '\r'); } if (row_width) width = row_width[current_line]; else width = display_width; os = s; while (*os) { if (*os == '\n' || *os == '\r') { /* If newline is the last character, save it * until next call to avoid bumping up the * display output. */ if (*os == '\n' && !os[1]) { pending_newline = 1; current_line++; if (current_line > display_lines-1) current_line = display_lines-1; spin_unlock(&progress_lock); return; } /* RTAS wants CR-LF, not just LF */ if (*os == '\n') { rtas_call(display_character, 1, 1, NULL, '\r'); rtas_call(display_character, 1, 1, NULL, '\n'); } else { /* CR might be used to re-draw a line, so we'll * leave it alone and not add LF. */ rtas_call(display_character, 1, 1, NULL, *os); } if (row_width) width = row_width[current_line]; else width = display_width; } else { width--; rtas_call(display_character, 1, 1, NULL, *os); } os++; /* if we overwrite the screen length */ if (width <= 0) while ((*os != 0) && (*os != '\n') && (*os != '\r')) os++; } spin_unlock(&progress_lock); }
static void rtas_flash_firmware(void) { unsigned long image_size; struct flash_block_list *f, *next, *flist; unsigned long rtas_block_list; int i, status, update_token; update_token = rtas_token("ibm,update-flash-64-and-reboot"); if (update_token == RTAS_UNKNOWN_SERVICE) { printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?\n"); printk(KERN_ALERT "FLASH: firmware will not be flashed\n"); return; } /* NOTE: the "first" block list is a global var with no data * blocks in the kernel data segment. We do this because * we want to ensure this block_list addr is under 4GB. */ rtas_firmware_flash_list.num_blocks = 0; flist = (struct flash_block_list *)&rtas_firmware_flash_list; rtas_block_list = virt_to_abs(flist); if (rtas_block_list >= 4UL*1024*1024*1024) { printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); return; } printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); /* Update the block_list in place. */ image_size = 0; for (f = flist; f; f = next) { /* Translate data addrs to absolute */ for (i = 0; i < f->num_blocks; i++) { f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data); image_size += f->blocks[i].length; } next = f->next; /* Don't translate NULL pointer for last entry */ if (f->next) f->next = (struct flash_block_list *)virt_to_abs(f->next); else f->next = NULL; /* make num_blocks into the version/length field */ f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16); } printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); printk(KERN_ALERT "FLASH: performing flash and reboot\n"); ppc_md.progress("Flashing \n", 0x0); ppc_md.progress("Please Wait... ", 0x0); printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); switch (status) { /* should only get "bad" status */ case 0: printk(KERN_ALERT "FLASH: success\n"); break; case -1: printk(KERN_ALERT "FLASH: hardware error. Firmware may not be not flashed\n"); break; case -3: printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform. Firmware not flashed\n"); break; case -4: printk(KERN_ALERT "FLASH: flash failed when partially complete. System may not reboot\n"); break; default: printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); break; } }
/****************************************************************** * Find all PHBs in the system and initialize a set of data * structures to represent them. ******************************************************************/ unsigned long __init find_and_init_phbs(void) { struct device_node *Pci_Node; struct pci_controller *phb; unsigned int root_addr_size_words = 0, this_addr_size_words = 0; unsigned int this_addr_count = 0, range_stride; unsigned int *ui_ptr = NULL, *ranges; char *model; struct pci_range64 range; struct resource *res; unsigned int memno, rlen, i, index; unsigned int *opprop; int has_isa = 0; PPCDBG(PPCDBG_PHBINIT, "find_and_init_phbs\n"); read_pci_config = rtas_token("read-pci-config"); write_pci_config = rtas_token("write-pci-config"); ibm_read_pci_config = rtas_token("ibm,read-pci-config"); ibm_write_pci_config = rtas_token("ibm,write-pci-config"); if (naca->interrupt_controller == IC_OPEN_PIC) { opprop = (unsigned int *)get_property(find_path_device("/"), "platform-open-pic", NULL); } /* Get the root address word size. */ ui_ptr = (unsigned int *) get_property(find_path_device("/"), "#size-cells", NULL); if (ui_ptr) { root_addr_size_words = *ui_ptr; } else { PPCDBG(PPCDBG_PHBINIT, "\tget #size-cells failed.\n"); return(-1); } if (find_type_devices("isa")) { has_isa = 1; PPCDBG(PPCDBG_PHBINIT, "\tFound an ISA bus.\n"); } index = 0; /****************************************************************** * Find all PHB devices and create an object for them. ******************************************************************/ for (Pci_Node = find_devices("pci"); Pci_Node != NULL; Pci_Node = Pci_Node->next) { model = (char *) get_property(Pci_Node, "model", NULL); if (model != NULL) { phb = alloc_phb(Pci_Node, model, root_addr_size_words); if (phb == NULL) return(-1); } else { continue; } /* Get this node's address word size. */ ui_ptr = (unsigned int *) get_property(Pci_Node, "#size-cells", NULL); if (ui_ptr) this_addr_size_words = *ui_ptr; else this_addr_size_words = 1; /* Get this node's address word count. */ ui_ptr = (unsigned int *) get_property(Pci_Node, "#address-cells", NULL); if (ui_ptr) this_addr_count = *ui_ptr; else this_addr_count = 3; range_stride = this_addr_count + root_addr_size_words + this_addr_size_words; memno = 0; phb->io_base_phys = 0; ranges = (unsigned int *) get_property(Pci_Node, "ranges", &rlen); PPCDBG(PPCDBG_PHBINIT, "\trange_stride = 0x%lx, rlen = 0x%x\n", range_stride, rlen); for (i = 0; i < (rlen/sizeof(*ranges)); i+=range_stride) { /* Put the PCI addr part of the current element into a * '64' struct. */ range = *((struct pci_range64 *)(ranges + i)); /* If this is a '32' element, map into a 64 struct. */ if ((range_stride * sizeof(int)) == sizeof(struct pci_range32)) { range.parent_addr = (unsigned long)(*(ranges + i + 3)); range.size = (((unsigned long)(*(ranges + i + 4)))<<32) | (*(ranges + i + 5)); } else { range.parent_addr = (((unsigned long)(*(ranges + i + 3)))<<32) | (*(ranges + i + 4)); range.size = (((unsigned long)(*(ranges + i + 5)))<<32) | (*(ranges + i + 6)); } PPCDBG(PPCDBG_PHBINIT, "\trange.parent_addr = 0x%lx\n", range.parent_addr); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.hi = 0x%lx\n", range.child_addr.a_hi); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.mid = 0x%lx\n", range.child_addr.a_mid); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.lo = 0x%lx\n", range.child_addr.a_lo); PPCDBG(PPCDBG_PHBINIT, "\trange.size = 0x%lx\n", range.size); res = NULL; switch ((range.child_addr.a_hi >> 24) & 0x3) { case 1: /* I/O space */ PPCDBG(PPCDBG_PHBINIT, "\tIO Space\n"); phb->io_base_phys = range.parent_addr; res = &phb->io_resource; res->name = Pci_Node->full_name; res->flags = IORESOURCE_IO; phb->io_base_virt = __ioremap(phb->io_base_phys, range.size, _PAGE_NO_CACHE); if (!pci_io_base) { pci_io_base = (unsigned long)phb->io_base_virt; if (has_isa) isa_io_base = pci_io_base; } res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); res->start += (unsigned long)phb->io_base_virt - pci_io_base; res->end = res->start + range.size - 1; res->parent = NULL; res->sibling = NULL; res->child = NULL; phb->pci_io_offset = range.parent_addr - ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); PPCDBG(PPCDBG_PHBINIT, "\tpci_io_offset = 0x%lx\n", phb->pci_io_offset); break; case 2: /* mem space */ PPCDBG(PPCDBG_PHBINIT, "\tMem Space\n"); phb->pci_mem_offset = range.parent_addr - ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); PPCDBG(PPCDBG_PHBINIT, "\tpci_mem_offset = 0x%lx\n", phb->pci_mem_offset); if (memno < sizeof(phb->mem_resources)/sizeof(phb->mem_resources[0])) { res = &(phb->mem_resources[memno]); ++memno; res->name = Pci_Node->full_name; res->flags = IORESOURCE_MEM; res->start = range.parent_addr; res->end = range.parent_addr + range.size - 1; res->parent = NULL; res->sibling = NULL; res->child = NULL; } break; } } PPCDBG(PPCDBG_PHBINIT, "\tphb->io_base_phys = 0x%lx\n", phb->io_base_phys); PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%lx\n", phb->pci_mem_offset); if (naca->interrupt_controller == IC_OPEN_PIC) { int addr = root_addr_size_words * (index + 2) - 1; openpic_setup_ISU(index, opprop[addr]); } index++; } pci_devs_phb_init(); return 0; /*Success */ }