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 bfc2abafac44..67a84d8f118d 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c | |||
@@ -94,12 +94,8 @@ struct flash_block_list { | |||
94 | struct flash_block_list *next; | 94 | struct flash_block_list *next; |
95 | struct flash_block blocks[FLASH_BLOCKS_PER_NODE]; | 95 | struct flash_block blocks[FLASH_BLOCKS_PER_NODE]; |
96 | }; | 96 | }; |
97 | struct flash_block_list_header { /* just the header of flash_block_list */ | ||
98 | unsigned long num_blocks; | ||
99 | struct flash_block_list *next; | ||
100 | }; | ||
101 | 97 | ||
102 | static struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; | 98 | static struct flash_block_list *rtas_firmware_flash_list; |
103 | 99 | ||
104 | /* Use slab cache to guarantee 4k alignment */ | 100 | /* Use slab cache to guarantee 4k alignment */ |
105 | static struct kmem_cache *flash_block_cache = NULL; | 101 | static struct kmem_cache *flash_block_cache = NULL; |
@@ -108,13 +104,14 @@ static struct kmem_cache *flash_block_cache = NULL; | |||
108 | 104 | ||
109 | /* Local copy of the flash block list. | 105 | /* Local copy of the flash block list. |
110 | * We only allow one open of the flash proc file and create this | 106 | * We only allow one open of the flash proc file and create this |
111 | * list as we go. This list will be put in the | 107 | * list as we go. The rtas_firmware_flash_list varable will be |
112 | * rtas_firmware_flash_list var once it is fully read. | 108 | * set once the data is fully read. |
113 | * | 109 | * |
114 | * For convenience as we build the list we use virtual addrs, | 110 | * For convenience as we build the list we use virtual addrs, |
115 | * we do not fill in the version number, and the length field | 111 | * we do not fill in the version number, and the length field |
116 | * is treated as the number of entries currently in the block | 112 | * is treated as the number of entries currently in the block |
117 | * (i.e. not a byte count). This is all fixed on release. | 113 | * (i.e. not a byte count). This is all fixed when calling |
114 | * the flash routine. | ||
118 | */ | 115 | */ |
119 | 116 | ||
120 | /* Status int must be first member of struct */ | 117 | /* Status int must be first member of struct */ |
@@ -201,16 +198,16 @@ static int rtas_flash_release(struct inode *inode, struct file *file) | |||
201 | if (uf->flist) { | 198 | if (uf->flist) { |
202 | /* File was opened in write mode for a new flash attempt */ | 199 | /* File was opened in write mode for a new flash attempt */ |
203 | /* Clear saved list */ | 200 | /* Clear saved list */ |
204 | if (rtas_firmware_flash_list.next) { | 201 | if (rtas_firmware_flash_list) { |
205 | free_flash_list(rtas_firmware_flash_list.next); | 202 | free_flash_list(rtas_firmware_flash_list); |
206 | rtas_firmware_flash_list.next = NULL; | 203 | rtas_firmware_flash_list = NULL; |
207 | } | 204 | } |
208 | 205 | ||
209 | if (uf->status != FLASH_AUTH) | 206 | if (uf->status != FLASH_AUTH) |
210 | uf->status = flash_list_valid(uf->flist); | 207 | uf->status = flash_list_valid(uf->flist); |
211 | 208 | ||
212 | if (uf->status == FLASH_IMG_READY) | 209 | if (uf->status == FLASH_IMG_READY) |
213 | rtas_firmware_flash_list.next = uf->flist; | 210 | rtas_firmware_flash_list = uf->flist; |
214 | else | 211 | else |
215 | free_flash_list(uf->flist); | 212 | free_flash_list(uf->flist); |
216 | 213 | ||
@@ -593,7 +590,7 @@ static void rtas_flash_firmware(int reboot_type) | |||
593 | unsigned long rtas_block_list; | 590 | unsigned long rtas_block_list; |
594 | int i, status, update_token; | 591 | int i, status, update_token; |
595 | 592 | ||
596 | if (rtas_firmware_flash_list.next == NULL) | 593 | if (rtas_firmware_flash_list == NULL) |
597 | return; /* nothing to do */ | 594 | return; /* nothing to do */ |
598 | 595 | ||
599 | if (reboot_type != SYS_RESTART) { | 596 | if (reboot_type != SYS_RESTART) { |
@@ -610,20 +607,25 @@ static void rtas_flash_firmware(int reboot_type) | |||
610 | return; | 607 | return; |
611 | } | 608 | } |
612 | 609 | ||
613 | /* NOTE: the "first" block list is a global var with no data | 610 | /* |
614 | * blocks in the kernel data segment. We do this because | 611 | * NOTE: the "first" block must be under 4GB, so we create |
615 | * we want to ensure this block_list addr is under 4GB. | 612 | * an entry with no data blocks in the reserved buffer in |
613 | * the kernel data segment. | ||
616 | */ | 614 | */ |
617 | rtas_firmware_flash_list.num_blocks = 0; | 615 | spin_lock(&rtas_data_buf_lock); |
618 | flist = (struct flash_block_list *)&rtas_firmware_flash_list; | 616 | flist = (struct flash_block_list *)&rtas_data_buf[0]; |
617 | flist->num_blocks = 0; | ||
618 | flist->next = rtas_firmware_flash_list; | ||
619 | rtas_block_list = virt_to_abs(flist); | 619 | rtas_block_list = virt_to_abs(flist); |
620 | if (rtas_block_list >= 4UL*1024*1024*1024) { | 620 | if (rtas_block_list >= 4UL*1024*1024*1024) { |
621 | printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); | 621 | printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); |
622 | spin_unlock(&rtas_data_buf_lock); | ||
622 | return; | 623 | return; |
623 | } | 624 | } |
624 | 625 | ||
625 | printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); | 626 | printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); |
626 | /* Update the block_list in place. */ | 627 | /* Update the block_list in place. */ |
628 | rtas_firmware_flash_list = NULL; /* too hard to backout on error */ | ||
627 | image_size = 0; | 629 | image_size = 0; |
628 | for (f = flist; f; f = next) { | 630 | for (f = flist; f; f = next) { |
629 | /* Translate data addrs to absolute */ | 631 | /* Translate data addrs to absolute */ |
@@ -664,6 +666,7 @@ static void rtas_flash_firmware(int reboot_type) | |||
664 | printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); | 666 | printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); |
665 | break; | 667 | break; |
666 | } | 668 | } |
669 | spin_unlock(&rtas_data_buf_lock); | ||
667 | } | 670 | } |
668 | 671 | ||
669 | static void remove_flash_pde(struct proc_dir_entry *dp) | 672 | static void remove_flash_pde(struct proc_dir_entry *dp) |