Index: firmware_class.c =================================================================== RCS file: /sources/repository/external_source/linux/linux-2.6.12.2/drivers/base/firmware_class.c,v retrieving revision 1.1 retrieving revision 1.2 diff -p -u -r1.1 -r1.2 --- firmware_class.c 17 Jan 2006 16:49:35 -0000 1.1 +++ firmware_class.c 15 Feb 2006 14:01:29 -0000 1.2 @@ -31,6 +31,7 @@ enum { }; static int loading_timeout = 10; /* In seconds */ +static char grow_faster = 1; /* Boolean */ /* fw_lock could be moved to 'struct firmware_priv' but since it is just * guarding for corner cases a global lock should be OK */ @@ -79,6 +80,28 @@ firmware_timeout_store(struct class *cla static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); +static ssize_t +firmware_grow_faster_show(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", grow_faster); +} + +/** + * firmware_grow_faster_store: + * Description: + * Sets or clears a flag that causes the reallocate routine to + * grow the firmware buffer size more or less quickly. + * + **/ +static ssize_t +firmware_grow_faster_store(struct class *class, const char *buf, size_t count) +{ + grow_faster = simple_strtol(buf, NULL, 10) != 0; + return count; +} + +static CLASS_ATTR(grow_faster, 0644, firmware_grow_faster_show, firmware_grow_faster_store); + static void fw_class_dev_release(struct class_device *class_dev); int firmware_class_hotplug(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size); @@ -198,18 +221,27 @@ static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) { u8 *new_data; + int new_size; if (min_size <= fw_priv->alloc_size) return 0; - new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE); +#define ONE_MEG (1024 * 1024) + + new_size = grow_faster + ? ((fw_priv->alloc_size >= ONE_MEG) + ? (fw_priv->alloc_size + ONE_MEG) + : ((fw_priv->alloc_size >= PAGE_SIZE) ? (fw_priv->alloc_size * 2) : PAGE_SIZE)) + : (fw_priv->alloc_size + PAGE_SIZE); + new_data = vmalloc (new_size); if (!new_data) { - printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__); + printk(KERN_ERR "%s: unable to alloc buffer old size %d new size %d\n", + __FUNCTION__, fw_priv->alloc_size, new_size); /* Make sure that we don't keep incomplete data */ fw_load_abort(fw_priv); return -ENOMEM; } - fw_priv->alloc_size += PAGE_SIZE; + fw_priv->alloc_size = new_size; if (fw_priv->fw->data) { memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size); vfree(fw_priv->fw->data); @@ -249,6 +281,13 @@ firmware_data_write(struct kobject *kobj goto out; memcpy(fw->data + offset, buffer, count); + /* A successful write should cause us to reset the timeout + delay, as very large firmware files might take a while to + send through the sysfs file. We have the fw_lock taken at + the moment but the timeout function doesn't lock as it only + has to set a single volatile bit, so we're ok to mod it. */ + if (timer_pending (&fw_priv->timeout)) + mod_timer (&fw_priv->timeout, jiffies + loading_timeout * HZ); fw->size = max_t(size_t, offset + count, fw->size); retval = count; @@ -568,6 +607,12 @@ firmware_class_init(void) __FUNCTION__); class_unregister(&firmware_class); } + error = class_create_file(&firmware_class, &class_attr_grow_faster); + if (error) { + printk(KERN_ERR "%s: class_create_file failed\n", + __FUNCTION__); + class_unregister(&firmware_class); + } return error; }