Driver core patches for 4.2-rc1
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlWNoCQACgkQMUfUDdst+ym4JACdFrrXoMt2pb8nl5gMidGyM9/D jg8AnRgdW8ArDA/xOarULd/X43eA3J3C =Al2B -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
8d7804a2f0
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <gregkh@linuxfoundation.org>
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/tick.h>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -417,16 +417,152 @@ 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
device_lock(dev);
|
||||
if (dev->driver) {
|
||||
if (klist_node_attached(&dev->p->knode_driver)) {
|
||||
ret = 1;
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = device_bind_driver(dev);
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
else {
|
||||
dev->driver = NULL;
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
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.
|
||||
|
@ -443,31 +579,15 @@ static int __device_attach(struct device_driver *drv, void *data)
|
|||
*/
|
||||
int device_attach(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
device_lock(dev);
|
||||
if (dev->driver) {
|
||||
if (klist_node_attached(&dev->p->knode_driver)) {
|
||||
ret = 1;
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = device_bind_driver(dev);
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
else {
|
||||
dev->driver = NULL;
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
|
||||
pm_request_idle(dev);
|
||||
}
|
||||
out_unlock:
|
||||
device_unlock(dev);
|
||||
return ret;
|
||||
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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -150,17 +150,17 @@ struct firmware_buf {
|
|||
int page_array_size;
|
||||
struct list_head pending_list;
|
||||
#endif
|
||||
char fw_id[];
|
||||
const char *fw_id;
|
||||
};
|
||||
|
||||
struct fw_cache_entry {
|
||||
struct list_head list;
|
||||
char name[];
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct fw_name_devm {
|
||||
unsigned long magic;
|
||||
char name[];
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#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,
|
|||
{
|
||||
struct firmware_buf *buf;
|
||||
|
||||
buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1, GFP_ATOMIC);
|
||||
|
||||
buf = kzalloc(sizeof(*buf), GFP_ATOMIC);
|
||||
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);
|
||||
strcpy(buf->fw_id, fw_name);
|
||||
buf->fwc = fwc;
|
||||
init_completion(&buf->completion);
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
|
@ -257,6 +261,7 @@ static void __fw_free_buf(struct kref *ref)
|
|||
} else
|
||||
#endif
|
||||
vfree(buf->data);
|
||||
kfree_const(buf->fw_id);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
|
@ -320,9 +325,13 @@ fail:
|
|||
static int fw_get_filesystem_firmware(struct device *device,
|
||||
struct firmware_buf *buf)
|
||||
{
|
||||
int i;
|
||||
int i, len;
|
||||
int rc = -ENOENT;
|
||||
char *path = __getname();
|
||||
char *path;
|
||||
|
||||
path = __getname();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
|
||||
struct file *file;
|
||||
|
@ -331,7 +340,12 @@ static int fw_get_filesystem_firmware(struct device *device,
|
|||
if (!fw_path[i][0])
|
||||
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);
|
||||
if (IS_ERR(file))
|
||||
|
@ -392,6 +406,7 @@ static void fw_name_devm_release(struct device *dev, void *res)
|
|||
if (fwn->magic == (unsigned long)&fw_cache)
|
||||
pr_debug("%s: fw_name-%s devm-%p released\n",
|
||||
__func__, fwn->name, res);
|
||||
kfree_const(fwn->name);
|
||||
}
|
||||
|
||||
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)
|
|||
if (fwn)
|
||||
return 1;
|
||||
|
||||
fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
|
||||
strlen(name) + 1, GFP_KERNEL);
|
||||
fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm),
|
||||
GFP_KERNEL);
|
||||
if (!fwn)
|
||||
return -ENOMEM;
|
||||
fwn->name = kstrdup_const(name, GFP_KERNEL);
|
||||
if (!fwn->name) {
|
||||
kfree(fwn);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fwn->magic = (unsigned long)&fw_cache;
|
||||
strcpy(fwn->name, name);
|
||||
devres_add(dev, fwn);
|
||||
|
||||
return 0;
|
||||
|
@ -1247,6 +1266,7 @@ static void request_firmware_work_func(struct work_struct *work)
|
|||
put_device(fw_work->device); /* taken in request_firmware_nowait() */
|
||||
|
||||
module_put(fw_work->module);
|
||||
kfree_const(fw_work->name);
|
||||
kfree(fw_work);
|
||||
}
|
||||
|
||||
|
@ -1286,7 +1306,11 @@ request_firmware_nowait(
|
|||
return -ENOMEM;
|
||||
|
||||
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->context = context;
|
||||
fw_work->cont = cont;
|
||||
|
@ -1294,6 +1318,7 @@ request_firmware_nowait(
|
|||
(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
|
||||
|
||||
if (!try_module_get(module)) {
|
||||
kfree_const(fw_work->name);
|
||||
kfree(fw_work);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
@ -1384,11 +1409,16 @@ static struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
|
|||
{
|
||||
struct fw_cache_entry *fce;
|
||||
|
||||
fce = kzalloc(sizeof(*fce) + strlen(name) + 1, GFP_ATOMIC);
|
||||
fce = kzalloc(sizeof(*fce), GFP_ATOMIC);
|
||||
if (!fce)
|
||||
goto exit;
|
||||
|
||||
strcpy(fce->name, name);
|
||||
fce->name = kstrdup_const(name, GFP_ATOMIC);
|
||||
if (!fce->name) {
|
||||
kfree(fce);
|
||||
fce = NULL;
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
return fce;
|
||||
}
|
||||
|
@ -1428,6 +1458,7 @@ found:
|
|||
|
||||
static void free_fw_cache_entry(struct fw_cache_entry *fce)
|
||||
{
|
||||
kfree_const(fce->name);
|
||||
kfree(fce);
|
||||
}
|
||||
|
||||
|
|
|
@ -613,6 +613,19 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv,
|
|||
{
|
||||
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
|
||||
* futile probe attempts.
|
||||
|
|
|
@ -2964,6 +2964,7 @@ static struct pci_driver amd64_pci_driver = {
|
|||
.probe = probe_one_instance,
|
||||
.remove = remove_one_instance,
|
||||
.id_table = amd64_pci_table,
|
||||
.driver.probe_type = PROBE_FORCE_SYNCHRONOUS,
|
||||
};
|
||||
|
||||
static void setup_pci_device(void)
|
||||
|
|
|
@ -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_open_node *on = kn->attr.open;
|
||||
|
||||
/* need parent for the kobj, grab both */
|
||||
if (!kernfs_get_active(kn))
|
||||
goto trigger;
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
|
|||
return 0;
|
||||
|
||||
if (size) {
|
||||
if (pos > size)
|
||||
if (pos >= size)
|
||||
return 0;
|
||||
if (pos + count > size)
|
||||
count = size - pos;
|
||||
|
|
|
@ -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
|
||||
* 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,
|
||||
const struct attribute_group *grp)
|
||||
|
@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_group);
|
|||
* It will explicitly warn and error if any of the attribute files being
|
||||
* 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,
|
||||
const struct attribute_group **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
|
||||
* 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,
|
||||
const struct attribute_group *grp)
|
||||
|
|
|
@ -19,7 +19,7 @@ enum cache_type {
|
|||
/**
|
||||
* struct cacheinfo - represent a cache leaf node
|
||||
* @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
|
||||
* the minimum amount of data that gets transferred from memory
|
||||
* @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,
|
|||
extern struct kset *bus_get_kset(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
|
||||
* @name: Name of the device driver.
|
||||
|
@ -202,6 +230,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus);
|
|||
* @owner: The module owner.
|
||||
* @mod_name: Used for built-in modules.
|
||||
* @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.
|
||||
* @acpi_match_table: The ACPI match table.
|
||||
* @probe: Called to query the existence of a specific device,
|
||||
|
@ -235,6 +264,7 @@ struct device_driver {
|
|||
const char *mod_name; /* used for built-in modules */
|
||||
|
||||
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
|
||||
enum probe_type probe_type;
|
||||
|
||||
const struct of_device_id *of_match_table;
|
||||
const struct acpi_device_id *acpi_match_table;
|
||||
|
@ -975,6 +1005,7 @@ extern int __must_check device_bind_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 driver_attach(struct device_driver *drv);
|
||||
extern void device_initial_probe(struct device *dev);
|
||||
extern int __must_check device_reprobe(struct device *dev);
|
||||
|
||||
/*
|
||||
|
|
|
@ -257,6 +257,8 @@ struct module {
|
|||
bool sig_ok;
|
||||
#endif
|
||||
|
||||
bool async_probe_requested;
|
||||
|
||||
/* symbols that will be GPL-only in the near future. */
|
||||
const struct kernel_symbol *gpl_future_syms;
|
||||
const unsigned long *gpl_future_crcs;
|
||||
|
@ -508,6 +510,11 @@ int unregister_module_notifier(struct notifier_block *nb);
|
|||
|
||||
extern void print_modules(void);
|
||||
|
||||
static inline bool module_requested_async_probing(struct module *module)
|
||||
{
|
||||
return module && module->async_probe_requested;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_MODULES... */
|
||||
|
||||
/* Given an address, look for it in the exception tables. */
|
||||
|
@ -618,6 +625,12 @@ static inline int unregister_module_notifier(struct notifier_block *nb)
|
|||
static inline void print_modules(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool module_requested_async_probing(struct module *module)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
|
|
|
@ -310,6 +310,15 @@ static inline void __kernel_param_unlock(void)
|
|||
#define core_param(name, var, type, perm) \
|
||||
param_check_##type(name, &(var)); \
|
||||
__module_param_call("", name, ¶m_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, ¶m_ops_##type, &var, perm, \
|
||||
-1, KERNEL_PARAM_FL_UNSAFE)
|
||||
|
||||
#endif /* !MODULE */
|
||||
|
||||
/**
|
||||
|
@ -357,8 +366,9 @@ extern char *parse_args(const char *name,
|
|||
unsigned num,
|
||||
s16 level_min,
|
||||
s16 level_max,
|
||||
void *arg,
|
||||
int (*unknown)(char *param, char *val,
|
||||
const char *doing));
|
||||
const char *doing, void *arg));
|
||||
|
||||
/* Called by module remove. */
|
||||
#ifdef CONFIG_SYSFS
|
||||
|
|
25
init/main.c
25
init/main.c
|
@ -235,7 +235,8 @@ static int __init loglevel(char *str)
|
|||
early_param("loglevel", loglevel);
|
||||
|
||||
/* 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) {
|
||||
/* param=val or param="val"? */
|
||||
|
@ -252,14 +253,15 @@ static int __init repair_env_string(char *param, char *val, const char *unused)
|
|||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
if (panic_later)
|
||||
return 0;
|
||||
|
||||
repair_env_string(param, val, unused);
|
||||
repair_env_string(param, val, unused, NULL);
|
||||
|
||||
for (i = 0; argv_init[i]; i++) {
|
||||
if (i == MAX_INIT_ARGS) {
|
||||
|
@ -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
|
||||
* 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 */
|
||||
if (obsolete_checksetup(param))
|
||||
|
@ -410,7 +413,8 @@ static noinline void __init_refok rest_init(void)
|
|||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@ -429,7 +433,8 @@ static int __init do_early_param(char *param, char *val, const char *unused)
|
|||
|
||||
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. */
|
||||
|
@ -535,10 +540,10 @@ asmlinkage __visible void __init start_kernel(void)
|
|||
after_dashes = parse_args("Booting kernel",
|
||||
static_command_line, __start___param,
|
||||
__stop___param - __start___param,
|
||||
-1, -1, &unknown_bootoption);
|
||||
-1, -1, NULL, &unknown_bootoption);
|
||||
if (!IS_ERR_OR_NULL(after_dashes))
|
||||
parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
|
||||
set_init_arg);
|
||||
NULL, set_init_arg);
|
||||
|
||||
jump_label_init();
|
||||
|
||||
|
@ -848,7 +853,7 @@ static void __init do_initcall_level(int level)
|
|||
initcall_command_line, __start___param,
|
||||
__stop___param - __start___param,
|
||||
level, level,
|
||||
&repair_env_string);
|
||||
NULL, &repair_env_string);
|
||||
|
||||
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
|
||||
do_one_initcall(*fn);
|
||||
|
|
|
@ -3107,7 +3107,7 @@ static noinline int do_init_module(struct module *mod)
|
|||
*
|
||||
* 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();
|
||||
|
||||
mutex_lock(&module_mutex);
|
||||
|
@ -3237,10 +3237,19 @@ out:
|
|||
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 */
|
||||
int ret = ddebug_dyndbg_module_param_cb(param, val, modname);
|
||||
ret = ddebug_dyndbg_module_param_cb(param, val, modname);
|
||||
if (ret != 0)
|
||||
pr_warn("%s: unknown parameter '%s' ignored\n", modname, param);
|
||||
return 0;
|
||||
|
@ -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. */
|
||||
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)) {
|
||||
err = PTR_ERR(after_dashes);
|
||||
goto bug_cleanup;
|
||||
|
|
|
@ -100,8 +100,9 @@ static int parse_one(char *param,
|
|||
unsigned num_params,
|
||||
s16 min_level,
|
||||
s16 max_level,
|
||||
void *arg,
|
||||
int (*handle_unknown)(char *param, char *val,
|
||||
const char *doing))
|
||||
const char *doing, void *arg))
|
||||
{
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
@ -128,7 +129,7 @@ static int parse_one(char *param,
|
|||
|
||||
if (handle_unknown) {
|
||||
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);
|
||||
|
@ -194,7 +195,9 @@ char *parse_args(const char *doing,
|
|||
unsigned num,
|
||||
s16 min_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;
|
||||
|
||||
|
@ -214,7 +217,7 @@ char *parse_args(const char *doing,
|
|||
return args;
|
||||
irq_was_disabled = irqs_disabled();
|
||||
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())
|
||||
pr_warn("%s: option '%s' enabled irq's!\n",
|
||||
doing, param);
|
||||
|
|
|
@ -887,7 +887,7 @@ static int ddebug_dyndbg_param_cb(char *param, char *val,
|
|||
|
||||
/* handle both dyndbg and $module.dyndbg params at boot */
|
||||
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);
|
||||
return ddebug_dyndbg_param_cb(param, val, NULL, 0);
|
||||
|
@ -1028,7 +1028,7 @@ static int __init dynamic_debug_init(void)
|
|||
*/
|
||||
cmdline = kstrdup(saved_command_line, GFP_KERNEL);
|
||||
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);
|
||||
return 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue