Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] dell_rbu: changes in packet update mechanism

In the current dell_rbu code ver 2.0 the packet update mechanism makes the
user app dump every individual packet in to the driver.

This adds in efficiency as every packet update makes the
/sys/class/firmware/dell_rbu/loading and data files to disappear and reappear
again. Thus the user app needs to wait for the files to reappear to dump
another packet. This slows down the packet update tremendously in case of
large number of packets. I am submitting a new patch for dell_rbu which will
change the way we do packet updates;

In the new method the user app will create a new single file which has already
packetized the rbu image and all the packets are now staged in this file.

This driver also creates a new entry in
/sys/devices/platform/dell_rbu/packet_size ; the user needs to echo the packet
size here before downloading the packet file.

The user should do the following:

create one single file which has all the packets stacked together.
echo the packet size in to /sys/devices/platform/dell_rbu/packet_size.
echo 1 > /sys/class/firmware/dell_rbu/loading
cat the packetfile > /sys/class/firmware/dell_rbu/data
echo 0 > /sys/class/firmware/dell_rbu/loading

The driver takes the file which came through /sys/class/firmware/dell_rbu/data
and takes chunks of paket_size data from it and place in contiguous memory.

This makes packet update process very efficient and fast. As all the packet
update happens in one single operation. The user can still read back the
downloaded file from /sys/devices/platform/dell_rbu/data.

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>

authored by

Abhay Salunke and committed by
Linus Torvalds
ad6ce87e e4314bf4

+123 -93
+28 -10
Documentation/dell_rbu.txt
··· 35 35 /sys/class/firmware/dell_rbu/data 36 36 /sys/devices/platform/dell_rbu/image_type 37 37 /sys/devices/platform/dell_rbu/data 38 + /sys/devices/platform/dell_rbu/packet_size 38 39 39 40 The driver supports two types of update mechanism; monolithic and packetized. 40 41 These update mechanism depends upon the BIOS currently running on the system. ··· 48 47 changed to packets during the driver load time by specifying the load 49 48 parameter image_type=packet. This can also be changed later as below 50 49 echo packet > /sys/devices/platform/dell_rbu/image_type 51 - Also echoing either mono ,packet or init in to image_type will free up the 52 - memory allocated by the driver. 50 + 51 + In packet update mode the packet size has to be given before any packets can 52 + be downloaded. It is done as below 53 + echo XXXX > /sys/devices/platform/dell_rbu/packet_size 54 + In the packet update mechanism, the user neesd to create a new file having 55 + packets of data arranged back to back. It can be done as follows 56 + The user creates packets header, gets the chunk of the BIOS image and 57 + placs it next to the packetheader; now, the packetheader + BIOS image chunk 58 + added to geather should match the specified packet_size. This makes one 59 + packet, the user needs to create more such packets out of the entire BIOS 60 + image file and then arrange all these packets back to back in to one single 61 + file. 62 + This file is then copied to /sys/class/firmware/dell_rbu/data. 63 + Once this file gets to the driver, the driver extracts packet_size data from 64 + the file and spreads it accross the physical memory in contiguous packet_sized 65 + space. 66 + This method makes sure that all the packets get to the driver in a single operation. 67 + 68 + In monolithic update the user simply get the BIOS image (.hdr file) and copies 69 + to the data file as is without any change to the BIOS image itself. 53 70 54 71 Do the steps below to download the BIOS image. 55 72 1) echo 1 > /sys/class/firmware/dell_rbu/loading ··· 77 58 The /sys/class/firmware/dell_rbu/ entries will remain till the following is 78 59 done. 79 60 echo -1 > /sys/class/firmware/dell_rbu/loading. 80 - Until this step is completed the drivr cannot be unloaded. 61 + Until this step is completed the driver cannot be unloaded. 62 + Also echoing either mono ,packet or init in to image_type will free up the 63 + memory allocated by the driver. 64 + 81 65 If an user by accident executes steps 1 and 3 above without executing step 2; 82 66 it will make the /sys/class/firmware/dell_rbu/ entries to disappear. 83 67 The entries can be recreated by doing the following ··· 88 66 NOTE: echoing init in image_type does not change it original value. 89 67 90 68 Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to 91 - read back the image downloaded. This is useful in case of packet update 92 - mechanism where the above steps 1,2,3 will repeated for every packet. 93 - By reading the /sys/devices/platform/dell_rbu/data file all packet data 94 - downloaded can be verified in a single file. 95 - The packets are arranged in this file one after the other in a FIFO order. 69 + read back the image downloaded. 96 70 97 71 NOTE: 98 - This driver requires a patch for firmware_class.c which has the addition 99 - of request_firmware_nowait_nohotplug function to wortk 72 + This driver requires a patch for firmware_class.c which has the modified 73 + request_firmware_nowait function. 100 74 Also after updating the BIOS image an user mdoe application neeeds to execute 101 75 code which message the BIOS update request to the BIOS. So on the next reboot 102 76 the BIOS knows about the new image downloaded and it updates it self.
+95 -83
drivers/firmware/dell_rbu.c
··· 50 50 MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); 51 51 MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); 52 52 MODULE_LICENSE("GPL"); 53 - MODULE_VERSION("2.0"); 53 + MODULE_VERSION("3.0"); 54 54 55 55 #define BIOS_SCAN_LIMIT 0xffffffff 56 56 #define MAX_IMAGE_LENGTH 16 ··· 62 62 int dma_alloc; 63 63 spinlock_t lock; 64 64 unsigned long packet_read_count; 65 - unsigned long packet_write_count; 66 65 unsigned long num_packets; 67 66 unsigned long packetsize; 67 + unsigned long imagesize; 68 68 int entry_created; 69 69 } rbu_data; 70 70 71 71 static char image_type[MAX_IMAGE_LENGTH + 1] = "mono"; 72 72 module_param_string(image_type, image_type, sizeof (image_type), 0); 73 - MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet"); 73 + MODULE_PARM_DESC(image_type, 74 + "BIOS image type. choose- mono or packet or init"); 74 75 75 76 struct packet_data { 76 77 struct list_head list; ··· 89 88 static void init_packet_head(void) 90 89 { 91 90 INIT_LIST_HEAD(&packet_data_head.list); 92 - rbu_data.packet_write_count = 0; 93 91 rbu_data.packet_read_count = 0; 94 92 rbu_data.num_packets = 0; 95 93 rbu_data.packetsize = 0; 94 + rbu_data.imagesize = 0; 96 95 } 97 96 98 - static int fill_last_packet(void *data, size_t length) 99 - { 100 - struct list_head *ptemp_list; 101 - struct packet_data *packet = NULL; 102 - int packet_count = 0; 103 - 104 - pr_debug("fill_last_packet: entry \n"); 105 - 106 - if (!rbu_data.num_packets) { 107 - pr_debug("fill_last_packet: num_packets=0\n"); 108 - return -ENOMEM; 109 - } 110 - 111 - packet_count = rbu_data.num_packets; 112 - 113 - ptemp_list = (&packet_data_head.list)->prev; 114 - 115 - packet = list_entry(ptemp_list, struct packet_data, list); 116 - 117 - if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) { 118 - pr_debug("dell_rbu:%s: packet size data " 119 - "overrun\n", __FUNCTION__); 120 - return -EINVAL; 121 - } 122 - 123 - pr_debug("fill_last_packet : buffer = %p\n", packet->data); 124 - 125 - memcpy((packet->data + rbu_data.packet_write_count), data, length); 126 - 127 - if ((rbu_data.packet_write_count + length) == rbu_data.packetsize) { 128 - /* 129 - * this was the last data chunk in the packet 130 - * so reinitialize the packet data counter to zero 131 - */ 132 - rbu_data.packet_write_count = 0; 133 - } else 134 - rbu_data.packet_write_count += length; 135 - 136 - pr_debug("fill_last_packet: exit \n"); 137 - return 0; 138 - } 139 - 140 - static int create_packet(size_t length) 97 + static int create_packet(void *data, size_t length) 141 98 { 142 99 struct packet_data *newpacket; 143 100 int ordernum = 0; ··· 145 186 INIT_LIST_HEAD(&newpacket->list); 146 187 list_add_tail(&newpacket->list, &packet_data_head.list); 147 188 /* 148 - * packets have fixed size 189 + * packets may not have fixed size 149 190 */ 150 - newpacket->length = rbu_data.packetsize; 191 + newpacket->length = length; 192 + 193 + memcpy(newpacket->data, data, length); 151 194 152 195 pr_debug("create_packet: exit \n"); 153 196 ··· 159 198 static int packetize_data(void *data, size_t length) 160 199 { 161 200 int rc = 0; 162 - 163 - if (!rbu_data.packet_write_count) { 164 - if ((rc = create_packet(length))) 165 - return rc; 201 + int done = 0; 202 + int packet_length; 203 + u8 *temp; 204 + u8 *end = (u8 *) data + length; 205 + pr_debug("packetize_data: data length %d\n", length); 206 + if (!rbu_data.packetsize) { 207 + printk(KERN_WARNING 208 + "dell_rbu: packetsize not specified\n"); 209 + return -EIO; 166 210 } 167 - if ((rc = fill_last_packet(data, length))) 168 - return rc; 211 + 212 + temp = (u8 *) data; 213 + 214 + /* packetize the hunk */ 215 + while (!done) { 216 + if ((temp + rbu_data.packetsize) < end) 217 + packet_length = rbu_data.packetsize; 218 + else { 219 + /* this is the last packet */ 220 + packet_length = end - temp; 221 + done = 1; 222 + } 223 + 224 + if ((rc = create_packet(temp, packet_length))) 225 + return rc; 226 + 227 + pr_debug("%lu:%lu\n", temp, (end - temp)); 228 + temp += packet_length; 229 + } 230 + 231 + rbu_data.imagesize = length; 169 232 170 233 return rc; 171 234 } ··· 228 243 return bytes_copied; 229 244 } 230 245 231 - static int packet_read_list(char *data, size_t *pread_length) 246 + static int packet_read_list(char *data, size_t * pread_length) 232 247 { 233 248 struct list_head *ptemp_list; 234 249 int temp_count = 0; ··· 288 303 newpacket->ordernum); 289 304 kfree(newpacket); 290 305 } 291 - rbu_data.packet_write_count = 0; 292 306 rbu_data.packet_read_count = 0; 293 307 rbu_data.num_packets = 0; 294 - rbu_data.packetsize = 0; 308 + rbu_data.imagesize = 0; 295 309 } 296 310 297 311 /* ··· 409 425 size_t bytes_left; 410 426 size_t data_length; 411 427 char *ptempBuf = buffer; 412 - unsigned long imagesize; 413 428 414 429 /* check to see if we have something to return */ 415 430 if (rbu_data.num_packets == 0) { ··· 417 434 goto read_rbu_data_exit; 418 435 } 419 436 420 - imagesize = rbu_data.num_packets * rbu_data.packetsize; 421 - 422 - if (pos > imagesize) { 437 + if (pos > rbu_data.imagesize) { 423 438 retval = 0; 424 439 printk(KERN_WARNING "dell_rbu:read_packet_data: " 425 440 "data underrun\n"); 426 441 goto read_rbu_data_exit; 427 442 } 428 443 429 - bytes_left = imagesize - pos; 444 + bytes_left = rbu_data.imagesize - pos; 430 445 data_length = min(bytes_left, count); 431 446 432 447 if ((retval = packet_read_list(ptempBuf, &data_length)) < 0) 433 448 goto read_rbu_data_exit; 434 449 435 - if ((pos + count) > imagesize) { 450 + if ((pos + count) > rbu_data.imagesize) { 436 451 rbu_data.packet_read_count = 0; 437 452 /* this was the last copy */ 438 453 retval = bytes_left; ··· 480 499 } 481 500 482 501 static ssize_t read_rbu_data(struct kobject *kobj, char *buffer, 483 - loff_t pos, size_t count) 502 + loff_t pos, size_t count) 484 503 { 485 504 ssize_t ret_count = 0; 486 505 ··· 512 531 memcpy(rbu_data.image_update_buffer, 513 532 fw->data, fw->size); 514 533 } else if (!strcmp(image_type, "packet")) { 515 - if (!rbu_data.packetsize) 516 - rbu_data.packetsize = fw->size; 517 - else if (rbu_data.packetsize != fw->size) { 534 + /* 535 + * we need to free previous packets if a 536 + * new hunk of packets needs to be downloaded 537 + */ 538 + packet_empty_list(); 539 + if (packetize_data(fw->data, fw->size)) 540 + /* Incase something goes wrong when we are 541 + * in middle of packetizing the data, we 542 + * need to free up whatever packets might 543 + * have been created before we quit. 544 + */ 518 545 packet_empty_list(); 519 - rbu_data.packetsize = fw->size; 520 - } 521 - packetize_data(fw->data, fw->size); 522 546 } else 523 547 pr_debug("invalid image type specified.\n"); 524 548 spin_unlock(&rbu_data.lock); ··· 539 553 } 540 554 541 555 static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer, 542 - loff_t pos, size_t count) 556 + loff_t pos, size_t count) 543 557 { 544 558 int size = 0; 545 559 if (!pos) ··· 548 562 } 549 563 550 564 static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer, 551 - loff_t pos, size_t count) 565 + loff_t pos, size_t count) 552 566 { 553 567 int rc = count; 554 568 int req_firm_rc = 0; ··· 607 621 return rc; 608 622 } 609 623 624 + static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer, 625 + loff_t pos, size_t count) 626 + { 627 + int size = 0; 628 + if (!pos) { 629 + spin_lock(&rbu_data.lock); 630 + size = sprintf(buffer, "%lu\n", rbu_data.packetsize); 631 + spin_unlock(&rbu_data.lock); 632 + } 633 + return size; 634 + } 635 + 636 + static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer, 637 + loff_t pos, size_t count) 638 + { 639 + unsigned long temp; 640 + spin_lock(&rbu_data.lock); 641 + packet_empty_list(); 642 + sscanf(buffer, "%lu", &temp); 643 + if (temp < 0xffffffff) 644 + rbu_data.packetsize = temp; 645 + 646 + spin_unlock(&rbu_data.lock); 647 + return count; 648 + } 649 + 610 650 static struct bin_attribute rbu_data_attr = { 611 - .attr = { 612 - .name = "data", 613 - .owner = THIS_MODULE, 614 - .mode = 0444, 615 - }, 651 + .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444}, 616 652 .read = read_rbu_data, 617 653 }; 618 654 619 655 static struct bin_attribute rbu_image_type_attr = { 620 - .attr = { 621 - .name = "image_type", 622 - .owner = THIS_MODULE, 623 - .mode = 0644, 624 - }, 656 + .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644}, 625 657 .read = read_rbu_image_type, 626 658 .write = write_rbu_image_type, 659 + }; 660 + 661 + static struct bin_attribute rbu_packet_size_attr = { 662 + .attr = {.name = "packet_size",.owner = THIS_MODULE,.mode = 0644}, 663 + .read = read_rbu_packet_size, 664 + .write = write_rbu_packet_size, 627 665 }; 628 666 629 667 static int __init dcdrbu_init(void) ··· 667 657 668 658 sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); 669 659 sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); 660 + sysfs_create_bin_file(&rbu_device->dev.kobj, 661 + &rbu_packet_size_attr); 670 662 671 663 rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, 672 664 "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu);