diff options
author | Abhay Salunke <Abhay_Salunke@dell.com> | 2005-09-16 22:28:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-17 14:50:02 -0400 |
commit | e61c0e336f3931842f09e6709d76146bfd81184e (patch) | |
tree | c5f1083fcf162f80080874b3934bcd7a48893f9f | |
parent | 3013449243adc3421b507696e5d247a3d292ee0c (diff) |
[PATCH] dell_rbu: enhancements and fixes
BUG fixes:
The driver used to allocate memory with spinlock held which has been
fixed in this patch.
The driver was printing the entire buffer when it received a invalid
entry in image_type. The fix is to only print a warning message and not
the buffer.
Usability enhancements:
It is possible that due to user error the /sys/class/firmware/dell_rbu
entries might be missing, this can happen if the user does the following
echo 1 > /sys/class/firmware/dell_rbu/loading
echo 0 > /sys/class/firmware/dell_rbu/loading
This will make the entries in /sys/class/firmware/ to disappear and the
only way get them back was bby unloading and loading the driver.
This patch makes the user recreate these entries by echoing init in to
image_type.
This patch has been tested with Libsmbios and Dell OpenManage.
Signed-off-by: Abhay Salunke <Abhay_Salunke@dell.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | Documentation/dell_rbu.txt | 18 | ||||
-rw-r--r-- | drivers/firmware/dell_rbu.c | 251 |
2 files changed, 167 insertions, 102 deletions
diff --git a/Documentation/dell_rbu.txt b/Documentation/dell_rbu.txt index bcfa5c35036b..95d7f62e4dbc 100644 --- a/Documentation/dell_rbu.txt +++ b/Documentation/dell_rbu.txt | |||
@@ -13,6 +13,8 @@ the BIOS on Dell servers (starting from servers sold since 1999), desktops | |||
13 | and notebooks (starting from those sold in 2005). | 13 | and notebooks (starting from those sold in 2005). |
14 | Please go to http://support.dell.com register and you can find info on | 14 | Please go to http://support.dell.com register and you can find info on |
15 | OpenManage and Dell Update packages (DUP). | 15 | OpenManage and Dell Update packages (DUP). |
16 | Libsmbios can also be used to update BIOS on Dell systems go to | ||
17 | http://linux.dell.com/libsmbios/ for details. | ||
16 | 18 | ||
17 | Dell_RBU driver supports BIOS update using the monilothic image and packetized | 19 | Dell_RBU driver supports BIOS update using the monilothic image and packetized |
18 | image methods. In case of moniolithic the driver allocates a contiguous chunk | 20 | image methods. In case of moniolithic the driver allocates a contiguous chunk |
@@ -22,8 +24,8 @@ would place each packet in contiguous physical memory. The driver also | |||
22 | maintains a link list of packets for reading them back. | 24 | maintains a link list of packets for reading them back. |
23 | If the dell_rbu driver is unloaded all the allocated memory is freed. | 25 | If the dell_rbu driver is unloaded all the allocated memory is freed. |
24 | 26 | ||
25 | The rbu driver needs to have an application which will inform the BIOS to | 27 | The rbu driver needs to have an application (as mentioned above)which will |
26 | enable the update in the next system reboot. | 28 | inform the BIOS to enable the update in the next system reboot. |
27 | 29 | ||
28 | The user should not unload the rbu driver after downloading the BIOS image | 30 | The user should not unload the rbu driver after downloading the BIOS image |
29 | or updating. | 31 | or updating. |
@@ -42,9 +44,11 @@ In case of packet mechanism the single memory can be broken in smaller chuks | |||
42 | of contiguous memory and the BIOS image is scattered in these packets. | 44 | of contiguous memory and the BIOS image is scattered in these packets. |
43 | 45 | ||
44 | By default the driver uses monolithic memory for the update type. This can be | 46 | By default the driver uses monolithic memory for the update type. This can be |
45 | changed to contiguous during the driver load time by specifying the load | 47 | changed to packets during the driver load time by specifying the load |
46 | parameter image_type=packet. This can also be changed later as below | 48 | parameter image_type=packet. This can also be changed later as below |
47 | echo packet > /sys/devices/platform/dell_rbu/image_type | 49 | echo packet > /sys/devices/platform/dell_rbu/image_type |
50 | Also echoing either mono ,packet or init in to image_type will free up the | ||
51 | memory allocated by the driver. | ||
48 | 52 | ||
49 | Do the steps below to download the BIOS image. | 53 | Do the steps below to download the BIOS image. |
50 | 1) echo 1 > /sys/class/firmware/dell_rbu/loading | 54 | 1) echo 1 > /sys/class/firmware/dell_rbu/loading |
@@ -53,9 +57,13 @@ Do the steps below to download the BIOS image. | |||
53 | 57 | ||
54 | The /sys/class/firmware/dell_rbu/ entries will remain till the following is | 58 | The /sys/class/firmware/dell_rbu/ entries will remain till the following is |
55 | done. | 59 | done. |
56 | echo -1 > /sys/class/firmware/dell_rbu/loading | 60 | echo -1 > /sys/class/firmware/dell_rbu/loading. |
57 | |||
58 | Until this step is completed the drivr cannot be unloaded. | 61 | Until this step is completed the drivr cannot be unloaded. |
62 | If an user by accident executes steps 1 and 3 above without executing step 2; | ||
63 | it will make the /sys/class/firmware/dell_rbu/ entries to disappear. | ||
64 | The entries can be recreated by doing the following | ||
65 | echo init > /sys/devices/platform/dell_rbu/image_type | ||
66 | NOTE: echoing init in image_type does not change it original value. | ||
59 | 67 | ||
60 | Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to | 68 | Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to |
61 | read back the image downloaded. This is useful in case of packet update | 69 | read back the image downloaded. This is useful in case of packet update |
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 3b865f34a095..9c2c2b199454 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c | |||
@@ -50,7 +50,7 @@ | |||
50 | MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); | 50 | MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); |
51 | MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); | 51 | MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); |
52 | MODULE_LICENSE("GPL"); | 52 | MODULE_LICENSE("GPL"); |
53 | MODULE_VERSION("1.0"); | 53 | MODULE_VERSION("2.0"); |
54 | 54 | ||
55 | #define BIOS_SCAN_LIMIT 0xffffffff | 55 | #define BIOS_SCAN_LIMIT 0xffffffff |
56 | #define MAX_IMAGE_LENGTH 16 | 56 | #define MAX_IMAGE_LENGTH 16 |
@@ -65,10 +65,11 @@ static struct _rbu_data { | |||
65 | unsigned long packet_write_count; | 65 | unsigned long packet_write_count; |
66 | unsigned long num_packets; | 66 | unsigned long num_packets; |
67 | unsigned long packetsize; | 67 | unsigned long packetsize; |
68 | int entry_created; | ||
68 | } rbu_data; | 69 | } rbu_data; |
69 | 70 | ||
70 | static char image_type[MAX_IMAGE_LENGTH] = "mono"; | 71 | static char image_type[MAX_IMAGE_LENGTH + 1] = "mono"; |
71 | module_param_string(image_type, image_type, sizeof(image_type), 0); | 72 | module_param_string(image_type, image_type, sizeof (image_type), 0); |
72 | MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet"); | 73 | MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet"); |
73 | 74 | ||
74 | struct packet_data { | 75 | struct packet_data { |
@@ -84,7 +85,8 @@ static struct platform_device *rbu_device; | |||
84 | static int context; | 85 | static int context; |
85 | static dma_addr_t dell_rbu_dmaaddr; | 86 | static dma_addr_t dell_rbu_dmaaddr; |
86 | 87 | ||
87 | static void init_packet_head(void) | 88 | static void |
89 | init_packet_head(void) | ||
88 | { | 90 | { |
89 | INIT_LIST_HEAD(&packet_data_head.list); | 91 | INIT_LIST_HEAD(&packet_data_head.list); |
90 | rbu_data.packet_write_count = 0; | 92 | rbu_data.packet_write_count = 0; |
@@ -93,7 +95,8 @@ static void init_packet_head(void) | |||
93 | rbu_data.packetsize = 0; | 95 | rbu_data.packetsize = 0; |
94 | } | 96 | } |
95 | 97 | ||
96 | static int fill_last_packet(void *data, size_t length) | 98 | static int |
99 | fill_last_packet(void *data, size_t length) | ||
97 | { | 100 | { |
98 | struct list_head *ptemp_list; | 101 | struct list_head *ptemp_list; |
99 | struct packet_data *packet = NULL; | 102 | struct packet_data *packet = NULL; |
@@ -114,7 +117,7 @@ static int fill_last_packet(void *data, size_t length) | |||
114 | 117 | ||
115 | if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) { | 118 | if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) { |
116 | pr_debug("dell_rbu:%s: packet size data " | 119 | pr_debug("dell_rbu:%s: packet size data " |
117 | "overrun\n", __FUNCTION__); | 120 | "overrun\n", __FUNCTION__); |
118 | return -EINVAL; | 121 | return -EINVAL; |
119 | } | 122 | } |
120 | 123 | ||
@@ -135,7 +138,8 @@ static int fill_last_packet(void *data, size_t length) | |||
135 | return 0; | 138 | return 0; |
136 | } | 139 | } |
137 | 140 | ||
138 | static int create_packet(size_t length) | 141 | static int |
142 | create_packet(size_t length) | ||
139 | { | 143 | { |
140 | struct packet_data *newpacket; | 144 | struct packet_data *newpacket; |
141 | int ordernum = 0; | 145 | int ordernum = 0; |
@@ -146,12 +150,14 @@ static int create_packet(size_t length) | |||
146 | pr_debug("create_packet: packetsize not specified\n"); | 150 | pr_debug("create_packet: packetsize not specified\n"); |
147 | return -EINVAL; | 151 | return -EINVAL; |
148 | } | 152 | } |
153 | spin_unlock(&rbu_data.lock); | ||
154 | newpacket = kmalloc(sizeof (struct packet_data), GFP_KERNEL); | ||
155 | spin_lock(&rbu_data.lock); | ||
149 | 156 | ||
150 | newpacket = kmalloc(sizeof(struct packet_data), GFP_KERNEL); | ||
151 | if (!newpacket) { | 157 | if (!newpacket) { |
152 | printk(KERN_WARNING | 158 | printk(KERN_WARNING |
153 | "dell_rbu:%s: failed to allocate new " | 159 | "dell_rbu:%s: failed to allocate new " |
154 | "packet\n", __FUNCTION__); | 160 | "packet\n", __FUNCTION__); |
155 | return -ENOMEM; | 161 | return -ENOMEM; |
156 | } | 162 | } |
157 | 163 | ||
@@ -160,15 +166,17 @@ static int create_packet(size_t length) | |||
160 | * there is no upper limit on memory | 166 | * there is no upper limit on memory |
161 | * address for packetized mechanism | 167 | * address for packetized mechanism |
162 | */ | 168 | */ |
163 | newpacket->data = (unsigned char *)__get_free_pages(GFP_KERNEL, | 169 | spin_unlock(&rbu_data.lock); |
164 | ordernum); | 170 | newpacket->data = (unsigned char *) __get_free_pages(GFP_KERNEL, |
171 | ordernum); | ||
172 | spin_lock(&rbu_data.lock); | ||
165 | 173 | ||
166 | pr_debug("create_packet: newpacket %p\n", newpacket->data); | 174 | pr_debug("create_packet: newpacket %p\n", newpacket->data); |
167 | 175 | ||
168 | if (!newpacket->data) { | 176 | if (!newpacket->data) { |
169 | printk(KERN_WARNING | 177 | printk(KERN_WARNING |
170 | "dell_rbu:%s: failed to allocate new " | 178 | "dell_rbu:%s: failed to allocate new " |
171 | "packet\n", __FUNCTION__); | 179 | "packet\n", __FUNCTION__); |
172 | kfree(newpacket); | 180 | kfree(newpacket); |
173 | return -ENOMEM; | 181 | return -ENOMEM; |
174 | } | 182 | } |
@@ -190,7 +198,8 @@ static int create_packet(size_t length) | |||
190 | return 0; | 198 | return 0; |
191 | } | 199 | } |
192 | 200 | ||
193 | static int packetize_data(void *data, size_t length) | 201 | static int |
202 | packetize_data(void *data, size_t length) | ||
194 | { | 203 | { |
195 | int rc = 0; | 204 | int rc = 0; |
196 | 205 | ||
@@ -206,7 +215,7 @@ static int packetize_data(void *data, size_t length) | |||
206 | 215 | ||
207 | static int | 216 | static int |
208 | do_packet_read(char *data, struct list_head *ptemp_list, | 217 | do_packet_read(char *data, struct list_head *ptemp_list, |
209 | int length, int bytes_read, int *list_read_count) | 218 | int length, int bytes_read, int *list_read_count) |
210 | { | 219 | { |
211 | void *ptemp_buf; | 220 | void *ptemp_buf; |
212 | struct packet_data *newpacket = NULL; | 221 | struct packet_data *newpacket = NULL; |
@@ -239,7 +248,8 @@ do_packet_read(char *data, struct list_head *ptemp_list, | |||
239 | return bytes_copied; | 248 | return bytes_copied; |
240 | } | 249 | } |
241 | 250 | ||
242 | static int packet_read_list(char *data, size_t * pread_length) | 251 | static int |
252 | packet_read_list(char *data, size_t * pread_length) | ||
243 | { | 253 | { |
244 | struct list_head *ptemp_list; | 254 | struct list_head *ptemp_list; |
245 | int temp_count = 0; | 255 | int temp_count = 0; |
@@ -258,8 +268,7 @@ static int packet_read_list(char *data, size_t * pread_length) | |||
258 | ptemp_list = (&packet_data_head.list)->next; | 268 | ptemp_list = (&packet_data_head.list)->next; |
259 | while (!list_empty(ptemp_list)) { | 269 | while (!list_empty(ptemp_list)) { |
260 | bytes_copied = do_packet_read(pdest, ptemp_list, | 270 | bytes_copied = do_packet_read(pdest, ptemp_list, |
261 | remaining_bytes, bytes_read, | 271 | remaining_bytes, bytes_read, &temp_count); |
262 | &temp_count); | ||
263 | remaining_bytes -= bytes_copied; | 272 | remaining_bytes -= bytes_copied; |
264 | bytes_read += bytes_copied; | 273 | bytes_read += bytes_copied; |
265 | pdest += bytes_copied; | 274 | pdest += bytes_copied; |
@@ -278,7 +287,8 @@ static int packet_read_list(char *data, size_t * pread_length) | |||
278 | return 0; | 287 | return 0; |
279 | } | 288 | } |
280 | 289 | ||
281 | static void packet_empty_list(void) | 290 | static void |
291 | packet_empty_list(void) | ||
282 | { | 292 | { |
283 | struct list_head *ptemp_list; | 293 | struct list_head *ptemp_list; |
284 | struct list_head *pnext_list; | 294 | struct list_head *pnext_list; |
@@ -287,7 +297,7 @@ static void packet_empty_list(void) | |||
287 | ptemp_list = (&packet_data_head.list)->next; | 297 | ptemp_list = (&packet_data_head.list)->next; |
288 | while (!list_empty(ptemp_list)) { | 298 | while (!list_empty(ptemp_list)) { |
289 | newpacket = | 299 | newpacket = |
290 | list_entry(ptemp_list, struct packet_data, list); | 300 | list_entry(ptemp_list, struct packet_data, list); |
291 | pnext_list = ptemp_list->next; | 301 | pnext_list = ptemp_list->next; |
292 | list_del(ptemp_list); | 302 | list_del(ptemp_list); |
293 | ptemp_list = pnext_list; | 303 | ptemp_list = pnext_list; |
@@ -296,8 +306,8 @@ static void packet_empty_list(void) | |||
296 | * to make sure there are no stale RBU packets left in memory | 306 | * to make sure there are no stale RBU packets left in memory |
297 | */ | 307 | */ |
298 | memset(newpacket->data, 0, rbu_data.packetsize); | 308 | memset(newpacket->data, 0, rbu_data.packetsize); |
299 | free_pages((unsigned long)newpacket->data, | 309 | free_pages((unsigned long) newpacket->data, |
300 | newpacket->ordernum); | 310 | newpacket->ordernum); |
301 | kfree(newpacket); | 311 | kfree(newpacket); |
302 | } | 312 | } |
303 | rbu_data.packet_write_count = 0; | 313 | rbu_data.packet_write_count = 0; |
@@ -310,7 +320,8 @@ static void packet_empty_list(void) | |||
310 | * img_update_free: Frees the buffer allocated for storing BIOS image | 320 | * img_update_free: Frees the buffer allocated for storing BIOS image |
311 | * Always called with lock held and returned with lock held | 321 | * Always called with lock held and returned with lock held |
312 | */ | 322 | */ |
313 | static void img_update_free(void) | 323 | static void |
324 | img_update_free(void) | ||
314 | { | 325 | { |
315 | if (!rbu_data.image_update_buffer) | 326 | if (!rbu_data.image_update_buffer) |
316 | return; | 327 | return; |
@@ -319,14 +330,13 @@ static void img_update_free(void) | |||
319 | * BIOS image copied in memory. | 330 | * BIOS image copied in memory. |
320 | */ | 331 | */ |
321 | memset(rbu_data.image_update_buffer, 0, | 332 | memset(rbu_data.image_update_buffer, 0, |
322 | rbu_data.image_update_buffer_size); | 333 | rbu_data.image_update_buffer_size); |
323 | if (rbu_data.dma_alloc == 1) | 334 | if (rbu_data.dma_alloc == 1) |
324 | dma_free_coherent(NULL, rbu_data.bios_image_size, | 335 | dma_free_coherent(NULL, rbu_data.bios_image_size, |
325 | rbu_data.image_update_buffer, | 336 | rbu_data.image_update_buffer, dell_rbu_dmaaddr); |
326 | dell_rbu_dmaaddr); | ||
327 | else | 337 | else |
328 | free_pages((unsigned long)rbu_data.image_update_buffer, | 338 | free_pages((unsigned long) rbu_data.image_update_buffer, |
329 | rbu_data.image_update_ordernum); | 339 | rbu_data.image_update_ordernum); |
330 | 340 | ||
331 | /* | 341 | /* |
332 | * Re-initialize the rbu_data variables after a free | 342 | * Re-initialize the rbu_data variables after a free |
@@ -348,7 +358,8 @@ static void img_update_free(void) | |||
348 | * already allocated size, then that memory is reused. This function is | 358 | * already allocated size, then that memory is reused. This function is |
349 | * called with lock held and returns with lock held. | 359 | * called with lock held and returns with lock held. |
350 | */ | 360 | */ |
351 | static int img_update_realloc(unsigned long size) | 361 | static int |
362 | img_update_realloc(unsigned long size) | ||
352 | { | 363 | { |
353 | unsigned char *image_update_buffer = NULL; | 364 | unsigned char *image_update_buffer = NULL; |
354 | unsigned long rc; | 365 | unsigned long rc; |
@@ -366,7 +377,7 @@ static int img_update_realloc(unsigned long size) | |||
366 | */ | 377 | */ |
367 | if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { | 378 | if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { |
368 | printk(KERN_ERR "dell_rbu:%s: corruption " | 379 | printk(KERN_ERR "dell_rbu:%s: corruption " |
369 | "check failed\n", __FUNCTION__); | 380 | "check failed\n", __FUNCTION__); |
370 | return -EINVAL; | 381 | return -EINVAL; |
371 | } | 382 | } |
372 | /* | 383 | /* |
@@ -385,17 +396,16 @@ static int img_update_realloc(unsigned long size) | |||
385 | 396 | ||
386 | ordernum = get_order(size); | 397 | ordernum = get_order(size); |
387 | image_update_buffer = | 398 | image_update_buffer = |
388 | (unsigned char *)__get_free_pages(GFP_KERNEL, ordernum); | 399 | (unsigned char *) __get_free_pages(GFP_KERNEL, ordernum); |
389 | 400 | ||
390 | img_buf_phys_addr = | 401 | img_buf_phys_addr = |
391 | (unsigned long)virt_to_phys(image_update_buffer); | 402 | (unsigned long) virt_to_phys(image_update_buffer); |
392 | 403 | ||
393 | if (img_buf_phys_addr > BIOS_SCAN_LIMIT) { | 404 | if (img_buf_phys_addr > BIOS_SCAN_LIMIT) { |
394 | free_pages((unsigned long)image_update_buffer, ordernum); | 405 | free_pages((unsigned long) image_update_buffer, ordernum); |
395 | ordernum = -1; | 406 | ordernum = -1; |
396 | image_update_buffer = dma_alloc_coherent(NULL, size, | 407 | image_update_buffer = dma_alloc_coherent(NULL, size, |
397 | &dell_rbu_dmaaddr, | 408 | &dell_rbu_dmaaddr, GFP_KERNEL); |
398 | GFP_KERNEL); | ||
399 | dma_alloc = 1; | 409 | dma_alloc = 1; |
400 | } | 410 | } |
401 | 411 | ||
@@ -405,20 +415,21 @@ static int img_update_realloc(unsigned long size) | |||
405 | rbu_data.image_update_buffer = image_update_buffer; | 415 | rbu_data.image_update_buffer = image_update_buffer; |
406 | rbu_data.image_update_buffer_size = size; | 416 | rbu_data.image_update_buffer_size = size; |
407 | rbu_data.bios_image_size = | 417 | rbu_data.bios_image_size = |
408 | rbu_data.image_update_buffer_size; | 418 | rbu_data.image_update_buffer_size; |
409 | rbu_data.image_update_ordernum = ordernum; | 419 | rbu_data.image_update_ordernum = ordernum; |
410 | rbu_data.dma_alloc = dma_alloc; | 420 | rbu_data.dma_alloc = dma_alloc; |
411 | rc = 0; | 421 | rc = 0; |
412 | } else { | 422 | } else { |
413 | pr_debug("Not enough memory for image update:" | 423 | pr_debug("Not enough memory for image update:" |
414 | "size = %ld\n", size); | 424 | "size = %ld\n", size); |
415 | rc = -ENOMEM; | 425 | rc = -ENOMEM; |
416 | } | 426 | } |
417 | 427 | ||
418 | return rc; | 428 | return rc; |
419 | } | 429 | } |
420 | 430 | ||
421 | static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) | 431 | static ssize_t |
432 | read_packet_data(char *buffer, loff_t pos, size_t count) | ||
422 | { | 433 | { |
423 | int retval; | 434 | int retval; |
424 | size_t bytes_left; | 435 | size_t bytes_left; |
@@ -438,7 +449,7 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) | |||
438 | if (pos > imagesize) { | 449 | if (pos > imagesize) { |
439 | retval = 0; | 450 | retval = 0; |
440 | printk(KERN_WARNING "dell_rbu:read_packet_data: " | 451 | printk(KERN_WARNING "dell_rbu:read_packet_data: " |
441 | "data underrun\n"); | 452 | "data underrun\n"); |
442 | goto read_rbu_data_exit; | 453 | goto read_rbu_data_exit; |
443 | } | 454 | } |
444 | 455 | ||
@@ -459,7 +470,8 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) | |||
459 | return retval; | 470 | return retval; |
460 | } | 471 | } |
461 | 472 | ||
462 | static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) | 473 | static ssize_t |
474 | read_rbu_mono_data(char *buffer, loff_t pos, size_t count) | ||
463 | { | 475 | { |
464 | unsigned char *ptemp = NULL; | 476 | unsigned char *ptemp = NULL; |
465 | size_t bytes_left = 0; | 477 | size_t bytes_left = 0; |
@@ -468,11 +480,11 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) | |||
468 | 480 | ||
469 | /* check to see if we have something to return */ | 481 | /* check to see if we have something to return */ |
470 | if ((rbu_data.image_update_buffer == NULL) || | 482 | if ((rbu_data.image_update_buffer == NULL) || |
471 | (rbu_data.bios_image_size == 0)) { | 483 | (rbu_data.bios_image_size == 0)) { |
472 | pr_debug("read_rbu_data_mono: image_update_buffer %p ," | 484 | pr_debug("read_rbu_data_mono: image_update_buffer %p ," |
473 | "bios_image_size %lu\n", | 485 | "bios_image_size %lu\n", |
474 | rbu_data.image_update_buffer, | 486 | rbu_data.image_update_buffer, |
475 | rbu_data.bios_image_size); | 487 | rbu_data.bios_image_size); |
476 | ret_count = -ENOMEM; | 488 | ret_count = -ENOMEM; |
477 | goto read_rbu_data_exit; | 489 | goto read_rbu_data_exit; |
478 | } | 490 | } |
@@ -515,9 +527,46 @@ read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count) | |||
515 | return ret_count; | 527 | return ret_count; |
516 | } | 528 | } |
517 | 529 | ||
530 | static void | ||
531 | callbackfn_rbu(const struct firmware *fw, void *context) | ||
532 | { | ||
533 | int rc = 0; | ||
534 | |||
535 | if (!fw || !fw->size) { | ||
536 | rbu_data.entry_created = 0; | ||
537 | return; | ||
538 | } | ||
539 | |||
540 | spin_lock(&rbu_data.lock); | ||
541 | if (!strcmp(image_type, "mono")) { | ||
542 | if (!img_update_realloc(fw->size)) | ||
543 | memcpy(rbu_data.image_update_buffer, | ||
544 | fw->data, fw->size); | ||
545 | } else if (!strcmp(image_type, "packet")) { | ||
546 | if (!rbu_data.packetsize) | ||
547 | rbu_data.packetsize = fw->size; | ||
548 | else if (rbu_data.packetsize != fw->size) { | ||
549 | packet_empty_list(); | ||
550 | rbu_data.packetsize = fw->size; | ||
551 | } | ||
552 | packetize_data(fw->data, fw->size); | ||
553 | } else | ||
554 | pr_debug("invalid image type specified.\n"); | ||
555 | spin_unlock(&rbu_data.lock); | ||
556 | |||
557 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, | ||
558 | "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); | ||
559 | if (rc) | ||
560 | printk(KERN_ERR | ||
561 | "dell_rbu:%s request_firmware_nowait failed" | ||
562 | " %d\n", __FUNCTION__, rc); | ||
563 | else | ||
564 | rbu_data.entry_created = 1; | ||
565 | } | ||
566 | |||
518 | static ssize_t | 567 | static ssize_t |
519 | read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, | 568 | read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, |
520 | size_t count) | 569 | size_t count) |
521 | { | 570 | { |
522 | int size = 0; | 571 | int size = 0; |
523 | if (!pos) | 572 | if (!pos) |
@@ -527,25 +576,63 @@ read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, | |||
527 | 576 | ||
528 | static ssize_t | 577 | static ssize_t |
529 | write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, | 578 | write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, |
530 | size_t count) | 579 | size_t count) |
531 | { | 580 | { |
532 | int rc = count; | 581 | int rc = count; |
582 | int req_firm_rc = 0; | ||
583 | int i; | ||
533 | spin_lock(&rbu_data.lock); | 584 | spin_lock(&rbu_data.lock); |
534 | 585 | /* | |
535 | if (strlen(buffer) < MAX_IMAGE_LENGTH) | 586 | * Find the first newline or space |
536 | sscanf(buffer, "%s", image_type); | 587 | */ |
537 | else | 588 | for (i = 0; i < count; ++i) |
538 | printk(KERN_WARNING "dell_rbu: image_type is invalid" | 589 | if (buffer[i] == '\n' || buffer[i] == ' ') { |
539 | "max chars = %d, \n incoming str--%s-- \n", | 590 | buffer[i] = '\0'; |
540 | MAX_IMAGE_LENGTH, buffer); | 591 | break; |
592 | } | ||
593 | if (i == count) | ||
594 | buffer[count] = '\0'; | ||
595 | |||
596 | if (strstr(buffer, "mono")) | ||
597 | strcpy(image_type, "mono"); | ||
598 | else if (strstr(buffer, "packet")) | ||
599 | strcpy(image_type, "packet"); | ||
600 | else if (strstr(buffer, "init")) { | ||
601 | /* | ||
602 | * If due to the user error the driver gets in a bad | ||
603 | * state where even though it is loaded , the | ||
604 | * /sys/class/firmware/dell_rbu entries are missing. | ||
605 | * to cover this situation the user can recreate entries | ||
606 | * by writing init to image_type. | ||
607 | */ | ||
608 | if (!rbu_data.entry_created) { | ||
609 | spin_unlock(&rbu_data.lock); | ||
610 | req_firm_rc = request_firmware_nowait(THIS_MODULE, | ||
611 | FW_ACTION_NOHOTPLUG, "dell_rbu", | ||
612 | &rbu_device->dev, &context, | ||
613 | callbackfn_rbu); | ||
614 | if (req_firm_rc) { | ||
615 | printk(KERN_ERR | ||
616 | "dell_rbu:%s request_firmware_nowait" | ||
617 | " failed %d\n", __FUNCTION__, rc); | ||
618 | rc = -EIO; | ||
619 | } else | ||
620 | rbu_data.entry_created = 1; | ||
621 | |||
622 | spin_lock(&rbu_data.lock); | ||
623 | } | ||
624 | } else { | ||
625 | printk(KERN_WARNING "dell_rbu: image_type is invalid\n"); | ||
626 | spin_unlock(&rbu_data.lock); | ||
627 | return -EINVAL; | ||
628 | } | ||
541 | 629 | ||
542 | /* we must free all previous allocations */ | 630 | /* we must free all previous allocations */ |
543 | packet_empty_list(); | 631 | packet_empty_list(); |
544 | img_update_free(); | 632 | img_update_free(); |
545 | |||
546 | spin_unlock(&rbu_data.lock); | 633 | spin_unlock(&rbu_data.lock); |
547 | return rc; | ||
548 | 634 | ||
635 | return rc; | ||
549 | } | 636 | } |
550 | 637 | ||
551 | static struct bin_attribute rbu_data_attr = { | 638 | static struct bin_attribute rbu_data_attr = { |
@@ -559,51 +646,19 @@ static struct bin_attribute rbu_image_type_attr = { | |||
559 | .write = write_rbu_image_type, | 646 | .write = write_rbu_image_type, |
560 | }; | 647 | }; |
561 | 648 | ||
562 | static void callbackfn_rbu(const struct firmware *fw, void *context) | 649 | static int __init |
563 | { | 650 | dcdrbu_init(void) |
564 | int rc = 0; | ||
565 | |||
566 | if (!fw || !fw->size) | ||
567 | return; | ||
568 | |||
569 | spin_lock(&rbu_data.lock); | ||
570 | if (!strcmp(image_type, "mono")) { | ||
571 | if (!img_update_realloc(fw->size)) | ||
572 | memcpy(rbu_data.image_update_buffer, | ||
573 | fw->data, fw->size); | ||
574 | } else if (!strcmp(image_type, "packet")) { | ||
575 | if (!rbu_data.packetsize) | ||
576 | rbu_data.packetsize = fw->size; | ||
577 | else if (rbu_data.packetsize != fw->size) { | ||
578 | packet_empty_list(); | ||
579 | rbu_data.packetsize = fw->size; | ||
580 | } | ||
581 | packetize_data(fw->data, fw->size); | ||
582 | } else | ||
583 | pr_debug("invalid image type specified.\n"); | ||
584 | spin_unlock(&rbu_data.lock); | ||
585 | |||
586 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, | ||
587 | "dell_rbu", &rbu_device->dev, | ||
588 | &context, callbackfn_rbu); | ||
589 | if (rc) | ||
590 | printk(KERN_ERR | ||
591 | "dell_rbu:%s request_firmware_nowait failed" | ||
592 | " %d\n", __FUNCTION__, rc); | ||
593 | } | ||
594 | |||
595 | static int __init dcdrbu_init(void) | ||
596 | { | 651 | { |
597 | int rc = 0; | 652 | int rc = 0; |
598 | spin_lock_init(&rbu_data.lock); | 653 | spin_lock_init(&rbu_data.lock); |
599 | 654 | ||
600 | init_packet_head(); | 655 | init_packet_head(); |
601 | rbu_device = | 656 | rbu_device = |
602 | platform_device_register_simple("dell_rbu", -1, NULL, 0); | 657 | platform_device_register_simple("dell_rbu", -1, NULL, 0); |
603 | if (!rbu_device) { | 658 | if (!rbu_device) { |
604 | printk(KERN_ERR | 659 | printk(KERN_ERR |
605 | "dell_rbu:%s:platform_device_register_simple " | 660 | "dell_rbu:%s:platform_device_register_simple " |
606 | "failed\n", __FUNCTION__); | 661 | "failed\n", __FUNCTION__); |
607 | return -EIO; | 662 | return -EIO; |
608 | } | 663 | } |
609 | 664 | ||
@@ -611,17 +666,19 @@ static int __init dcdrbu_init(void) | |||
611 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); | 666 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); |
612 | 667 | ||
613 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, | 668 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, |
614 | "dell_rbu", &rbu_device->dev, | 669 | "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); |
615 | &context, callbackfn_rbu); | ||
616 | if (rc) | 670 | if (rc) |
617 | printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait" | 671 | printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait" |
618 | " failed %d\n", __FUNCTION__, rc); | 672 | " failed %d\n", __FUNCTION__, rc); |
673 | else | ||
674 | rbu_data.entry_created = 1; | ||
619 | 675 | ||
620 | return rc; | 676 | return rc; |
621 | 677 | ||
622 | } | 678 | } |
623 | 679 | ||
624 | static __exit void dcdrbu_exit(void) | 680 | static __exit void |
681 | dcdrbu_exit(void) | ||
625 | { | 682 | { |
626 | spin_lock(&rbu_data.lock); | 683 | spin_lock(&rbu_data.lock); |
627 | packet_empty_list(); | 684 | packet_empty_list(); |