diff options
Diffstat (limited to 'arch/powerpc/kernel/rtas_flash.c')
| -rw-r--r-- | arch/powerpc/kernel/rtas_flash.c | 39 | 
1 files changed, 21 insertions, 18 deletions
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index bfc2abafac4..67a84d8f118 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -94,12 +94,8 @@ struct flash_block_list {  	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}; +static struct flash_block_list *rtas_firmware_flash_list;  /* Use slab cache to guarantee 4k alignment */  static struct kmem_cache *flash_block_cache = NULL; @@ -108,13 +104,14 @@ static struct kmem_cache *flash_block_cache = NULL;  /* 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. + * list as we go.  The rtas_firmware_flash_list varable will be + * set once the data 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. + * (i.e. not a byte count).  This is all fixed when calling  + * the flash routine.   */  /* Status int must be first member of struct */ @@ -201,16 +198,16 @@ static int rtas_flash_release(struct inode *inode, struct file *file)  	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 (rtas_firmware_flash_list) { +			free_flash_list(rtas_firmware_flash_list); +			rtas_firmware_flash_list = 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; +			rtas_firmware_flash_list = uf->flist;  		else  			free_flash_list(uf->flist); @@ -593,7 +590,7 @@ static void rtas_flash_firmware(int reboot_type)  	unsigned long rtas_block_list;  	int i, status, update_token; -	if (rtas_firmware_flash_list.next == NULL) +	if (rtas_firmware_flash_list == NULL)  		return;		/* nothing to do */  	if (reboot_type != SYS_RESTART) { @@ -610,20 +607,25 @@ static void rtas_flash_firmware(int reboot_type)  		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. +	/* +	 * NOTE: the "first" block must be under 4GB, so we create +	 * an entry with no data blocks in the reserved buffer in +	 * the kernel data segment.  	 */ -	rtas_firmware_flash_list.num_blocks = 0; -	flist = (struct flash_block_list *)&rtas_firmware_flash_list; +	spin_lock(&rtas_data_buf_lock); +	flist = (struct flash_block_list *)&rtas_data_buf[0]; +	flist->num_blocks = 0; +	flist->next = 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"); +		spin_unlock(&rtas_data_buf_lock);  		return;  	}  	printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n");  	/* Update the block_list in place. */ +	rtas_firmware_flash_list = NULL; /* too hard to backout on error */  	image_size = 0;  	for (f = flist; f; f = next) {  		/* Translate data addrs to absolute */ @@ -664,6 +666,7 @@ static void rtas_flash_firmware(int reboot_type)  		printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status);  		break;  	} +	spin_unlock(&rtas_data_buf_lock);  }  static void remove_flash_pde(struct proc_dir_entry *dp)  |