From f4fcbbe9a7fdf11305fea657202b954bdc2228ec Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 3 Nov 2005 14:41:19 +1100 Subject: [PATCH] powerpc: Merge remaining RTAS code 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 --- arch/powerpc/Kconfig | 12 +- arch/powerpc/kernel/Makefile | 3 +- arch/{ppc64 => powerpc}/kernel/rtas-proc.c | 0 arch/powerpc/kernel/rtas.c | 19 ++- arch/{ppc64 => powerpc}/kernel/rtas_flash.c | 113 ++++++++++++++++- arch/powerpc/kernel/rtas_fw.c | 136 --------------------- arch/powerpc/platforms/pseries/Kconfig | 9 -- arch/powerpc/platforms/pseries/Makefile | 2 +- .../kernel => powerpc/platforms/pseries}/rtasd.c | 0 arch/powerpc/platforms/pseries/setup.c | 6 +- arch/ppc64/kernel/Makefile | 4 +- include/asm-powerpc/rtas.h | 28 +---- 12 files changed, 147 insertions(+), 185 deletions(-) rename arch/{ppc64 => powerpc}/kernel/rtas-proc.c (100%) rename arch/{ppc64 => powerpc}/kernel/rtas_flash.c (83%) delete mode 100644 arch/powerpc/kernel/rtas_fw.c rename arch/{ppc64/kernel => powerpc/platforms/pseries}/rtasd.c (100%) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1c44a1d..3cf03ab 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -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 diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index abad305..601ddbf 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -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/ppc64/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c similarity index 100% rename from arch/ppc64/kernel/rtas-proc.c rename to arch/powerpc/kernel/rtas-proc.c diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 4d22eee..b7fc2d8 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -43,6 +43,13 @@ 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 * is why the token is hard-coded to 10. @@ -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/ppc64/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c similarity index 83% rename from arch/ppc64/kernel/rtas_flash.c rename to arch/powerpc/kernel/rtas_flash.c index 923e2e2..5050009 100644 --- a/arch/ppc64/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -19,6 +19,7 @@ #include #include #include +#include #define MODULE_VERS "1.0" #define MODULE_NAME "rtas_flash" @@ -71,10 +72,36 @@ #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 kernel's - * rtas_firmware_flash_list global var once it is fully read. + * 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 @@ -562,6 +589,86 @@ static int validate_flash_release(struct inode *inode, struct file *file) 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) { @@ -701,6 +808,7 @@ int __init rtas_flash_init(void) if (rc != 0) goto cleanup; + rtas_flash_term_hook = rtas_flash_firmware; return 0; cleanup: @@ -714,6 +822,7 @@ cleanup: 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); diff --git a/arch/powerpc/kernel/rtas_fw.c b/arch/powerpc/kernel/rtas_fw.c deleted file mode 100644 index 448922e..0000000 --- a/arch/powerpc/kernel/rtas_fw.c +++ /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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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); diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 2d57f58..e3fc340 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -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 diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 91909a8..b9938fe 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -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/ppc64/kernel/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c similarity index 100% rename from arch/ppc64/kernel/rtasd.c rename to arch/powerpc/platforms/pseries/rtasd.c diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index c0a3d91..f73d691 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -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, diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 990df09..74892ad 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -29,19 +29,17 @@ ifneq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o endif -obj-$(CONFIG_PPC_PSERIES) += rtasd.o udbg_16550.o +obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o obj-$(CONFIG_KEXEC) += machine_kexec.o obj-$(CONFIG_EEH) += eeh.o obj-$(CONFIG_PROC_FS) += proc_ppc64.o -obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o ifneq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_MODULES) += ppc_ksyms.o endif obj-$(CONFIG_PPC_RTAS) += rtas_pci.o -obj-$(CONFIG_RTAS_PROC) += rtas-proc.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_LPARCFG) += lparcfg.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h index d9fd786..d1bb611 100644 --- a/include/asm-powerpc/rtas.h +++ b/include/asm-powerpc/rtas.h @@ -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; -- 2.7.4