diff options
Diffstat (limited to 'drivers/firmware/dell_rbu.c')
| -rw-r--r-- | drivers/firmware/dell_rbu.c | 174 |
1 files changed, 93 insertions, 81 deletions
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index b667823982..4f4ba9b6d1 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("2.0"); | 53 | MODULE_VERSION("3.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 |
| @@ -62,15 +62,16 @@ static struct _rbu_data { | |||
| 62 | int dma_alloc; | 62 | int dma_alloc; |
| 63 | spinlock_t lock; | 63 | spinlock_t lock; |
| 64 | unsigned long packet_read_count; | 64 | unsigned long packet_read_count; |
| 65 | unsigned long packet_write_count; | ||
| 66 | unsigned long num_packets; | 65 | unsigned long num_packets; |
| 67 | unsigned long packetsize; | 66 | unsigned long packetsize; |
| 67 | unsigned long imagesize; | ||
| 68 | int entry_created; | 68 | int entry_created; |
| 69 | } rbu_data; | 69 | } rbu_data; |
| 70 | 70 | ||
| 71 | static char image_type[MAX_IMAGE_LENGTH + 1] = "mono"; | 71 | static char image_type[MAX_IMAGE_LENGTH + 1] = "mono"; |
| 72 | module_param_string(image_type, image_type, sizeof (image_type), 0); | 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 | struct packet_data { | 76 | struct packet_data { |
| 76 | struct list_head list; | 77 | struct list_head list; |
| @@ -88,55 +89,13 @@ static dma_addr_t dell_rbu_dmaaddr; | |||
| 88 | static void init_packet_head(void) | 89 | static void init_packet_head(void) |
| 89 | { | 90 | { |
| 90 | INIT_LIST_HEAD(&packet_data_head.list); | 91 | INIT_LIST_HEAD(&packet_data_head.list); |
| 91 | rbu_data.packet_write_count = 0; | ||
| 92 | rbu_data.packet_read_count = 0; | 92 | rbu_data.packet_read_count = 0; |
| 93 | rbu_data.num_packets = 0; | 93 | rbu_data.num_packets = 0; |
| 94 | rbu_data.packetsize = 0; | 94 | rbu_data.packetsize = 0; |
| 95 | rbu_data.imagesize = 0; | ||
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | static int fill_last_packet(void *data, size_t length) | 98 | static int create_packet(void *data, size_t length) |
| 98 | { | ||
| 99 | struct list_head *ptemp_list; | ||
| 100 | struct packet_data *packet = NULL; | ||
| 101 | int packet_count = 0; | ||
| 102 | |||
| 103 | pr_debug("fill_last_packet: entry \n"); | ||
| 104 | |||
| 105 | if (!rbu_data.num_packets) { | ||
| 106 | pr_debug("fill_last_packet: num_packets=0\n"); | ||
| 107 | return -ENOMEM; | ||
| 108 | } | ||
| 109 | |||
| 110 | packet_count = rbu_data.num_packets; | ||
| 111 | |||
| 112 | ptemp_list = (&packet_data_head.list)->prev; | ||
| 113 | |||
| 114 | packet = list_entry(ptemp_list, struct packet_data, list); | ||
| 115 | |||
| 116 | if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) { | ||
| 117 | pr_debug("dell_rbu:%s: packet size data " | ||
| 118 | "overrun\n", __FUNCTION__); | ||
| 119 | return -EINVAL; | ||
| 120 | } | ||
| 121 | |||
| 122 | pr_debug("fill_last_packet : buffer = %p\n", packet->data); | ||
| 123 | |||
| 124 | memcpy((packet->data + rbu_data.packet_write_count), data, length); | ||
| 125 | |||
| 126 | if ((rbu_data.packet_write_count + length) == rbu_data.packetsize) { | ||
| 127 | /* | ||
| 128 | * this was the last data chunk in the packet | ||
| 129 | * so reinitialize the packet data counter to zero | ||
| 130 | */ | ||
| 131 | rbu_data.packet_write_count = 0; | ||
| 132 | } else | ||
| 133 | rbu_data.packet_write_count += length; | ||
| 134 | |||
| 135 | pr_debug("fill_last_packet: exit \n"); | ||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int create_packet(size_t length) | ||
| 140 | { | 99 | { |
| 141 | struct packet_data *newpacket; | 100 | struct packet_data *newpacket; |
| 142 | int ordernum = 0; | 101 | int ordernum = 0; |
| @@ -186,9 +145,11 @@ static int create_packet(size_t length) | |||
| 186 | INIT_LIST_HEAD(&newpacket->list); | 145 | INIT_LIST_HEAD(&newpacket->list); |
| 187 | list_add_tail(&newpacket->list, &packet_data_head.list); | 146 | list_add_tail(&newpacket->list, &packet_data_head.list); |
| 188 | /* | 147 | /* |
| 189 | * packets have fixed size | 148 | * packets may not have fixed size |
| 190 | */ | 149 | */ |
| 191 | newpacket->length = rbu_data.packetsize; | 150 | newpacket->length = length; |
| 151 | |||
| 152 | memcpy(newpacket->data, data, length); | ||
| 192 | 153 | ||
| 193 | pr_debug("create_packet: exit \n"); | 154 | pr_debug("create_packet: exit \n"); |
| 194 | 155 | ||
| @@ -198,13 +159,37 @@ static int create_packet(size_t length) | |||
| 198 | static int packetize_data(void *data, size_t length) | 159 | static int packetize_data(void *data, size_t length) |
| 199 | { | 160 | { |
| 200 | int rc = 0; | 161 | int rc = 0; |
| 162 | int done = 0; | ||
| 163 | int packet_length; | ||
| 164 | u8 *temp; | ||
| 165 | u8 *end = (u8 *) data + length; | ||
| 166 | pr_debug("packetize_data: data length %d\n", length); | ||
| 167 | if (!rbu_data.packetsize) { | ||
| 168 | printk(KERN_WARNING | ||
| 169 | "dell_rbu: packetsize not specified\n"); | ||
| 170 | return -EIO; | ||
| 171 | } | ||
| 201 | 172 | ||
| 202 | if (!rbu_data.packet_write_count) { | 173 | temp = (u8 *) data; |
| 203 | if ((rc = create_packet(length))) | 174 | |
| 175 | /* packetize the hunk */ | ||
| 176 | while (!done) { | ||
| 177 | if ((temp + rbu_data.packetsize) < end) | ||
| 178 | packet_length = rbu_data.packetsize; | ||
| 179 | else { | ||
| 180 | /* this is the last packet */ | ||
| 181 | packet_length = end - temp; | ||
| 182 | done = 1; | ||
| 183 | } | ||
| 184 | |||
| 185 | if ((rc = create_packet(temp, packet_length))) | ||
| 204 | return rc; | 186 | return rc; |
| 187 | |||
| 188 | pr_debug("%lu:%lu\n", temp, (end - temp)); | ||
| 189 | temp += packet_length; | ||
| 205 | } | 190 | } |
| 206 | if ((rc = fill_last_packet(data, length))) | 191 | |
| 207 | return rc; | 192 | rbu_data.imagesize = length; |
| 208 | 193 | ||
| 209 | return rc; | 194 | return rc; |
| 210 | } | 195 | } |
| @@ -243,7 +228,7 @@ static int do_packet_read(char *data, struct list_head *ptemp_list, | |||
| 243 | return bytes_copied; | 228 | return bytes_copied; |
| 244 | } | 229 | } |
| 245 | 230 | ||
| 246 | static int packet_read_list(char *data, size_t *pread_length) | 231 | static int packet_read_list(char *data, size_t * pread_length) |
| 247 | { | 232 | { |
| 248 | struct list_head *ptemp_list; | 233 | struct list_head *ptemp_list; |
| 249 | int temp_count = 0; | 234 | int temp_count = 0; |
| @@ -303,10 +288,9 @@ static void packet_empty_list(void) | |||
| 303 | newpacket->ordernum); | 288 | newpacket->ordernum); |
| 304 | kfree(newpacket); | 289 | kfree(newpacket); |
| 305 | } | 290 | } |
| 306 | rbu_data.packet_write_count = 0; | ||
| 307 | rbu_data.packet_read_count = 0; | 291 | rbu_data.packet_read_count = 0; |
| 308 | rbu_data.num_packets = 0; | 292 | rbu_data.num_packets = 0; |
| 309 | rbu_data.packetsize = 0; | 293 | rbu_data.imagesize = 0; |
| 310 | } | 294 | } |
| 311 | 295 | ||
| 312 | /* | 296 | /* |
| @@ -425,7 +409,6 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) | |||
| 425 | size_t bytes_left; | 409 | size_t bytes_left; |
| 426 | size_t data_length; | 410 | size_t data_length; |
| 427 | char *ptempBuf = buffer; | 411 | char *ptempBuf = buffer; |
| 428 | unsigned long imagesize; | ||
| 429 | 412 | ||
| 430 | /* check to see if we have something to return */ | 413 | /* check to see if we have something to return */ |
| 431 | if (rbu_data.num_packets == 0) { | 414 | if (rbu_data.num_packets == 0) { |
| @@ -434,22 +417,20 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) | |||
| 434 | goto read_rbu_data_exit; | 417 | goto read_rbu_data_exit; |
| 435 | } | 418 | } |
| 436 | 419 | ||
| 437 | imagesize = rbu_data.num_packets * rbu_data.packetsize; | 420 | if (pos > rbu_data.imagesize) { |
| 438 | |||
| 439 | if (pos > imagesize) { | ||
| 440 | retval = 0; | 421 | retval = 0; |
| 441 | printk(KERN_WARNING "dell_rbu:read_packet_data: " | 422 | printk(KERN_WARNING "dell_rbu:read_packet_data: " |
| 442 | "data underrun\n"); | 423 | "data underrun\n"); |
| 443 | goto read_rbu_data_exit; | 424 | goto read_rbu_data_exit; |
| 444 | } | 425 | } |
| 445 | 426 | ||
| 446 | bytes_left = imagesize - pos; | 427 | bytes_left = rbu_data.imagesize - pos; |
| 447 | data_length = min(bytes_left, count); | 428 | data_length = min(bytes_left, count); |
| 448 | 429 | ||
| 449 | if ((retval = packet_read_list(ptempBuf, &data_length)) < 0) | 430 | if ((retval = packet_read_list(ptempBuf, &data_length)) < 0) |
| 450 | goto read_rbu_data_exit; | 431 | goto read_rbu_data_exit; |
| 451 | 432 | ||
| 452 | if ((pos + count) > imagesize) { | 433 | if ((pos + count) > rbu_data.imagesize) { |
| 453 | rbu_data.packet_read_count = 0; | 434 | rbu_data.packet_read_count = 0; |
| 454 | /* this was the last copy */ | 435 | /* this was the last copy */ |
| 455 | retval = bytes_left; | 436 | retval = bytes_left; |
| @@ -499,7 +480,7 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) | |||
| 499 | } | 480 | } |
| 500 | 481 | ||
| 501 | static ssize_t read_rbu_data(struct kobject *kobj, char *buffer, | 482 | static ssize_t read_rbu_data(struct kobject *kobj, char *buffer, |
| 502 | loff_t pos, size_t count) | 483 | loff_t pos, size_t count) |
| 503 | { | 484 | { |
| 504 | ssize_t ret_count = 0; | 485 | ssize_t ret_count = 0; |
| 505 | 486 | ||
| @@ -531,13 +512,18 @@ static void callbackfn_rbu(const struct firmware *fw, void *context) | |||
| 531 | memcpy(rbu_data.image_update_buffer, | 512 | memcpy(rbu_data.image_update_buffer, |
| 532 | fw->data, fw->size); | 513 | fw->data, fw->size); |
| 533 | } else if (!strcmp(image_type, "packet")) { | 514 | } else if (!strcmp(image_type, "packet")) { |
| 534 | if (!rbu_data.packetsize) | 515 | /* |
| 535 | rbu_data.packetsize = fw->size; | 516 | * we need to free previous packets if a |
| 536 | else if (rbu_data.packetsize != fw->size) { | 517 | * new hunk of packets needs to be downloaded |
| 518 | */ | ||
| 519 | packet_empty_list(); | ||
| 520 | if (packetize_data(fw->data, fw->size)) | ||
| 521 | /* Incase something goes wrong when we are | ||
| 522 | * in middle of packetizing the data, we | ||
| 523 | * need to free up whatever packets might | ||
| 524 | * have been created before we quit. | ||
| 525 | */ | ||
| 537 | packet_empty_list(); | 526 | packet_empty_list(); |
| 538 | rbu_data.packetsize = fw->size; | ||
| 539 | } | ||
| 540 | packetize_data(fw->data, fw->size); | ||
| 541 | } else | 527 | } else |
| 542 | pr_debug("invalid image type specified.\n"); | 528 | pr_debug("invalid image type specified.\n"); |
| 543 | spin_unlock(&rbu_data.lock); | 529 | spin_unlock(&rbu_data.lock); |
| @@ -553,7 +539,7 @@ static void callbackfn_rbu(const struct firmware *fw, void *context) | |||
| 553 | } | 539 | } |
| 554 | 540 | ||
| 555 | static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer, | 541 | static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer, |
| 556 | loff_t pos, size_t count) | 542 | loff_t pos, size_t count) |
| 557 | { | 543 | { |
| 558 | int size = 0; | 544 | int size = 0; |
| 559 | if (!pos) | 545 | if (!pos) |
| @@ -562,7 +548,7 @@ static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer, | |||
| 562 | } | 548 | } |
| 563 | 549 | ||
| 564 | static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer, | 550 | static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer, |
| 565 | loff_t pos, size_t count) | 551 | loff_t pos, size_t count) |
| 566 | { | 552 | { |
| 567 | int rc = count; | 553 | int rc = count; |
| 568 | int req_firm_rc = 0; | 554 | int req_firm_rc = 0; |
| @@ -621,25 +607,49 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer, | |||
| 621 | return rc; | 607 | return rc; |
| 622 | } | 608 | } |
| 623 | 609 | ||
| 610 | static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer, | ||
| 611 | loff_t pos, size_t count) | ||
| 612 | { | ||
| 613 | int size = 0; | ||
| 614 | if (!pos) { | ||
| 615 | spin_lock(&rbu_data.lock); | ||
| 616 | size = sprintf(buffer, "%lu\n", rbu_data.packetsize); | ||
| 617 | spin_unlock(&rbu_data.lock); | ||
| 618 | } | ||
| 619 | return size; | ||
| 620 | } | ||
| 621 | |||
| 622 | static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer, | ||
| 623 | loff_t pos, size_t count) | ||
| 624 | { | ||
| 625 | unsigned long temp; | ||
| 626 | spin_lock(&rbu_data.lock); | ||
| 627 | packet_empty_list(); | ||
| 628 | sscanf(buffer, "%lu", &temp); | ||
| 629 | if (temp < 0xffffffff) | ||
| 630 | rbu_data.packetsize = temp; | ||
| 631 | |||
| 632 | spin_unlock(&rbu_data.lock); | ||
| 633 | return count; | ||
| 634 | } | ||
| 635 | |||
| 624 | static struct bin_attribute rbu_data_attr = { | 636 | static struct bin_attribute rbu_data_attr = { |
| 625 | .attr = { | 637 | .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444}, |
| 626 | .name = "data", | ||
| 627 | .owner = THIS_MODULE, | ||
| 628 | .mode = 0444, | ||
| 629 | }, | ||
| 630 | .read = read_rbu_data, | 638 | .read = read_rbu_data, |
| 631 | }; | 639 | }; |
| 632 | 640 | ||
| 633 | static struct bin_attribute rbu_image_type_attr = { | 641 | static struct bin_attribute rbu_image_type_attr = { |
| 634 | .attr = { | 642 | .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644}, |
| 635 | .name = "image_type", | ||
| 636 | .owner = THIS_MODULE, | ||
| 637 | .mode = 0644, | ||
| 638 | }, | ||
| 639 | .read = read_rbu_image_type, | 643 | .read = read_rbu_image_type, |
| 640 | .write = write_rbu_image_type, | 644 | .write = write_rbu_image_type, |
| 641 | }; | 645 | }; |
| 642 | 646 | ||
| 647 | static struct bin_attribute rbu_packet_size_attr = { | ||
| 648 | .attr = {.name = "packet_size",.owner = THIS_MODULE,.mode = 0644}, | ||
| 649 | .read = read_rbu_packet_size, | ||
| 650 | .write = write_rbu_packet_size, | ||
| 651 | }; | ||
| 652 | |||
| 643 | static int __init dcdrbu_init(void) | 653 | static int __init dcdrbu_init(void) |
| 644 | { | 654 | { |
| 645 | int rc = 0; | 655 | int rc = 0; |
| @@ -657,6 +667,8 @@ static int __init dcdrbu_init(void) | |||
| 657 | 667 | ||
| 658 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); | 668 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); |
| 659 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); | 669 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); |
| 670 | sysfs_create_bin_file(&rbu_device->dev.kobj, | ||
| 671 | &rbu_packet_size_attr); | ||
| 660 | 672 | ||
| 661 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, | 673 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, |
| 662 | "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); | 674 | "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); |
