Commit 8d7804a2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'driver-core-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core

Pull driver core updates from Greg KH:
 "Here is the driver core / firmware changes for 4.2-rc1.

  A number of small changes all over the place in the driver core, and
  in the firmware subsystem.  Nothing really major, full details in the
  shortlog.  Some of it is a bit of churn, given that the platform
  driver probing changes was found to not work well, so they were
  reverted.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'driver-core-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (31 commits)
  Revert "base/platform: Only insert MEM and IO resources"
  Revert "base/platform: Continue on insert_resource() error"
  Revert "of/platform: Use platform_device interface"
  Revert "base/platform: Remove code duplication"
  firmware: add missing kfree for work on async call
  fs: sysfs: don't pass count == 0 to bin file readers
  base:dd - Fix for typo in comment to function driver_deferred_probe_trigger().
  base/platform: Remove code duplication
  of/platform: Use platform_device interface
  base/platform: Continue on insert_resource() error
  base/platform: Only insert MEM and IO resources
  firmware: use const for remaining firmware names
  firmware: fix possible use after free on name on asynchronous request
  firmware: check for file truncation on direct firmware loading
  firmware: fix __getname() missing failure check
  drivers: of/base: move of_init to driver_init
  drivers/base: cacheinfo: fix annoying typo when DT nodes are absent
  sysfs: disambiguate between "error code" and "failure" in comments
  driver-core: fix build for !CONFIG_MODULES
  driver-core: make __device_attach() static
  ...
parents d8782381 0e6c861f
...@@ -243,7 +243,7 @@ Description: Parameters for the CPU cache attributes ...@@ -243,7 +243,7 @@ Description: Parameters for the CPU cache attributes
coherency_line_size: the minimum amount of data in bytes that gets coherency_line_size: the minimum amount of data in bytes that gets
transferred from memory to cache transferred from memory to cache
level: the cache hierarcy in the multi-level cache configuration level: the cache hierarchy in the multi-level cache configuration
number_of_sets: total number of sets in the cache, a set is a number_of_sets: total number of sets in the cache, a set is a
collection of cache lines with the same cache index collection of cache lines with the same cache index
......
...@@ -953,6 +953,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -953,6 +953,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
auto selects the default scheme, which automatically auto selects the default scheme, which automatically
enables eagerfpu restore for xsaveopt. enables eagerfpu restore for xsaveopt.
module.async_probe [KNL]
Enable asynchronous probe on this module.
early_ioremap_debug [KNL] early_ioremap_debug [KNL]
Enable debug messages in early_ioremap support. This Enable debug messages in early_ioremap support. This
is useful for tracking down temporary early mappings is useful for tracking down temporary early mappings
......
...@@ -3450,16 +3450,17 @@ F: drivers/block/drbd/ ...@@ -3450,16 +3450,17 @@ F: drivers/block/drbd/
F: lib/lru_cache.c F: lib/lru_cache.c
F: Documentation/blockdev/drbd/ F: Documentation/blockdev/drbd/
DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS DRIVER CORE, KOBJECTS, DEBUGFS, KERNFS AND SYSFS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
S: Supported S: Supported
F: Documentation/kobject.txt F: Documentation/kobject.txt
F: drivers/base/ F: drivers/base/
F: fs/sysfs/
F: fs/debugfs/ F: fs/debugfs/
F: include/linux/kobj* F: fs/kernfs/
F: fs/sysfs/
F: include/linux/debugfs.h F: include/linux/debugfs.h
F: include/linux/kobj*
F: lib/kobj* F: lib/kobj*
DRM DRIVERS DRM DRIVERS
......
...@@ -336,7 +336,7 @@ int alloc_bootmem_huge_page(struct hstate *hstate) ...@@ -336,7 +336,7 @@ int alloc_bootmem_huge_page(struct hstate *hstate)
unsigned long gpage_npages[MMU_PAGE_COUNT]; unsigned long gpage_npages[MMU_PAGE_COUNT];
static int __init do_gpage_early_setup(char *param, char *val, static int __init do_gpage_early_setup(char *param, char *val,
const char *unused) const char *unused, void *arg)
{ {
static phys_addr_t size; static phys_addr_t size;
unsigned long npages; unsigned long npages;
...@@ -385,7 +385,7 @@ void __init reserve_hugetlb_gpages(void) ...@@ -385,7 +385,7 @@ void __init reserve_hugetlb_gpages(void)
strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE); strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE);
parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0, parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0,
&do_gpage_early_setup); NULL, &do_gpage_early_setup);
/* /*
* Walk gpage list in reverse, allocating larger page sizes first. * Walk gpage list in reverse, allocating larger page sizes first.
......
...@@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv, ...@@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv,
{ {
return drv->bus->match ? drv->bus->match(dev, drv) : 1; return drv->bus->match ? drv->bus->match(dev, drv) : 1;
} }
extern bool driver_allows_async_probing(struct device_driver *drv);
extern int driver_add_groups(struct device_driver *drv, extern int driver_add_groups(struct device_driver *drv,
const struct attribute_group **groups); const struct attribute_group **groups);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* *
*/ */
#include <linux/async.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev) ...@@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev)
{ {
struct bus_type *bus = dev->bus; struct bus_type *bus = dev->bus;
struct subsys_interface *sif; struct subsys_interface *sif;
int ret;
if (!bus) if (!bus)
return; return;
if (bus->p->drivers_autoprobe) { if (bus->p->drivers_autoprobe)
ret = device_attach(dev); device_initial_probe(dev);
WARN_ON(ret < 0);
}
mutex_lock(&bus->p->mutex); mutex_lock(&bus->p->mutex);
list_for_each_entry(sif, &bus->p->interfaces, node) list_for_each_entry(sif, &bus->p->interfaces, node)
...@@ -659,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf, ...@@ -659,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf,
} }
static DRIVER_ATTR_WO(uevent); static DRIVER_ATTR_WO(uevent);
static void driver_attach_async(void *_drv, async_cookie_t cookie)
{
struct device_driver *drv = _drv;
int ret;
ret = driver_attach(drv);
pr_debug("bus: '%s': driver %s async attach completed: %d\n",
drv->bus->name, drv->name, ret);
}
/** /**
* bus_add_driver - Add a driver to the bus. * bus_add_driver - Add a driver to the bus.
* @drv: driver. * @drv: driver.
...@@ -691,9 +700,15 @@ int bus_add_driver(struct device_driver *drv) ...@@ -691,9 +700,15 @@ int bus_add_driver(struct device_driver *drv)
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) { if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv); if (driver_allows_async_probing(drv)) {
if (error) pr_debug("bus: '%s': probing driver %s asynchronously\n",
goto out_unregister; drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
} }
module_add_driver(drv->owner, drv); module_add_driver(drv->owner, drv);
......
...@@ -191,12 +191,12 @@ static int detect_cache_attributes(unsigned int cpu) ...@@ -191,12 +191,12 @@ static int detect_cache_attributes(unsigned int cpu)
if (ret) if (ret)
goto free_ci; goto free_ci;
/* /*
* For systems using DT for cache hierarcy, of_node and shared_cpu_map * For systems using DT for cache hierarchy, of_node and shared_cpu_map
* will be set up here only if they are not populated already * will be set up here only if they are not populated already
*/ */
ret = cache_shared_cpu_map_setup(cpu); ret = cache_shared_cpu_map_setup(cpu);
if (ret) { if (ret) {
pr_warn("Unable to detect cache hierarcy from DT for CPU %d\n", pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n",
cpu); cpu);
goto free_ci; goto free_ci;
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/cpufeature.h> #include <linux/cpufeature.h>
#include <linux/tick.h>
#include "base.h" #include "base.h"
...@@ -265,6 +266,30 @@ static ssize_t print_cpus_offline(struct device *dev, ...@@ -265,6 +266,30 @@ static ssize_t print_cpus_offline(struct device *dev,
} }
static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
static ssize_t print_cpus_isolated(struct device *dev,
struct device_attribute *attr, char *buf)
{
int n = 0, len = PAGE_SIZE-2;
n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(cpu_isolated_map));
return n;
}
static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL);
#ifdef CONFIG_NO_HZ_FULL
static ssize_t print_cpus_nohz_full(struct device *dev,
struct device_attribute *attr, char *buf)
{
int n = 0, len = PAGE_SIZE-2;
n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
return n;
}
static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
#endif
static void cpu_device_release(struct device *dev) static void cpu_device_release(struct device *dev)
{ {
/* /*
...@@ -431,6 +456,10 @@ static struct attribute *cpu_root_attrs[] = { ...@@ -431,6 +456,10 @@ static struct attribute *cpu_root_attrs[] = {
&cpu_attrs[2].attr.attr, &cpu_attrs[2].attr.attr,
&dev_attr_kernel_max.attr, &dev_attr_kernel_max.attr,
&dev_attr_offline.attr, &dev_attr_offline.attr,
&dev_attr_isolated.attr,
#ifdef CONFIG_NO_HZ_FULL
&dev_attr_nohz_full.attr,
#endif
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE #ifdef CONFIG_GENERIC_CPU_AUTOPROBE
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
#endif #endif
......
...@@ -141,7 +141,7 @@ static bool driver_deferred_probe_enable = false; ...@@ -141,7 +141,7 @@ static bool driver_deferred_probe_enable = false;
* more than one device is probing at the same time, it is possible for one * more than one device is probing at the same time, it is possible for one
* probe to complete successfully while another is about to defer. If the second * probe to complete successfully while another is about to defer. If the second
* depends on the first, then it will get put on the pending list after the * depends on the first, then it will get put on the pending list after the
* trigger event has already occured and will be stuck there. * trigger event has already occurred and will be stuck there.
* *
* The atomic 'deferred_trigger_count' is used to determine if a successful * The atomic 'deferred_trigger_count' is used to determine if a successful
* trigger has occurred in the midst of probing a driver. If the trigger count * trigger has occurred in the midst of probing a driver. If the trigger count
...@@ -417,31 +417,107 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) ...@@ -417,31 +417,107 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
return ret; return ret;
} }
static int __device_attach(struct device_driver *drv, void *data) bool driver_allows_async_probing(struct device_driver *drv)
{ {
struct device *dev = data; switch (drv->probe_type) {
case PROBE_PREFER_ASYNCHRONOUS:
return true;
case PROBE_FORCE_SYNCHRONOUS:
return false;
default:
if (module_requested_async_probing(drv->owner))
return true;
return false;
}
}
struct device_attach_data {
struct device *dev;
/*
* Indicates whether we are are considering asynchronous probing or
* not. Only initial binding after device or driver registration
* (including deferral processing) may be done asynchronously, the
* rest is always synchronous, as we expect it is being done by
* request from userspace.
*/
bool check_async;
/*
* Indicates if we are binding synchronous or asynchronous drivers.
* When asynchronous probing is enabled we'll execute 2 passes
* over drivers: first pass doing synchronous probing and second
* doing asynchronous probing (if synchronous did not succeed -
* most likely because there was no driver requiring synchronous
* probing - and we found asynchronous driver during first pass).
* The 2 passes are done because we can't shoot asynchronous
* probe for given device and driver from bus_for_each_drv() since
* driver pointer is not guaranteed to stay valid once
* bus_for_each_drv() iterates to the next driver on the bus.
*/
bool want_async;
/*
* We'll set have_async to 'true' if, while scanning for matching
* driver, we'll encounter one that requests asynchronous probing.
*/
bool have_async;
};
static int __device_attach_driver(struct device_driver *drv, void *_data)
{
struct device_attach_data *data = _data;
struct device *dev = data->dev;
bool async_allowed;
/*
* Check if device has already been claimed. This may
* happen with driver loading, device discovery/registration,
* and deferred probe processing happens all at once with
* multiple threads.
*/
if (dev->driver)
return -EBUSY;
if (!driver_match_device(drv, dev)) if (!driver_match_device(drv, dev))
return 0; return 0;
async_allowed = driver_allows_async_probing(drv);
if (async_allowed)
data->have_async = true;
if (data->check_async && async_allowed != data->want_async)
return 0;
return driver_probe_device(drv, dev); return driver_probe_device(drv, dev);
} }
/** static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
* device_attach - try to attach device to a driver. {
* @dev: device. struct device *dev = _dev;
* struct device_attach_data data = {
* Walk the list of drivers that the bus has and call .dev = dev,
* driver_probe_device() for each pair. If a compatible .check_async = true,
* pair is found, break out and return. .want_async = true,
* };
* Returns 1 if the device was bound to a driver;
* 0 if no matching driver was found; device_lock(dev);
* -ENODEV if the device is not registered.
* bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
* When called for a USB interface, @dev->parent lock must be held. dev_dbg(dev, "async probe completed\n");
*/
int device_attach(struct device *dev) pm_request_idle(dev);
device_unlock(dev);
put_device(dev);
}
static int __device_attach(struct device *dev, bool allow_async)
{ {
int ret = 0; int ret = 0;
...@@ -459,15 +535,59 @@ int device_attach(struct device *dev) ...@@ -459,15 +535,59 @@ int device_attach(struct device *dev)
ret = 0; ret = 0;
} }
} else { } else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); struct device_attach_data data = {
pm_request_idle(dev); .dev = dev,
.check_async = allow_async,
.want_async = false,
};
ret = bus_for_each_drv(dev->bus, NULL, &data,
__device_attach_driver);
if (!ret && allow_async && data.have_async) {
/*
* If we could not find appropriate driver
* synchronously and we are allowed to do
* async probes and there are drivers that
* want to probe asynchronously, we'll
* try them.
*/
dev_dbg(dev, "scheduling asynchronous probe\n");
get_device(dev);
async_schedule(__device_attach_async_helper, dev);
} else {
pm_request_idle(dev);
}
} }
out_unlock: out_unlock:
device_unlock(dev); device_unlock(dev);
return ret; return ret;
} }
/**
* device_attach - try to attach device to a driver.
* @dev: device.
*
* Walk the list of drivers that the bus has and call
* driver_probe_device() for each pair. If a compatible
* pair is found, break out and return.
*
* Returns 1 if the device was bound to a driver;
* 0 if no matching driver was found;
* -ENODEV if the device is not registered.
*
* When called for a USB interface, @dev->parent lock must be held.
*/
int device_attach(struct device *dev)
{
return __device_attach(dev, false);
}
EXPORT_SYMBOL_GPL(device_attach); EXPORT_SYMBOL_GPL(device_attach);
void device_initial_probe(struct device *dev)
{
__device_attach(dev, true);
}
static int __driver_attach(struct device *dev, void *data) static int __driver_attach(struct device *dev, void *data)
{ {
struct device_driver *drv = data; struct device_driver *drv = data;
...@@ -522,6 +642,9 @@ static void __device_release_driver(struct device *dev) ...@@ -522,6 +642,9 @@ static void __device_release_driver(struct device *dev)
drv = dev->driver; drv = dev->driver;
if (drv) { if (drv) {
if (driver_allows_async_probing(drv))
async_synchronize_full();
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
driver_sysfs_remove(dev); driver_sysfs_remove(dev);
......
...@@ -150,17 +150,17 @@ struct firmware_buf { ...@@ -150,17 +150,17 @@ struct firmware_buf {
int page_array_size; int page_array_size;
struct list_head pending_list; struct list_head pending_list;
#endif #endif
char fw_id[]; const char *fw_id;
}; };
struct fw_cache_entry { struct fw_cache_entry {
struct list_head list; struct list_head list;
char name[]; const char *name;
}; };
struct fw_name_devm { struct fw_name_devm {
unsigned long magic; unsigned long magic;
char name[]; const char *name;
}; };
#define to_fwbuf(d) container_of(d, struct firmware_buf, ref) #define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
...@@ -181,13 +181,17 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, ...@@ -181,13 +181,17 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
{ {
struct firmware_buf *buf; struct firmware_buf *buf;
buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1, GFP_ATOMIC); buf = kzalloc(sizeof(*buf), GFP_ATOMIC);
if (!buf) if (!buf)
return buf; return NULL;
buf->fw_id = kstrdup_const(fw_name, GFP_ATOMIC);
if (!buf->fw_id) {
kfree(buf);
return NULL;
}
kref_init(&buf->ref); kref_init(&buf->ref);
strcpy(buf->fw_id, fw_name);
buf->fwc = fwc; buf->fwc = fwc;
init_completion(&buf->completion); init_completion(&buf->completion);
#ifdef CONFIG_FW_LOADER_USER_HELPER #ifdef CONFIG_FW_LOADER_USER_HELPER
...@@ -257,6 +261,7 @@ static void __fw_free_buf(struct kref *ref) ...@@ -257,6 +261,7 @@ static void __fw_free_buf(struct kref *ref)
} else } else
#endif #endif
vfree(buf->data); vfree(buf->data);
kfree_const(buf->fw_id);
kfree(buf); kfree(buf);
} }
...@@ -320,9 +325,13 @@ static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf) ...@@ -320,9 +325,13 @@ static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
static int fw_get_filesystem_firmware(struct device *device, static int fw_get_filesystem_firmware(struct device *device,
struct firmware_buf *buf) struct firmware_buf *buf)
{ {
int i; int i, len;
int rc = -ENOENT; int rc = -ENOENT;
char *path = __getname(); char *path;
path = __getname();
if (!path)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(fw_path); i++) { for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
struct file *file; struct file *file;
...@@ -331,7 +340,12 @@ static int fw_get_filesystem_firmware(struct device *device, ...@@ -331,7 +340,12 @@ static int fw_get_filesystem_firmware(struct device *device,
if (!fw_path[i][0]) if (!fw_path[i][0])
continue; continue;
snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id); len = snprintf(path, PATH_MAX, "%s/%s",
fw_path[i], buf->fw_id);
if (len >= PATH_MAX) {
rc = -ENAMETOOLONG;
break;
}
file = filp_open(path, O_RDONLY, 0); file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(file)) if (IS_ERR(file))
...@@ -392,6 +406,7 @@ static void fw_name_devm_release(struct device *dev, void *res) ...@@ -392,6 +406,7 @@ static void fw_name_devm_release(struct device *dev, void *res)
if (fwn->magic == (unsigned long)&fw_cache) if (fwn->magic == (unsigned long)&fw_cache)
pr_debug("%s: fw_name-%s devm-%p released\n", pr_debug("%s: fw_name-%s devm-%p released\n",
__func__, fwn->name, res); __func__, fwn->name, res);
kfree_const(fwn->name);
} }
static int fw_devm_match(struct device *dev, void *res, static int fw_devm_match(struct device *dev, void *res,
...@@ -422,13 +437,17 @@ static int fw_add_devm_name(struct device *dev, const char *name) ...@@ -422,13 +437,17 @@ static int fw_add_devm_name(struct device *dev, const char *name)
if (fwn) if (fwn)
return 1; return 1;
fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) + fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm),
strlen(name) + 1, GFP_KERNEL); GFP_KERNEL);
if (!fwn) if (!fwn)
return -ENOMEM; return -ENOMEM;
fwn->name = kstrdup_const(name, GFP_KERNEL);
if (!fwn->name) {
kfree(fwn);
return -ENOMEM;
}
fwn->magic = (unsigned long)&fw_cache; fwn->magic = (unsigned long)&fw_cache;
strcpy(fwn->name, name);
devres_add(dev, fwn); devres_add(dev, fwn);
return 0; return 0;
...@@ -1247,6 +1266,7 @@ static void request_firmware_work_func(struct work_struct *work) ...@@ -1247,6 +1266,7 @@ static void request_firmware_work_func(struct work_struct *work)
put_device(fw_work->device); /* taken in request_firmware_nowait() */ put_device(fw_work->device); /* taken in request_firmware_nowait() */
module_put(fw_work->module); module_put(fw_work->module);
kfree_const(fw_work->name);
kfree(fw_work); kfree(fw_work);
} }
...@@ -1286,7 +1306,11 @@ request_firmware_nowait( ...@@ -1286,7 +1306,11 @@ request_firmware_nowait(
return -ENOMEM; return -ENOMEM;
fw_work->module = module; fw_work->module = module;
fw_work->name = name; fw_work->name = kstrdup_const(name, gfp);
if (!fw_work->name) {
kfree(fw_work);
return -ENOMEM;
}
fw_work->device = device; fw_work->device = device;
fw_work->context = context; fw_work->context = context;
fw_work->cont = cont; fw_work->cont = cont;
...@@ -1294,6 +1318,7 @@ request_firmware_nowait( ...@@ -1294,6 +1318,7 @@ request_firmware_nowait(
(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER); (uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
if (!try_module_get(module)) { if (!try_module_get(module)) {
kfree_const(fw_work->name);
kfree(fw_work); kfree(fw_work);
return -EFAULT; return -EFAULT;
} }
...@@ -1384,11 +1409,16 @@ static struct fw_cache_entry *alloc_fw_cache_entry(const char *name) ...@@ -1384,11 +1409,16 @@ static struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
{ {
struct fw_cache_entry *fce; struct fw_cache_entry *fce;
fce = kzalloc(sizeof(*fce) + strlen(name) + 1, GFP_ATOMIC); fce = kzalloc(sizeof(*fce), GFP_ATOMIC);
if (!fce) if (!fce)
goto exit; goto exit;
strcpy(fce->name, name); fce->name = kstrdup_const(name, GFP_ATOMIC);
if (!fce->name) {
kfree(fce);
fce = NULL;
goto exit;
}
exit: exit:
return fce; return fce;
} }
...@@ -1428,6 +1458,7 @@ static int fw_cache_piggyback_on_request(const char *name) ...@@ -1428,6 +1458,7 @@ static int fw_cache_piggyback_on_request(const char *name)
static void free_fw_cache_entry(struct fw_cache_entry *fce) static void free_fw_cache_entry(struct fw_cache_entry *fce)
{ {
kfree_const(fce->name);
kfree(fce); kfree(fce);
} }
......
...@@ -613,6 +613,19 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv, ...@@ -613,6 +613,19 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv,
{ {
int retval, code; int retval, code;
if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) {
pr_err("%s: drivers registered with %s can not be probed asynchronously\n",
drv->driver.name, __func__);
return -EINVAL;
}
/*
* We have to run our probes synchronously because we check if
* we find any devices to bind to and exit with error if there
* are any.
*/
drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
/* /*
* Prevent driver from requesting probe deferral to avoid further * Prevent driver from requesting probe deferral to avoid further
* futile probe attempts. * futile probe attempts.
......
...@@ -2964,6 +2964,7 @@ static struct pci_driver amd64_pci_driver = { ...@@ -2964,6 +2964,7 @@ static struct pci_driver amd64_pci_driver = {
.probe = probe_one_instance, .probe = probe_one_instance,
.remove = remove_one_instance, .remove = remove_one_instance,
.id_table = amd64_pci_table, .id_table = amd64_pci_table,
.driver.probe_type = PROBE_FORCE_SYNCHRONOUS,
}; };
static void setup_pci_device(void) static void setup_pci_device(void)
......
...@@ -785,7 +785,6 @@ static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait) ...@@ -785,7 +785,6 @@ static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait)
struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; struct kernfs_node *kn = filp->f_path.dentry->d_fsdata;
struct kernfs_open_node *on = kn->attr.open; struct kernfs_open_node *on = kn->attr.open;
/* need parent for the kobj, grab both */
if (!kernfs_get_active(kn)) if (!kernfs_get_active(kn))
goto trigger; goto trigger;
......
...@@ -90,7 +90,7 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, ...@@ -90,7 +90,7 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
return 0; return 0;
if (size) { if (size) {
if (pos > size) if (pos >= size)
return 0; return 0;
if (pos + count > size) if (pos + count > size)
count = size - pos; count = size - pos;
......
...@@ -135,7 +135,7 @@ static int internal_create_group(struct kobject *kobj, int update, ...@@ -135,7 +135,7 @@ static int internal_create_group(struct kobject *kobj, int update,
* This function creates a group for the first time. It will explicitly * This function creates a group for the first time. It will explicitly
* warn and error if any of the attribute files being created already exist. * warn and error if any of the attribute files being created already exist.
* *
* Returns 0 on success or error. * Returns 0 on success or error code on failure.
*/ */
int sysfs_create_group(struct kobject *kobj, int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp) const struct attribute_group *grp)
...@@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_group); ...@@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_group);
* It will explicitly warn and error if any of the attribute files being * It will explicitly warn and error if any of the attribute files being
* created already exist. * created already exist.
* *
* Returns 0 on success or error code from sysfs_create_group on error. * Returns 0 on success or error code from sysfs_create_group on failure.
*/ */
int sysfs_create_groups(struct kobject *kobj, int sysfs_create_groups(struct kobject *kobj,
const struct attribute_group **groups) const struct attribute_group **groups)
...@@ -193,7 +193,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_groups); ...@@ -193,7 +193,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_groups);
* The primary use for this function is to call it after making a change * The primary use for this function is to call it after making a change
* that affects group visibility. * that affects group visibility.
* *
* Returns 0 on success or error. * Returns 0 on success or error code on failure.
*/ */
int sysfs_update_group(struct kobject *kobj, int sysfs_update_group(struct kobject *kobj,
const struct attribute_group *grp) const struct attribute_group *grp)
......
...@@ -19,7 +19,7 @@ enum cache_type { ...@@ -19,7 +19,7 @@ enum cache_type {
/** /**
* struct cacheinfo - represent a cache leaf node * struct cacheinfo - represent a cache leaf node
* @type: type of the cache - data, inst or unified * @type: type of the cache - data, inst or unified
* @level: represents the hierarcy in the multi-level cache * @level: represents the hierarchy in the multi-level cache
* @coherency_line_size: size of each cache line usually representing * @coherency_line_size: size of each cache line usually representing
* the minimum amount of data that gets transferred from memory * the minimum amount of data that gets transferred from memory
* @number_of_sets: total number of sets, a set is a collection of cache * @number_of_sets: total number of sets, a set is a collection of cache
......
...@@ -195,6 +195,34 @@ extern int bus_unregister_notifier(struct bus_type *bus, ...@@ -195,6 +195,34 @@ extern int bus_unregister_notifier(struct bus_type *bus,
extern struct kset *bus_get_kset(struct bus_type *bus); extern struct kset *bus_get_kset(struct bus_type *bus);
extern struct klist *bus_get_device_klist(struct bus_type *bus); extern struct klist *bus_get_device_klist(struct bus_type *bus);
/**
* enum probe_type - device driver probe type to try
* Device drivers may opt in for special handling of their
* respective probe routines. This tells the core what to
* expect and prefer.
*
* @PROBE_DEFAULT_STRATEGY: Used by drivers that work equally well
* whether probed synchronously or asynchronously.
* @PROBE_PREFER_ASYNCHRONOUS: Drivers for "slow" devices which
* probing order is not essential for booting the system may
* opt into executing their probes asynchronously.
* @PROBE_FORCE_SYNCHRONOUS: Use this to annotate drivers that need
* their probe routines to run synchronously with driver and
* device registration (with the exception of -EPROBE_DEFER
* handling - re-probing always ends up being done asynchronously).
*
* Note that the end goal is to switch the kernel to use asynchronous
* probing by default, so annotating drivers with
* %PROBE_PREFER_ASYNCHRONOUS is a temporary measure that allows us
* to speed up boot process while we are validating the rest of the
* drivers.
*/
enum probe_type {
PROBE_DEFAULT_STRATEGY,
PROBE_PREFER_ASYNCHRONOUS,
PROBE_FORCE_SYNCHRONOUS,
};
/** /**
* struct device_driver - The basic device driver structure * struct device_driver - The basic device driver structure
* @name: Name of the device driver. * @name: Name of the device driver.
...@@ -202,6 +230,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus); ...@@ -202,6 +230,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus);
* @owner: The module owner. * @owner: The module owner.
* @mod_name: Used for built-in modules. * @mod_name: Used for built-in modules.
* @suppress_bind_attrs: Disables bind/unbind via sysfs. * @suppress_bind_attrs: Disables bind/unbind via sysfs.
* @probe_type: Type of the probe (synchronous or asynchronous) to use.
* @of_match_table: The open firmware table. * @of_match_table: The open firmware table.
* @acpi_match_table: The ACPI match table. * @acpi_match_table: The ACPI match table.
* @probe: Called to query the existence of a specific device, * @probe: Called to query the existence of a specific device,
...@@ -235,6 +264,7 @@ struct device_driver { ...@@ -235,6 +264,7 @@ struct device_driver {
const char *mod_name; /* used for built-in modules */ const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
enum probe_type probe_type;
const struct of_device_id *of_match_table; const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table; const struct acpi_device_id *acpi_match_table;
...@@ -975,6 +1005,7 @@ extern int __must_check device_bind_driver(struct device *dev); ...@@ -975,6 +1005,7 @@ extern int __must_check device_bind_driver(struct device *dev);
extern void device_release_driver(struct device *dev); extern void device_release_driver(struct device *dev);
extern int __must_check device_attach(struct device *dev); extern int __must_check device_attach(struct device *dev);
extern int __must_check driver_attach(struct device_driver *drv); extern int __must_check driver_attach(struct device_driver *drv);
extern void device_initial_probe(struct device *dev);
extern int __must_check device_reprobe(struct device *dev); extern int __must_check device_reprobe(struct device *dev);
/* /*
......
...@@ -257,6 +257,8 @@ struct module { ...@@ -257,6 +257,8 @@ struct module {
bool sig_ok; bool sig_ok;
#endif #endif
bool async_probe_requested;
/* symbols that will be GPL-only in the near future. */ /* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms; const struct kernel_symbol *gpl_future_syms;
const unsigned long *gpl_future_crcs; const unsigned long *gpl_future_crcs;
...@@ -508,6 +510,11 @@ int unregister_module_notifier(struct notifier_block *nb); ...@@ -508,6 +510,11 @@ int unregister_module_notifier(struct notifier_block *nb);
extern void print_modules(void); extern void print_modules(void);
static inline bool module_requested_async_probing(struct module *module)
{
return module && module->async_probe_requested;
}
#else /* !CONFIG_MODULES... */ #else /* !CONFIG_MODULES... */
/* Given an address, look for it in the exception tables. */ /* Given an address, look for it in the exception tables. */
...@@ -618,6 +625,12 @@ static inline int unregister_module_notifier(struct notifier_block *nb) ...@@ -618,6 +625,12 @@ static inline int unregister_module_notifier(struct notifier_block *nb)
static inline void print_modules(void) static inline void print_modules(void)
{ {
} }
static inline bool module_requested_async_probing(struct module *module)
{
return false;
}
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
......
...@@ -310,6 +310,15 @@ static inline void __kernel_param_unlock(void) ...@@ -310,6 +310,15 @@ static inline void __kernel_param_unlock(void)
#define core_param(name, var, type, perm) \ #define core_param(name, var, type, perm) \
param_check_##type(name, &(var)); \ param_check_##type(name, &(var)); \
__module_param_call("", name, &param_ops_##type, &var, perm, -1, 0) __module_param_call("", name, &param_ops_##type, &var, perm, -1, 0)
/**
* core_param_unsafe - same as core_param but taints kernel
*/
#define core_param_unsafe(name, var, type, perm) \
param_check_##type(name, &(var)); \
__module_param_call("", name, &param_ops_##type, &var, perm, \
-1, KERNEL_PARAM_FL_UNSAFE)
#endif /* !MODULE */ #endif /* !MODULE */
/** /**
...@@ -357,8 +366,9 @@ extern char *parse_args(const char *name, ...@@ -357,8 +366,9 @@ extern char *parse_args(const char *name,
unsigned num, unsigned num,
s16 level_min, s16 level_min,
s16 level_max, s16 level_max,
void *arg,
int (*unknown)(char *param, char *val, int (*unknown)(char *param, char *val,
const char *doing)); const char *doing, void *arg));
/* Called by module remove. */ /* Called by module remove. */
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
......
...@@ -235,7 +235,8 @@ static int __init loglevel(char *str) ...@@ -235,7 +235,8 @@ static int __init loglevel(char *str)
early_param("loglevel", loglevel); early_param("loglevel", loglevel);
/* Change NUL term back to "=", to make "param" the whole string. */ /* Change NUL term back to "=", to make "param" the whole string. */
static int __init repair_env_string(char *param, char *val, const char *unused) static int __init repair_env_string(char *param, char *val,
const char *unused, void *arg)
{ {
if (val) { if (val) {
/* param=val or param="val"? */ /* param=val or param="val"? */
...@@ -252,14 +253,15 @@ static int __init repair_env_string(char *param, char *val, const char *unused) ...@@ -252,14 +253,15 @@ static int __init repair_env_string(char *param, char *val, const char *unused)
} }
/* Anything after -- gets handed straight to init. */ /* Anything after -- gets handed straight to init. */
static int __init set_init_arg(char *param, char *val, const char *unused) static int __init set_init_arg(char *param, char *val,
const char *unused, void *arg)
{ {
unsigned int i; unsigned int i;
if (panic_later) if (panic_later)
return 0; return 0;
repair_env_string(param, val, unused); repair_env_string(param, val, unused, NULL);
for (i = 0; argv_init[i]; i++) { for (i = 0; argv_init[i]; i++) {
if (i == MAX_INIT_ARGS) { if (i == MAX_INIT_ARGS) {
...@@ -276,9 +278,10 @@ static int __init set_init_arg(char *param, char *val, const char *unused) ...@@ -276,9 +278,10 @@ static int __init set_init_arg(char *param, char *val, const char *unused)
* Unknown boot options get handed to init, unless they look like * Unknown boot options get handed to init, unless they look like
* unused parameters (modprobe will find them in /proc/cmdline). * unused parameters (modprobe will find them in /proc/cmdline).
*/ */
static int __init unknown_bootoption(char *param, char *val, const char *unused) static int __init unknown_bootoption(char *param, char *val,
const char *unused, void *arg)
{ {
repair_env_string(param, val, unused); repair_env_string(param, val, unused, NULL);
/* Handle obsolete-style parameters */ /* Handle obsolete-style parameters */
if (obsolete_checksetup(param)) if (obsolete_checksetup(param))
...@@ -410,7 +413,8 @@ static noinline void __init_refok rest_init(void) ...@@ -410,7 +413,8 @@ static noinline void __init_refok rest_init(void)
} }
/* Check for early params. */ /* Check for early params. */
static int __init do_early_param(char *param, char *val, const char *unused) static int __init do_early_param(char *param, char *val,
const char *unused, void *arg)
{ {
const struct obs_kernel_param *p; const struct obs_kernel_param *p;
...@@ -429,7 +433,8 @@ static int __init do_early_param(char *param, char *val, const char *unused) ...@@ -429,7 +433,8 @@ static int __init do_early_param(char *param, char *val, const char *unused)
void __init parse_early_options(char *cmdline) void __init parse_early_options(char *cmdline)
{ {
parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param); parse_args("early options", cmdline, NULL, 0, 0, 0, NULL,
do_early_param);
} }
/* Arch code calls this early on, or if not, just before other parsing. */ /* Arch code calls this early on, or if not, just before other parsing. */
...@@ -535,10 +540,10 @@ asmlinkage __visible void __init start_kernel(void) ...@@ -535,10 +540,10 @@ asmlinkage __visible void __init start_kernel(void)
after_dashes = parse_args("Booting kernel", after_dashes = parse_args("Booting kernel",
static_command_line, __start___param, static_command_line, __start___param,
__stop___param - __start___param, __stop___param - __start___param,
-1, -1, &unknown_bootoption); -1, -1, NULL, &unknown_bootoption);
if (!IS_ERR_OR_NULL(after_dashes)) if (!IS_ERR_OR_NULL(after_dashes))
parse_args("Setting init args", after_dashes, NULL, 0, -1, -1, parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
set_init_arg); NULL, set_init_arg);
jump_label_init(); jump_label_init();
...@@ -848,7 +853,7 @@ static void __init do_initcall_level(int level) ...@@ -848,7 +853,7 @@ static void __init do_initcall_level(int level)
initcall_command_line, __start___param, initcall_command_line, __start___param,
__stop___param - __start___param, __stop___param - __start___param,
level, level, level, level,
&repair_env_string); NULL, &repair_env_string);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(*fn); do_one_initcall(*fn);
......
...@@ -3107,7 +3107,7 @@ static noinline int do_init_module(struct module *mod) ...@@ -3107,7 +3107,7 @@ static noinline int do_init_module(struct module *mod)
* *
* http://thread.gmane.org/gmane.linux.kernel/1420814 * http://thread.gmane.org/gmane.linux.kernel/1420814
*/ */
if (current->flags & PF_USED_ASYNC) if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
async_synchronize_full(); async_synchronize_full();
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
...@@ -3237,10 +3237,19 @@ static int complete_formation(struct module *mod, struct load_info *info) ...@@ -3237,10 +3237,19 @@ static int complete_formation(struct module *mod, struct load_info *info)
return err; return err;
} }
static int unknown_module_param_cb(char *param, char *val, const char *modname) static int unknown_module_param_cb(char *param, char *val, const char *modname,
void *arg)
{ {
struct module *mod = arg;
int ret;
if (strcmp(param, "async_probe") == 0) {
mod->async_probe_requested = true;
return 0;
}
/* Check for magic 'dyndbg' arg */ /* Check for magic 'dyndbg' arg */
int ret = ddebug_dyndbg_module_param_cb(param, val, modname); ret = ddebug_dyndbg_module_param_cb(param, val, modname);
if (ret != 0) if (ret != 0)
pr_warn("%s: unknown parameter '%s' ignored\n", modname, param); pr_warn("%s: unknown parameter '%s' ignored\n", modname, param);
return 0; return 0;
...@@ -3342,7 +3351,8 @@ static int load_module(struct load_info *info, const char __user *uargs, ...@@ -3342,7 +3351,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
/* Module is ready to execute: parsing args may do that. */ /* Module is ready to execute: parsing args may do that. */
after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-32768, 32767, unknown_module_param_cb); -32768, 32767, NULL,
unknown_module_param_cb);
if (IS_ERR(after_dashes)) { if (IS_ERR(after_dashes)) {
err = PTR_ERR(after_dashes); err = PTR_ERR(after_dashes);
goto bug_cleanup; goto bug_cleanup;
......
...@@ -100,8 +100,9 @@ static int parse_one(char *param, ...@@ -100,8 +100,9 @@ static int parse_one(char *param,
unsigned num_params, unsigned num_params,
s16 min_level, s16 min_level,
s16 max_level, s16 max_level,
void *arg,
int (*handle_unknown)(char *param, char *val, int (*handle_unknown)(char *param, char *val,
const char *doing)) const char *doing, void *arg))
{ {
unsigned int i; unsigned int i;
int err; int err;
...@@ -128,7 +129,7 @@ static int parse_one(char *param, ...@@ -128,7 +129,7 @@ static int parse_one(char *param,
if (handle_unknown) { if (handle_unknown) {
pr_debug("doing %s: %s='%s'\n", doing, param, val); pr_debug("doing %s: %s='%s'\n", doing, param, val);
return handle_unknown(param, val, doing); return handle_unknown(param, val, doing, arg);
} }
pr_debug("Unknown argument '%s'\n", param); pr_debug("Unknown argument '%s'\n", param);
...@@ -194,7 +195,9 @@ char *parse_args(const char *doing, ...@@ -194,7 +195,9 @@ char *parse_args(const char *doing,
unsigned num, unsigned num,
s16 min_level, s16 min_level,
s16 max_level, s16 max_level,
int (*unknown)(char *param, char *val, const char *doing)) void *arg,
int (*unknown)(char *param, char *val,
const char *doing, void *arg))
{ {
char *param, *val; char *param, *val;
...@@ -214,7 +217,7 @@ char *parse_args(const char *doing, ...@@ -214,7 +217,7 @@ char *parse_args(const char *doing,
return args; return args;
irq_was_disabled = irqs_disabled(); irq_was_disabled = irqs_disabled();
ret = parse_one(param, val, doing, params, num, ret = parse_one(param, val, doing, params, num,
min_level, max_level, unknown); min_level, max_level, arg, unknown);
if (irq_was_disabled && !irqs_disabled()) if (irq_was_disabled && !irqs_disabled())
pr_warn("%s: option '%s' enabled irq's!\n", pr_warn("%s: option '%s' enabled irq's!\n",
doing, param); doing, param);
......
...@@ -887,7 +887,7 @@ static int ddebug_dyndbg_param_cb(char *param, char *val, ...@@ -887,7 +887,7 @@ static int ddebug_dyndbg_param_cb(char *param, char *val,
/* handle both dyndbg and $module.dyndbg params at boot */ /* handle both dyndbg and $module.dyndbg params at boot */
static int ddebug_dyndbg_boot_param_cb(char *param, char *val, static int ddebug_dyndbg_boot_param_cb(char *param, char *val,
const char *unused) const char *unused, void *arg)
{ {
vpr_info("%s=\"%s\"\n", param, val); vpr_info("%s=\"%s\"\n", param, val);
return ddebug_dyndbg_param_cb(param, val, NULL, 0); return ddebug_dyndbg_param_cb(param, val, NULL, 0);
...@@ -1028,7 +1028,7 @@ static int __init dynamic_debug_init(void) ...@@ -1028,7 +1028,7 @@ static int __init dynamic_debug_init(void)
*/ */
cmdline = kstrdup(saved_command_line, GFP_KERNEL); cmdline = kstrdup(saved_command_line, GFP_KERNEL);
parse_args("dyndbg params", cmdline, NULL, parse_args("dyndbg params", cmdline, NULL,
0, 0, 0, &ddebug_dyndbg_boot_param_cb); 0, 0, 0, NULL, &ddebug_dyndbg_boot_param_cb);
kfree(cmdline); kfree(cmdline);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment