|
@@ -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)
|