diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Kconfig | 7 | ||||
-rw-r--r-- | drivers/base/class.c | 9 | ||||
-rw-r--r-- | drivers/base/core.c | 130 | ||||
-rw-r--r-- | drivers/base/cpu.c | 2 | ||||
-rw-r--r-- | drivers/base/dd.c | 4 | ||||
-rw-r--r-- | drivers/base/devtmpfs.c | 5 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 206 | ||||
-rw-r--r-- | drivers/base/module.c | 4 | ||||
-rw-r--r-- | drivers/base/platform.c | 34 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 10 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 65 |
11 files changed, 333 insertions, 143 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index fd52c48ee76..ef38aff737e 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -18,9 +18,9 @@ config UEVENT_HELPER_PATH config DEVTMPFS bool "Maintain a devtmpfs filesystem to mount at /dev" - depends on HOTPLUG && SHMEM && TMPFS + depends on HOTPLUG help - This creates a tmpfs filesystem instance early at bootup. + This creates a tmpfs/ramfs filesystem instance early at bootup. In this filesystem, the kernel driver core maintains device nodes with their default names and permissions for all registered devices with an assigned major/minor number. @@ -33,6 +33,9 @@ config DEVTMPFS functional /dev without any further help. It also allows simple rescue systems, and reliably handles dynamic major/minor numbers. + Notice: if CONFIG_TMPFS isn't enabled, the simpler ramfs + file system will be used instead. + config DEVTMPFS_MOUNT bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs" depends on DEVTMPFS diff --git a/drivers/base/class.c b/drivers/base/class.c index 9c6a0d6408e..8e231d05b40 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -63,6 +63,14 @@ static void class_release(struct kobject *kobj) kfree(cp); } +static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj) +{ + struct class_private *cp = to_class(kobj); + struct class *class = cp->class; + + return class->ns_type; +} + static const struct sysfs_ops class_sysfs_ops = { .show = class_attr_show, .store = class_attr_store, @@ -71,6 +79,7 @@ static const struct sysfs_ops class_sysfs_ops = { static struct kobj_type class_ktype = { .sysfs_ops = &class_sysfs_ops, .release = class_release, + .child_ns_type = class_child_ns_type, }; /* Hotplug events for classes go to the class class_subsys */ diff --git a/drivers/base/core.c b/drivers/base/core.c index b56a0ba31d4..9630fbdf4e6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -20,7 +20,6 @@ #include <linux/notifier.h> #include <linux/genhd.h> #include <linux/kallsyms.h> -#include <linux/semaphore.h> #include <linux/mutex.h> #include <linux/async.h> @@ -132,9 +131,21 @@ static void device_release(struct kobject *kobj) kfree(p); } +static const void *device_namespace(struct kobject *kobj) +{ + struct device *dev = to_dev(kobj); + const void *ns = NULL; + + if (dev->class && dev->class->ns_type) + ns = dev->class->namespace(dev); + + return ns; +} + static struct kobj_type device_ktype = { .release = device_release, .sysfs_ops = &dev_sysfs_ops, + .namespace = device_namespace, }; @@ -559,10 +570,10 @@ void device_initialize(struct device *dev) dev->kobj.kset = devices_kset; kobject_init(&dev->kobj, &device_ktype); INIT_LIST_HEAD(&dev->dma_pools); - init_MUTEX(&dev->sem); + mutex_init(&dev->mutex); + lockdep_set_novalidate_class(&dev->mutex); spin_lock_init(&dev->devres_lock); INIT_LIST_HEAD(&dev->devres_head); - device_init_wakeup(dev, 0); device_pm_init(dev); set_dev_node(dev, -1); } @@ -596,11 +607,59 @@ static struct kobject *virtual_device_parent(struct device *dev) return virtual_dir; } -static struct kobject *get_device_parent(struct device *dev, - struct device *parent) +struct class_dir { + struct kobject kobj; + struct class *class; +}; + +#define to_class_dir(obj) container_of(obj, struct class_dir, kobj) + +static void class_dir_release(struct kobject *kobj) +{ + struct class_dir *dir = to_class_dir(kobj); + kfree(dir); +} + +static const +struct kobj_ns_type_operations *class_dir_child_ns_type(struct kobject *kobj) { + struct class_dir *dir = to_class_dir(kobj); + return dir->class->ns_type; +} + +static struct kobj_type class_dir_ktype = { + .release = class_dir_release, + .sysfs_ops = &kobj_sysfs_ops, + .child_ns_type = class_dir_child_ns_type +}; + +static struct kobject * +class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) +{ + struct class_dir *dir; int retval; + dir = kzalloc(sizeof(*dir), GFP_KERNEL); + if (!dir) + return NULL; + + dir->class = class; + kobject_init(&dir->kobj, &class_dir_ktype); + + dir->kobj.kset = &class->p->class_dirs; + + retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); + if (retval < 0) { + kobject_put(&dir->kobj); + return NULL; + } + return &dir->kobj; +} + + +static struct kobject *get_device_parent(struct device *dev, + struct device *parent) +{ if (dev->class) { static DEFINE_MUTEX(gdp_mutex); struct kobject *kobj = NULL; @@ -635,18 +694,7 @@ static struct kobject *get_device_parent(struct device *dev, } /* or create a new class-directory at the parent device */ - k = kobject_create(); - if (!k) { - mutex_unlock(&gdp_mutex); - return NULL; - } - k->kset = &dev->class->p->class_dirs; - retval = kobject_add(k, parent_kobj, "%s", dev->class->name); - if (retval < 0) { - mutex_unlock(&gdp_mutex); - kobject_put(k); - return NULL; - } + k = class_dir_create_and_add(dev->class, parent_kobj); /* do not emit an uevent for this simple "glue" directory */ mutex_unlock(&gdp_mutex); return k; @@ -738,7 +786,7 @@ out_device: out_busid: if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) - sysfs_remove_link(&dev->class->p->class_subsys.kobj, + sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); #else /* link in the class directory pointing to the device */ @@ -756,7 +804,7 @@ out_busid: return 0; out_busid: - sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev)); + sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); #endif out_subsys: @@ -784,13 +832,13 @@ static void device_remove_class_symlinks(struct device *dev) if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) - sysfs_remove_link(&dev->class->p->class_subsys.kobj, + sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); #else if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); - sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev)); + sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); #endif sysfs_remove_link(&dev->kobj, "subsystem"); @@ -1372,7 +1420,7 @@ struct device *__root_device_register(const char *name, struct module *owner) return ERR_PTR(err); } -#ifdef CONFIG_MODULE /* gotta find a "cleaner" way to do this */ +#ifdef CONFIG_MODULES /* gotta find a "cleaner" way to do this */ if (owner) { struct module_kobject *mk = &owner->mkobj; @@ -1576,6 +1624,14 @@ int device_rename(struct device *dev, char *new_name) goto out; } +#ifndef CONFIG_SYSFS_DEPRECATED + if (dev->class) { + error = sysfs_rename_link(&dev->class->p->class_subsys.kobj, + &dev->kobj, old_device_name, new_name); + if (error) + goto out; + } +#endif error = kobject_rename(&dev->kobj, new_name); if (error) goto out; @@ -1590,11 +1646,6 @@ int device_rename(struct device *dev, char *new_name) new_class_name); } } -#else - if (dev->class) { - error = sysfs_rename_link(&dev->class->p->class_subsys.kobj, - &dev->kobj, old_device_name, new_name); - } #endif out: @@ -1735,10 +1786,25 @@ EXPORT_SYMBOL_GPL(device_move); */ void device_shutdown(void) { - struct device *dev, *devn; + struct device *dev; + + spin_lock(&devices_kset->list_lock); + /* + * Walk the devices list backward, shutting down each in turn. + * Beware that device unplug events may also start pulling + * devices offline, even as the system is shutting down. + */ + while (!list_empty(&devices_kset->list)) { + dev = list_entry(devices_kset->list.prev, struct device, + kobj.entry); + get_device(dev); + /* + * Make sure the device is off the kset list, in the + * event that dev->*->shutdown() doesn't remove it. + */ + list_del_init(&dev->kobj.entry); + spin_unlock(&devices_kset->list_lock); - list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list, - kobj.entry) { if (dev->bus && dev->bus->shutdown) { dev_dbg(dev, "shutdown\n"); dev->bus->shutdown(dev); @@ -1746,6 +1812,10 @@ void device_shutdown(void) dev_dbg(dev, "shutdown\n"); dev->driver->shutdown(dev); } + put_device(dev); + + spin_lock(&devices_kset->list_lock); } + spin_unlock(&devices_kset->list_lock); async_synchronize_full(); } diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index f35719aab3c..251acea3d35 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -186,7 +186,7 @@ static ssize_t print_cpus_offline(struct sysdev_class *class, /* display offline cpus < nr_cpu_ids */ if (!alloc_cpumask_var(&offline, GFP_KERNEL)) return -ENOMEM; - cpumask_complement(offline, cpu_online_mask); + cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask); n = cpulist_scnprintf(buf, len, offline); free_cpumask_var(offline); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index c89291f8a16..503c2620bbc 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -40,11 +40,11 @@ static void driver_bound(struct device *dev) pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev), __func__, dev->driver->name); + klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); + if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); - - klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); } static int driver_sysfs_add(struct device *dev) diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 057cf11326b..af0600143d1 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -20,6 +20,7 @@ #include <linux/namei.h> #include <linux/fs.h> #include <linux/shmem_fs.h> +#include <linux/ramfs.h> #include <linux/cred.h> #include <linux/sched.h> #include <linux/init_task.h> @@ -45,7 +46,11 @@ __setup("devtmpfs.mount=", mount_param); static int dev_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { +#ifdef CONFIG_TMPFS return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt); +#else + return get_sb_single(fs_type, flags, data, ramfs_fill_super, mnt); +#endif } static struct file_system_type dev_fs_type = { diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 985da11174e..3f093b0dd21 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -27,6 +27,52 @@ MODULE_AUTHOR("Manuel Estrada Sainz"); MODULE_DESCRIPTION("Multi purpose firmware loading support"); MODULE_LICENSE("GPL"); +/* Builtin firmware support */ + +#ifdef CONFIG_FW_LOADER + +extern struct builtin_fw __start_builtin_fw[]; +extern struct builtin_fw __end_builtin_fw[]; + +static bool fw_get_builtin_firmware(struct firmware *fw, const char *name) +{ + struct builtin_fw *b_fw; + + for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { + if (strcmp(name, b_fw->name) == 0) { + fw->size = b_fw->size; + fw->data = b_fw->data; + return true; + } + } + + return false; +} + +static bool fw_is_builtin_firmware(const struct firmware *fw) +{ + struct builtin_fw *b_fw; + + for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) + if (fw->data == b_fw->data) + return true; + + return false; +} + +#else /* Module case - no builtin firmware support */ + +static inline bool fw_get_builtin_firmware(struct firmware *fw, const char *name) +{ + return false; +} + +static inline bool fw_is_builtin_firmware(const struct firmware *fw) +{ + return false; +} +#endif + enum { FW_STATUS_LOADING, FW_STATUS_DONE, @@ -40,7 +86,6 @@ static int loading_timeout = 60; /* In seconds */ static DEFINE_MUTEX(fw_lock); struct firmware_priv { - char *fw_id; struct completion completion; struct bin_attribute attr_data; struct firmware *fw; @@ -48,18 +93,11 @@ struct firmware_priv { struct page **pages; int nr_pages; int page_array_size; - const char *vdata; struct timer_list timeout; + bool nowait; + char fw_id[]; }; -#ifdef CONFIG_FW_LOADER -extern struct builtin_fw __start_builtin_fw[]; -extern struct builtin_fw __end_builtin_fw[]; -#else /* Module case. Avoid ifdefs later; it'll all optimise out */ -static struct builtin_fw *__start_builtin_fw; -static struct builtin_fw *__end_builtin_fw; -#endif - static void fw_load_abort(struct firmware_priv *fw_priv) { @@ -100,9 +138,25 @@ firmware_timeout_store(struct class *class, return count; } -static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); +static struct class_attribute firmware_class_attrs[] = { + __ATTR(timeout, S_IWUSR | S_IRUGO, + firmware_timeout_show, firmware_timeout_store), + __ATTR_NULL +}; + +static void fw_dev_release(struct device *dev) +{ + struct firmware_priv *fw_priv = dev_get_drvdata(dev); + int i; + + for (i = 0; i < fw_priv->nr_pages; i++) + __free_page(fw_priv->pages[i]); + kfree(fw_priv->pages); + kfree(fw_priv); + kfree(dev); -static void fw_dev_release(struct device *dev); + module_put(THIS_MODULE); +} static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) { @@ -112,12 +166,15 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENOMEM; if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) return -ENOMEM; + if (add_uevent_var(env, "ASYNC=%d", fw_priv->nowait)) + return -ENOMEM; return 0; } static struct class firmware_class = { .name = "firmware", + .class_attrs = firmware_class_attrs, .dev_uevent = firmware_uevent, .dev_release = fw_dev_release, }; @@ -130,6 +187,17 @@ static ssize_t firmware_loading_show(struct device *dev, return sprintf(buf, "%d\n", loading); } +static void firmware_free_data(const struct firmware *fw) +{ + int i; + vunmap(fw->data); + if (fw->pages) { + for (i = 0; i < PFN_UP(fw->size); i++) + __free_page(fw->pages[i]); + kfree(fw->pages); + } +} + /* Some architectures don't have PAGE_KERNEL_RO */ #ifndef PAGE_KERNEL_RO #define PAGE_KERNEL_RO PAGE_KERNEL @@ -162,21 +230,21 @@ static ssize_t firmware_loading_store(struct device *dev, mutex_unlock(&fw_lock); break; } - vfree(fw_priv->fw->data); - fw_priv->fw->data = NULL; + firmware_free_data(fw_priv->fw); + memset(fw_priv->fw, 0, sizeof(struct firmware)); + /* If the pages are not owned by 'struct firmware' */ for (i = 0; i < fw_priv->nr_pages; i++) __free_page(fw_priv->pages[i]); kfree(fw_priv->pages); fw_priv->pages = NULL; fw_priv->page_array_size = 0; fw_priv->nr_pages = 0; - fw_priv->fw->size = 0; set_bit(FW_STATUS_LOADING, &fw_priv->status); mutex_unlock(&fw_lock); break; case 0: if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { - vfree(fw_priv->fw->data); + vunmap(fw_priv->fw->data); fw_priv->fw->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, PAGE_KERNEL_RO); @@ -184,7 +252,10 @@ static ssize_t firmware_loading_store(struct device *dev, dev_err(dev, "%s: vmap() failed\n", __func__); goto err; } - /* Pages will be freed by vfree() */ + /* Pages are now owned by 'struct firmware' */ + fw_priv->fw->pages = fw_priv->pages; + fw_priv->pages = NULL; + fw_priv->page_array_size = 0; fw_priv->nr_pages = 0; complete(&fw_priv->completion); @@ -207,8 +278,9 @@ static ssize_t firmware_loading_store(struct device *dev, static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); static ssize_t -firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr, - char *buffer, loff_t offset, size_t count) +firmware_data_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buffer, loff_t offset, + size_t count) { struct device *dev = to_dev(kobj); struct firmware_priv *fw_priv = dev_get_drvdata(dev); @@ -291,6 +363,7 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) /** * firmware_data_write - write method for firmware + * @filp: open sysfs file * @kobj: kobject for the device * @bin_attr: bin_attr structure * @buffer: buffer being written @@ -301,8 +374,9 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) * the driver as a firmware image. **/ static ssize_t -firmware_data_write(struct kobject *kobj, struct bin_attribute *bin_attr, - char *buffer, loff_t offset, size_t count) +firmware_data_write(struct file* filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buffer, + loff_t offset, size_t count) { struct device *dev = to_dev(kobj); struct firmware_priv *fw_priv = dev_get_drvdata(dev); @@ -353,21 +427,6 @@ static struct bin_attribute firmware_attr_data_tmpl = { .write = firmware_data_write, }; -static void fw_dev_release(struct device *dev) -{ - struct firmware_priv *fw_priv = dev_get_drvdata(dev); - int i; - - for (i = 0; i < fw_priv->nr_pages; i++) - __free_page(fw_priv->pages[i]); - kfree(fw_priv->pages); - kfree(fw_priv->fw_id); - kfree(fw_priv); - kfree(dev); - - module_put(THIS_MODULE); -} - static void firmware_class_timeout(u_long data) { @@ -379,8 +438,8 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, struct device *device) { int retval; - struct firmware_priv *fw_priv = kzalloc(sizeof(*fw_priv), - GFP_KERNEL); + struct firmware_priv *fw_priv = + kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL); struct device *f_dev = kzalloc(sizeof(*f_dev), GFP_KERNEL); *dev_p = NULL; @@ -391,16 +450,9 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, goto error_kfree; } + strcpy(fw_priv->fw_id, fw_name); init_completion(&fw_priv->completion); fw_priv->attr_data = firmware_attr_data_tmpl; - fw_priv->fw_id = kstrdup(fw_name, GFP_KERNEL); - if (!fw_priv->fw_id) { - dev_err(device, "%s: Firmware name allocation failed\n", - __func__); - retval = -ENOMEM; - goto error_kfree; - } - fw_priv->timeout.function = firmware_class_timeout; fw_priv->timeout.data = (u_long) fw_priv; init_timer(&fw_priv->timeout); @@ -427,7 +479,7 @@ error_kfree: static int fw_setup_device(struct firmware *fw, struct device **dev_p, const char *fw_name, struct device *device, - int uevent) + int uevent, bool nowait) { struct device *f_dev; struct firmware_priv *fw_priv; @@ -443,6 +495,8 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p, fw_priv = dev_get_drvdata(f_dev); + fw_priv->nowait = nowait; + fw_priv->fw = fw; sysfs_bin_attr_init(&fw_priv->attr_data); retval = sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data); @@ -470,12 +524,11 @@ out: static int _request_firmware(const struct firmware **firmware_p, const char *name, - struct device *device, int uevent) + struct device *device, int uevent, bool nowait) { struct device *f_dev; struct firmware_priv *fw_priv; struct firmware *firmware; - struct builtin_fw *builtin; int retval; if (!firmware_p) @@ -489,21 +542,16 @@ _request_firmware(const struct firmware **firmware_p, const char *name, goto out; } - for (builtin = __start_builtin_fw; builtin != __end_builtin_fw; - builtin++) { - if (strcmp(name, builtin->name)) - continue; - dev_info(device, "firmware: using built-in firmware %s\n", - name); - firmware->size = builtin->size; - firmware->data = builtin->data; + if (fw_get_builtin_firmware(firmware, name)) { + dev_dbg(device, "firmware: using built-in firmware %s\n", name); return 0; } if (uevent) - dev_info(device, "firmware: requesting %s\n", name); + dev_dbg(device, "firmware: requesting %s\n", name); - retval = fw_setup_device(firmware, &f_dev, name, device, uevent); + retval = fw_setup_device(firmware, &f_dev, name, device, + uevent, nowait); if (retval) goto error_kfree_fw; @@ -560,26 +608,18 @@ request_firmware(const struct firmware **firmware_p, const char *name, struct device *device) { int uevent = 1; - return _request_firmware(firmware_p, name, device, uevent); + return _request_firmware(firmware_p, name, device, uevent, false); } /** * release_firmware: - release the resource associated with a firmware image * @fw: firmware resource to release **/ -void -release_firmware(const struct firmware *fw) +void release_firmware(const struct firmware *fw) { - struct builtin_fw *builtin; - if (fw) { - for (builtin = __start_builtin_fw; builtin != __end_builtin_fw; - builtin++) { - if (fw->data == builtin->data) - goto free_fw; - } - vfree(fw->data); - free_fw: + if (!fw_is_builtin_firmware(fw)) + firmware_free_data(fw); kfree(fw); } } @@ -606,7 +646,7 @@ request_firmware_work_func(void *arg) return 0; } ret = _request_firmware(&fw, fw_work->name, fw_work->device, - fw_work->uevent); + fw_work->uevent, true); fw_work->cont(fw, fw_work->context); @@ -670,26 +710,12 @@ request_firmware_nowait( return 0; } -static int __init -firmware_class_init(void) +static int __init firmware_class_init(void) { - int error; - error = class_register(&firmware_class); - if (error) { - printk(KERN_ERR "%s: class_register failed\n", __func__); - return error; - } - error = class_create_file(&firmware_class, &class_attr_timeout); - if (error) { - printk(KERN_ERR "%s: class_create_file failed\n", - __func__); - class_unregister(&firmware_class); - } - return error; - + return class_register(&firmware_class); } -static void __exit -firmware_class_exit(void) + +static void __exit firmware_class_exit(void) { class_unregister(&firmware_class); } diff --git a/drivers/base/module.c b/drivers/base/module.c index f32f2f9b7be..db930d3ee31 100644 --- a/drivers/base/module.c +++ b/drivers/base/module.c @@ -15,12 +15,10 @@ static char *make_driver_name(struct device_driver *drv) { char *driver_name; - driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2, - GFP_KERNEL); + driver_name = kasprintf(GFP_KERNEL, "%s:%s", drv->bus->name, drv->name); if (!driver_name) return NULL; - sprintf(driver_name, "%s:%s", drv->bus->name, drv->name); return driver_name; } diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c5fbe198fbd..4d99c8bdfed 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -735,7 +735,7 @@ static void platform_pm_complete(struct device *dev) #ifdef CONFIG_SUSPEND -static int platform_pm_suspend(struct device *dev) +int __weak platform_pm_suspend(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -753,7 +753,7 @@ static int platform_pm_suspend(struct device *dev) return ret; } -static int platform_pm_suspend_noirq(struct device *dev) +int __weak platform_pm_suspend_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -769,7 +769,7 @@ static int platform_pm_suspend_noirq(struct device *dev) return ret; } -static int platform_pm_resume(struct device *dev) +int __weak platform_pm_resume(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -787,7 +787,7 @@ static int platform_pm_resume(struct device *dev) return ret; } -static int platform_pm_resume_noirq(struct device *dev) +int __weak platform_pm_resume_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -967,17 +967,17 @@ static int platform_pm_restore_noirq(struct device *dev) int __weak platform_pm_runtime_suspend(struct device *dev) { - return -ENOSYS; + return pm_generic_runtime_suspend(dev); }; int __weak platform_pm_runtime_resume(struct device *dev) { - return -ENOSYS; + return pm_generic_runtime_resume(dev); }; int __weak platform_pm_runtime_idle(struct device *dev) { - return -ENOSYS; + return pm_generic_runtime_idle(dev); }; #else /* !CONFIG_PM_RUNTIME */ @@ -1254,6 +1254,26 @@ static int __init early_platform_driver_probe_id(char *class_str, } if (match) { + /* + * Set up a sensible init_name to enable + * dev_name() and others to be used before the + * rest of the driver core is initialized. + */ + if (!match->dev.init_name && slab_is_available()) { + if (match->id != -1) + match->dev.init_name = + kasprintf(GFP_KERNEL, "%s.%d", + match->name, + match->id); + else + match->dev.init_name = + kasprintf(GFP_KERNEL, "%s", + match->name); + + if (!match->dev.init_name) + return -ENOMEM; + } + if (epdrv->pdrv->probe(match)) pr_warning("%s: unable to probe %s early.\n", class_str, match->name); diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 626dd147b75..b0ec0e9f27e 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -229,14 +229,16 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) if (retval) { dev->power.runtime_status = RPM_ACTIVE; - pm_runtime_cancel_pending(dev); - if (retval == -EAGAIN || retval == -EBUSY) { - notify = true; + if (dev->power.timer_expires == 0) + notify = true; dev->power.runtime_error = 0; + } else { + pm_runtime_cancel_pending(dev); } } else { dev->power.runtime_status = RPM_SUSPENDED; + pm_runtime_deactivate_timer(dev); if (dev->parent) { parent = dev->parent; @@ -659,8 +661,6 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay) if (dev->power.runtime_status == RPM_SUSPENDED) retval = 1; - else if (dev->power.runtime_status == RPM_SUSPENDING) - retval = -EINPROGRESS; else if (atomic_read(&dev->power.usage_count) > 0 || dev->power.disable_depth > 0) retval = -EAGAIN; diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 86fd9373447..a4c33bc5125 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -5,6 +5,7 @@ #include <linux/device.h> #include <linux/string.h> #include <linux/pm_runtime.h> +#include <asm/atomic.h> #include "power.h" /* @@ -143,7 +144,59 @@ wake_store(struct device * dev, struct device_attribute *attr, static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); -#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG +#ifdef CONFIG_PM_ADVANCED_DEBUG +#ifdef CONFIG_PM_RUNTIME + +static ssize_t rtpm_usagecount_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", atomic_read(&dev->power.usage_count)); +} + +static ssize_t rtpm_children_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", dev->power.ignore_children ? + 0 : atomic_read(&dev->power.child_count)); +} + +static ssize_t rtpm_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if ((dev->power.disable_depth) && (dev->power.runtime_auto == false)) + return sprintf(buf, "disabled & forbidden\n"); + else if (dev->power.disable_depth) + return sprintf(buf, "disabled\n"); + else if (dev->power.runtime_auto == false) + return sprintf(buf, "forbidden\n"); + return sprintf(buf, "enabled\n"); +} + +static ssize_t rtpm_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (dev->power.runtime_error) + return sprintf(buf, "error\n"); + switch (dev->power.runtime_status) { + case RPM_SUSPENDED: + return sprintf(buf, "suspended\n"); + case RPM_SUSPENDING: + return sprintf(buf, "suspending\n"); + case RPM_RESUMING: + return sprintf(buf, "resuming\n"); + case RPM_ACTIVE: + return sprintf(buf, "active\n"); + } + return -EIO; +} + +static DEVICE_ATTR(runtime_usage, 0444, rtpm_usagecount_show, NULL); +static DEVICE_ATTR(runtime_active_kids, 0444, rtpm_children_show, NULL); +static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL); +static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL); + +#endif + static ssize_t async_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -170,15 +223,21 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(async, 0644, async_show, async_store); -#endif /* CONFIG_PM_SLEEP_ADVANCED_DEBUG */ +#endif /* CONFIG_PM_ADVANCED_DEBUG */ static struct attribute * power_attrs[] = { #ifdef CONFIG_PM_RUNTIME &dev_attr_control.attr, #endif &dev_attr_wakeup.attr, -#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG +#ifdef CONFIG_PM_ADVANCED_DEBUG &dev_attr_async.attr, +#ifdef CONFIG_PM_RUNTIME + &dev_attr_runtime_usage.attr, + &dev_attr_runtime_active_kids.attr, + &dev_attr_runtime_status.attr, + &dev_attr_runtime_enabled.attr, +#endif #endif NULL, }; |