static void do_event_scan(void) { int error; do { memset(logdata, 0, rtas_error_log_max); error = rtas_call(event_scan, 4, 1, NULL, RTAS_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) pSeries_log_error(logdata, ERR_TYPE_RTAS_LOG, 0); } while(error == 0); }
/* ****************************************************************** */ static ssize_t ppc_rtas_clock_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct rtc_time tm; unsigned long nowtime; int error = parse_number(buf, count, &nowtime); if (error) return error; to_tm(nowtime, &tm); error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 0); if (error) printk(KERN_WARNING "error: setting the clock returned: %s\n", ppc_rtas_process_error(error)); return count; }
/* ****************************************************************** */ static int ppc_rtas_clock_show(struct seq_file *m, void *v) { int ret[8]; int error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); if (error) { printk(KERN_WARNING "error: reading the clock returned: %s\n", ppc_rtas_process_error(error)); seq_printf(m, "0"); } else { unsigned int year, mon, day, hour, min, sec; year = ret[0]; mon = ret[1]; day = ret[2]; hour = ret[3]; min = ret[4]; sec = ret[5]; seq_printf(m, "%lu\n", mktime(year, mon, day, hour, min, sec)); } return 0; }
static void udbg_rtascon_putc(char c) { int tries; if (!rtas.base) return; /* Add CRs before LFs */ if (c == '\n') udbg_rtascon_putc('\r'); /* if there is more than one character to be displayed, wait a bit */ for (tries = 0; tries < 16; tries++) { if (rtas_call(rtas_putchar_token, 1, 1, NULL, c) == 0) break; udelay(1000); } }
static void validate_flash(struct rtas_validate_flash_t *args_buf) { int token = rtas_token("ibm,validate-flash-image"); int update_results; s32 rc; rc = 0; do { spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE); rc = rtas_call(token, 2, 2, &update_results, (u32) __pa(rtas_data_buf), args_buf->buf_size); memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); } while (rtas_busy_delay(rc)); args_buf->status = rc; args_buf->update_results = update_results; }
void xics_disable_irq( u_int virq ) { u_int irq; unsigned long status; long call_status; virq -= XICS_IRQ_OFFSET; irq = virt_irq_to_real(virq); call_status = rtas_call(ibm_int_off, 1, 1, (unsigned long*)&status, irq); if( call_status != 0 ) { printk("xics_disable_irq: irq=%x: rtas_call failed, retn=%lx\n", irq, call_status); return; } }
static int ics_rtas_map(struct ics *ics, unsigned int virq) { unsigned int hw_irq = (unsigned int)virq_to_hw(virq); int status[2]; int rc; if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)) return -EINVAL; /* Check if RTAS knows about this interrupt */ rc = rtas_call(ibm_get_xive, 1, 3, status, hw_irq); if (rc) return -ENXIO; irq_set_chip_and_handler(virq, &ics_rtas_irq_chip, handle_fasteoi_irq); irq_set_chip_data(virq, &ics_rtas); return 0; }
static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) { unsigned int i; unsigned long len; int done; unsigned long flags; char *p = buf; if (nvram_size == 0 || nvram_fetch == RTAS_UNKNOWN_SERVICE) return -ENODEV; if (*index >= nvram_size) return 0; i = *index; if (i + count > nvram_size) count = nvram_size - i; spin_lock_irqsave(&nvram_lock, flags); for (; count != 0; count -= len) { len = count; if (len > NVRW_CNT) len = NVRW_CNT; if ((rtas_call(nvram_fetch, 3, 2, &done, i, __pa(nvram_buf), len) != 0) || len != done) { spin_unlock_irqrestore(&nvram_lock, flags); return -EIO; } memcpy(p, nvram_buf, len); p += len; i += len; } spin_unlock_irqrestore(&nvram_lock, flags); *index = i; return p - buf; }
static void manage_flash(struct rtas_manage_flash_t *args_buf) { unsigned int wait_time; s32 rc; while (1) { rc = (s32) rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1, NULL, (long) args_buf->op); if (rc == RTAS_RC_BUSY) udelay(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); udelay(wait_time * 1000); } else break; } args_buf->status = rc; }
int rtas_errinjct_open(void) { u32 ret[2]; int open_token; int rc; /* The rc and open_token values are backwards due to a misprint in * the RPA */ open_token = rtas_call(rtas_token("ibm,open-errinjct"), 0, 2, (void *) &ret); rc = ret[0]; if (rc < 0) { printk(KERN_WARNING "error: ibm,open-errinjct failed (%d)\n", rc); return rc; } return open_token; }
/* ****************************************************************** */ static ssize_t ppc_rtas_tone_volume_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned long volume; int error = parse_number(buf, count, &volume); if (error) return error; if (volume > 100) volume = 100; rtas_tone_volume = volume; /* save it for later */ error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, TONE_VOLUME, 0, volume); if (error) printk(KERN_WARNING "error: setting tone volume returned: %s\n", ppc_rtas_process_error(error)); return count; }
/** * wdrtas_set_interval - sets the watchdog interval * @interval: new interval * * returns 0 on success, <0 on failures * * wdrtas_set_interval sets the watchdog keepalive interval by calling the * RTAS function set-indicator (surveillance). The unit of interval is * seconds. */ static int wdrtas_set_interval(int interval) { long result; static int print_msg = 10; /* rtas uses minutes */ interval = (interval + 59) / 60; result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL, WDRTAS_SURVEILLANCE_IND, 0, interval); if ( (result < 0) && (print_msg) ) { printk(KERN_ERR "wdrtas: setting the watchdog to %i " "timeout failed: %li\n", interval, result); print_msg--; } return result; }
/** * smp_startup_cpu() - start the given cpu * * At boot time, there is nothing to do for primary threads which were * started from Open Firmware. For anything else, call RTAS with the * appropriate start location. * * Returns: * 0 - failure * 1 - success */ static inline int __devinit smp_startup_cpu(unsigned int lcpu) { int status; unsigned long start_here = __pa((u32)*((unsigned long *) generic_secondary_smp_init)); unsigned int pcpu; int start_cpu; if (cpumask_test_cpu(lcpu, of_spin_mask)) /* Already started by OF and sitting in spin loop */ return 1; pcpu = get_hard_smp_processor_id(lcpu); /* Check to see if the CPU out of FW already for kexec */ if (smp_query_cpu_stopped(pcpu) == QCSS_NOT_STOPPED){ cpumask_set_cpu(lcpu, of_spin_mask); return 1; } /* Fixup atomic count: it exited inside IRQ handler. */ task_thread_info(paca[lcpu].__current)->preempt_count = 0; if (get_cpu_current_state(lcpu) == CPU_STATE_INACTIVE) goto out; /* * If the RTAS start-cpu token does not exist then presume the * cpu is already spinning. */ start_cpu = rtas_token("start-cpu"); if (start_cpu == RTAS_UNKNOWN_SERVICE) return 1; status = rtas_call(start_cpu, 3, 1, NULL, pcpu, start_here, pcpu); if (status != 0) { printk(KERN_ERR "start-cpu failed: %i\n", status); return 0; } out: return 1; }
static ssize_t scanlog_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { unsigned long status; if (buf) { if (strncmp(buf, "reset", 5) == 0) { DEBUG("reset scanlog\n"); status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, NULL, 0); DEBUG("rtas returns %ld\n", status); } else if (strncmp(buf, "debugon", 7) == 0) { printk(KERN_ERR "scanlog: debug on\n"); scanlog_debug = 1; } else if (strncmp(buf, "debugoff", 8) == 0) { printk(KERN_ERR "scanlog: debug off\n"); scanlog_debug = 0; } } return count; }
void rtas_os_term(char *str) { int status; if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term")) return; snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str); do { status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, __pa(rtas_os_term_buf)); if (status == RTAS_BUSY) udelay(1); else if (status != 0) printk(KERN_EMERG "ibm,os-term call failed %d\n", status); } while (status == RTAS_BUSY); }
void rtas_configure_bridge(struct pci_dn *pdn) { int config_addr; int rc; /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; rc = rtas_call(ibm_configure_bridge,3,1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); if (rc) { printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", rc, pdn->node->full_name); } }
/* Query where a cpu is now. Return codes #defined in plpar_wrappers.h */ int smp_query_cpu_stopped(unsigned int pcpu) { int cpu_status, status; int qcss_tok = rtas_token("query-cpu-stopped-state"); if (qcss_tok == RTAS_UNKNOWN_SERVICE) { printk_once(KERN_INFO "Firmware doesn't support query-cpu-stopped-state\n"); return QCSS_HARDWARE_ERROR; } status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu); if (status != 0) { printk(KERN_ERR "RTAS query-cpu-stopped-state failed: %i\n", status); return status; } return cpu_status; }
/** * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable * @dn: device node * @option: operation to be issued * * The function is used to control the EEH functionality globally. * Currently, following options are support according to PAPR: * Enable EEH, Disable EEH, Enable MMIO and Enable DMA */ static int pseries_eeh_set_option(struct device_node *dn, int option) { int ret = 0; struct eeh_dev *edev; const u32 *reg; int config_addr; edev = of_node_to_eeh_dev(dn); /* * When we're enabling or disabling EEH functioality on * the particular PE, the PE config address is possibly * unavailable. Therefore, we have to figure it out from * the FDT node. */ switch (option) { case EEH_OPT_DISABLE: case EEH_OPT_ENABLE: reg = of_get_property(dn, "reg", NULL); config_addr = reg[0]; break; case EEH_OPT_THAW_MMIO: case EEH_OPT_THAW_DMA: config_addr = edev->config_addr; if (edev->pe_config_addr) config_addr = edev->pe_config_addr; break; default: pr_err("%s: Invalid option %d\n", __func__, option); return -EINVAL; } ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), option); return ret; }
/* ****************************************************************** */ static int ppc_rtas_sensors_show(struct seq_file *m, void *v) { int i,j; int state, error; int get_sensor_state = rtas_token("get-sensor-state"); seq_printf(m, "RTAS (RunTime Abstraction Services) Sensor Information\n"); seq_printf(m, "Sensor\t\tValue\t\tCondition\tLocation\n"); seq_printf(m, "********************************************************\n"); if (ppc_rtas_find_all_sensors() != 0) { seq_printf(m, "\nNo sensors are available\n"); return 0; } for (i=0; i<sensors.quant; i++) { struct individual_sensor *p = &sensors.sensor[i]; char rstr[64]; const char *loc; int llen, offs; sprintf (rstr, SENSOR_PREFIX"%04d", p->token); loc = of_get_property(rtas_node, rstr, &llen); /* A sensor may have multiple instances */ for (j = 0, offs = 0; j <= p->quant; j++) { error = rtas_call(get_sensor_state, 2, 2, &state, p->token, j); ppc_rtas_process_sensor(m, p, state, error, loc); seq_putc(m, '\n'); if (loc) { offs += strlen(loc) + 1; loc += strlen(loc) + 1; if (offs >= llen) loc = NULL; } } } return 0; }
static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_when_done) { u16 slb_size = mmu_slb_size; int rc = H_MULTI_THREADS_ACTIVE; int cpu; slb_set_size(SLB_MIN_SIZE); printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n", smp_processor_id()); while (rc == H_MULTI_THREADS_ACTIVE && !data->done) { rc = rtas_call(data->token, 0, 1, NULL); if (rc && rc != H_MULTI_THREADS_ACTIVE) printk(KERN_DEBUG "ibm,suspend-me returned %d\n", rc); } smp_rmb(); if (rc || data->error) slb_set_size(slb_size); if (data->error) rc = data->error; data->error = rc; if (wake_when_done) { smp_wmb(); data->done = 1; /* Ensure data->done is seen on all CPUs that are about to wake up as a result of the H_PROD below */ mb(); for_each_online_cpu(cpu) plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu)); } if (atomic_dec_return(&data->working) == 0) complete(data->complete); return rc; }
int dlpar_release_drc(u32 drc_index) { int dr_status, rc; rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, DR_ENTITY_SENSE, drc_index); if (rc || dr_status != DR_ENTITY_PRESENT) return -1; rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); if (rc) return rc; rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); if (rc) { rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); return rc; } return 0; }
static ssize_t read_nvram(struct file *file, char *buf, size_t count, loff_t *ppos) { unsigned int i; unsigned long len; char *p = buf; if (verify_area(VERIFY_WRITE, buf, count)) return -EFAULT; if (*ppos >= rtas_nvram_size) return 0; for (i = *ppos; count > 0 && i < rtas_nvram_size; ++i, ++p, --count) { if ((rtas_call(nvram_fetch, 3, 2, &len, i, __pa(nvram_buf), 1) != 0) || len != 1) return -EIO; if (__put_user(nvram_buf[0], p)) return -EFAULT; } *ppos = i; return p - buf; }
/* ****************************************************************** */ static ssize_t ppc_rtas_poweron_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct rtc_time tm; unsigned long nowtime; int error = parse_number(buf, count, &nowtime); if (error) return error; power_on_time = nowtime; /* save the time */ to_tm(nowtime, &tm); error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */); if (error) printk(KERN_WARNING "error: setting poweron time returned: %s\n", ppc_rtas_process_error(error)); return count; }
static unsigned char chrp_nvram_read(int addr) { unsigned int done; unsigned long flags; unsigned char ret; if (addr >= nvram_size) { printk(KERN_DEBUG "%s: read addr %d > nvram_size %u\n", current->comm, addr, nvram_size); return 0xff; } spin_lock_irqsave(&nvram_lock, flags); if ((rtas_call(rtas_token("nvram-fetch"), 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done) ret = 0xff; else ret = nvram_buf[0]; spin_unlock_irqrestore(&nvram_lock, flags); return ret; }
static ssize_t scanlog_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { char stkbuf[20]; int status; if (count > 19) count = 19; if (copy_from_user (stkbuf, buf, count)) { return -EFAULT; } stkbuf[count] = 0; if (buf) { if (strncmp(stkbuf, "reset", 5) == 0) { pr_debug("scanlog: reset scanlog\n"); status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, 0, 0); pr_debug("scanlog: rtas returns %d\n", status); } } return count; }
/* * 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; }
int rtas_set_power_level(int powerdomain, int level, int *setlevel) { int token = rtas_token("set-power-level"); unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return RTAS_UNKNOWN_OP; while (1) { rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); if (rc == RTAS_BUSY) udelay(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); udelay(wait_time * 1000); } else break; } return rc; }
int rtas_get_sensor(int sensor, int index, int *state) { int token = rtas_token("get-sensor-state"); unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return RTAS_UNKNOWN_OP; while (1) { rc = rtas_call(token, 2, 2, state, sensor, index); if (rc == RTAS_BUSY) udelay(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); udelay(wait_time * 1000); } else break; } return rc; }
/** * read_slot_reset_state - Read the reset state of a device node's slot * @dn: device node to read * @rets: array to return results in */ static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) { int token, outputs; int config_addr; if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { token = ibm_read_slot_reset_state2; outputs = 4; } else { token = ibm_read_slot_reset_state; rets[2] = 0; /* fake PE Unavailable info */ outputs = 3; } /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; return rtas_call(token, 3, outputs, rets, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); }
void rtas_get_rtc_time(struct rtc_time *rtc_tm) { int ret[8]; int error; unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); wait_time = rtas_busy_delay_time(error); if (wait_time) { if (in_interrupt()) { memset(rtc_tm, 0, sizeof(struct rtc_time)); printk_ratelimited(KERN_WARNING "error: reading clock " "would delay interrupt\n"); return; /* */ } msleep(wait_time); } } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0) { printk_ratelimited(KERN_WARNING "error: reading the clock failed (%d)\n", error); return; } rtc_tm->tm_sec = ret[5]; rtc_tm->tm_min = ret[4]; rtc_tm->tm_hour = ret[3]; rtc_tm->tm_mday = ret[2]; rtc_tm->tm_mon = ret[1] - 1; rtc_tm->tm_year = ret[0] - 1900; }