mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
[PATCH] modified firmware_class.c to support no hotplug
Upgrade the request_firmware_nowait function to not start the hotplug action on a firmware update. This patch is tested along with dell_rbu driver on i386 and x86-64 systems. Signed-off-by: Abhay Salunke <Abhay_Salunke@dell.com> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
f3ef6f63e5
commit
6e3eaab020
2 changed files with 54 additions and 30 deletions
|
@ -28,6 +28,7 @@ enum {
|
|||
FW_STATUS_DONE,
|
||||
FW_STATUS_ABORT,
|
||||
FW_STATUS_READY,
|
||||
FW_STATUS_READY_NOHOTPLUG,
|
||||
};
|
||||
|
||||
static int loading_timeout = 10; /* In seconds */
|
||||
|
@ -344,7 +345,7 @@ error_kfree:
|
|||
|
||||
static int
|
||||
fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
|
||||
const char *fw_name, struct device *device)
|
||||
const char *fw_name, struct device *device, int hotplug)
|
||||
{
|
||||
struct class_device *class_dev;
|
||||
struct firmware_priv *fw_priv;
|
||||
|
@ -376,7 +377,10 @@ fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
|
|||
goto error_unreg;
|
||||
}
|
||||
|
||||
if (hotplug)
|
||||
set_bit(FW_STATUS_READY, &fw_priv->status);
|
||||
else
|
||||
set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
|
||||
*class_dev_p = class_dev;
|
||||
goto out;
|
||||
|
||||
|
@ -386,6 +390,65 @@ out:
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_request_firmware(const struct firmware **firmware_p, const char *name,
|
||||
struct device *device, int hotplug)
|
||||
{
|
||||
struct class_device *class_dev;
|
||||
struct firmware_priv *fw_priv;
|
||||
struct firmware *firmware;
|
||||
int retval;
|
||||
|
||||
if (!firmware_p)
|
||||
return -EINVAL;
|
||||
|
||||
*firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL);
|
||||
if (!firmware) {
|
||||
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
|
||||
__FUNCTION__);
|
||||
retval = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
memset(firmware, 0, sizeof (*firmware));
|
||||
|
||||
retval = fw_setup_class_device(firmware, &class_dev, name, device,
|
||||
hotplug);
|
||||
if (retval)
|
||||
goto error_kfree_fw;
|
||||
|
||||
fw_priv = class_get_devdata(class_dev);
|
||||
|
||||
if (hotplug) {
|
||||
if (loading_timeout > 0) {
|
||||
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
|
||||
add_timer(&fw_priv->timeout);
|
||||
}
|
||||
|
||||
kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
|
||||
wait_for_completion(&fw_priv->completion);
|
||||
set_bit(FW_STATUS_DONE, &fw_priv->status);
|
||||
del_timer_sync(&fw_priv->timeout);
|
||||
} else
|
||||
wait_for_completion(&fw_priv->completion);
|
||||
|
||||
down(&fw_lock);
|
||||
if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
|
||||
retval = -ENOENT;
|
||||
release_firmware(fw_priv->fw);
|
||||
*firmware_p = NULL;
|
||||
}
|
||||
fw_priv->fw = NULL;
|
||||
up(&fw_lock);
|
||||
class_device_unregister(class_dev);
|
||||
goto out;
|
||||
|
||||
error_kfree_fw:
|
||||
kfree(firmware);
|
||||
*firmware_p = NULL;
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* request_firmware: - request firmware to hotplug and wait for it
|
||||
* Description:
|
||||
|
@ -402,56 +465,8 @@ int
|
|||
request_firmware(const struct firmware **firmware_p, const char *name,
|
||||
struct device *device)
|
||||
{
|
||||
struct class_device *class_dev;
|
||||
struct firmware_priv *fw_priv;
|
||||
struct firmware *firmware;
|
||||
int retval;
|
||||
|
||||
if (!firmware_p)
|
||||
return -EINVAL;
|
||||
|
||||
*firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL);
|
||||
if (!firmware) {
|
||||
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
|
||||
__FUNCTION__);
|
||||
retval = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
memset(firmware, 0, sizeof (*firmware));
|
||||
|
||||
retval = fw_setup_class_device(firmware, &class_dev, name, device);
|
||||
if (retval)
|
||||
goto error_kfree_fw;
|
||||
|
||||
fw_priv = class_get_devdata(class_dev);
|
||||
|
||||
if (loading_timeout > 0) {
|
||||
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
|
||||
add_timer(&fw_priv->timeout);
|
||||
}
|
||||
|
||||
kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
|
||||
wait_for_completion(&fw_priv->completion);
|
||||
set_bit(FW_STATUS_DONE, &fw_priv->status);
|
||||
|
||||
del_timer_sync(&fw_priv->timeout);
|
||||
|
||||
down(&fw_lock);
|
||||
if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
|
||||
retval = -ENOENT;
|
||||
release_firmware(fw_priv->fw);
|
||||
*firmware_p = NULL;
|
||||
}
|
||||
fw_priv->fw = NULL;
|
||||
up(&fw_lock);
|
||||
class_device_unregister(class_dev);
|
||||
goto out;
|
||||
|
||||
error_kfree_fw:
|
||||
kfree(firmware);
|
||||
*firmware_p = NULL;
|
||||
out:
|
||||
return retval;
|
||||
int hotplug = 1;
|
||||
return _request_firmware(firmware_p, name, device, hotplug);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -491,6 +506,7 @@ struct firmware_work {
|
|||
struct device *device;
|
||||
void *context;
|
||||
void (*cont)(const struct firmware *fw, void *context);
|
||||
int hotplug;
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -503,7 +519,8 @@ request_firmware_work_func(void *arg)
|
|||
return 0;
|
||||
}
|
||||
daemonize("%s/%s", "firmware", fw_work->name);
|
||||
request_firmware(&fw, fw_work->name, fw_work->device);
|
||||
_request_firmware(&fw, fw_work->name, fw_work->device,
|
||||
fw_work->hotplug);
|
||||
fw_work->cont(fw, fw_work->context);
|
||||
release_firmware(fw);
|
||||
module_put(fw_work->module);
|
||||
|
@ -518,6 +535,9 @@ request_firmware_work_func(void *arg)
|
|||
* Asynchronous variant of request_firmware() for contexts where
|
||||
* it is not possible to sleep.
|
||||
*
|
||||
* @hotplug invokes hotplug event to copy the firmware image if this flag
|
||||
* is non-zero else the firmware copy must be done manually.
|
||||
*
|
||||
* @cont will be called asynchronously when the firmware request is over.
|
||||
*
|
||||
* @context will be passed over to @cont.
|
||||
|
@ -527,7 +547,7 @@ request_firmware_work_func(void *arg)
|
|||
**/
|
||||
int
|
||||
request_firmware_nowait(
|
||||
struct module *module,
|
||||
struct module *module, int hotplug,
|
||||
const char *name, struct device *device, void *context,
|
||||
void (*cont)(const struct firmware *fw, void *context))
|
||||
{
|
||||
|
@ -548,6 +568,7 @@ request_firmware_nowait(
|
|||
.device = device,
|
||||
.context = context,
|
||||
.cont = cont,
|
||||
.hotplug = hotplug,
|
||||
};
|
||||
|
||||
ret = kernel_thread(request_firmware_work_func, fw_work,
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#define FIRMWARE_NAME_MAX 30
|
||||
#define FW_ACTION_NOHOTPLUG 0
|
||||
#define FW_ACTION_HOTPLUG 1
|
||||
|
||||
struct firmware {
|
||||
size_t size;
|
||||
u8 *data;
|
||||
|
@ -11,7 +14,7 @@ struct device;
|
|||
int request_firmware(const struct firmware **fw, const char *name,
|
||||
struct device *device);
|
||||
int request_firmware_nowait(
|
||||
struct module *module,
|
||||
struct module *module, int hotplug,
|
||||
const char *name, struct device *device, void *context,
|
||||
void (*cont)(const struct firmware *fw, void *context));
|
||||
|
||||
|
|
Loading…
Reference in a new issue