diff options
Diffstat (limited to 'arch/ppc64')
-rw-r--r-- | arch/ppc64/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/ppc64/kernel/rtas-proc.c | 808 | ||||
-rw-r--r-- | arch/ppc64/kernel/rtas_flash.c | 725 | ||||
-rw-r--r-- | arch/ppc64/kernel/rtasd.c | 527 |
4 files changed, 1 insertions, 2063 deletions
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 990df0905c8..74892ad032b 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -29,19 +29,17 @@ ifneq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o endif -obj-$(CONFIG_PPC_PSERIES) += rtasd.o udbg_16550.o +obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o obj-$(CONFIG_KEXEC) += machine_kexec.o obj-$(CONFIG_EEH) += eeh.o obj-$(CONFIG_PROC_FS) += proc_ppc64.o -obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o ifneq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_MODULES) += ppc_ksyms.o endif obj-$(CONFIG_PPC_RTAS) += rtas_pci.o -obj-$(CONFIG_RTAS_PROC) += rtas-proc.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_LPARCFG) += lparcfg.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o diff --git a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c deleted file mode 100644 index 5bdd5b079d9..00000000000 --- a/arch/ppc64/kernel/rtas-proc.c +++ /dev/null @@ -1,808 +0,0 @@ -/* - * arch/ppc64/kernel/rtas-proc.c - * Copyright (C) 2000 Tilmann Bitterberg - * (tilmann@bitterberg.de) - * - * RTAS (Runtime Abstraction Services) stuff - * Intention is to provide a clean user interface - * to use the RTAS. - * - * TODO: - * Split off a header file and maybe move it to a different - * location. Write Documentation on what the /proc/rtas/ entries - * actually do. - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/ctype.h> -#include <linux/time.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/seq_file.h> -#include <linux/bitops.h> -#include <linux/rtc.h> - -#include <asm/uaccess.h> -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/rtas.h> -#include <asm/machdep.h> /* for ppc_md */ -#include <asm/time.h> -#include <asm/systemcfg.h> - -/* Token for Sensors */ -#define KEY_SWITCH 0x0001 -#define ENCLOSURE_SWITCH 0x0002 -#define THERMAL_SENSOR 0x0003 -#define LID_STATUS 0x0004 -#define POWER_SOURCE 0x0005 -#define BATTERY_VOLTAGE 0x0006 -#define BATTERY_REMAINING 0x0007 -#define BATTERY_PERCENTAGE 0x0008 -#define EPOW_SENSOR 0x0009 -#define BATTERY_CYCLESTATE 0x000a -#define BATTERY_CHARGING 0x000b - -/* IBM specific sensors */ -#define IBM_SURVEILLANCE 0x2328 /* 9000 */ -#define IBM_FANRPM 0x2329 /* 9001 */ -#define IBM_VOLTAGE 0x232a /* 9002 */ -#define IBM_DRCONNECTOR 0x232b /* 9003 */ -#define IBM_POWERSUPPLY 0x232c /* 9004 */ - -/* Status return values */ -#define SENSOR_CRITICAL_HIGH 13 -#define SENSOR_WARNING_HIGH 12 -#define SENSOR_NORMAL 11 -#define SENSOR_WARNING_LOW 10 -#define SENSOR_CRITICAL_LOW 9 -#define SENSOR_SUCCESS 0 -#define SENSOR_HW_ERROR -1 -#define SENSOR_BUSY -2 -#define SENSOR_NOT_EXIST -3 -#define SENSOR_DR_ENTITY -9000 - -/* Location Codes */ -#define LOC_SCSI_DEV_ADDR 'A' -#define LOC_SCSI_DEV_LOC 'B' -#define LOC_CPU 'C' -#define LOC_DISKETTE 'D' -#define LOC_ETHERNET 'E' -#define LOC_FAN 'F' -#define LOC_GRAPHICS 'G' -/* reserved / not used 'H' */ -#define LOC_IO_ADAPTER 'I' -/* reserved / not used 'J' */ -#define LOC_KEYBOARD 'K' -#define LOC_LCD 'L' -#define LOC_MEMORY 'M' -#define LOC_NV_MEMORY 'N' -#define LOC_MOUSE 'O' -#define LOC_PLANAR 'P' -#define LOC_OTHER_IO 'Q' -#define LOC_PARALLEL 'R' -#define LOC_SERIAL 'S' -#define LOC_DEAD_RING 'T' -#define LOC_RACKMOUNTED 'U' /* for _u_nit is rack mounted */ -#define LOC_VOLTAGE 'V' -#define LOC_SWITCH_ADAPTER 'W' -#define LOC_OTHER 'X' -#define LOC_FIRMWARE 'Y' -#define LOC_SCSI 'Z' - -/* Tokens for indicators */ -#define TONE_FREQUENCY 0x0001 /* 0 - 1000 (HZ)*/ -#define TONE_VOLUME 0x0002 /* 0 - 100 (%) */ -#define SYSTEM_POWER_STATE 0x0003 -#define WARNING_LIGHT 0x0004 -#define DISK_ACTIVITY_LIGHT 0x0005 -#define HEX_DISPLAY_UNIT 0x0006 -#define BATTERY_WARNING_TIME 0x0007 -#define CONDITION_CYCLE_REQUEST 0x0008 -#define SURVEILLANCE_INDICATOR 0x2328 /* 9000 */ -#define DR_ACTION 0x2329 /* 9001 */ -#define DR_INDICATOR 0x232a /* 9002 */ -/* 9003 - 9004: Vendor specific */ -/* 9006 - 9999: Vendor specific */ - -/* other */ -#define MAX_SENSORS 17 /* I only know of 17 sensors */ -#define MAX_LINELENGTH 256 -#define SENSOR_PREFIX "ibm,sensor-" -#define cel_to_fahr(x) ((x*9/5)+32) - - -/* Globals */ -static struct rtas_sensors sensors; -static struct device_node *rtas_node = NULL; -static unsigned long power_on_time = 0; /* Save the time the user set */ -static char progress_led[MAX_LINELENGTH]; - -static unsigned long rtas_tone_frequency = 1000; -static unsigned long rtas_tone_volume = 0; - -/* ****************STRUCTS******************************************* */ -struct individual_sensor { - unsigned int token; - unsigned int quant; -}; - -struct rtas_sensors { - struct individual_sensor sensor[MAX_SENSORS]; - unsigned int quant; -}; - -/* ****************************************************************** */ -/* Declarations */ -static int ppc_rtas_sensors_show(struct seq_file *m, void *v); -static int ppc_rtas_clock_show(struct seq_file *m, void *v); -static ssize_t ppc_rtas_clock_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static int ppc_rtas_progress_show(struct seq_file *m, void *v); -static ssize_t ppc_rtas_progress_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static int ppc_rtas_poweron_show(struct seq_file *m, void *v); -static ssize_t ppc_rtas_poweron_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); - -static ssize_t ppc_rtas_tone_freq_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static int ppc_rtas_tone_freq_show(struct seq_file *m, void *v); -static ssize_t ppc_rtas_tone_volume_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static int ppc_rtas_tone_volume_show(struct seq_file *m, void *v); -static int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v); - -static int sensors_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_sensors_show, NULL); -} - -struct file_operations ppc_rtas_sensors_operations = { - .open = sensors_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int poweron_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_poweron_show, NULL); -} - -struct file_operations ppc_rtas_poweron_operations = { - .open = poweron_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_poweron_write, - .release = single_release, -}; - -static int progress_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_progress_show, NULL); -} - -struct file_operations ppc_rtas_progress_operations = { - .open = progress_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_progress_write, - .release = single_release, -}; - -static int clock_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_clock_show, NULL); -} - -struct file_operations ppc_rtas_clock_operations = { - .open = clock_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_clock_write, - .release = single_release, -}; - -static int tone_freq_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_tone_freq_show, NULL); -} - -struct file_operations ppc_rtas_tone_freq_operations = { - .open = tone_freq_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_tone_freq_write, - .release = single_release, -}; - -static int tone_volume_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_tone_volume_show, NULL); -} - -struct file_operations ppc_rtas_tone_volume_operations = { - .open = tone_volume_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_tone_volume_write, - .release = single_release, -}; - -static int rmo_buf_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_rmo_buf_show, NULL); -} - -struct file_operations ppc_rtas_rmo_buf_ops = { - .open = rmo_buf_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int ppc_rtas_find_all_sensors(void); -static void ppc_rtas_process_sensor(struct seq_file *m, - struct individual_sensor *s, int state, int error, char *loc); -static char *ppc_rtas_process_error(int error); -static void get_location_code(struct seq_file *m, - struct individual_sensor *s, char *loc); -static void check_location_string(struct seq_file *m, char *c); -static void check_location(struct seq_file *m, char *c); - -static int __init proc_rtas_init(void) -{ - struct proc_dir_entry *entry; - - if (!(systemcfg->platform & PLATFORM_PSERIES)) - return 1; - - rtas_node = of_find_node_by_name(NULL, "rtas"); - if (rtas_node == NULL) - return 1; - - entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_progress_operations; - - entry = create_proc_entry("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_clock_operations; - - entry = create_proc_entry("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_poweron_operations; - - entry = create_proc_entry("ppc64/rtas/sensors", S_IRUGO, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_sensors_operations; - - entry = create_proc_entry("ppc64/rtas/frequency", S_IWUSR|S_IRUGO, - NULL); - if (entry) - entry->proc_fops = &ppc_rtas_tone_freq_operations; - - entry = create_proc_entry("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_tone_volume_operations; - - entry = create_proc_entry("ppc64/rtas/rmo_buffer", S_IRUSR, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_rmo_buf_ops; - - return 0; -} - -__initcall(proc_rtas_init); - -static int parse_number(const char __user *p, size_t count, unsigned long *val) -{ - char buf[40]; - char *end; - - if (count > 39) - return -EINVAL; - - if (copy_from_user(buf, p, count)) - return -EFAULT; - - buf[count] = 0; - - *val = simple_strtoul(buf, &end, 10); - if (*end && *end != '\n') - return -EINVAL; - - return 0; -} - -/* ****************************************************************** */ -/* POWER-ON-TIME */ -/* ****************************************************************** */ -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 int ppc_rtas_poweron_show(struct seq_file *m, void *v) -{ - if (power_on_time == 0) - seq_printf(m, "Power on time not set\n"); - else - seq_printf(m, "%lu\n",power_on_time); - return 0; -} - -/* ****************************************************************** */ -/* PROGRESS */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_progress_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long hex; - - if (count >= MAX_LINELENGTH) - count = MAX_LINELENGTH -1; - if (copy_from_user(progress_led, buf, count)) { /* save the string */ - return -EFAULT; - } - progress_led[count] = 0; - - /* Lets see if the user passed hexdigits */ - hex = simple_strtoul(progress_led, NULL, 10); - - rtas_progress ((char *)progress_led, hex); - return count; - - /* clear the line */ - /* rtas_progress(" ", 0xffff);*/ -} -/* ****************************************************************** */ -static int ppc_rtas_progress_show(struct seq_file *m, void *v) -{ - if (progress_led) - seq_printf(m, "%s\n", progress_led); - return 0; -} - -/* ****************************************************************** */ -/* CLOCK */ -/* ****************************************************************** */ -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; -} - -/* ****************************************************************** */ -/* SENSOR STUFF */ -/* ****************************************************************** */ -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]; - char *loc; - int llen, offs; - - sprintf (rstr, SENSOR_PREFIX"%04d", p->token); - loc = (char *) 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 ppc_rtas_find_all_sensors(void) -{ - unsigned int *utmp; - int len, i; - - utmp = (unsigned int *) get_property(rtas_node, "rtas-sensors", &len); - if (utmp == NULL) { - printk (KERN_ERR "error: could not get rtas-sensors\n"); - return 1; - } - - sensors.quant = len / 8; /* int + int */ - - for (i=0; i<sensors.quant; i++) { - sensors.sensor[i].token = *utmp++; - sensors.sensor[i].quant = *utmp++; - } - return 0; -} - -/* ****************************************************************** */ -/* - * Builds a string of what rtas returned - */ -static char *ppc_rtas_process_error(int error) -{ - switch (error) { - case SENSOR_CRITICAL_HIGH: - return "(critical high)"; - case SENSOR_WARNING_HIGH: - return "(warning high)"; - case SENSOR_NORMAL: - return "(normal)"; - case SENSOR_WARNING_LOW: - return "(warning low)"; - case SENSOR_CRITICAL_LOW: - return "(critical low)"; - case SENSOR_SUCCESS: - return "(read ok)"; - case SENSOR_HW_ERROR: - return "(hardware error)"; - case SENSOR_BUSY: - return "(busy)"; - case SENSOR_NOT_EXIST: - return "(non existent)"; - case SENSOR_DR_ENTITY: - return "(dr entity removed)"; - default: - return "(UNKNOWN)"; - } -} - -/* ****************************************************************** */ -/* - * Builds a string out of what the sensor said - */ - -static void ppc_rtas_process_sensor(struct seq_file *m, - struct individual_sensor *s, int state, int error, char *loc) -{ - /* Defined return vales */ - const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t", - "Maintenance" }; - const char * enclosure_switch[] = { "Closed", "Open" }; - const char * lid_status[] = { " ", "Open", "Closed" }; - const char * power_source[] = { "AC\t", "Battery", - "AC & Battery" }; - const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" }; - const char * epow_sensor[] = { - "EPOW Reset", "Cooling warning", "Power warning", - "System shutdown", "System halt", "EPOW main enclosure", - "EPOW power off" }; - const char * battery_cyclestate[] = { "None", "In progress", - "Requested" }; - const char * battery_charging[] = { "Charging", "Discharching", - "No current flow" }; - const char * ibm_drconnector[] = { "Empty", "Present", "Unusable", - "Exchange" }; - - int have_strings = 0; - int num_states = 0; - int temperature = 0; - int unknown = 0; - - /* What kind of sensor do we have here? */ - - switch (s->token) { - case KEY_SWITCH: - seq_printf(m, "Key switch:\t"); - num_states = sizeof(key_switch) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", key_switch[state]); - have_strings = 1; - } - break; - case ENCLOSURE_SWITCH: - seq_printf(m, "Enclosure switch:\t"); - num_states = sizeof(enclosure_switch) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - enclosure_switch[state]); - have_strings = 1; - } - break; - case THERMAL_SENSOR: - seq_printf(m, "Temp. (C/F):\t"); - temperature = 1; - break; - case LID_STATUS: - seq_printf(m, "Lid status:\t"); - num_states = sizeof(lid_status) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", lid_status[state]); - have_strings = 1; - } - break; - case POWER_SOURCE: - seq_printf(m, "Power source:\t"); - num_states = sizeof(power_source) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - power_source[state]); - have_strings = 1; - } - break; - case BATTERY_VOLTAGE: - seq_printf(m, "Battery voltage:\t"); - break; - case BATTERY_REMAINING: - seq_printf(m, "Battery remaining:\t"); - num_states = sizeof(battery_remaining) / sizeof(char *); - if (state < num_states) - { - seq_printf(m, "%s\t", - battery_remaining[state]); - have_strings = 1; - } - break; - case BATTERY_PERCENTAGE: - seq_printf(m, "Battery percentage:\t"); - break; - case EPOW_SENSOR: - seq_printf(m, "EPOW Sensor:\t"); - num_states = sizeof(epow_sensor) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", epow_sensor[state]); - have_strings = 1; - } - break; - case BATTERY_CYCLESTATE: - seq_printf(m, "Battery cyclestate:\t"); - num_states = sizeof(battery_cyclestate) / - sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - battery_cyclestate[state]); - have_strings = 1; - } - break; - case BATTERY_CHARGING: - seq_printf(m, "Battery Charging:\t"); - num_states = sizeof(battery_charging) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - battery_charging[state]); - have_strings = 1; - } - break; - case IBM_SURVEILLANCE: - seq_printf(m, "Surveillance:\t"); - break; - case IBM_FANRPM: - seq_printf(m, "Fan (rpm):\t"); - break; - case IBM_VOLTAGE: - seq_printf(m, "Voltage (mv):\t"); - break; - case IBM_DRCONNECTOR: - seq_printf(m, "DR connector:\t"); - num_states = sizeof(ibm_drconnector) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - ibm_drconnector[state]); - have_strings = 1; - } - break; - case IBM_POWERSUPPLY: - seq_printf(m, "Powersupply:\t"); - break; - default: - seq_printf(m, "Unknown sensor (type %d), ignoring it\n", - s->token); - unknown = 1; - have_strings = 1; - break; - } - if (have_strings == 0) { - if (temperature) { - seq_printf(m, "%4d /%4d\t", state, cel_to_fahr(state)); - } else - seq_printf(m, "%10d\t", state); - } - if (unknown == 0) { - seq_printf(m, "%s\t", ppc_rtas_process_error(error)); - get_location_code(m, s, loc); - } -} - -/* ****************************************************************** */ - -static void check_location(struct seq_file *m, char *c) -{ - switch (c[0]) { - case LOC_PLANAR: - seq_printf(m, "Planar #%c", c[1]); - break; - case LOC_CPU: - seq_printf(m, "CPU #%c", c[1]); - break; - case LOC_FAN: - seq_printf(m, "Fan #%c", c[1]); - break; - case LOC_RACKMOUNTED: - seq_printf(m, "Rack #%c", c[1]); - break; - case LOC_VOLTAGE: - seq_printf(m, "Voltage #%c", c[1]); - break; - case LOC_LCD: - seq_printf(m, "LCD #%c", c[1]); - break; - case '.': - seq_printf(m, "- %c", c[1]); - break; - default: - seq_printf(m, "Unknown location"); - break; - } -} - - -/* ****************************************************************** */ -/* - * Format: - * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ] - * the '.' may be an abbrevation - */ -static void check_location_string(struct seq_file *m, char *c) -{ - while (*c) { - if (isalpha(*c) || *c == '.') - check_location(m, c); - else if (*c == '/' || *c == '-') - seq_printf(m, " at "); - c++; - } -} - - -/* ****************************************************************** */ - -static void get_location_code(struct seq_file *m, struct individual_sensor *s, char *loc) -{ - if (!loc || !*loc) { - seq_printf(m, "---");/* does not have a location */ - } else { - check_location_string(m, loc); - } - seq_putc(m, ' '); -} -/* ****************************************************************** */ -/* INDICATORS - Tone Frequency */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_freq_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long freq; - int error = parse_number(buf, count, &freq); - if (error) - return error; - - rtas_tone_frequency = freq; /* save it for later */ - error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, - TONE_FREQUENCY, 0, freq); - if (error) - printk(KERN_WARNING "error: setting tone frequency returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static int ppc_rtas_tone_freq_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%lu\n", rtas_tone_frequency); - return 0; -} -/* ****************************************************************** */ -/* INDICATORS - Tone Volume */ -/* ****************************************************************** */ -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; -} -/* ****************************************************************** */ -static int ppc_rtas_tone_volume_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%lu\n", rtas_tone_volume); - return 0; -} - -#define RMO_READ_BUF_MAX 30 - -/* RTAS Userspace access */ -static int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%016lx %x\n", rtas_rmo_buf, RTAS_RMOBUF_MAX); - return 0; -} diff --git a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c deleted file mode 100644 index 923e2e201a7..00000000000 --- a/arch/ppc64/kernel/rtas_flash.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM Corp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * /proc/ppc64/rtas/firmware_flash interface - * - * This file implements a firmware_flash interface to pump a firmware - * image into the kernel. At reboot time rtas_restart() will see the - * firmware image and flash it as it reboots (see rtas.c). - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <asm/delay.h> -#include <asm/uaccess.h> -#include <asm/rtas.h> - -#define MODULE_VERS "1.0" -#define MODULE_NAME "rtas_flash" - -#define FIRMWARE_FLASH_NAME "firmware_flash" -#define FIRMWARE_UPDATE_NAME "firmware_update" -#define MANAGE_FLASH_NAME "manage_flash" -#define VALIDATE_FLASH_NAME "validate_flash" - -/* General RTAS Status Codes */ -#define RTAS_RC_SUCCESS 0 -#define RTAS_RC_HW_ERR -1 -#define RTAS_RC_BUSY -2 - -/* Flash image status values */ -#define FLASH_AUTH -9002 /* RTAS Not Service Authority Partition */ -#define FLASH_NO_OP -1099 /* No operation initiated by user */ -#define FLASH_IMG_SHORT -1005 /* Flash image shorter than expected */ -#define FLASH_IMG_BAD_LEN -1004 /* Bad length value in flash list block */ -#define FLASH_IMG_NULL_DATA -1003 /* Bad data value in flash list block */ -#define FLASH_IMG_READY 0 /* Firmware img ready for flash on reboot */ - -/* Manage image status values */ -#define MANAGE_AUTH -9002 /* RTAS Not Service Authority Partition */ -#define MANAGE_ACTIVE_ERR -9001 /* RTAS Cannot Overwrite Active Img */ -#define MANAGE_NO_OP -1099 /* No operation initiated by user */ -#define MANAGE_PARAM_ERR -3 /* RTAS Parameter Error */ -#define MANAGE_HW_ERR -1 /* RTAS Hardware Error */ - -/* Validate image status values */ -#define VALIDATE_AUTH -9002 /* RTAS Not Service Authority Partition */ -#define VALIDATE_NO_OP -1099 /* No operation initiated by the user */ -#define VALIDATE_INCOMPLETE -1002 /* User copied < VALIDATE_BUF_SIZE */ -#define VALIDATE_READY -1001 /* Firmware image ready for validation */ -#define VALIDATE_PARAM_ERR -3 /* RTAS Parameter Error */ -#define VALIDATE_HW_ERR -1 /* RTAS Hardware Error */ -#define VALIDATE_TMP_UPDATE 0 /* Validate Return Status */ -#define VALIDATE_FLASH_AUTH 1 /* Validate Return Status */ -#define VALIDATE_INVALID_IMG 2 /* Validate Return Status */ -#define VALIDATE_CUR_UNKNOWN 3 /* Validate Return Status */ -#define VALIDATE_TMP_COMMIT_DL 4 /* Validate Return Status */ -#define VALIDATE_TMP_COMMIT 5 /* Validate Return Status */ -#define VALIDATE_TMP_UPDATE_DL 6 /* Validate Return Status */ - -/* ibm,manage-flash-image operation tokens */ -#define RTAS_REJECT_TMP_IMG 0 -#define RTAS_COMMIT_TMP_IMG 1 - -/* Array sizes */ -#define VALIDATE_BUF_SIZE 4096 -#define RTAS_MSG_MAXLEN 64 - -/* Local copy of the flash block list. - * We only allow one open of the flash proc file and create this - * list as we go. This list will be put in the kernel's - * rtas_firmware_flash_list global var once it is fully read. - * - * For convenience as we build the list we use virtual addrs, - * we do not fill in the version number, and the length field - * is treated as the number of entries currently in the block - * (i.e. not a byte count). This is all fixed on release. - */ - -/* Status int must be first member of struct */ -struct rtas_update_flash_t -{ - int status; /* Flash update status */ - struct flash_block_list *flist; /* Local copy of flash block list */ -}; - -/* Status int must be first member of struct */ -struct rtas_manage_flash_t -{ - int status; /* Returned status */ - unsigned int op; /* Reject or commit image */ -}; - -/* Status int must be first member of struct */ -struct rtas_validate_flash_t -{ - int status; /* Returned status */ - char buf[VALIDATE_BUF_SIZE]; /* Candidate image buffer */ - unsigned int buf_size; /* Size of image buf */ - unsigned int update_results; /* Update results token */ -}; - -static DEFINE_SPINLOCK(flash_file_open_lock); -static struct proc_dir_entry *firmware_flash_pde; -static struct proc_dir_entry *firmware_update_pde; -static struct proc_dir_entry *validate_pde; -static struct proc_dir_entry *manage_pde; - -/* Do simple sanity checks on the flash image. */ -static int flash_list_valid(struct flash_block_list *flist) -{ - struct flash_block_list *f; - int i; - unsigned long block_size, image_size; - - /* Paranoid self test here. We also collect the image size. */ - image_size = 0; - for (f = flist; f; f = f->next) { - for (i = 0; i < f->num_blocks; i++) { - if (f->blocks[i].data == NULL) { - return FLASH_IMG_NULL_DATA; - } - block_size = f->blocks[i].length; - if (block_size <= 0 || block_size > PAGE_SIZE) { - return FLASH_IMG_BAD_LEN; - } - image_size += block_size; - } - } - - if (image_size < (256 << 10)) { - if (image_size < 2) - return FLASH_NO_OP; - } - - printk(KERN_INFO "FLASH: flash image with %ld bytes stored for hardware flash on reboot\n", image_size); - - return FLASH_IMG_READY; -} - -static void free_flash_list(struct flash_block_list *f) -{ - struct flash_block_list *next; - int i; - - while (f) { - for (i = 0; i < f->num_blocks; i++) - free_page((unsigned long)(f->blocks[i].data)); - next = f->next; - free_page((unsigned long)f); - f = next; - } -} - -static int rtas_flash_release(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_update_flash_t *uf; - - uf = (struct rtas_update_flash_t *) dp->data; - if (uf->flist) { - /* File was opened in write mode for a new flash attempt */ - /* Clear saved list */ - if (rtas_firmware_flash_list.next) { - free_flash_list(rtas_firmware_flash_list.next); - rtas_firmware_flash_list.next = NULL; - } - - if (uf->status != FLASH_AUTH) - uf->status = flash_list_valid(uf->flist); - - if (uf->status == FLASH_IMG_READY) - rtas_firmware_flash_list.next = uf->flist; - else - free_flash_list(uf->flist); - - uf->flist = NULL; - } - - atomic_dec(&dp->count); - return 0; -} - -static void get_flash_status_msg(int status, char *buf) -{ - char *msg; - - switch (status) { - case FLASH_AUTH: - msg = "error: this partition does not have service authority\n"; - break; - case FLASH_NO_OP: - msg = "info: no firmware image for flash\n"; - break; - case FLASH_IMG_SHORT: - msg = "error: flash image short\n"; - break; - case FLASH_IMG_BAD_LEN: - msg = "error: internal error bad length\n"; - break; - case FLASH_IMG_NULL_DATA: - msg = "error: internal error null data\n"; - break; - case FLASH_IMG_READY: - msg = "ready: firmware image ready for flash on reboot\n"; - break; - default: - sprintf(buf, "error: unexpected status value %d\n", status); - return; - } - - strcpy(buf, msg); -} - -/* Reading the proc file will show status (not the firmware contents) */ -static ssize_t rtas_flash_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_update_flash_t *uf; - char msg[RTAS_MSG_MAXLEN]; - int msglen; - - uf = (struct rtas_update_flash_t *) dp->data; - - if (!strcmp(dp->name, FIRMWARE_FLASH_NAME)) { - get_flash_status_msg(uf->status, msg); - } else { /* FIRMWARE_UPDATE_NAME */ - sprintf(msg, "%d\n", uf->status); - } - msglen = strlen(msg); - if (msglen > count) - msglen = count; - - if (ppos && *ppos != 0) - return 0; /* be cheap */ - - if (!access_ok(VERIFY_WRITE, buf, msglen)) - return -EINVAL; - - if (copy_to_user(buf, msg, msglen)) - return -EFAULT; - - if (ppos) - *ppos = msglen; - return msglen; -} - -/* We could be much more efficient here. But to keep this function - * simple we allocate a page to the block list no matter how small the - * count is. If the system is low on memory it will be just as well - * that we fail.... - */ -static ssize_t rtas_flash_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_update_flash_t *uf; - char *p; - int next_free; - struct flash_block_list *fl; - - uf = (struct rtas_update_flash_t *) dp->data; - - if (uf->status == FLASH_AUTH || count == 0) - return count; /* discard data */ - - /* In the case that the image is not ready for flashing, the memory - * allocated for the block list will be freed upon the release of the - * proc file - */ - if (uf->flist == NULL) { - uf->flist = (struct flash_block_list *) get_zeroed_page(GFP_KERNEL); - if (!uf->flist) - return -ENOMEM; - } - - fl = uf->flist; - while (fl->next) - fl = fl->next; /* seek to last block_list for append */ - next_free = fl->num_blocks; - if (next_free == FLASH_BLOCKS_PER_NODE) { - /* Need to allocate another block_list */ - fl->next = (struct flash_block_list *)get_zeroed_page(GFP_KERNEL); - if (!fl->next) - return -ENOMEM; - fl = fl->next; - next_free = 0; - } - - if (count > PAGE_SIZE) - count = PAGE_SIZE; - p = (char *)get_zeroed_page(GFP_KERNEL); - if (!p) - return -ENOMEM; - - if(copy_from_user(p, buffer, count)) { - free_page((unsigned long)p); - return -EFAULT; - } - fl->blocks[next_free].data = p; - fl->blocks[next_free].length = count; - fl->num_blocks++; - - return count; -} - -static int rtas_excl_open(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *dp = PDE(inode); - - /* Enforce exclusive open with use count of PDE */ - spin_lock(&flash_file_open_lock); - if (atomic_read(&dp->count) > 1) { - spin_unlock(&flash_file_open_lock); - return -EBUSY; - } - - atomic_inc(&dp->count); - spin_unlock(&flash_file_open_lock); - - return 0; -} - -static int rtas_excl_release(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *dp = PDE(inode); - - atomic_dec(&dp->count); - - return 0; -} - -static void manage_flash(struct rtas_manage_flash_t *args_buf) -{ - unsigned int wait_time; - s32 rc; - - while (1) { - rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, - 1, NULL, 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; -} - -static ssize_t manage_flash_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_manage_flash_t *args_buf; - char msg[RTAS_MSG_MAXLEN]; - int msglen; - - args_buf = (struct rtas_manage_flash_t *) dp->data; - if (args_buf == NULL) - return 0; - - msglen = sprintf(msg, "%d\n", args_buf->status); - if (msglen > count) - msglen = count; - - if (ppos && *ppos != 0) - return 0; /* be cheap */ - - if (!access_ok(VERIFY_WRITE, buf, msglen)) - return -EINVAL; - - if (copy_to_user(buf, msg, msglen)) - return -EFAULT; - - if (ppos) - *ppos = msglen; - return msglen; -} - -static ssize_t manage_flash_write(struct file *file, const char __user *buf, - size_t count, loff_t *off) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_manage_flash_t *args_buf; - const char reject_str[] = "0"; - const char commit_str[] = "1"; - char stkbuf[10]; - int op; - - args_buf = (struct rtas_manage_flash_t *) dp->data; - if ((args_buf->status == MANAGE_AUTH) || (count == 0)) - return count; - - op = -1; - if (buf) { - if (count > 9) count = 9; - if (copy_from_user (stkbuf, buf, count)) { - return -EFAULT; - } - if (strncmp(stkbuf, reject_str, strlen(reject_str)) == 0) - op = RTAS_REJECT_TMP_IMG; - else if (strncmp(stkbuf, commit_str, strlen(commit_str)) == 0) - op = RTAS_COMMIT_TMP_IMG; - } - - if (op == -1) /* buf is empty, or contains invalid string */ - return -EINVAL; - - args_buf->op = op; - manage_flash(args_buf); - - return count; -} - -static void validate_flash(struct rtas_validate_flash_t *args_buf) -{ - int token = rtas_token("ibm,validate-flash-image"); - unsigned int wait_time; - int update_results; - s32 rc; - - rc = 0; - while(1) { - 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); - - 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; - args_buf->update_results = update_results; -} - -static int get_validate_flash_msg(struct rtas_validate_flash_t *args_buf, - char *msg) -{ - int n; - - if (args_buf->status >= VALIDATE_TMP_UPDATE) { - n = sprintf(msg, "%d\n", args_buf->update_results); - if ((args_buf->update_results >= VALIDATE_CUR_UNKNOWN) || - (args_buf->update_results == VALIDATE_TMP_UPDATE)) - n += sprintf(msg + n, "%s\n", args_buf->buf); - } else { - n = sprintf(msg, "%d\n", args_buf->status); - } - return n; -} - -static ssize_t validate_flash_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_validate_flash_t *args_buf; - char msg[RTAS_MSG_MAXLEN]; - int msglen; - - args_buf = (struct rtas_validate_flash_t *) dp->data; - - if (ppos && *ppos != 0) - return 0; /* be cheap */ - - msglen = get_validate_flash_msg(args_buf, msg); - if (msglen > count) - msglen = count; - - if (!access_ok(VERIFY_WRITE, buf, msglen)) - return -EINVAL; - - if (copy_to_user(buf, msg, msglen)) - return -EFAULT; - - if (ppos) - *ppos = msglen; - return msglen; -} - -static ssize_t validate_flash_write(struct file *file, const char __user *buf, - size_t count, loff_t *off) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_validate_flash_t *args_buf; - int rc; - - args_buf = (struct rtas_validate_flash_t *) dp->data; - - if (dp->data == NULL) { - dp->data = kmalloc(sizeof(struct rtas_validate_flash_t), - GFP_KERNEL); - if (dp->data == NULL) - return -ENOMEM; - } - - /* We are only interested in the first 4K of the - * candidate image */ - if ((*off >= VALIDATE_BUF_SIZE) || - (args_buf->status == VALIDATE_AUTH)) { - *off += count; - return count; - } - - if (*off + count >= VALIDATE_BUF_SIZE) { - count = VALIDATE_BUF_SIZE - *off; - args_buf->status = VALIDATE_READY; - } else { - args_buf->status = VALIDATE_INCOMPLETE; - } - - if (!access_ok(VERIFY_READ, buf, count)) { - rc = -EFAULT; - goto done; - } - if (copy_from_user(args_buf->buf + *off, buf, count)) { - rc = -EFAULT; - goto done; - } - - *off += count; - rc = count; -done: - if (rc < 0) { - kfree(dp->data); - dp->data = NULL; - } - return rc; -} - -static int validate_flash_release(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_validate_flash_t *args_buf; - - args_buf = (struct rtas_validate_flash_t *) dp->data; - - if (args_buf->status == VALIDATE_READY) { - args_buf->buf_size = VALIDATE_BUF_SIZE; - validate_flash(args_buf); - } - - /* The matching atomic_inc was in rtas_excl_open() */ - atomic_dec(&dp->count); - - return 0; -} - -static void remove_flash_pde(struct proc_dir_entry *dp) -{ - if (dp) { - if (dp->data != NULL) - kfree(dp->data); - dp->owner = NULL; - remove_proc_entry(dp->name, dp->parent); - } -} - -static int initialize_flash_pde_data(const char *rtas_call_name, - size_t buf_size, - struct proc_dir_entry *dp) -{ - int *status; - int token; - - dp->data = kmalloc(buf_size, GFP_KERNEL); - if (dp->data == NULL) { - remove_flash_pde(dp); - return -ENOMEM; - } - - memset(dp->data, 0, buf_size); - - /* - * This code assumes that the status int is the first member of the - * struct - */ - status = (int *) dp->data; - token = rtas_token(rtas_call_name); - if (token == RTAS_UNKNOWN_SERVICE) - *status = FLASH_AUTH; - else - *status = FLASH_NO_OP; - - return 0; -} - -static struct proc_dir_entry *create_flash_pde(const char *filename, - struct file_operations *fops) -{ - struct proc_dir_entry *ent = NULL; - - ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, NULL); - if (ent != NULL) { - ent->nlink = 1; - ent->proc_fops = fops; - ent->owner = THIS_MODULE; - } - - return ent; -} - -static struct file_operations rtas_flash_operations = { - .read = rtas_flash_read, - .write = rtas_flash_write, - .open = rtas_excl_open, - .release = rtas_flash_release, -}; - -static struct file_operations manage_flash_operations = { - .read = manage_flash_read, - .write = manage_flash_write, - .open = rtas_excl_open, - .release = rtas_excl_release, -}; - -static struct file_operations validate_flash_operations = { - .read = validate_flash_read, - .write = validate_flash_write, - .open = rtas_excl_open, - .release = validate_flash_release, -}; - -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("ppc64/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("ppc64/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("ppc64/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("ppc64/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; - - 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; -} - -void __exit rtas_flash_cleanup(void) -{ - remove_flash_pde(firmware_flash_pde); - remove_flash_pde(firmware_update_pde); - remove_flash_pde(validate_pde); - remove_flash_pde(manage_pde); -} - -module_init(rtas_flash_init); -module_exit(rtas_flash_cleanup); -MODULE_LICENSE("GPL"); diff --git a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c deleted file mode 100644 index e26b0420b6d..00000000000 --- a/arch/ppc64/kernel/rtasd.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Communication to userspace based on kernel/printk.c - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/poll.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/vmalloc.h> -#include <linux/spinlock.h> -#include <linux/cpu.h> -#include <linux/delay.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/rtas.h> -#include <asm/prom.h> -#include <asm/nvram.h> -#include <asm/atomic.h> -#include <asm/systemcfg.h> - -#if 0 -#define DEBUG(A...) printk(KERN_ERR A) -#else -#define DEBUG(A...) -#endif - -static DEFINE_SPINLOCK(rtasd_log_lock); - -DECLARE_WAIT_QUEUE_HEAD(rtas_log_wait); - -static char *rtas_log_buf; -static unsigned long rtas_log_start; -static unsigned long rtas_log_size; - -static int surveillance_timeout = -1; -static unsigned int rtas_event_scan_rate; -static unsigned int rtas_error_log_max; -static unsigned int rtas_error_log_buffer_max; - -static int full_rtas_msgs = 0; - -extern int no_logging; - -volatile int error_log_cnt = 0; - -/* - * Since we use 32 bit RTAS, the physical address of this must be below - * 4G or else bad things happen. Allocate this in the kernel data and - * make it big enough. - */ -static unsigned char logdata[RTAS_ERROR_LOG_MAX]; - -static int get_eventscan_parms(void); - -static char *rtas_type[] = { - "Unknown", "Retry", "TCE Error", "Internal Device Failure", - "Timeout", "Data Parity", "Address Parity", "Cache Parity", - "Address Invalid", "ECC Uncorrected", "ECC Corrupted", -}; - -static char *rtas_event_type(int type) -{ - if ((type > 0) && (type < 11)) - return rtas_type[type]; - - switch (type) { - case RTAS_TYPE_EPOW: - return "EPOW"; - case RTAS_TYPE_PLATFORM: - return "Platform Error"; - case RTAS_TYPE_IO: - return "I/O Event"; - case RTAS_TYPE_INFO: - return "Platform Information Event"; - case RTAS_TYPE_DEALLOC: - return "Resource Deallocation Event"; - case RTAS_TYPE_DUMP: - return "Dump Notification Event"; - } - - return rtas_type[0]; -} - -/* To see this info, grep RTAS /var/log/messages and each entry - * will be collected together with obvious begin/end. - * There will be a unique identifier on the begin and end lines. - * This will persist across reboots. - * - * format of error logs returned from RTAS: - * bytes (size) : contents - * -------------------------------------------------------- - * 0-7 (8) : rtas_error_log - * 8-47 (40) : extended info - * 48-51 (4) : vendor id - * 52-1023 (vendor specific) : location code and debug data - */ -static void printk_log_rtas(char *buf, int len) -{ - - int i,j,n = 0; - int perline = 16; - char buffer[64]; - char * str = "RTAS event"; - - if (full_rtas_msgs) { - printk(RTAS_DEBUG "%d -------- %s begin --------\n", - error_log_cnt, str); - - /* - * Print perline bytes on each line, each line will start - * with RTAS and a changing number, so syslogd will - * print lines that are otherwise the same. Separate every - * 4 bytes with a space. - */ - for (i = 0; i < len; i++) { - j = i % perline; - if (j == 0) { - memset(buffer, 0, sizeof(buffer)); - n = sprintf(buffer, "RTAS %d:", i/perline); - } - - if ((i % 4) == 0) - n += sprintf(buffer+n, " "); - - n += sprintf(buffer+n, "%02x", (unsigned char)buf[i]); - - if (j == (perline-1)) - printk(KERN_DEBUG "%s\n", buffer); - } - if ((i % perline) != 0) - printk(KERN_DEBUG "%s\n", buffer); - - printk(RTAS_DEBUG "%d -------- %s end ----------\n", - error_log_cnt, str); - } else { - struct rtas_error_log *errlog = (struct rtas_error_log *)buf; - - printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n", - error_log_cnt, rtas_event_type(errlog->type), - errlog->severity); - } -} - -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) { - get_eventscan_parms(); - } - if (len > rtas_error_log_max) - len = rtas_error_log_max; - - return len; -} - -/* - * First write to nvram, if fatal error, that is the only - * place we log the info. The error will be picked up - * on the next reboot by rtasd. If not fatal, run the - * method for the type of error. Currently, only RTAS - * errors have methods implemented, but in the future - * there might be a need to store data in nvram before a - * call to panic(). - * - * XXX We write to nvram periodically, to indicate error has - * been written and sync'd, but there is a possibility - * that if we don't shutdown correctly, a duplicate error - * record will be created on next reboot. - */ -void pSeries_log_error(char *buf, unsigned int err_type, int fatal) -{ - unsigned long offset; - unsigned long s; - int len = 0; - - DEBUG("logging event\n"); - if (buf == NULL) - return; - - spin_lock_irqsave(&rtasd_log_lock, s); - - /* get length and increase count */ - switch (err_type & ERR_TYPE_MASK) { - case ERR_TYPE_RTAS_LOG: - len = log_rtas_len(buf); - if (!(err_type & ERR_FLAG_BOOT)) - error_log_cnt++; - break; - case ERR_TYPE_KERNEL_PANIC: - default: - spin_unlock_irqrestore(&rtasd_log_lock, s); - return; - } - - /* Write error to NVRAM */ - if (!no_logging && !(err_type & ERR_FLAG_BOOT)) - nvram_write_error_log(buf, len, err_type); - - /* - * rtas errors can occur during boot, and we do want to capture - * those somewhere, even if nvram isn't ready (why not?), and even - * if rtasd isn't ready. Put them into the boot log, at least. - */ - if ((err_type & ERR_TYPE_MASK) == ERR_TYPE_RTAS_LOG) - printk_log_rtas(buf, len); - - /* Check to see if we need to or have stopped logging */ - if (fatal || no_logging) { - no_logging = 1; - spin_unlock_irqrestore(&rtasd_log_lock, s); - return; - } - - /* call type specific method for error */ - switch (err_type & ERR_TYPE_MASK) { - case ERR_TYPE_RTAS_LOG: - offset = rtas_error_log_buffer_max * - ((rtas_log_start+rtas_log_size) & LOG_NUMBER_MASK); - - /* First copy over sequence number */ - memcpy(&rtas_log_buf[offset], (void *) &error_log_cnt, sizeof(int)); - - /* Second copy over error log data */ - offset += sizeof(int); - memcpy(&rtas_log_buf[offset], buf, len); - - if (rtas_log_size < LOG_NUMBER) - rtas_log_size += 1; - else - rtas_log_start += 1; - - spin_unlock_irqrestore(&rtasd_log_lock, s); - wake_up_interruptible(&rtas_log_wait); - break; - case ERR_TYPE_KERNEL_PANIC: - default: - spin_unlock_irqrestore(&rtasd_log_lock, s); - return; - } - -} - - -static int rtas_log_open(struct inode * inode, struct file * file) -{ - return 0; -} - -static int rtas_log_release(struct inode * inode, struct file * file) -{ - return 0; -} - -/* This will check if all events are logged, if they are then, we - * know that we can safely clear the events in NVRAM. - * Next we'll sit and wait for something else to log. - */ -static ssize_t rtas_log_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - int error; - char *tmp; - unsigned long s; - unsigned long offset; - - if (!buf || count < rtas_error_log_buffer_max) - return -EINVAL; - - count = rtas_error_log_buffer_max; - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - - tmp = kmalloc(count, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - - spin_lock_irqsave(&rtasd_log_lock, s); - /* if it's 0, then we know we got the last one (the one in NVRAM) */ - if (rtas_log_size == 0 && !no_logging) - nvram_clear_error_log(); - spin_unlock_irqrestore(&rtasd_log_lock, s); - - - error = wait_event_interruptible(rtas_log_wait, rtas_log_size); - if (error) - goto out; - - spin_lock_irqsave(&rtasd_log_lock, s); - offset = rtas_error_log_buffer_max * (rtas_log_start & LOG_NUMBER_MASK); - memcpy(tmp, &rtas_log_buf[offset], count); - - rtas_log_start += 1; - rtas_log_size -= 1; - spin_unlock_irqrestore(&rtasd_log_lock, s); - - error = copy_to_user(buf, tmp, count) ? -EFAULT : count; -out: - kfree(tmp); - return error; -} - -static unsigned int rtas_log_poll(struct file *file, poll_table * wait) -{ - poll_wait(file, &rtas_log_wait, wait); - if (rtas_log_size) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations proc_rtas_log_operations = { - .read = rtas_log_read, - .poll = rtas_log_poll, - .open = rtas_log_open, - .release = rtas_log_release, -}; - -static int enable_surveillance(int timeout) -{ - int error; - - error = rtas_set_indicator(SURVEILLANCE_TOKEN, 0, timeout); - - if (error == 0) - return 0; - - if (error == -EINVAL) { - printk(KERN_INFO "rtasd: surveillance not supported\n"); - return 0; - } - - printk(KERN_ERR "rtasd: could not update surveillance\n"); - return -1; -} - -static int get_eventscan_parms(void) -{ - struct device_node *node; - int *ip; - - node = of_find_node_by_path("/rtas"); - - ip = (int *)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; -} - -static void do_event_scan(int event_scan) -{ - 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 void do_event_scan_all_cpus(long delay) -{ - int cpu; - - lock_cpu_hotplug(); - cpu = first_cpu(cpu_online_map); - for (;;) { - set_cpus_allowed(current, cpumask_of_cpu(cpu)); - do_event_scan(rtas_token("event-scan")); - set_cpus_allowed(current, CPU_MASK_ALL); - - /* Drop hotplug lock, and sleep for the specified delay */ - unlock_cpu_hotplug(); - msleep_interruptible(delay); - lock_cpu_hotplug(); - - cpu = next_cpu(cpu, cpu_online_map); - if (cpu == NR_CPUS) - break; - } - unlock_cpu_hotplug(); -} - -static int rtasd(void *unused) -{ - unsigned int err_type; - int event_scan = rtas_token("event-scan"); - 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; - } - - printk(KERN_INFO "RTAS daemon started\n"); - - DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); - - /* 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); - - /* We can use rtas_log_buf now */ - no_logging = 0; - - if (!rc) { - if (err_type != ERR_FLAG_ALREADY_LOGGED) { - pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0); - } - } - - /* First pass. */ - do_event_scan_all_cpus(1000); - - if (surveillance_timeout != -1) { - DEBUG("enabling surveillance\n"); - enable_surveillance(surveillance_timeout); - DEBUG("surveillance enabled\n"); - } - - /* Delay should be at least one second since some - * machines have problems if we call event-scan too - * quickly. */ - for (;;) - do_event_scan_all_cpus(30000/rtas_event_scan_rate); - -error: - /* Should delete proc entries */ - return -EINVAL; -} - -static int __init rtas_init(void) -{ - struct proc_dir_entry *entry; - - /* No RTAS, only warn if we are on a pSeries box */ - if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { - if (systemcfg->platform & PLATFORM_PSERIES) - printk(KERN_INFO "rtasd: no event-scan on system\n"); - return 1; - } - - 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 __init surveillance_setup(char *str) -{ - int i; - - if (get_option(&str,&i)) { - if (i >= 0 && i <= 255) - surveillance_timeout = i; - } - - return 1; -} - -static int __init rtasmsgs_setup(char *str) -{ - if (strcmp(str, "on") == 0) - full_rtas_msgs = 1; - else if (strcmp(str, "off") == 0) - full_rtas_msgs = 0; - - return 1; -} -__initcall(rtas_init); -__setup("surveillance=", surveillance_setup); -__setup("rtasmsgs=", rtasmsgs_setup); |