diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Kconfig | 64 | ||||
-rw-r--r-- | drivers/base/devres.c | 1 | ||||
-rw-r--r-- | drivers/base/devtmpfs.c | 7 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 11 | ||||
-rw-r--r-- | drivers/base/memory.c | 2 | ||||
-rw-r--r-- | drivers/base/platform.c | 21 | ||||
-rw-r--r-- | drivers/base/power/clock_ops.c | 111 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 33 | ||||
-rw-r--r-- | drivers/base/power/opp.c | 2 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 10 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 2 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-i2c.c | 1 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-spi.c | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 7 |
14 files changed, 157 insertions, 118 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index b605d01f5d45..21cf46f45245 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -16,6 +16,11 @@ config UEVENT_HELPER_PATH that it creates a high system load, or on smaller systems it is known to create out-of-memory situations during bootup. + To disable user space helper program execution at early boot + time specify an empty string here. This setting can be altered + via /proc/sys/kernel/hotplug or via /sys/kernel/uevent_helper + later at runtime. + config DEVTMPFS bool "Maintain a devtmpfs filesystem to mount at /dev" depends on HOTPLUG @@ -65,17 +70,17 @@ config PREVENT_FIRMWARE_BUILD default y help Say yes to avoid building firmware. Firmware is usually shipped - with the driver, and only when updating the firmware a rebuild - should be made. - If unsure say Y here. + with the driver and only when updating the firmware should a + rebuild be made. + If unsure, say Y here. config FW_LOADER tristate "Userspace firmware loading support" if EXPERT default y ---help--- - This option is provided for the case where no in-kernel-tree modules - require userspace firmware loading support, but a module built outside - the kernel tree does. + This option is provided for the case where none of the in-tree modules + require userspace firmware loading support, but a module built + out-of-tree does. config FIRMWARE_IN_KERNEL bool "Include in-kernel firmware blobs in kernel binary" @@ -83,22 +88,22 @@ config FIRMWARE_IN_KERNEL default y help The kernel source tree includes a number of firmware 'blobs' - which are used by various drivers. The recommended way to - use these is to run "make firmware_install" and to copy the - resulting binary files created in usr/lib/firmware directory - of the kernel tree to the /lib/firmware on your system so + that are used by various drivers. The recommended way to + use these is to run "make firmware_install", which, after + converting ihex files to binary, copies all of the needed + binary files in firmware/ to /lib/firmware/ on your system so that they can be loaded by userspace helpers on request. Enabling this option will build each required firmware blob into the kernel directly, where request_firmware() will find them without having to call out to userspace. This may be - useful if your root file system requires a device which uses - such firmware, and do not wish to use an initrd. + useful if your root file system requires a device that uses + such firmware and do not wish to use an initrd. This single option controls the inclusion of firmware for - every driver which uses request_firmware() and ships its - firmware in the kernel source tree, to avoid a proliferation - of 'Include firmware for xxx device' options. + every driver that uses request_firmware() and ships its + firmware in the kernel source tree, which avoids a + proliferation of 'Include firmware for xxx device' options. Say 'N' and let firmware be loaded from userspace. @@ -106,27 +111,27 @@ config EXTRA_FIRMWARE string "External firmware blobs to build into the kernel binary" depends on FW_LOADER help - This option allows firmware to be built into the kernel, for the - cases where the user either cannot or doesn't want to provide it from + This option allows firmware to be built into the kernel for the case + where the user either cannot or doesn't want to provide it from userspace at runtime (for example, when the firmware in question is required for accessing the boot device, and the user doesn't want to use an initrd). - This option is a string, and takes the (space-separated) names of the - firmware files -- the same names which appear in MODULE_FIRMWARE() + This option is a string and takes the (space-separated) names of the + firmware files -- the same names that appear in MODULE_FIRMWARE() and request_firmware() in the source. These files should exist under the directory specified by the EXTRA_FIRMWARE_DIR option, which is - by default the firmware/ subdirectory of the kernel source tree. + by default the firmware subdirectory of the kernel source tree. - So, for example, you might set CONFIG_EXTRA_FIRMWARE="usb8388.bin", - copy the usb8388.bin file into the firmware/ directory, and build the - kernel. Then any request_firmware("usb8388.bin") will be - satisfied internally without needing to call out to userspace. + For example, you might set CONFIG_EXTRA_FIRMWARE="usb8388.bin", copy + the usb8388.bin file into the firmware directory, and build the kernel. + Then any request_firmware("usb8388.bin") will be satisfied internally + without needing to call out to userspace. WARNING: If you include additional firmware files into your binary - kernel image which are not available under the terms of the GPL, + kernel image that are not available under the terms of the GPL, then it may be a violation of the GPL to distribute the resulting - image -- since it combines both GPL and non-GPL work. You should + image since it combines both GPL and non-GPL work. You should consult a lawyer of your own before distributing such an image. config EXTRA_FIRMWARE_DIR @@ -136,10 +141,9 @@ config EXTRA_FIRMWARE_DIR help This option controls the directory in which the kernel build system looks for the firmware files listed in the EXTRA_FIRMWARE option. - The default is the firmware/ directory in the kernel source tree, - but by changing this option you can point it elsewhere, such as - the /lib/firmware/ directory or another separate directory - containing firmware files. + The default is firmware/ in the kernel source tree, but by changing + this option you can point it elsewhere, such as /lib/firmware/ or + some other directory containing the firmware files. config DEBUG_DRIVER bool "Driver Core verbose debug messages" diff --git a/drivers/base/devres.c b/drivers/base/devres.c index cf7a0c788052..65cd74832450 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -397,6 +397,7 @@ static int remove_nodes(struct device *dev, static int release_nodes(struct device *dev, struct list_head *first, struct list_head *end, unsigned long flags) + __releases(&dev->devres_lock) { LIST_HEAD(todo); int cnt; diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 6d678c99512e..a4760e095ff5 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -166,7 +166,7 @@ static int create_path(const char *nodepath) { char *path; char *s; - int err; + int err = 0; /* parent directories do not exist, create them */ path = kstrdup(nodepath, GFP_KERNEL); @@ -376,7 +376,7 @@ int devtmpfs_mount(const char *mntdir) return err; } -static __initdata DECLARE_COMPLETION(setup_done); +static DECLARE_COMPLETION(setup_done); static int handle(const char *name, mode_t mode, struct device *dev) { @@ -406,9 +406,10 @@ static int devtmpfsd(void *p) requests = NULL; spin_unlock(&req_lock); while (req) { + struct req *next = req->next; req->err = handle(req->name, req->mode, req->dev); complete(&req->done); - req = req->next; + req = next; } spin_lock(&req_lock); } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index bbb03e6f7255..06ed6b4e7df5 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -521,11 +521,6 @@ static int _request_firmware(const struct firmware **firmware_p, if (!firmware_p) return -EINVAL; - if (WARN_ON(usermodehelper_is_disabled())) { - dev_err(device, "firmware: %s will not be loaded\n", name); - return -EBUSY; - } - *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { dev_err(device, "%s: kmalloc(struct firmware) failed\n", @@ -539,6 +534,12 @@ static int _request_firmware(const struct firmware **firmware_p, return 0; } + if (WARN_ON(usermodehelper_is_disabled())) { + dev_err(device, "firmware: %s will not be loaded\n", name); + retval = -EBUSY; + goto out; + } + if (uevent) dev_dbg(device, "firmware: requesting %s\n", name); diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 45d7c8fc73bd..2840ed4668c1 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -24,7 +24,7 @@ #include <linux/stat.h> #include <linux/slab.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <asm/uaccess.h> static DEFINE_MUTEX(mem_sysfs_mutex); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 6040717b62bb..99a5272d7c2f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -32,6 +32,25 @@ struct device platform_bus = { EXPORT_SYMBOL_GPL(platform_bus); /** + * arch_setup_pdev_archdata - Allow manipulation of archdata before its used + * @pdev: platform device + * + * This is called before platform_device_add() such that any pdev_archdata may + * be setup before the platform_notifier is called. So if a user needs to + * manipulate any relevant information in the pdev_archdata they can do: + * + * platform_devic_alloc() + * ... manipulate ... + * platform_device_add() + * + * And if they don't care they can just call platform_device_register() and + * everything will just work out. + */ +void __weak arch_setup_pdev_archdata(struct platform_device *pdev) +{ +} + +/** * platform_get_resource - get a resource for a device * @dev: platform device * @type: resource type @@ -173,6 +192,7 @@ struct platform_device *platform_device_alloc(const char *name, int id) pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; + arch_setup_pdev_archdata(&pa->pdev); } return pa ? &pa->pdev : NULL; @@ -334,6 +354,7 @@ EXPORT_SYMBOL_GPL(platform_device_del); int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); + arch_setup_pdev_archdata(pdev); return platform_device_add(pdev); } EXPORT_SYMBOL_GPL(platform_device_register); diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index a846b2f95cfb..b97294e2d95b 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -19,7 +19,7 @@ struct pm_clk_data { struct list_head clock_list; - struct mutex lock; + spinlock_t lock; }; enum pce_status { @@ -42,6 +42,22 @@ static struct pm_clk_data *__to_pcd(struct device *dev) } /** + * pm_clk_acquire - Acquire a device clock. + * @dev: Device whose clock is to be acquired. + * @ce: PM clock entry corresponding to the clock. + */ +static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) +{ + ce->clk = clk_get(dev, ce->con_id); + if (IS_ERR(ce->clk)) { + ce->status = PCE_STATUS_ERROR; + } else { + ce->status = PCE_STATUS_ACQUIRED; + dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); + } +} + +/** * pm_clk_add - Start using a device clock for power management. * @dev: Device whose clock is going to be used for power management. * @con_id: Connection ID of the clock. @@ -73,26 +89,23 @@ int pm_clk_add(struct device *dev, const char *con_id) } } - mutex_lock(&pcd->lock); + pm_clk_acquire(dev, ce); + + spin_lock_irq(&pcd->lock); list_add_tail(&ce->node, &pcd->clock_list); - mutex_unlock(&pcd->lock); + spin_unlock_irq(&pcd->lock); return 0; } /** * __pm_clk_remove - Destroy PM clock entry. * @ce: PM clock entry to destroy. - * - * This routine must be called under the mutex protecting the PM list of clocks - * corresponding the the @ce's device. */ static void __pm_clk_remove(struct pm_clock_entry *ce) { if (!ce) return; - list_del(&ce->node); - if (ce->status < PCE_STATUS_ERROR) { if (ce->status == PCE_STATUS_ENABLED) clk_disable(ce->clk); @@ -123,21 +136,25 @@ void pm_clk_remove(struct device *dev, const char *con_id) if (!pcd) return; - mutex_lock(&pcd->lock); + spin_lock_irq(&pcd->lock); list_for_each_entry(ce, &pcd->clock_list, node) { - if (!con_id && !ce->con_id) { - __pm_clk_remove(ce); - break; - } else if (!con_id || !ce->con_id) { + if (!con_id && !ce->con_id) + goto remove; + else if (!con_id || !ce->con_id) continue; - } else if (!strcmp(con_id, ce->con_id)) { - __pm_clk_remove(ce); - break; - } + else if (!strcmp(con_id, ce->con_id)) + goto remove; } - mutex_unlock(&pcd->lock); + spin_unlock_irq(&pcd->lock); + return; + + remove: + list_del(&ce->node); + spin_unlock_irq(&pcd->lock); + + __pm_clk_remove(ce); } /** @@ -158,7 +175,7 @@ int pm_clk_init(struct device *dev) } INIT_LIST_HEAD(&pcd->clock_list); - mutex_init(&pcd->lock); + spin_lock_init(&pcd->lock); dev->power.subsys_data = pcd; return 0; } @@ -175,20 +192,27 @@ void pm_clk_destroy(struct device *dev) { struct pm_clk_data *pcd = __to_pcd(dev); struct pm_clock_entry *ce, *c; + struct list_head list; if (!pcd) return; dev->power.subsys_data = NULL; + INIT_LIST_HEAD(&list); - mutex_lock(&pcd->lock); + spin_lock_irq(&pcd->lock); list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node) - __pm_clk_remove(ce); + list_move(&ce->node, &list); - mutex_unlock(&pcd->lock); + spin_unlock_irq(&pcd->lock); kfree(pcd); + + list_for_each_entry_safe_reverse(ce, c, &list, node) { + list_del(&ce->node); + __pm_clk_remove(ce); + } } #endif /* CONFIG_PM */ @@ -196,23 +220,6 @@ void pm_clk_destroy(struct device *dev) #ifdef CONFIG_PM_RUNTIME /** - * pm_clk_acquire - Acquire a device clock. - * @dev: Device whose clock is to be acquired. - * @con_id: Connection ID of the clock. - */ -static void pm_clk_acquire(struct device *dev, - struct pm_clock_entry *ce) -{ - ce->clk = clk_get(dev, ce->con_id); - if (IS_ERR(ce->clk)) { - ce->status = PCE_STATUS_ERROR; - } else { - ce->status = PCE_STATUS_ACQUIRED; - dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); - } -} - -/** * pm_clk_suspend - Disable clocks in a device's PM clock list. * @dev: Device to disable the clocks for. */ @@ -220,25 +227,23 @@ int pm_clk_suspend(struct device *dev) { struct pm_clk_data *pcd = __to_pcd(dev); struct pm_clock_entry *ce; + unsigned long flags; dev_dbg(dev, "%s()\n", __func__); if (!pcd) return 0; - mutex_lock(&pcd->lock); + spin_lock_irqsave(&pcd->lock, flags); list_for_each_entry_reverse(ce, &pcd->clock_list, node) { - if (ce->status == PCE_STATUS_NONE) - pm_clk_acquire(dev, ce); - if (ce->status < PCE_STATUS_ERROR) { clk_disable(ce->clk); ce->status = PCE_STATUS_ACQUIRED; } } - mutex_unlock(&pcd->lock); + spin_unlock_irqrestore(&pcd->lock, flags); return 0; } @@ -251,25 +256,23 @@ int pm_clk_resume(struct device *dev) { struct pm_clk_data *pcd = __to_pcd(dev); struct pm_clock_entry *ce; + unsigned long flags; dev_dbg(dev, "%s()\n", __func__); if (!pcd) return 0; - mutex_lock(&pcd->lock); + spin_lock_irqsave(&pcd->lock, flags); list_for_each_entry(ce, &pcd->clock_list, node) { - if (ce->status == PCE_STATUS_NONE) - pm_clk_acquire(dev, ce); - if (ce->status < PCE_STATUS_ERROR) { clk_enable(ce->clk); ce->status = PCE_STATUS_ENABLED; } } - mutex_unlock(&pcd->lock); + spin_unlock_irqrestore(&pcd->lock, flags); return 0; } @@ -344,6 +347,7 @@ int pm_clk_suspend(struct device *dev) { struct pm_clk_data *pcd = __to_pcd(dev); struct pm_clock_entry *ce; + unsigned long flags; dev_dbg(dev, "%s()\n", __func__); @@ -351,12 +355,12 @@ int pm_clk_suspend(struct device *dev) if (!pcd || !dev->driver) return 0; - mutex_lock(&pcd->lock); + spin_lock_irqsave(&pcd->lock, flags); list_for_each_entry_reverse(ce, &pcd->clock_list, node) clk_disable(ce->clk); - mutex_unlock(&pcd->lock); + spin_unlock_irqrestore(&pcd->lock, flags); return 0; } @@ -369,6 +373,7 @@ int pm_clk_resume(struct device *dev) { struct pm_clk_data *pcd = __to_pcd(dev); struct pm_clock_entry *ce; + unsigned long flags; dev_dbg(dev, "%s()\n", __func__); @@ -376,12 +381,12 @@ int pm_clk_resume(struct device *dev) if (!pcd || !dev->driver) return 0; - mutex_lock(&pcd->lock); + spin_lock_irqsave(&pcd->lock, flags); list_for_each_entry(ce, &pcd->clock_list, node) clk_enable(ce->clk); - mutex_unlock(&pcd->lock); + spin_unlock_irqrestore(&pcd->lock, flags); return 0; } diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index be8714aa9dd6..1c374579407c 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -80,7 +80,6 @@ static void genpd_set_active(struct generic_pm_domain *genpd) int pm_genpd_poweron(struct generic_pm_domain *genpd) { struct generic_pm_domain *parent = genpd->parent; - DEFINE_WAIT(wait); int ret = 0; start: @@ -112,7 +111,7 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd) } if (genpd->power_on) { - int ret = genpd->power_on(genpd); + ret = genpd->power_on(genpd); if (ret) goto out; } @@ -461,6 +460,21 @@ static int pm_genpd_runtime_resume(struct device *dev) return 0; } +/** + * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use. + */ +void pm_genpd_poweroff_unused(void) +{ + struct generic_pm_domain *genpd; + + mutex_lock(&gpd_list_lock); + + list_for_each_entry(genpd, &gpd_list, gpd_list_node) + genpd_queue_power_off_work(genpd); + + mutex_unlock(&gpd_list_lock); +} + #else static inline void genpd_power_off_work_fn(struct work_struct *work) {} @@ -1256,18 +1270,3 @@ void pm_genpd_init(struct generic_pm_domain *genpd, list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); } - -/** - * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use. - */ -void pm_genpd_poweroff_unused(void) -{ - struct generic_pm_domain *genpd; - - mutex_lock(&gpd_list_lock); - - list_for_each_entry(genpd, &gpd_list, gpd_list_node) - genpd_queue_power_off_work(genpd); - - mutex_unlock(&gpd_list_lock); -} diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 5cc12322ef32..b23de185cb04 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -453,7 +453,7 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) static int opp_set_availability(struct device *dev, unsigned long freq, bool availability_req) { - struct device_opp *tmp_dev_opp, *dev_opp = NULL; + struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV); struct opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV); int r = 0; diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 8dc247c974af..acb3f83b8079 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -226,11 +226,17 @@ static int rpm_idle(struct device *dev, int rpmflags) callback = NULL; if (callback) { - spin_unlock_irq(&dev->power.lock); + if (dev->power.irq_safe) + spin_unlock(&dev->power.lock); + else + spin_unlock_irq(&dev->power.lock); callback(dev); - spin_lock_irq(&dev->power.lock); + if (dev->power.irq_safe) + spin_lock(&dev->power.lock); + else + spin_lock_irq(&dev->power.lock); } dev->power.idle_notification = false; diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 942d6a7c9ae1..17b7934f31cb 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -5,7 +5,7 @@ #include <linux/device.h> #include <linux/string.h> #include <linux/pm_runtime.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <linux/jiffies.h> #include "power.h" diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index c2231ff06cbc..c4f7a45cd2c3 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -113,3 +113,4 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c, } EXPORT_SYMBOL_GPL(regmap_init_i2c); +MODULE_LICENSE("GPL"); diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 4deba0621bc7..f8396945d6ed 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -13,6 +13,7 @@ #include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/init.h> +#include <linux/module.h> static int regmap_spi_write(struct device *dev, const void *data, size_t count) { @@ -70,3 +71,5 @@ struct regmap *regmap_init_spi(struct spi_device *spi, return regmap_init(&spi->dev, ®map_spi, config); } EXPORT_SYMBOL_GPL(regmap_init_spi); + +MODULE_LICENSE("GPL"); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index cf3565cae93d..20663f8dae45 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -168,13 +168,11 @@ struct regmap *regmap_init(struct device *dev, map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL); if (map->work_buf == NULL) { ret = -ENOMEM; - goto err_bus; + goto err_map; } return map; -err_bus: - module_put(map->bus->owner); err_map: kfree(map); err: @@ -188,7 +186,6 @@ EXPORT_SYMBOL_GPL(regmap_init); void regmap_exit(struct regmap *map) { kfree(map->work_buf); - module_put(map->bus->owner); kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); @@ -317,7 +314,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, u8[0] |= map->bus->read_flag_mask; ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes, - val, map->format.val_bytes); + val, val_len); if (ret != 0) return ret; |