From 1a5d76dbe825fa6deba3d8979bbd334ea17b6dcc Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Sat, 8 Dec 2012 15:38:06 -0200 Subject: drivers/base/core.c: Remove two unused variables and two useless calls to kfree old_class_name, and new_class_name are never used. This patch remove the declaration and calls to kfree. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r1 forall@ type T; identifier i; @@ * T *i = NULL; ... when != i * kfree(i); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index a235085e343..27603a6c0a9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1685,8 +1685,6 @@ EXPORT_SYMBOL_GPL(device_destroy); */ int device_rename(struct device *dev, const char *new_name) { - char *old_class_name = NULL; - char *new_class_name = NULL; char *old_device_name = NULL; int error; @@ -1717,8 +1715,6 @@ int device_rename(struct device *dev, const char *new_name) out: put_device(dev); - kfree(new_class_name); - kfree(old_class_name); kfree(old_device_name); return error; -- cgit v1.2.3 From f5e097f0465e874ac76e8b6ae355b6faa83973a1 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 11 Dec 2012 16:05:26 +0100 Subject: dma_buf: Cleanup dma_buf_fd Remove redundant 'error' variable. Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman --- drivers/base/dma-buf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index a3f79c495a4..ff5b745c470 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -134,15 +134,14 @@ EXPORT_SYMBOL_GPL(dma_buf_export); */ int dma_buf_fd(struct dma_buf *dmabuf, int flags) { - int error, fd; + int fd; if (!dmabuf || !dmabuf->file) return -EINVAL; - error = get_unused_fd_flags(flags); - if (error < 0) - return error; - fd = error; + fd = get_unused_fd_flags(flags); + if (fd < 0) + return fd; fd_install(fd, dmabuf->file); -- cgit v1.2.3 From e79798659339be800bf553c0b6fb06745aecf37f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Dec 2012 10:19:07 -0800 Subject: drivers: base: Convert print_symbol to %pSR Use the new vsprintf extension to avoid any possible message interleaving. Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index 27603a6c0a9..2937c631ea4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -97,8 +97,8 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { - print_symbol("dev_attr_show: %s returned bad count\n", - (unsigned long)dev_attr->show); + printk("dev_attr_show: %pSR returned bad count\n", + dev_attr->show); } return ret; } -- cgit v1.2.3 From 190888ac01d059e38ffe77a2291d44cafa9016fb Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 19 Nov 2012 23:35:17 +0800 Subject: driver core: fix possible missing of device probe Inside bus_add_driver(), one device might be added(device_add()) into the bus or probed which is triggered by deferred probe just after completing of driver_attach() and before 'klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers)', so the device won't be probed by this driver. This patch moves the below line 'klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers)' before driver_attach() inside bus_add_driver() to fix the problem. Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 24eb0786834..f9d31320bd3 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -700,12 +700,12 @@ int bus_add_driver(struct device_driver *drv) if (error) goto out_unregister; + klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } - klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); -- cgit v1.2.3 From 53a9c87e7e02abf3575be98c9fb2018fa30a61b9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 Jan 2013 13:10:23 -0800 Subject: Revert "drivers: base: Convert print_symbol to %pSR" This reverts commit e79798659339be800bf553c0b6fb06745aecf37f as %pSR isn't in the tree yet. Cc: Joe Perches Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index 2937c631ea4..27603a6c0a9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -97,8 +97,8 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { - printk("dev_attr_show: %pSR returned bad count\n", - dev_attr->show); + print_symbol("dev_attr_show: %s returned bad count\n", + (unsigned long)dev_attr->show); } return ret; } -- cgit v1.2.3 From 4fa3e78be7e985ca814ce2aa0c09cbee404efcf7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 29 Jan 2013 16:44:27 -0700 Subject: Driver core: treat unregistered bus_types as having no devices A bus_type has a list of devices (klist_devices), but the list and the subsys_private structure that contains it are not initialized until the bus_type is registered with bus_register(). The panic/reboot path has fixups that look up devices in pci_bus_type. If we panic before registering pci_bus_type, the bus_type exists but the list does not, so mach_reboot_fixups() trips over a null pointer and panics again: mach_reboot_fixups pci_get_device .. bus_find_device(&pci_bus_type, ...) bus->p is NULL Joonsoo reported a problem when panicking before PCI was initialized. I think this patch should be sufficient to replace the patch he posted here: https://lkml.org/lkml/2012/12/28/75 ("[PATCH] x86, reboot: skip reboot_fixups in early boot phase") Reported-by: Joonsoo Kim Signed-off-by: Bjorn Helgaas Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index f9d31320bd3..519865b53f7 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -290,7 +290,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start, struct device *dev; int error = 0; - if (!bus) + if (!bus || !bus->p) return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i, @@ -324,7 +324,7 @@ struct device *bus_find_device(struct bus_type *bus, struct klist_iter i; struct device *dev; - if (!bus) + if (!bus || !bus->p) return NULL; klist_iter_init_node(&bus->p->klist_devices, &i, -- cgit v1.2.3 From 4e0c92d015235d1dc65f9668a10cef2cea468ba2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 31 Jan 2013 11:13:54 +0100 Subject: firmware: Refactoring for splitting user-mode helper code Since 3.7 kernel, the firmware loader can read the firmware files directly, and the traditional user-mode helper is invoked only as a fallback. This seems working pretty well, and the next step would be to reduce the redundant user-mode helper stuff in future. This patch is a preparation for that: refactor the code for splitting user-mode helper stuff more easily. No functional change. Acked-by: Ming Lei Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 287 ++++++++++++++++++++++-------------------- 1 file changed, 154 insertions(+), 133 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b392b353be3..40ec60affd8 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -319,7 +319,8 @@ static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf return true; } -static bool fw_get_filesystem_firmware(struct firmware_buf *buf) +static bool fw_get_filesystem_firmware(struct device *device, + struct firmware_buf *buf) { int i; bool success = false; @@ -343,6 +344,16 @@ static bool fw_get_filesystem_firmware(struct firmware_buf *buf) break; } __putname(path); + + if (success) { + dev_dbg(device, "firmware: direct-loading firmware %s\n", + buf->fw_id); + mutex_lock(&fw_lock); + set_bit(FW_STATUS_DONE, &buf->status); + complete_all(&buf->completion); + mutex_unlock(&fw_lock); + } + return success; } @@ -796,99 +807,112 @@ static int fw_add_devm_name(struct device *dev, const char *name) } #endif -static void _request_firmware_cleanup(const struct firmware **firmware_p) +/* wait until the shared firmware_buf becomes ready (or error) */ +static int sync_cached_firmware_buf(struct firmware_buf *buf) { - release_firmware(*firmware_p); - *firmware_p = NULL; + int ret = 0; + + mutex_lock(&fw_lock); + while (!test_bit(FW_STATUS_DONE, &buf->status)) { + if (test_bit(FW_STATUS_ABORT, &buf->status)) { + ret = -ENOENT; + break; + } + mutex_unlock(&fw_lock); + wait_for_completion(&buf->completion); + mutex_lock(&fw_lock); + } + mutex_unlock(&fw_lock); + return ret; } -static struct firmware_priv * -_request_firmware_prepare(const struct firmware **firmware_p, const char *name, - struct device *device, bool uevent, bool nowait) +/* prepare firmware and firmware_buf structs; + * return 0 if a firmware is already assigned, 1 if need to load one, + * or a negative error code + */ +static int +_request_firmware_prepare(struct firmware **firmware_p, const char *name, + struct device *device) { struct firmware *firmware; - struct firmware_priv *fw_priv = NULL; struct firmware_buf *buf; int ret; - if (!firmware_p) - return ERR_PTR(-EINVAL); - *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { dev_err(device, "%s: kmalloc(struct firmware) failed\n", __func__); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } if (fw_get_builtin_firmware(firmware, name)) { dev_dbg(device, "firmware: using built-in firmware %s\n", name); - return NULL; + return 0; /* assigned */ } ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf); - if (!ret) - fw_priv = fw_create_instance(firmware, name, device, - uevent, nowait); - if (IS_ERR(fw_priv) || ret < 0) { - kfree(firmware); - *firmware_p = NULL; - return ERR_PTR(-ENOMEM); - } else if (fw_priv) { - fw_priv->buf = buf; + /* + * bind with 'buf' now to avoid warning in failure path + * of requesting firmware. + */ + firmware->priv = buf; - /* - * bind with 'buf' now to avoid warning in failure path - * of requesting firmware. - */ - firmware->priv = buf; - return fw_priv; + if (ret > 0) { + ret = sync_cached_firmware_buf(buf); + if (!ret) { + fw_set_page_data(buf, firmware); + return 0; /* assigned */ + } } - /* share the cached buf, which is inprogessing or completed */ - check_status: + if (ret < 0) + return ret; + return 1; /* need to load */ +} + +static int assign_firmware_buf(struct firmware *fw, struct device *device) +{ + struct firmware_buf *buf = fw->priv; + mutex_lock(&fw_lock); - if (test_bit(FW_STATUS_ABORT, &buf->status)) { - fw_priv = ERR_PTR(-ENOENT); - firmware->priv = buf; - _request_firmware_cleanup(firmware_p); - goto exit; - } else if (test_bit(FW_STATUS_DONE, &buf->status)) { - fw_priv = NULL; - fw_set_page_data(buf, firmware); - goto exit; + if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status)) { + mutex_unlock(&fw_lock); + return -ENOENT; } - mutex_unlock(&fw_lock); - wait_for_completion(&buf->completion); - goto check_status; -exit: + /* + * add firmware name into devres list so that we can auto cache + * and uncache firmware for device. + * + * device may has been deleted already, but the problem + * should be fixed in devres or driver core. + */ + if (device) + fw_add_devm_name(device, buf->fw_id); + + /* + * After caching firmware image is started, let it piggyback + * on request firmware. + */ + if (buf->fwc->state == FW_LOADER_START_CACHE) { + if (fw_cache_piggyback_on_request(buf->fw_id)) + kref_get(&buf->ref); + } + + /* pass the pages buffer to driver at the last minute */ + fw_set_page_data(buf, fw); mutex_unlock(&fw_lock); - return fw_priv; + return 0; } +/* load a firmware via user helper */ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, long timeout) { int retval = 0; struct device *f_dev = &fw_priv->dev; struct firmware_buf *buf = fw_priv->buf; - struct firmware_cache *fwc = &fw_cache; - int direct_load = 0; - - /* try direct loading from fs first */ - if (fw_get_filesystem_firmware(buf)) { - dev_dbg(f_dev->parent, "firmware: direct-loading" - " firmware %s\n", buf->fw_id); - - mutex_lock(&fw_lock); - set_bit(FW_STATUS_DONE, &buf->status); - mutex_unlock(&fw_lock); - complete_all(&buf->completion); - direct_load = 1; - goto handle_fw; - } /* fall back on userspace loading */ buf->fmt = PAGE_BUF; @@ -929,38 +953,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, cancel_delayed_work_sync(&fw_priv->timeout_work); -handle_fw: - mutex_lock(&fw_lock); - if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status)) - retval = -ENOENT; - - /* - * add firmware name into devres list so that we can auto cache - * and uncache firmware for device. - * - * f_dev->parent may has been deleted already, but the problem - * should be fixed in devres or driver core. - */ - if (!retval && f_dev->parent) - fw_add_devm_name(f_dev->parent, buf->fw_id); - - /* - * After caching firmware image is started, let it piggyback - * on request firmware. - */ - if (!retval && fwc->state == FW_LOADER_START_CACHE) { - if (fw_cache_piggyback_on_request(buf->fw_id)) - kref_get(&buf->ref); - } - - /* pass the pages buffer to driver at the last minute */ - fw_set_page_data(buf, fw_priv->fw); - fw_priv->buf = NULL; - mutex_unlock(&fw_lock); - - if (direct_load) - goto err_put_dev; device_remove_file(f_dev, &dev_attr_loading); err_del_bin_attr: @@ -972,6 +965,73 @@ err_put_dev: return retval; } +static int fw_load_from_user_helper(struct firmware *firmware, + const char *name, struct device *device, + bool uevent, bool nowait, long timeout) +{ + struct firmware_priv *fw_priv; + + fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); + if (IS_ERR(fw_priv)) + return PTR_ERR(fw_priv); + + fw_priv->buf = firmware->priv; + return _request_firmware_load(fw_priv, uevent, timeout); +} + +/* called from request_firmware() and request_firmware_work_func() */ +static int +_request_firmware(const struct firmware **firmware_p, const char *name, + struct device *device, bool uevent, bool nowait) +{ + struct firmware *fw; + long timeout; + int ret; + + if (!firmware_p) + return -EINVAL; + + ret = _request_firmware_prepare(&fw, name, device); + if (ret <= 0) /* error or already assigned */ + goto out; + + ret = 0; + timeout = firmware_loading_timeout(); + if (nowait) { + timeout = usermodehelper_read_lock_wait(timeout); + if (!timeout) { + dev_dbg(device, "firmware: %s loading timed out\n", + name); + ret = -EBUSY; + goto out; + } + } else { + ret = usermodehelper_read_trylock(); + if (WARN_ON(ret)) { + dev_err(device, "firmware: %s will not be loaded\n", + name); + goto out; + } + } + + if (!fw_get_filesystem_firmware(device, fw->priv)) + ret = fw_load_from_user_helper(fw, name, device, + uevent, nowait, timeout); + if (!ret) + ret = assign_firmware_buf(fw, device); + + usermodehelper_read_unlock(); + + out: + if (ret < 0) { + release_firmware(fw); + fw = NULL; + } + + *firmware_p = fw; + return ret; +} + /** * request_firmware: - send firmware request and wait for it * @firmware_p: pointer to firmware image @@ -996,26 +1056,7 @@ int request_firmware(const struct firmware **firmware_p, const char *name, struct device *device) { - struct firmware_priv *fw_priv; - int ret; - - fw_priv = _request_firmware_prepare(firmware_p, name, device, true, - false); - if (IS_ERR_OR_NULL(fw_priv)) - return PTR_RET(fw_priv); - - ret = usermodehelper_read_trylock(); - if (WARN_ON(ret)) { - dev_err(device, "firmware: %s will not be loaded\n", name); - } else { - ret = _request_firmware_load(fw_priv, true, - firmware_loading_timeout()); - usermodehelper_read_unlock(); - } - if (ret) - _request_firmware_cleanup(firmware_p); - - return ret; + return _request_firmware(firmware_p, name, device, true, false); } /** @@ -1046,33 +1087,13 @@ static void request_firmware_work_func(struct work_struct *work) { struct firmware_work *fw_work; const struct firmware *fw; - struct firmware_priv *fw_priv; - long timeout; - int ret; fw_work = container_of(work, struct firmware_work, work); - fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device, - fw_work->uevent, true); - if (IS_ERR_OR_NULL(fw_priv)) { - ret = PTR_RET(fw_priv); - goto out; - } - timeout = usermodehelper_read_lock_wait(firmware_loading_timeout()); - if (timeout) { - ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout); - usermodehelper_read_unlock(); - } else { - dev_dbg(fw_work->device, "firmware: %s loading timed out\n", - fw_work->name); - ret = -EAGAIN; - } - if (ret) - _request_firmware_cleanup(&fw); - - out: + _request_firmware(&fw, fw_work->name, fw_work->device, + fw_work->uevent, true); fw_work->cont(fw, fw_work->context); - put_device(fw_work->device); + put_device(fw_work->device); /* taken in request_firmware_nowait() */ module_put(fw_work->module); kfree(fw_work); -- cgit v1.2.3 From 7b1269f778782d2f42994a74bf4014d0cbebbf9f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 31 Jan 2013 11:13:55 +0100 Subject: firmware: Make user-mode helper optional This patch adds a new kconfig, CONFIG_FW_LOADER_USER_HELPER, and guards the user-helper codes in firmware_class.c with ifdefs. Yeah, yeah, there are lots of ifdefs in this patch. The further clean-up with code shuffling follows in the next. Acked-by: Ming Lei Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 11 +++++++++ drivers/base/firmware_class.c | 57 +++++++++++++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 13 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index c8b453939da..07abd9d76f7 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -145,6 +145,17 @@ config EXTRA_FIRMWARE_DIR this option you can point it elsewhere, such as /lib/firmware/ or some other directory containing the firmware files. +config FW_LOADER_USER_HELPER + bool "Fallback user-helper invocation for firmware loading" + depends on FW_LOADER + default y + help + This option enables / disables the invocation of user-helper + (e.g. udev) for loading firmware files as a fallback after the + direct file loading in kernel fails. The user-mode helper is + no longer required unless you have a special firmware file that + resides in a non-standard path. + config DEBUG_DRIVER bool "Driver Core verbose debug messages" depends on DEBUG_KERNEL diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 40ec60affd8..84b1c8d0ea5 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -88,10 +88,12 @@ enum { FW_STATUS_ABORT, }; +#ifdef CONFIG_FW_LOADER_USER_HELPER enum fw_buf_fmt { VMALLOC_BUF, /* used in direct loading */ PAGE_BUF, /* used in loading via userspace */ }; +#endif /* CONFIG_FW_LOADER_USER_HELPER */ static int loading_timeout = 60; /* In seconds */ @@ -128,12 +130,14 @@ struct firmware_buf { struct completion completion; struct firmware_cache *fwc; unsigned long status; - enum fw_buf_fmt fmt; void *data; size_t size; +#ifdef CONFIG_FW_LOADER_USER_HELPER + enum fw_buf_fmt fmt; struct page **pages; int nr_pages; int page_array_size; +#endif char fw_id[]; }; @@ -142,6 +146,7 @@ struct fw_cache_entry { char name[]; }; +#ifdef CONFIG_FW_LOADER_USER_HELPER struct firmware_priv { struct delayed_work timeout_work; bool nowait; @@ -149,6 +154,7 @@ struct firmware_priv { struct firmware_buf *buf; struct firmware *fw; }; +#endif struct fw_name_devm { unsigned long magic; @@ -182,7 +188,9 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, strcpy(buf->fw_id, fw_name); buf->fwc = fwc; init_completion(&buf->completion); +#ifdef CONFIG_FW_LOADER_USER_HELPER buf->fmt = VMALLOC_BUF; +#endif pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); @@ -240,7 +248,6 @@ static void __fw_free_buf(struct kref *ref) { struct firmware_buf *buf = to_fwbuf(ref); struct firmware_cache *fwc = buf->fwc; - int i; pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", __func__, buf->fw_id, buf, buf->data, @@ -250,12 +257,15 @@ static void __fw_free_buf(struct kref *ref) spin_unlock(&fwc->lock); +#ifdef CONFIG_FW_LOADER_USER_HELPER if (buf->fmt == PAGE_BUF) { + int i; vunmap(buf->data); for (i = 0; i < buf->nr_pages; i++) __free_page(buf->pages[i]); kfree(buf->pages); } else +#endif vfree(buf->data); kfree(buf); } @@ -357,6 +367,19 @@ static bool fw_get_filesystem_firmware(struct device *device, return success; } +/* firmware holds the ownership of pages */ +static void firmware_free_data(const struct firmware *fw) +{ + /* Loaded directly? */ + if (!fw->priv) { + vfree(fw->data); + return; + } + fw_free_buf(fw->priv); +} + +#ifdef CONFIG_FW_LOADER_USER_HELPER + static struct firmware_priv *to_firmware_priv(struct device *dev) { return container_of(dev, struct firmware_priv, dev); @@ -446,17 +469,6 @@ static ssize_t firmware_loading_show(struct device *dev, return sprintf(buf, "%d\n", loading); } -/* firmware holds the ownership of pages */ -static void firmware_free_data(const struct firmware *fw) -{ - /* Loaded directly? */ - if (!fw->priv) { - vfree(fw->data); - return; - } - fw_free_buf(fw->priv); -} - /* Some architectures don't have PAGE_KERNEL_RO */ #ifndef PAGE_KERNEL_RO #define PAGE_KERNEL_RO PAGE_KERNEL @@ -737,12 +749,15 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, exit: return fw_priv; } +#endif /* CONFIG_FW_LOADER_USER_HELPER */ /* store the pages buffer info firmware from buf */ static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) { fw->priv = buf; +#ifdef CONFIG_FW_LOADER_USER_HELPER fw->pages = buf->pages; +#endif fw->size = buf->size; fw->data = buf->data; @@ -906,6 +921,7 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device) return 0; } +#ifdef CONFIG_FW_LOADER_USER_HELPER /* load a firmware via user helper */ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, long timeout) @@ -978,6 +994,15 @@ static int fw_load_from_user_helper(struct firmware *firmware, fw_priv->buf = firmware->priv; return _request_firmware_load(fw_priv, uevent, timeout); } +#else /* CONFIG_FW_LOADER_USER_HELPER */ +static inline int +fw_load_from_user_helper(struct firmware *firmware, const char *name, + struct device *device, bool uevent, bool nowait, + long timeout) +{ + return -ENOENT; +} +#endif /* CONFIG_FW_LOADER_USER_HELPER */ /* called from request_firmware() and request_firmware_work_func() */ static int @@ -1495,7 +1520,11 @@ static void __init fw_cache_init(void) static int __init firmware_class_init(void) { fw_cache_init(); +#ifdef CONFIG_FW_LOADER_USER_HELPER return class_register(&firmware_class); +#else + return 0; +#endif } static void __exit firmware_class_exit(void) @@ -1504,7 +1533,9 @@ static void __exit firmware_class_exit(void) unregister_syscore_ops(&fw_syscore_ops); unregister_pm_notifier(&fw_cache.pm_notify); #endif +#ifdef CONFIG_FW_LOADER_USER_HELPER class_unregister(&firmware_class); +#endif } fs_initcall(firmware_class_init); -- cgit v1.2.3 From cd7239fab7d32e56909027bfb5a6c2d7d3d862f8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 31 Jan 2013 11:13:56 +0100 Subject: firmware: Reduce ifdef CONFIG_FW_LOADER_USER_HELPER By shuffling the code, reduce a few ifdefs in firmware_class.c. Also, firmware_buf fmt field is changed to is_pages_buf boolean for simplification. Acked-by: Ming Lei Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 313 ++++++++++++++++++++---------------------- 1 file changed, 151 insertions(+), 162 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 84b1c8d0ea5..51e62ca1d57 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -88,13 +88,6 @@ enum { FW_STATUS_ABORT, }; -#ifdef CONFIG_FW_LOADER_USER_HELPER -enum fw_buf_fmt { - VMALLOC_BUF, /* used in direct loading */ - PAGE_BUF, /* used in loading via userspace */ -}; -#endif /* CONFIG_FW_LOADER_USER_HELPER */ - static int loading_timeout = 60; /* In seconds */ static inline long firmware_loading_timeout(void) @@ -133,7 +126,7 @@ struct firmware_buf { void *data; size_t size; #ifdef CONFIG_FW_LOADER_USER_HELPER - enum fw_buf_fmt fmt; + bool is_paged_buf; struct page **pages; int nr_pages; int page_array_size; @@ -146,16 +139,6 @@ struct fw_cache_entry { char name[]; }; -#ifdef CONFIG_FW_LOADER_USER_HELPER -struct firmware_priv { - struct delayed_work timeout_work; - bool nowait; - struct device dev; - struct firmware_buf *buf; - struct firmware *fw; -}; -#endif - struct fw_name_devm { unsigned long magic; char name[]; @@ -188,9 +171,6 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, strcpy(buf->fw_id, fw_name); buf->fwc = fwc; init_completion(&buf->completion); -#ifdef CONFIG_FW_LOADER_USER_HELPER - buf->fmt = VMALLOC_BUF; -#endif pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); @@ -256,9 +236,8 @@ static void __fw_free_buf(struct kref *ref) list_del(&buf->list); spin_unlock(&fwc->lock); - #ifdef CONFIG_FW_LOADER_USER_HELPER - if (buf->fmt == PAGE_BUF) { + if (buf->is_paged_buf) { int i; vunmap(buf->data); for (i = 0; i < buf->nr_pages; i++) @@ -378,7 +357,89 @@ static void firmware_free_data(const struct firmware *fw) fw_free_buf(fw->priv); } +/* store the pages buffer info firmware from buf */ +static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) +{ + fw->priv = buf; +#ifdef CONFIG_FW_LOADER_USER_HELPER + fw->pages = buf->pages; +#endif + fw->size = buf->size; + fw->data = buf->data; + + pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", + __func__, buf->fw_id, buf, buf->data, + (unsigned int)buf->size); +} + +#ifdef CONFIG_PM_SLEEP +static void fw_name_devm_release(struct device *dev, void *res) +{ + struct fw_name_devm *fwn = res; + + if (fwn->magic == (unsigned long)&fw_cache) + pr_debug("%s: fw_name-%s devm-%p released\n", + __func__, fwn->name, res); +} + +static int fw_devm_match(struct device *dev, void *res, + void *match_data) +{ + struct fw_name_devm *fwn = res; + + return (fwn->magic == (unsigned long)&fw_cache) && + !strcmp(fwn->name, match_data); +} + +static struct fw_name_devm *fw_find_devm_name(struct device *dev, + const char *name) +{ + struct fw_name_devm *fwn; + + fwn = devres_find(dev, fw_name_devm_release, + fw_devm_match, (void *)name); + return fwn; +} + +/* add firmware name into devres list */ +static int fw_add_devm_name(struct device *dev, const char *name) +{ + struct fw_name_devm *fwn; + + fwn = fw_find_devm_name(dev, name); + if (fwn) + return 1; + + fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) + + strlen(name) + 1, GFP_KERNEL); + if (!fwn) + return -ENOMEM; + + fwn->magic = (unsigned long)&fw_cache; + strcpy(fwn->name, name); + devres_add(dev, fwn); + + return 0; +} +#else +static int fw_add_devm_name(struct device *dev, const char *name) +{ + return 0; +} +#endif + + +/* + * user-mode helper code + */ #ifdef CONFIG_FW_LOADER_USER_HELPER +struct firmware_priv { + struct delayed_work timeout_work; + bool nowait; + struct device dev; + struct firmware_buf *buf; + struct firmware *fw; +}; static struct firmware_priv *to_firmware_priv(struct device *dev) { @@ -477,7 +538,7 @@ static ssize_t firmware_loading_show(struct device *dev, /* one pages buffer should be mapped/unmapped only once */ static int fw_map_pages_buf(struct firmware_buf *buf) { - if (buf->fmt != PAGE_BUF) + if (!buf->is_paged_buf) return 0; if (buf->data) @@ -749,78 +810,89 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, exit: return fw_priv; } -#endif /* CONFIG_FW_LOADER_USER_HELPER */ -/* store the pages buffer info firmware from buf */ -static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) +/* load a firmware via user helper */ +static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, + long timeout) { - fw->priv = buf; -#ifdef CONFIG_FW_LOADER_USER_HELPER - fw->pages = buf->pages; -#endif - fw->size = buf->size; - fw->data = buf->data; + int retval = 0; + struct device *f_dev = &fw_priv->dev; + struct firmware_buf *buf = fw_priv->buf; - pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", - __func__, buf->fw_id, buf, buf->data, - (unsigned int)buf->size); -} + /* fall back on userspace loading */ + buf->is_paged_buf = true; -#ifdef CONFIG_PM_SLEEP -static void fw_name_devm_release(struct device *dev, void *res) -{ - struct fw_name_devm *fwn = res; + dev_set_uevent_suppress(f_dev, true); - if (fwn->magic == (unsigned long)&fw_cache) - pr_debug("%s: fw_name-%s devm-%p released\n", - __func__, fwn->name, res); -} + /* Need to pin this module until class device is destroyed */ + __module_get(THIS_MODULE); -static int fw_devm_match(struct device *dev, void *res, - void *match_data) -{ - struct fw_name_devm *fwn = res; + retval = device_add(f_dev); + if (retval) { + dev_err(f_dev, "%s: device_register failed\n", __func__); + goto err_put_dev; + } - return (fwn->magic == (unsigned long)&fw_cache) && - !strcmp(fwn->name, match_data); -} + retval = device_create_bin_file(f_dev, &firmware_attr_data); + if (retval) { + dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__); + goto err_del_dev; + } -static struct fw_name_devm *fw_find_devm_name(struct device *dev, - const char *name) -{ - struct fw_name_devm *fwn; + retval = device_create_file(f_dev, &dev_attr_loading); + if (retval) { + dev_err(f_dev, "%s: device_create_file failed\n", __func__); + goto err_del_bin_attr; + } - fwn = devres_find(dev, fw_name_devm_release, - fw_devm_match, (void *)name); - return fwn; -} + if (uevent) { + dev_set_uevent_suppress(f_dev, false); + dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id); + if (timeout != MAX_SCHEDULE_TIMEOUT) + schedule_delayed_work(&fw_priv->timeout_work, timeout); -/* add firmware name into devres list */ -static int fw_add_devm_name(struct device *dev, const char *name) -{ - struct fw_name_devm *fwn; + kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); + } - fwn = fw_find_devm_name(dev, name); - if (fwn) - return 1; + wait_for_completion(&buf->completion); - fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) + - strlen(name) + 1, GFP_KERNEL); - if (!fwn) - return -ENOMEM; + cancel_delayed_work_sync(&fw_priv->timeout_work); - fwn->magic = (unsigned long)&fw_cache; - strcpy(fwn->name, name); - devres_add(dev, fwn); + fw_priv->buf = NULL; - return 0; + device_remove_file(f_dev, &dev_attr_loading); +err_del_bin_attr: + device_remove_bin_file(f_dev, &firmware_attr_data); +err_del_dev: + device_del(f_dev); +err_put_dev: + put_device(f_dev); + return retval; } -#else -static int fw_add_devm_name(struct device *dev, const char *name) + +static int fw_load_from_user_helper(struct firmware *firmware, + const char *name, struct device *device, + bool uevent, bool nowait, long timeout) { - return 0; + struct firmware_priv *fw_priv; + + fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); + if (IS_ERR(fw_priv)) + return PTR_ERR(fw_priv); + + fw_priv->buf = firmware->priv; + return _request_firmware_load(fw_priv, uevent, timeout); } -#endif +#else /* CONFIG_FW_LOADER_USER_HELPER */ +static inline int +fw_load_from_user_helper(struct firmware *firmware, const char *name, + struct device *device, bool uevent, bool nowait, + long timeout) +{ + return -ENOENT; +} +#endif /* CONFIG_FW_LOADER_USER_HELPER */ + /* wait until the shared firmware_buf becomes ready (or error) */ static int sync_cached_firmware_buf(struct firmware_buf *buf) @@ -921,89 +993,6 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device) return 0; } -#ifdef CONFIG_FW_LOADER_USER_HELPER -/* load a firmware via user helper */ -static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, - long timeout) -{ - int retval = 0; - struct device *f_dev = &fw_priv->dev; - struct firmware_buf *buf = fw_priv->buf; - - /* fall back on userspace loading */ - buf->fmt = PAGE_BUF; - - dev_set_uevent_suppress(f_dev, true); - - /* Need to pin this module until class device is destroyed */ - __module_get(THIS_MODULE); - - retval = device_add(f_dev); - if (retval) { - dev_err(f_dev, "%s: device_register failed\n", __func__); - goto err_put_dev; - } - - retval = device_create_bin_file(f_dev, &firmware_attr_data); - if (retval) { - dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__); - goto err_del_dev; - } - - retval = device_create_file(f_dev, &dev_attr_loading); - if (retval) { - dev_err(f_dev, "%s: device_create_file failed\n", __func__); - goto err_del_bin_attr; - } - - if (uevent) { - dev_set_uevent_suppress(f_dev, false); - dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id); - if (timeout != MAX_SCHEDULE_TIMEOUT) - schedule_delayed_work(&fw_priv->timeout_work, timeout); - - kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); - } - - wait_for_completion(&buf->completion); - - cancel_delayed_work_sync(&fw_priv->timeout_work); - - fw_priv->buf = NULL; - - device_remove_file(f_dev, &dev_attr_loading); -err_del_bin_attr: - device_remove_bin_file(f_dev, &firmware_attr_data); -err_del_dev: - device_del(f_dev); -err_put_dev: - put_device(f_dev); - return retval; -} - -static int fw_load_from_user_helper(struct firmware *firmware, - const char *name, struct device *device, - bool uevent, bool nowait, long timeout) -{ - struct firmware_priv *fw_priv; - - fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); - if (IS_ERR(fw_priv)) - return PTR_ERR(fw_priv); - - fw_priv->buf = firmware->priv; - return _request_firmware_load(fw_priv, uevent, timeout); -} -#else /* CONFIG_FW_LOADER_USER_HELPER */ -static inline int -fw_load_from_user_helper(struct firmware *firmware, const char *name, - struct device *device, bool uevent, bool nowait, - long timeout) -{ - return -ENOENT; -} -#endif /* CONFIG_FW_LOADER_USER_HELPER */ - /* called from request_firmware() and request_firmware_work_func() */ static int _request_firmware(const struct firmware **firmware_p, const char *name, -- cgit v1.2.3 From 807be03cae191cb88e2f267adcd49aba785c658b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 31 Jan 2013 11:13:57 +0100 Subject: firmware: Ignore abort check when no user-helper is used FW_STATUS_ABORT can be set only during the user-helper invocation, thus we can ignore the check when CONFIG_HW_LOADER_USER_HELPER is disabled. Acked-by: Ming Lei Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 51e62ca1d57..4a223fedcd7 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -454,6 +454,9 @@ static void fw_load_abort(struct firmware_priv *fw_priv) complete_all(&buf->completion); } +#define is_fw_load_aborted(buf) \ + test_bit(FW_STATUS_ABORT, &(buf)->status) + static ssize_t firmware_timeout_show(struct class *class, struct class_attribute *attr, char *buf) @@ -891,6 +894,10 @@ fw_load_from_user_helper(struct firmware *firmware, const char *name, { return -ENOENT; } + +/* No abort during direct loading */ +#define is_fw_load_aborted(buf) false + #endif /* CONFIG_FW_LOADER_USER_HELPER */ @@ -901,7 +908,7 @@ static int sync_cached_firmware_buf(struct firmware_buf *buf) mutex_lock(&fw_lock); while (!test_bit(FW_STATUS_DONE, &buf->status)) { - if (test_bit(FW_STATUS_ABORT, &buf->status)) { + if (is_fw_load_aborted(buf)) { ret = -ENOENT; break; } @@ -963,7 +970,7 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device) struct firmware_buf *buf = fw->priv; mutex_lock(&fw_lock); - if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status)) { + if (!buf->size || is_fw_load_aborted(buf)) { mutex_unlock(&fw_lock); return -ENOENT; } -- cgit v1.2.3 From 9f3b795a626ee79574595e06d1437fe0c7d51d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 1 Feb 2013 20:40:17 +0100 Subject: driver-core: constify data for class_find_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All in-kernel users of class_find_device() don't really need mutable data for match callback. In two places (kernel/power/suspend_test.c, drivers/scsi/osd/osd_uld.c) this patch changes match callbacks to use const search data. The const is propagated to rtc_class_open() and power_supply_get_by_name() parameters. Note that there's a dev reference leak in suspend_test.c that's not touched in this patch. Signed-off-by: Michał Mirosław Acked-by: Grant Likely Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 4 ++-- drivers/base/core.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/class.c b/drivers/base/class.c index 03243d4002f..3ce84547132 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -420,8 +420,8 @@ EXPORT_SYMBOL_GPL(class_for_each_device); * code. There's no locking restriction. */ struct device *class_find_device(struct class *class, struct device *start, - void *data, - int (*match)(struct device *, void *)) + const void *data, + int (*match)(struct device *, const void *)) { struct class_dev_iter iter; struct device *dev; diff --git a/drivers/base/core.c b/drivers/base/core.c index 27603a6c0a9..56536f4b0f6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1617,9 +1617,9 @@ struct device *device_create(struct class *class, struct device *parent, } EXPORT_SYMBOL_GPL(device_create); -static int __match_devt(struct device *dev, void *data) +static int __match_devt(struct device *dev, const void *data) { - dev_t *devt = data; + const dev_t *devt = data; return dev->devt == *devt; } -- cgit v1.2.3 From d72cca1eee5b26e313da2a380d4862924e271031 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 14 Feb 2013 18:14:27 +0000 Subject: drivercore: Fix ordering between deferred_probe and exiting initcalls One of the side effects of deferred probe is that some drivers which used to be probed before initcalls completed are now happening slightly later. This causes two problems. - If a console driver gets deferred, then it may not be ready when userspace starts. For example, if a uart depends on pinctrl, then the uart will get deferred and /dev/console will not be available - __init sections will be discarded before built-in drivers are probed. Strictly speaking, __init functions should not be called in a drivers __probe path, but there are a lot of drivers (console stuff again) that do anyway. In the past it was perfectly safe to do so because all built-in drivers got probed before the end of initcalls. This patch fixes the problem by forcing the first pass of the deferred list to complete at late_initcall time. This is late enough to catch the drivers that are known to have the above issues. Signed-off-by: Grant Likely Tested-by: Haojian Zhuang Cc: Arnd Bergmann Cc: Russell King Cc: Linus Torvalds Cc: stable # 3.4+ Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index e3bbed8a617..61d3e1b4069 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -172,6 +172,8 @@ static int deferred_probe_initcall(void) driver_deferred_probe_enable = true; driver_deferred_probe_trigger(); + /* Sort as many dependencies as possible before exiting initcalls */ + flush_workqueue(deferred_wq); return 0; } late_initcall(deferred_probe_initcall); -- cgit v1.2.3 From 74fef7a8fd1d2bd94f925d6638bb4c3049e7c381 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 18 Feb 2013 21:09:03 +0200 Subject: base: memory: fix soft/hard_offline_page permissions those two sysfs files don't have a 'show' method, so they shouldn't have a read permission. Thanks to Greg Kroah-Hartman for actually looking into the source code and figuring out we had a real bug with these two files. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/base/memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 987604d56c8..83d0b17ba1c 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -494,8 +494,8 @@ store_hard_offline_page(struct device *dev, return ret ? ret : count; } -static DEVICE_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); -static DEVICE_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); +static DEVICE_ATTR(soft_offline_page, S_IWUSR, NULL, store_soft_offline_page); +static DEVICE_ATTR(hard_offline_page, S_IWUSR, NULL, store_hard_offline_page); static __init int memory_fail_init(void) { -- cgit v1.2.3