Skip to content

Commit

Permalink
Merge with Paulus
Browse files Browse the repository at this point in the history
  • Loading branch information
mpe committed Nov 4, 2005
2 parents 30415f6 + d3ab57e commit dc3a9ef
Show file tree
Hide file tree
Showing 34 changed files with 419 additions and 617 deletions.
12 changes: 7 additions & 5 deletions arch/powerpc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions arch/powerpc/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ endif
obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
signal_32.o pmc.o
obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
ptrace32.o systbl.o
signal_64.o ptrace32.o systbl.o
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)
Expand Down
16 changes: 16 additions & 0 deletions include/asm-ppc64/ppc32.h → arch/powerpc/kernel/ppc32.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ typedef struct sigaltstack_32 {
compat_size_t ss_size;
} stack_32_t;

struct pt_regs32 {
unsigned int gpr[32];
unsigned int nip;
unsigned int msr;
unsigned int orig_gpr3; /* Used for restarting system calls */
unsigned int ctr;
unsigned int link;
unsigned int xer;
unsigned int ccr;
unsigned int mq; /* 601 only (not used at present) */
unsigned int trap; /* Reason for being here */
unsigned int dar; /* Fault registers */
unsigned int dsisr;
unsigned int result; /* Result of a system call */
};

struct sigcontext32 {
unsigned int _unused[4];
int signal;
Expand Down
File renamed without changes.
19 changes: 18 additions & 1 deletion arch/powerpc/kernel/rtas.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -492,13 +500,17 @@ 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 (;;);
}

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));
Expand All @@ -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 */
Expand Down
113 changes: 111 additions & 2 deletions arch/ppc64/kernel/rtas_flash.c → arch/powerpc/kernel/rtas_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
Expand All @@ -714,6 +822,7 @@ int __init rtas_flash_init(void)

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);
Expand Down
Loading

0 comments on commit dc3a9ef

Please sign in to comment.