diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/dell_rbu.c | 121 | ||||
-rw-r--r-- | drivers/firmware/edd.c | 3 | ||||
-rw-r--r-- | drivers/firmware/efivars.c | 10 |
3 files changed, 99 insertions, 35 deletions
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 125929c9048..ba17292eb29 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -50,7 +50,7 @@ MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); MODULE_LICENSE("GPL"); -MODULE_VERSION("3.0"); +MODULE_VERSION("3.1"); #define BIOS_SCAN_LIMIT 0xffffffff #define MAX_IMAGE_LENGTH 16 @@ -73,6 +73,11 @@ module_param_string(image_type, image_type, sizeof (image_type), 0); MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet or init"); +static unsigned long allocation_floor = 0x100000; +module_param(allocation_floor, ulong, 0644); +MODULE_PARM_DESC(allocation_floor, + "Minimum address for allocations when using Packet mode"); + struct packet_data { struct list_head list; size_t length; @@ -99,61 +104,122 @@ static int create_packet(void *data, size_t length) { struct packet_data *newpacket; int ordernum = 0; + int retval = 0; + unsigned int packet_array_size = 0; + void **invalid_addr_packet_array = 0; + void *packet_data_temp_buf = 0; + unsigned int idx = 0; pr_debug("create_packet: entry \n"); if (!rbu_data.packetsize) { pr_debug("create_packet: packetsize not specified\n"); - return -EINVAL; + retval = -EINVAL; + goto out_noalloc; } + spin_unlock(&rbu_data.lock); - newpacket = kmalloc(sizeof (struct packet_data), GFP_KERNEL); - spin_lock(&rbu_data.lock); + + newpacket = kzalloc(sizeof (struct packet_data), GFP_KERNEL); if (!newpacket) { printk(KERN_WARNING "dell_rbu:%s: failed to allocate new " "packet\n", __FUNCTION__); - return -ENOMEM; + retval = -ENOMEM; + spin_lock(&rbu_data.lock); + goto out_noalloc; } ordernum = get_order(length); + /* - * there is no upper limit on memory - * address for packetized mechanism + * BIOS errata mean we cannot allocate packets below 1MB or they will + * be overwritten by BIOS. + * + * array to temporarily hold packets + * that are below the allocation floor + * + * NOTE: very simplistic because we only need the floor to be at 1MB + * due to BIOS errata. This shouldn't be used for higher floors + * or you will run out of mem trying to allocate the array. */ - spin_unlock(&rbu_data.lock); - newpacket->data = (unsigned char *) __get_free_pages(GFP_KERNEL, - ordernum); - spin_lock(&rbu_data.lock); + packet_array_size = max( + (unsigned int)(allocation_floor / rbu_data.packetsize), + (unsigned int)1); + invalid_addr_packet_array = kzalloc(packet_array_size * sizeof(void*), + GFP_KERNEL); - pr_debug("create_packet: newpacket %p\n", newpacket->data); - - if (!newpacket->data) { + if (!invalid_addr_packet_array) { printk(KERN_WARNING - "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); - kfree(newpacket); - return -ENOMEM; + "dell_rbu:%s: failed to allocate " + "invalid_addr_packet_array \n", + __FUNCTION__); + retval = -ENOMEM; + spin_lock(&rbu_data.lock); + goto out_alloc_packet; } + while (!packet_data_temp_buf) { + packet_data_temp_buf = (unsigned char *) + __get_free_pages(GFP_KERNEL, ordernum); + if (!packet_data_temp_buf) { + printk(KERN_WARNING + "dell_rbu:%s: failed to allocate new " + "packet\n", __FUNCTION__); + retval = -ENOMEM; + spin_lock(&rbu_data.lock); + goto out_alloc_packet_array; + } + + if ((unsigned long)virt_to_phys(packet_data_temp_buf) + < allocation_floor) { + pr_debug("packet 0x%lx below floor at 0x%lx.\n", + (unsigned long)virt_to_phys( + packet_data_temp_buf), + allocation_floor); + invalid_addr_packet_array[idx++] = packet_data_temp_buf; + packet_data_temp_buf = 0; + } + } + spin_lock(&rbu_data.lock); + + newpacket->data = packet_data_temp_buf; + + pr_debug("create_packet: newpacket at physical addr %lx\n", + (unsigned long)virt_to_phys(newpacket->data)); + + /* packets may not have fixed size */ + newpacket->length = length; newpacket->ordernum = ordernum; ++rbu_data.num_packets; - /* - * initialize the newly created packet headers - */ + + /* initialize the newly created packet headers */ INIT_LIST_HEAD(&newpacket->list); list_add_tail(&newpacket->list, &packet_data_head.list); - /* - * packets may not have fixed size - */ - newpacket->length = length; memcpy(newpacket->data, data, length); pr_debug("create_packet: exit \n"); - return 0; +out_alloc_packet_array: + /* always free packet array */ + for (;idx>0;idx--) { + pr_debug("freeing unused packet below floor 0x%lx.\n", + (unsigned long)virt_to_phys( + invalid_addr_packet_array[idx-1])); + free_pages((unsigned long)invalid_addr_packet_array[idx-1], + ordernum); + } + kfree(invalid_addr_packet_array); + +out_alloc_packet: + /* if error, free data */ + if (retval) + kfree(newpacket); + +out_noalloc: + return retval; } static int packetize_data(void *data, size_t length) @@ -693,3 +759,6 @@ static __exit void dcdrbu_exit(void) module_exit(dcdrbu_exit); module_init(dcdrbu_init); + +/* vim:noet:ts=8:sw=8 +*/ diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 6996476669f..b4502ed6579 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -715,7 +715,6 @@ edd_device_register(struct edd_device *edev, int i) if (!edev) return 1; - memset(edev, 0, sizeof (*edev)); edd_dev_set_info(edev, i); kobject_set_name(&edev->kobj, "int13_dev%02x", 0x80 + i); @@ -756,7 +755,7 @@ edd_init(void) return rc; for (i = 0; i < edd_num_devices() && !rc; i++) { - edev = kmalloc(sizeof (*edev), GFP_KERNEL); + edev = kzalloc(sizeof (*edev), GFP_KERNEL); if (!edev) return -ENOMEM; diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 33b17c6a46f..bda5bce681b 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -614,16 +614,14 @@ efivar_create_sysfs_entry(unsigned long variable_name_size, char *short_name; struct efivar_entry *new_efivar; - short_name = kmalloc(short_name_size + 1, GFP_KERNEL); - new_efivar = kmalloc(sizeof(struct efivar_entry), GFP_KERNEL); + short_name = kzalloc(short_name_size + 1, GFP_KERNEL); + new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); if (!short_name || !new_efivar) { kfree(short_name); kfree(new_efivar); return 1; } - memset(short_name, 0, short_name_size+1); - memset(new_efivar, 0, sizeof(struct efivar_entry)); memcpy(new_efivar->var.VariableName, variable_name, variable_name_size); @@ -674,14 +672,12 @@ efivars_init(void) if (!efi_enabled) return -ENODEV; - variable_name = kmalloc(variable_name_size, GFP_KERNEL); + variable_name = kzalloc(variable_name_size, GFP_KERNEL); if (!variable_name) { printk(KERN_ERR "efivars: Memory allocation failed.\n"); return -ENOMEM; } - memset(variable_name, 0, variable_name_size); - printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, EFIVARS_DATE); |