mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-17 20:25: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_DONE,
|
||||||
FW_STATUS_ABORT,
|
FW_STATUS_ABORT,
|
||||||
FW_STATUS_READY,
|
FW_STATUS_READY,
|
||||||
|
FW_STATUS_READY_NOHOTPLUG,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int loading_timeout = 10; /* In seconds */
|
static int loading_timeout = 10; /* In seconds */
|
||||||
|
@ -344,7 +345,7 @@ error_kfree:
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
|
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 class_device *class_dev;
|
||||||
struct firmware_priv *fw_priv;
|
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;
|
goto error_unreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hotplug)
|
||||||
set_bit(FW_STATUS_READY, &fw_priv->status);
|
set_bit(FW_STATUS_READY, &fw_priv->status);
|
||||||
|
else
|
||||||
|
set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
|
||||||
*class_dev_p = class_dev;
|
*class_dev_p = class_dev;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -386,6 +390,65 @@ out:
|
||||||
return retval;
|
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
|
* request_firmware: - request firmware to hotplug and wait for it
|
||||||
* Description:
|
* Description:
|
||||||
|
@ -402,56 +465,8 @@ int
|
||||||
request_firmware(const struct firmware **firmware_p, const char *name,
|
request_firmware(const struct firmware **firmware_p, const char *name,
|
||||||
struct device *device)
|
struct device *device)
|
||||||
{
|
{
|
||||||
struct class_device *class_dev;
|
int hotplug = 1;
|
||||||
struct firmware_priv *fw_priv;
|
return _request_firmware(firmware_p, name, device, hotplug);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -491,6 +506,7 @@ struct firmware_work {
|
||||||
struct device *device;
|
struct device *device;
|
||||||
void *context;
|
void *context;
|
||||||
void (*cont)(const struct firmware *fw, void *context);
|
void (*cont)(const struct firmware *fw, void *context);
|
||||||
|
int hotplug;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -503,7 +519,8 @@ request_firmware_work_func(void *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
daemonize("%s/%s", "firmware", fw_work->name);
|
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);
|
fw_work->cont(fw, fw_work->context);
|
||||||
release_firmware(fw);
|
release_firmware(fw);
|
||||||
module_put(fw_work->module);
|
module_put(fw_work->module);
|
||||||
|
@ -518,6 +535,9 @@ request_firmware_work_func(void *arg)
|
||||||
* Asynchronous variant of request_firmware() for contexts where
|
* Asynchronous variant of request_firmware() for contexts where
|
||||||
* it is not possible to sleep.
|
* 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.
|
* @cont will be called asynchronously when the firmware request is over.
|
||||||
*
|
*
|
||||||
* @context will be passed over to @cont.
|
* @context will be passed over to @cont.
|
||||||
|
@ -527,7 +547,7 @@ request_firmware_work_func(void *arg)
|
||||||
**/
|
**/
|
||||||
int
|
int
|
||||||
request_firmware_nowait(
|
request_firmware_nowait(
|
||||||
struct module *module,
|
struct module *module, int hotplug,
|
||||||
const char *name, struct device *device, void *context,
|
const char *name, struct device *device, void *context,
|
||||||
void (*cont)(const struct firmware *fw, void *context))
|
void (*cont)(const struct firmware *fw, void *context))
|
||||||
{
|
{
|
||||||
|
@ -548,6 +568,7 @@ request_firmware_nowait(
|
||||||
.device = device,
|
.device = device,
|
||||||
.context = context,
|
.context = context,
|
||||||
.cont = cont,
|
.cont = cont,
|
||||||
|
.hotplug = hotplug,
|
||||||
};
|
};
|
||||||
|
|
||||||
ret = kernel_thread(request_firmware_work_func, fw_work,
|
ret = kernel_thread(request_firmware_work_func, fw_work,
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#define FIRMWARE_NAME_MAX 30
|
#define FIRMWARE_NAME_MAX 30
|
||||||
|
#define FW_ACTION_NOHOTPLUG 0
|
||||||
|
#define FW_ACTION_HOTPLUG 1
|
||||||
|
|
||||||
struct firmware {
|
struct firmware {
|
||||||
size_t size;
|
size_t size;
|
||||||
u8 *data;
|
u8 *data;
|
||||||
|
@ -11,7 +14,7 @@ struct device;
|
||||||
int request_firmware(const struct firmware **fw, const char *name,
|
int request_firmware(const struct firmware **fw, const char *name,
|
||||||
struct device *device);
|
struct device *device);
|
||||||
int request_firmware_nowait(
|
int request_firmware_nowait(
|
||||||
struct module *module,
|
struct module *module, int hotplug,
|
||||||
const char *name, struct device *device, void *context,
|
const char *name, struct device *device, void *context,
|
||||||
void (*cont)(const struct firmware *fw, void *context));
|
void (*cont)(const struct firmware *fw, void *context));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue