powerpc: Merge remaining RTAS code
authorPaul Mackerras <paulus@samba.org>
Thu, 3 Nov 2005 03:41:19 +0000 (14:41 +1100)
committerPaul Mackerras <paulus@samba.org>
Thu, 3 Nov 2005 03:41:19 +0000 (14:41 +1100)
This moves rtas-proc.c and rtas_flash.c into arch/powerpc/kernel, since
cell wants them as well as pseries (and chrp can use rtas-proc.c too,
at least in principle).  rtas_fw.c is gone, with its bits moved into
rtas_flash.c and rtas.c.

Signed-off-by: Paul Mackerras <paulus@samba.org>
15 files changed:
arch/powerpc/Kconfig
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/rtas-proc.c [new file with mode: 0644]
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/rtas_flash.c [new file with mode: 0644]
arch/powerpc/kernel/rtas_fw.c [deleted file]
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/rtasd.c [new file with mode: 0644]
arch/powerpc/platforms/pseries/setup.c
arch/ppc64/kernel/Makefile
arch/ppc64/kernel/rtas-proc.c [deleted file]
arch/ppc64/kernel/rtas_flash.c [deleted file]
arch/ppc64/kernel/rtasd.c [deleted file]
include/asm-powerpc/rtas.h

index 1c44a1dac4213fc1ad677feab1420cc59fc99367..3cf03ab461132075e84815f3bd2d0f344ece85fe 100644 (file)
@@ -278,7 +278,6 @@ config PPC_PSERIES
        select PPC_I8259
        select PPC_RTAS
        select RTAS_ERROR_LOGGING
-       select RTAS_FW
        default y
 
 config PPC_CHRP
@@ -324,7 +323,6 @@ config PPC_CELL
        bool "  Cell Broadband Processor Architecture"
        depends on PPC_MULTIPLATFORM && PPC64
        select PPC_RTAS
-       select RTAS_FW
        select MMIO_NVRAM
 
 config PPC_OF
@@ -356,10 +354,14 @@ config RTAS_ERROR_LOGGING
        depends on PPC_RTAS
        default n
 
-config RTAS_FW
-       bool
+config RTAS_PROC
+       bool "Proc interface to RTAS"
        depends on PPC_RTAS
-       default n
+       default y
+
+config RTAS_FLASH
+       tristate "Firmware flash interface"
+       depends on PPC64 && RTAS_PROC
 
 config MMIO_NVRAM
        bool
index abad3059a21ad6d304f624dea0c2ae5ecaec7ee8..601ddbf1c20b06740f767ca09c3855d706d09e84 100644 (file)
@@ -18,7 +18,8 @@ obj-$(CONFIG_ALTIVEC)         += vecemu.o vector.o
 obj-$(CONFIG_POWER4)           += idle_power4.o
 obj-$(CONFIG_PPC_OF)           += of_device.o
 obj-$(CONFIG_PPC_RTAS)         += rtas.o
-obj-$(CONFIG_RTAS_FW)          += rtas_fw.o
+obj-$(CONFIG_RTAS_FLASH)       += rtas_flash.o
+obj-$(CONFIG_RTAS_PROC)                += rtas-proc.o
 obj-$(CONFIG_IBMVIO)           += vio.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
new file mode 100644 (file)
index 0000000..5bdd5b0
--- /dev/null
@@ -0,0 +1,808 @@
+/*
+ *   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;
+}
index 4d22eeeeb91ddc6fc9fc85804a3c783ad47130ae..b7fc2d884950c2fa31e935ca7628ace355167610 100644 (file)
@@ -42,6 +42,13 @@ DEFINE_SPINLOCK(rtas_data_buf_lock);
 char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
 unsigned long rtas_rmo_buf;
 
+/*
+ * If non-NULL, this gets called when the kernel terminates.
+ * This is done like this so rtas_flash can be a module.
+ */
+void (*rtas_flash_term_hook)(int);
+EXPORT_SYMBOL(rtas_flash_term_hook);
+
 /*
  * call_rtas_display_status and call_rtas_display_status_delay
  * are designed only for very early low-level debugging, which
@@ -206,6 +213,7 @@ void rtas_progress(char *s, unsigned short hex)
  
        spin_unlock(&progress_lock);
 }
+EXPORT_SYMBOL(rtas_progress);          /* needed by rtas_flash module */
 
 int rtas_token(const char *service)
 {
@@ -492,6 +500,8 @@ int rtas_set_indicator(int indicator, int index, int new_value)
 
 void rtas_restart(char *cmd)
 {
+       if (rtas_flash_term_hook)
+               rtas_flash_term_hook(SYS_RESTART);
        printk("RTAS system-reboot returned %d\n",
               rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
        for (;;);
@@ -499,6 +509,8 @@ void rtas_restart(char *cmd)
 
 void rtas_power_off(void)
 {
+       if (rtas_flash_term_hook)
+               rtas_flash_term_hook(SYS_POWER_OFF);
        /* allow power on only with power button press */
        printk("RTAS power-off returned %d\n",
               rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1));
@@ -507,7 +519,12 @@ void rtas_power_off(void)
 
 void rtas_halt(void)
 {
-       rtas_power_off();
+       if (rtas_flash_term_hook)
+               rtas_flash_term_hook(SYS_HALT);
+       /* allow power on only with power button press */
+       printk("RTAS power-off returned %d\n",
+              rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1));
+       for (;;);
 }
 
 /* Must be in the RMO region, so we place it here */
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
new file mode 100644 (file)
index 0000000..5050009
--- /dev/null
@@ -0,0 +1,834 @@
+/*
+ *  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>
+#include <asm/abs_addr.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
+
+struct flash_block {
+       char *data;
+       unsigned long length;
+};
+
+/* This struct is very similar but not identical to
+ * that needed by the rtas flash update.
+ * All we need to do for rtas is rewrite num_blocks
+ * into a version/length and translate the pointers
+ * to absolute.
+ */
+#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))
+struct flash_block_list {
+       unsigned long num_blocks;
+       struct flash_block_list *next;
+       struct flash_block blocks[FLASH_BLOCKS_PER_NODE];
+};
+struct flash_block_list_header { /* just the header of flash_block_list */
+       unsigned long num_blocks;
+       struct flash_block_list *next;
+};
+
+static struct flash_block_list_header rtas_firmware_flash_list = {0, NULL};
+
+#define FLASH_BLOCK_LIST_VERSION (1UL)
+
+/* 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
+ * rtas_firmware_flash_list 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 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.next == 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;
+       }
+
+       /* 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");
+       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;
+       }
+}
+
+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;
+
+       rtas_flash_term_hook = rtas_flash_firmware;
+       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)
+{
+       rtas_flash_term_hook = NULL;
+       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/powerpc/kernel/rtas_fw.c b/arch/powerpc/kernel/rtas_fw.c
deleted file mode 100644 (file)
index 448922e..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- *
- * Procedures for firmware flash updates.
- *
- * Peter Bergner, IBM  March 2001.
- * Copyright (C) 2001 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.
- */
-
-#include <stdarg.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <asm/prom.h>
-#include <asm/rtas.h>
-#include <asm/semaphore.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/param.h>
-#include <asm/system.h>
-#include <asm/abs_addr.h>
-#include <asm/udbg.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-#include <asm/systemcfg.h>
-
-struct flash_block_list_header rtas_firmware_flash_list = {0, NULL};
-
-#define FLASH_BLOCK_LIST_VERSION (1UL)
-
-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");
-       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;
-       }
-}
-
-void rtas_flash_bypass_warning(void)
-{
-       printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n");
-       printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n");
-}
-
-
-void rtas_fw_restart(char *cmd)
-{
-       if (rtas_firmware_flash_list.next)
-               rtas_flash_firmware();
-       rtas_restart(cmd);
-}
-
-void rtas_fw_power_off(void)
-{
-       if (rtas_firmware_flash_list.next)
-               rtas_flash_bypass_warning();
-       rtas_power_off();
-}
-
-void rtas_fw_halt(void)
-{
-       if (rtas_firmware_flash_list.next)
-               rtas_flash_bypass_warning();
-       rtas_halt();
-}
-
-EXPORT_SYMBOL(rtas_firmware_flash_list);
index 2d57f588151dd6db23f21f6a41bbb26cb988d1cf..e3fc3407bb1f1d65a0929466d724185b4ee62530 100644 (file)
@@ -21,15 +21,6 @@ config EEH
        depends on PPC_PSERIES
        default y if !EMBEDDED
 
-config RTAS_PROC
-       bool "Proc interface to RTAS"
-       depends on PPC_RTAS
-       default y
-
-config RTAS_FLASH
-       tristate "Firmware flash interface"
-       depends on PPC64 && RTAS_PROC
-
 config SCANLOG
        tristate "Scanlog dump interface"
        depends on RTAS_PROC && PPC_PSERIES
index 91909a84473652edbf9031144dde274c3bf3da64..b9938fece781612e1f213a6368af23b124213f08 100644 (file)
@@ -1,5 +1,5 @@
 obj-y                  := pci.o lpar.o hvCall.o nvram.o reconfig.o \
-                          setup.o iommu.o ras.o
+                          setup.o iommu.o ras.o rtasd.o
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_IBMVIO)   += vio.o
 obj-$(CONFIG_XICS)     += xics.o
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
new file mode 100644 (file)
index 0000000..e26b042
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * 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);
index c0a3d918148ad2fac0677fc476d79b1820350b15..f73d69143d35548b40f80b2cdcf8400d5330a5b6 100644 (file)
@@ -589,9 +589,9 @@ struct machdep_calls __initdata pSeries_md = {
        .pcibios_fixup          = pSeries_final_fixup,
        .pci_probe_mode         = pSeries_pci_probe_mode,
        .irq_bus_setup          = pSeries_irq_bus_setup,
-       .restart                = rtas_fw_restart,
-       .power_off              = rtas_fw_power_off,
-       .halt                   = rtas_fw_halt,
+       .restart                = rtas_restart,
+       .power_off              = rtas_power_off,
+       .halt                   = rtas_halt,
        .panic                  = rtas_os_term,
        .cpu_die                = pSeries_mach_cpu_die,
        .get_boot_time          = rtas_get_boot_time,
index 990df0905c874d0873c2ac3edd7f563f66493eff..74892ad032ba8af71b2df9d451ce188f75dc88ef 100644 (file)
@@ -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 (file)
index 5bdd5b0..0000000
+++ /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 (file)
index 923e2e2..0000000
+++ /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 (file)
index e26b042..0000000
+++ /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);
index d9fd7866927ff8b60eaa121d98454d4878a3c1c6..d1bb611ea626190189cf80d36d6982d2f2e607a9 100644 (file)
@@ -149,31 +149,11 @@ struct rtas_error_log {
        unsigned char buffer[1];
 };
 
-struct flash_block {
-       char *data;
-       unsigned long length;
-};
-
-/* This struct is very similar but not identical to
- * that needed by the rtas flash update.
- * All we need to do for rtas is rewrite num_blocks
- * into a version/length and translate the pointers
- * to absolute.
+/*
+ * This can be set by the rtas_flash module so that it can get called
+ * as the absolutely last thing before the kernel terminates.
  */
-#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))
-struct flash_block_list {
-       unsigned long num_blocks;
-       struct flash_block_list *next;
-       struct flash_block blocks[FLASH_BLOCKS_PER_NODE];
-};
-struct flash_block_list_header { /* just the header of flash_block_list */
-       unsigned long num_blocks;
-       struct flash_block_list *next;
-};
-extern struct flash_block_list_header rtas_firmware_flash_list;
-void rtas_fw_restart(char *cmd);
-void rtas_fw_power_off(void);
-void rtas_fw_halt(void);
+extern void (*rtas_flash_term_hook)(int);
 
 extern struct rtas_t rtas;