Skip to content

Commit

Permalink
Merge tag 'driver-core-4.2-rc1' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/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
  ...
  • Loading branch information
torvalds committed Jun 26, 2015
2 parents d878238 + 0e6c861 commit 8d7804a
Show file tree
Hide file tree
Showing 23 changed files with 367 additions and 79 deletions.
2 changes: 1 addition & 1 deletion Documentation/ABI/testing/sysfs-devices-system-cpu
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ Description: Parameters for the CPU cache attributes
coherency_line_size: the minimum amount of data in bytes that gets
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
collection of cache lines with the same cache index
Expand Down
3 changes: 3 additions & 0 deletions Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
auto selects the default scheme, which automatically
enables eagerfpu restore for xsaveopt.

module.async_probe [KNL]
Enable asynchronous probe on this module.

early_ioremap_debug [KNL]
Enable debug messages in early_ioremap support. This
is useful for tracking down temporary early mappings
Expand Down
7 changes: 4 additions & 3 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -3450,16 +3450,17 @@ F: drivers/block/drbd/
F: lib/lru_cache.c
F: Documentation/blockdev/drbd/

DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
DRIVER CORE, KOBJECTS, DEBUGFS, KERNFS AND SYSFS
M: Greg Kroah-Hartman <[email protected]>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
S: Supported
F: Documentation/kobject.txt
F: drivers/base/
F: fs/sysfs/
F: fs/debugfs/
F: include/linux/kobj*
F: fs/kernfs/
F: fs/sysfs/
F: include/linux/debugfs.h
F: include/linux/kobj*
F: lib/kobj*

DRM DRIVERS
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ int alloc_bootmem_huge_page(struct hstate *hstate)
unsigned long gpage_npages[MMU_PAGE_COUNT];

static int __init do_gpage_early_setup(char *param, char *val,
const char *unused)
const char *unused, void *arg)
{
static phys_addr_t size;
unsigned long npages;
Expand Down Expand Up @@ -385,7 +385,7 @@ void __init reserve_hugetlb_gpages(void)

strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE);
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.
Expand Down
1 change: 1 addition & 0 deletions drivers/base/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv,
{
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,
const struct attribute_group **groups);
Expand Down
31 changes: 23 additions & 8 deletions drivers/base/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*
*/

#include <linux/async.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
Expand Down Expand Up @@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
struct subsys_interface *sif;
int ret;

if (!bus)
return;

if (bus->p->drivers_autoprobe) {
ret = device_attach(dev);
WARN_ON(ret < 0);
}
if (bus->p->drivers_autoprobe)
device_initial_probe(dev);

mutex_lock(&bus->p->mutex);
list_for_each_entry(sif, &bus->p->interfaces, node)
Expand Down Expand Up @@ -659,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf,
}
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.
* @drv: driver.
Expand Down Expand Up @@ -691,9 +700,15 @@ int bus_add_driver(struct device_driver *drv)

klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
if (driver_allows_async_probing(drv)) {
pr_debug("bus: '%s': probing driver %s asynchronously\n",
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);

Expand Down
4 changes: 2 additions & 2 deletions drivers/base/cacheinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ static int detect_cache_attributes(unsigned int cpu)
if (ret)
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
*/
ret = cache_shared_cpu_map_setup(cpu);
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);
goto free_ci;
}
Expand Down
29 changes: 29 additions & 0 deletions drivers/base/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/cpufeature.h>
#include <linux/tick.h>

#include "base.h"

Expand Down Expand Up @@ -265,6 +266,30 @@ static ssize_t print_cpus_offline(struct device *dev,
}
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)
{
/*
Expand Down Expand Up @@ -431,6 +456,10 @@ static struct attribute *cpu_root_attrs[] = {
&cpu_attrs[2].attr.attr,
&dev_attr_kernel_max.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
&dev_attr_modalias.attr,
#endif
Expand Down
163 changes: 143 additions & 20 deletions drivers/base/dd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* 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
* 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
* trigger has occurred in the midst of probing a driver. If the trigger count
Expand Down Expand Up @@ -417,31 +417,107 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
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))
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);
}

/**
* 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)
static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
{
struct device *dev = _dev;
struct device_attach_data data = {
.dev = dev,
.check_async = true,
.want_async = true,
};

device_lock(dev);

bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
dev_dbg(dev, "async probe completed\n");

pm_request_idle(dev);

device_unlock(dev);

put_device(dev);
}

static int __device_attach(struct device *dev, bool allow_async)
{
int ret = 0;

Expand All @@ -459,15 +535,59 @@ int device_attach(struct device *dev)
ret = 0;
}
} else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_request_idle(dev);
struct device_attach_data data = {
.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:
device_unlock(dev);
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);

void device_initial_probe(struct device *dev)
{
__device_attach(dev, true);
}

static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
Expand Down Expand Up @@ -522,6 +642,9 @@ static void __device_release_driver(struct device *dev)

drv = dev->driver;
if (drv) {
if (driver_allows_async_probing(drv))
async_synchronize_full();

pm_runtime_get_sync(dev);

driver_sysfs_remove(dev);
Expand Down
Loading

0 comments on commit 8d7804a

Please sign in to comment.