[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:
committed by
Linus Torvalds
parent
f3ef6f63e5
commit
6e3eaab020
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_bit(FW_STATUS_READY, &fw_priv->status);
|
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;
|
*class_dev_p = class_dev;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -386,21 +390,9 @@ out:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int
|
||||||
* request_firmware: - request firmware to hotplug and wait for it
|
_request_firmware(const struct firmware **firmware_p, const char *name,
|
||||||
* Description:
|
struct device *device, int hotplug)
|
||||||
* @firmware will be used to return a firmware image by the name
|
|
||||||
* of @name for device @device.
|
|
||||||
*
|
|
||||||
* Should be called from user context where sleeping is allowed.
|
|
||||||
*
|
|
||||||
* @name will be use as $FIRMWARE in the hotplug environment and
|
|
||||||
* should be distinctive enough not to be confused with any other
|
|
||||||
* firmware image for this or any other device.
|
|
||||||
**/
|
|
||||||
int
|
|
||||||
request_firmware(const struct firmware **firmware_p, const char *name,
|
|
||||||
struct device *device)
|
|
||||||
{
|
{
|
||||||
struct class_device *class_dev;
|
struct class_device *class_dev;
|
||||||
struct firmware_priv *fw_priv;
|
struct firmware_priv *fw_priv;
|
||||||
@@ -419,22 +411,25 @@ request_firmware(const struct firmware **firmware_p, const char *name,
|
|||||||
}
|
}
|
||||||
memset(firmware, 0, sizeof (*firmware));
|
memset(firmware, 0, sizeof (*firmware));
|
||||||
|
|
||||||
retval = fw_setup_class_device(firmware, &class_dev, name, device);
|
retval = fw_setup_class_device(firmware, &class_dev, name, device,
|
||||||
|
hotplug);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto error_kfree_fw;
|
goto error_kfree_fw;
|
||||||
|
|
||||||
fw_priv = class_get_devdata(class_dev);
|
fw_priv = class_get_devdata(class_dev);
|
||||||
|
|
||||||
if (loading_timeout > 0) {
|
if (hotplug) {
|
||||||
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
|
if (loading_timeout > 0) {
|
||||||
add_timer(&fw_priv->timeout);
|
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
|
||||||
}
|
add_timer(&fw_priv->timeout);
|
||||||
|
}
|
||||||
|
|
||||||
kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
|
kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
|
||||||
wait_for_completion(&fw_priv->completion);
|
wait_for_completion(&fw_priv->completion);
|
||||||
set_bit(FW_STATUS_DONE, &fw_priv->status);
|
set_bit(FW_STATUS_DONE, &fw_priv->status);
|
||||||
|
del_timer_sync(&fw_priv->timeout);
|
||||||
del_timer_sync(&fw_priv->timeout);
|
} else
|
||||||
|
wait_for_completion(&fw_priv->completion);
|
||||||
|
|
||||||
down(&fw_lock);
|
down(&fw_lock);
|
||||||
if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
|
if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
|
||||||
@@ -454,6 +449,26 @@ out:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* request_firmware: - request firmware to hotplug and wait for it
|
||||||
|
* Description:
|
||||||
|
* @firmware will be used to return a firmware image by the name
|
||||||
|
* of @name for device @device.
|
||||||
|
*
|
||||||
|
* Should be called from user context where sleeping is allowed.
|
||||||
|
*
|
||||||
|
* @name will be use as $FIRMWARE in the hotplug environment and
|
||||||
|
* should be distinctive enough not to be confused with any other
|
||||||
|
* firmware image for this or any other device.
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
request_firmware(const struct firmware **firmware_p, const char *name,
|
||||||
|
struct device *device)
|
||||||
|
{
|
||||||
|
int hotplug = 1;
|
||||||
|
return _request_firmware(firmware_p, name, device, hotplug);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* release_firmware: - release the resource associated with a firmware image
|
* release_firmware: - release the resource associated with a firmware image
|
||||||
**/
|
**/
|
||||||
@@ -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));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user