Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4fcbbe9 authored by Paul Mackerras's avatar Paul Mackerras
Browse files

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: default avatarPaul Mackerras <paulus@samba.org>
parent 39838299
Loading
Loading
Loading
Loading
+7 −5
Original line number Original line Diff line number Diff line
@@ -278,7 +278,6 @@ config PPC_PSERIES
	select PPC_I8259
	select PPC_I8259
	select PPC_RTAS
	select PPC_RTAS
	select RTAS_ERROR_LOGGING
	select RTAS_ERROR_LOGGING
	select RTAS_FW
	default y
	default y


config PPC_CHRP
config PPC_CHRP
@@ -324,7 +323,6 @@ config PPC_CELL
	bool "  Cell Broadband Processor Architecture"
	bool "  Cell Broadband Processor Architecture"
	depends on PPC_MULTIPLATFORM && PPC64
	depends on PPC_MULTIPLATFORM && PPC64
	select PPC_RTAS
	select PPC_RTAS
	select RTAS_FW
	select MMIO_NVRAM
	select MMIO_NVRAM


config PPC_OF
config PPC_OF
@@ -356,10 +354,14 @@ config RTAS_ERROR_LOGGING
	depends on PPC_RTAS
	depends on PPC_RTAS
	default n
	default n


config RTAS_FW
config RTAS_PROC
	bool
	bool "Proc interface to RTAS"
	depends on PPC_RTAS
	depends on PPC_RTAS
	default n
	default y

config RTAS_FLASH
	tristate "Firmware flash interface"
	depends on PPC64 && RTAS_PROC


config MMIO_NVRAM
config MMIO_NVRAM
	bool
	bool
+2 −1
Original line number Original line Diff line number Diff line
@@ -18,7 +18,8 @@ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
obj-$(CONFIG_POWER4)		+= idle_power4.o
obj-$(CONFIG_POWER4)		+= idle_power4.o
obj-$(CONFIG_PPC_OF)		+= of_device.o
obj-$(CONFIG_PPC_OF)		+= of_device.o
obj-$(CONFIG_PPC_RTAS)		+= rtas.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
obj-$(CONFIG_IBMVIO)		+= vio.o


ifeq ($(CONFIG_PPC_MERGE),y)
ifeq ($(CONFIG_PPC_MERGE),y)
+18 −1
Original line number Original line Diff line number Diff line
@@ -42,6 +42,13 @@ DEFINE_SPINLOCK(rtas_data_buf_lock);
char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
unsigned long rtas_rmo_buf;
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
 * call_rtas_display_status and call_rtas_display_status_delay
 * are designed only for very early low-level debugging, which
 * 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);
	spin_unlock(&progress_lock);
}
}
EXPORT_SYMBOL(rtas_progress);		/* needed by rtas_flash module */


int rtas_token(const char *service)
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)
void rtas_restart(char *cmd)
{
{
	if (rtas_flash_term_hook)
		rtas_flash_term_hook(SYS_RESTART);
	printk("RTAS system-reboot returned %d\n",
	printk("RTAS system-reboot returned %d\n",
	       rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
	       rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
	for (;;);
	for (;;);
@@ -499,6 +509,8 @@ void rtas_restart(char *cmd)


void rtas_power_off(void)
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 */
	/* allow power on only with power button press */
	printk("RTAS power-off returned %d\n",
	printk("RTAS power-off returned %d\n",
	       rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1));
	       rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1));
@@ -507,7 +519,12 @@ void rtas_power_off(void)


void rtas_halt(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 */
/* Must be in the RMO region, so we place it here */
+111 −2
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <asm/delay.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <asm/rtas.h>
#include <asm/rtas.h>
#include <asm/abs_addr.h>


#define MODULE_VERS "1.0"
#define MODULE_VERS "1.0"
#define MODULE_NAME "rtas_flash"
#define MODULE_NAME "rtas_flash"
@@ -71,10 +72,36 @@
#define VALIDATE_BUF_SIZE 4096    
#define VALIDATE_BUF_SIZE 4096    
#define RTAS_MSG_MAXLEN   64
#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.
/* Local copy of the flash block list.
 * We only allow one open of the flash proc file and create this
 * 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
 * list as we go.  This list will be put in the
 * rtas_firmware_flash_list global var once it is fully read.
 * rtas_firmware_flash_list var once it is fully read.
 *
 *
 * For convenience as we build the list we use virtual addrs,
 * For convenience as we build the list we use virtual addrs,
 * we do not fill in the version number, and the length field
 * 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;
	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)
static void remove_flash_pde(struct proc_dir_entry *dp)
{
{
	if (dp) {
	if (dp) {
@@ -701,6 +808,7 @@ int __init rtas_flash_init(void)
	if (rc != 0)
	if (rc != 0)
		goto cleanup;
		goto cleanup;


	rtas_flash_term_hook = rtas_flash_firmware;
	return 0;
	return 0;


cleanup:
cleanup:
@@ -714,6 +822,7 @@ int __init rtas_flash_init(void)


void __exit rtas_flash_cleanup(void)
void __exit rtas_flash_cleanup(void)
{
{
	rtas_flash_term_hook = NULL;
	remove_flash_pde(firmware_flash_pde);
	remove_flash_pde(firmware_flash_pde);
	remove_flash_pde(firmware_update_pde);
	remove_flash_pde(firmware_update_pde);
	remove_flash_pde(validate_pde);
	remove_flash_pde(validate_pde);
Loading