patch-2.4.20 linux-2.4.20/arch/ppc64/kernel/rtas.c
Next file: linux-2.4.20/arch/ppc64/kernel/rtas_flash.c
Previous file: linux-2.4.20/arch/ppc64/kernel/ptrace32.c
Back to the patch index
Back to the overall index
- Lines: 208
- Date:
Thu Nov 28 15:53:11 2002
- Orig file:
linux-2.4.19/arch/ppc64/kernel/rtas.c
- Orig date:
Fri Aug 2 17:39:43 2002
diff -urN linux-2.4.19/arch/ppc64/kernel/rtas.c linux-2.4.20/arch/ppc64/kernel/rtas.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/spinlock.h>
+#include <linux/fs.h>
#include <asm/init.h>
#include <asm/prom.h>
@@ -24,8 +25,12 @@
#include <asm/paca.h>
#include <asm/page.h>
#include <asm/system.h>
+#include <asm/abs_addr.h>
#include <asm/udbg.h>
+struct proc_dir_entry *rtas_proc_dir; /* /proc/ppc64/rtas dir */
+struct flash_block_list_header rtas_firmware_flash_list = {0, 0};
+
/*
* prom_init() is called very early on, before the kernel text
* and data have been mapped to KERNELBASE. At this point the code
@@ -103,18 +108,13 @@
enter_rtas((void *)__pa((unsigned long)rtas));
}
-#if 0
-#define DEBUG_RTAS
-#endif
__openfirmware
int
rtas_token(const char *service)
{
int *tokp;
if (rtas.dev == NULL) {
-#ifdef DEBUG_RTAS
- udbg_printf("\tNo rtas device in device-tree...\n");
-#endif /* DEBUG_RTAS */
+ PPCDBG(PPCDBG_RTAS,"\tNo rtas device in device-tree...\n");
return RTAS_UNKNOWN_SERVICE;
}
tokp = (int *) get_property(rtas.dev, service, NULL);
@@ -131,13 +131,11 @@
unsigned long s;
struct rtas_args *rtas_args = &(get_paca()->xRtas);
-#ifdef DEBUG_RTAS
- udbg_printf("Entering rtas_call\n");
- udbg_printf("\ttoken = 0x%x\n", token);
- udbg_printf("\tnargs = %d\n", nargs);
- udbg_printf("\tnret = %d\n", nret);
- udbg_printf("\t&outputs = 0x%lx\n", outputs);
-#endif /* DEBUG_RTAS */
+ PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n");
+ PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token);
+ PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs);
+ PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret);
+ PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs);
if (token == RTAS_UNKNOWN_SERVICE)
return -1;
@@ -147,10 +145,8 @@
rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]);
va_start(list, outputs);
for (i = 0; i < nargs; ++i) {
- rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
-#ifdef DEBUG_RTAS
- udbg_printf("\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
-#endif /* DEBUG_RTAS */
+ rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
+ PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
}
va_end(list);
@@ -162,22 +158,19 @@
#else
spin_lock_irqsave(&rtas.lock, s);
#endif
-#ifdef DEBUG_RTAS
- udbg_printf("\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args));
-#endif /* DEBUG_RTAS */
+ PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n",
+ (void *)__pa((unsigned long)rtas_args));
enter_rtas((void *)__pa((unsigned long)rtas_args));
-#ifdef DEBUG_RTAS
- udbg_printf("\treturned from rtas ...\n");
-#endif /* DEBUG_RTAS */
+ PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n");
#if 0 /* Gotta do something different here, use global lock for now... */
spin_unlock_irqrestore(&rtas_args->lock, s);
#else
spin_unlock_irqrestore(&rtas.lock, s);
#endif
-#ifdef DEBUG_RTAS
- for(i=0; i < nret ;i++)
- udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
-#endif /* DEBUG_RTAS */
+ ifppcdebug(PPCDBG_RTAS) {
+ for(i=0; i < nret ;i++)
+ udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
+ }
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret-1; ++i)
@@ -185,9 +178,87 @@
return (ulong)((nret > 0) ? rtas_args->rets[0] : 0);
}
+#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_absolute((unsigned long)flist);
+ if (rtas_block_list >= (4UL << 20)) {
+ 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_absolute((unsigned long)f->blocks[i].data);
+ image_size += f->blocks[i].length;
+ }
+ next = f->next;
+ f->next = (struct flash_block_list *)virt_to_absolute((unsigned long)f->next);
+ /* make num_blocks into the version/length field */
+ f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16);
+ }
+
+ printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size);
+ printk(KERN_ALERT "FLASH: performing flash and reboot\n");
+ ppc_md.progress("Flashing \n", 0x0);
+ ppc_md.progress("Please Wait... ", 0x0);
+ printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n");
+ status = rtas_call(update_token, 1, 1, NULL, rtas_block_list);
+ switch (status) { /* should only get "bad" status */
+ case 0:
+ printk(KERN_ALERT "FLASH: success\n");
+ break;
+ case -1:
+ printk(KERN_ALERT "FLASH: hardware error. Firmware may not be not flashed\n");
+ break;
+ case -3:
+ printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform. Firmware not flashed\n");
+ break;
+ case -4:
+ printk(KERN_ALERT "FLASH: flash failed when partially complete. System may not reboot\n");
+ break;
+ default:
+ printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status);
+ break;
+ }
+}
+
+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 __chrp
rtas_restart(char *cmd)
{
+ if (rtas_firmware_flash_list.next)
+ rtas_flash_firmware();
+
printk("RTAS system-reboot returned %ld\n",
rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
for (;;);
@@ -196,6 +267,8 @@
void __chrp
rtas_power_off(void)
{
+ if (rtas_firmware_flash_list.next)
+ rtas_flash_bypass_warning();
/* allow power on only with power button press */
printk("RTAS power-off returned %ld\n",
rtas_call(rtas_token("power-off"), 2, 1, NULL,0xffffffff,0xffffffff));
@@ -205,5 +278,7 @@
void __chrp
rtas_halt(void)
{
+ if (rtas_firmware_flash_list.next)
+ rtas_flash_bypass_warning();
rtas_power_off();
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)