mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
Merge remote-tracking branch 'driver-core/driver-core-next' into gpio/for-next
This commit is contained in:
commit
a6e191963f
@ -127,6 +127,7 @@ parameter is applicable::
|
||||
NET Appropriate network support is enabled.
|
||||
NUMA NUMA support is enabled.
|
||||
NFS Appropriate NFS support is enabled.
|
||||
OF Devicetree is enabled.
|
||||
OSS OSS sound support is enabled.
|
||||
PV_OPS A paravirtualized kernel is enabled.
|
||||
PARIDE The ParIDE (parallel port IDE) subsystem is enabled.
|
||||
|
@ -3194,6 +3194,12 @@
|
||||
This can be set from sysctl after boot.
|
||||
See Documentation/admin-guide/sysctl/vm.rst for details.
|
||||
|
||||
of_devlink [OF, KNL] Create device links between consumer and
|
||||
supplier devices by scanning the devictree to infer the
|
||||
consumer/supplier relationships. A consumer device
|
||||
will not be probed until all the supplier devices have
|
||||
probed successfully.
|
||||
|
||||
ohci1394_dma=early [HW] enable debugging via the ohci1394 driver.
|
||||
See Documentation/debugging-via-ohci1394.txt for more
|
||||
info.
|
||||
|
@ -281,7 +281,8 @@ State machine
|
||||
:c:func:`driver_bound()`.)
|
||||
|
||||
* Before a consumer device is probed, presence of supplier drivers is
|
||||
verified by checking that links to suppliers are in ``DL_STATE_AVAILABLE``
|
||||
verified by checking the consumer device is not in the wait_for_suppliers
|
||||
list and by checking that links to suppliers are in ``DL_STATE_AVAILABLE``
|
||||
state. The state of the links is updated to ``DL_STATE_CONSUMER_PROBE``.
|
||||
(Call to :c:func:`device_links_check_suppliers()` from
|
||||
:c:func:`really_probe()`.)
|
||||
|
@ -316,6 +316,10 @@ IOMAP
|
||||
devm_ioremap_nocache()
|
||||
devm_ioremap_wc()
|
||||
devm_ioremap_resource() : checks resource, requests memory region, ioremaps
|
||||
devm_ioremap_resource_wc()
|
||||
devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device
|
||||
devm_platform_ioremap_resource_wc()
|
||||
devm_platform_ioremap_resource_byname()
|
||||
devm_iounmap()
|
||||
pcim_iomap()
|
||||
pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
|
||||
|
@ -169,6 +169,49 @@ A driver's probe() may return a negative errno value to indicate that
|
||||
the driver did not bind to this device, in which case it should have
|
||||
released all resources it allocated::
|
||||
|
||||
void (*sync_state)(struct device *dev);
|
||||
|
||||
sync_state is called only once for a device. It's called when all the consumer
|
||||
devices of the device have successfully probed. The list of consumers of the
|
||||
device is obtained by looking at the device links connecting that device to its
|
||||
consumer devices.
|
||||
|
||||
The first attempt to call sync_state() is made during late_initcall_sync() to
|
||||
give firmware and drivers time to link devices to each other. During the first
|
||||
attempt at calling sync_state(), if all the consumers of the device at that
|
||||
point in time have already probed successfully, sync_state() is called right
|
||||
away. If there are no consumers of the device during the first attempt, that
|
||||
too is considered as "all consumers of the device have probed" and sync_state()
|
||||
is called right away.
|
||||
|
||||
If during the first attempt at calling sync_state() for a device, there are
|
||||
still consumers that haven't probed successfully, the sync_state() call is
|
||||
postponed and reattempted in the future only when one or more consumers of the
|
||||
device probe successfully. If during the reattempt, the driver core finds that
|
||||
there are one or more consumers of the device that haven't probed yet, then
|
||||
sync_state() call is postponed again.
|
||||
|
||||
A typical use case for sync_state() is to have the kernel cleanly take over
|
||||
management of devices from the bootloader. For example, if a device is left on
|
||||
and at a particular hardware configuration by the bootloader, the device's
|
||||
driver might need to keep the device in the boot configuration until all the
|
||||
consumers of the device have probed. Once all the consumers of the device have
|
||||
probed, the device's driver can synchronize the hardware state of the device to
|
||||
match the aggregated software state requested by all the consumers. Hence the
|
||||
name sync_state().
|
||||
|
||||
While obvious examples of resources that can benefit from sync_state() include
|
||||
resources such as regulator, sync_state() can also be useful for complex
|
||||
resources like IOMMUs. For example, IOMMUs with multiple consumers (devices
|
||||
whose addresses are remapped by the IOMMU) might need to keep their mappings
|
||||
fixed at (or additive to) the boot configuration until all its consumers have
|
||||
probed.
|
||||
|
||||
While the typical use case for sync_state() is to have the kernel cleanly take
|
||||
over management of devices from the bootloader, the usage of sync_state() is
|
||||
not restricted to that. Use it whenever it makes sense to take an action after
|
||||
all the consumers of a device have probed.
|
||||
|
||||
int (*remove) (struct device *dev);
|
||||
|
||||
remove is called to unbind a driver from a device. This may be
|
||||
|
@ -68,41 +68,49 @@ actually necessary; the debugfs code provides a number of helper functions
|
||||
for simple situations. Files containing a single integer value can be
|
||||
created with any of:
|
||||
|
||||
struct dentry *debugfs_create_u8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value);
|
||||
struct dentry *debugfs_create_u16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value);
|
||||
void debugfs_create_u8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value);
|
||||
void debugfs_create_u16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value);
|
||||
struct dentry *debugfs_create_u32(const char *name, umode_t mode,
|
||||
struct dentry *parent, u32 *value);
|
||||
struct dentry *debugfs_create_u64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value);
|
||||
void debugfs_create_u64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value);
|
||||
|
||||
These files support both reading and writing the given value; if a specific
|
||||
file should not be written to, simply set the mode bits accordingly. The
|
||||
values in these files are in decimal; if hexadecimal is more appropriate,
|
||||
the following functions can be used instead:
|
||||
|
||||
struct dentry *debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value);
|
||||
struct dentry *debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value);
|
||||
struct dentry *debugfs_create_x32(const char *name, umode_t mode,
|
||||
struct dentry *parent, u32 *value);
|
||||
struct dentry *debugfs_create_x64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value);
|
||||
void debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value);
|
||||
void debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value);
|
||||
void debugfs_create_x32(const char *name, umode_t mode,
|
||||
struct dentry *parent, u32 *value);
|
||||
void debugfs_create_x64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value);
|
||||
|
||||
These functions are useful as long as the developer knows the size of the
|
||||
value to be exported. Some types can have different widths on different
|
||||
architectures, though, complicating the situation somewhat. There is a
|
||||
function meant to help out in one special case:
|
||||
architectures, though, complicating the situation somewhat. There are
|
||||
functions meant to help out in such special cases:
|
||||
|
||||
struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
size_t *value);
|
||||
void debugfs_create_size_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, size_t *value);
|
||||
|
||||
As might be expected, this function will create a debugfs file to represent
|
||||
a variable of type size_t.
|
||||
|
||||
Similarly, there are helpers for variables of type unsigned long, in decimal
|
||||
and hexadecimal:
|
||||
|
||||
struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
unsigned long *value);
|
||||
void debugfs_create_xul(const char *name, umode_t mode,
|
||||
struct dentry *parent, unsigned long *value);
|
||||
|
||||
Boolean values can be placed in debugfs with:
|
||||
|
||||
struct dentry *debugfs_create_bool(const char *name, umode_t mode,
|
||||
@ -114,8 +122,8 @@ lower-case values, or 1 or 0. Any other input will be silently ignored.
|
||||
|
||||
Also, atomic_t values can be placed in debugfs with:
|
||||
|
||||
struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, atomic_t *value)
|
||||
void debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, atomic_t *value)
|
||||
|
||||
A read of this file will get atomic_t values, and a write of this file
|
||||
will set atomic_t values.
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
struct dtl {
|
||||
struct dtl_entry *buf;
|
||||
struct dentry *file;
|
||||
int cpu;
|
||||
int buf_entries;
|
||||
u64 last_idx;
|
||||
@ -320,46 +319,28 @@ static const struct file_operations dtl_fops = {
|
||||
|
||||
static struct dentry *dtl_dir;
|
||||
|
||||
static int dtl_setup_file(struct dtl *dtl)
|
||||
static void dtl_setup_file(struct dtl *dtl)
|
||||
{
|
||||
char name[10];
|
||||
|
||||
sprintf(name, "cpu-%d", dtl->cpu);
|
||||
|
||||
dtl->file = debugfs_create_file(name, 0400, dtl_dir, dtl, &dtl_fops);
|
||||
if (!dtl->file)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
debugfs_create_file(name, 0400, dtl_dir, dtl, &dtl_fops);
|
||||
}
|
||||
|
||||
static int dtl_init(void)
|
||||
{
|
||||
struct dentry *event_mask_file, *buf_entries_file;
|
||||
int rc, i;
|
||||
int i;
|
||||
|
||||
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
|
||||
return -ENODEV;
|
||||
|
||||
/* set up common debugfs structure */
|
||||
|
||||
rc = -ENOMEM;
|
||||
dtl_dir = debugfs_create_dir("dtl", powerpc_debugfs_root);
|
||||
if (!dtl_dir) {
|
||||
printk(KERN_WARNING "%s: can't create dtl root dir\n",
|
||||
__func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
event_mask_file = debugfs_create_x8("dtl_event_mask", 0600,
|
||||
dtl_dir, &dtl_event_mask);
|
||||
buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0400,
|
||||
dtl_dir, &dtl_buf_entries);
|
||||
|
||||
if (!event_mask_file || !buf_entries_file) {
|
||||
printk(KERN_WARNING "%s: can't create dtl files\n", __func__);
|
||||
goto err_remove_dir;
|
||||
}
|
||||
debugfs_create_x8("dtl_event_mask", 0600, dtl_dir, &dtl_event_mask);
|
||||
debugfs_create_u32("dtl_buf_entries", 0400, dtl_dir, &dtl_buf_entries);
|
||||
|
||||
/* set up the per-cpu log structures */
|
||||
for_each_possible_cpu(i) {
|
||||
@ -367,16 +348,9 @@ static int dtl_init(void)
|
||||
spin_lock_init(&dtl->lock);
|
||||
dtl->cpu = i;
|
||||
|
||||
rc = dtl_setup_file(dtl);
|
||||
if (rc)
|
||||
goto err_remove_dir;
|
||||
dtl_setup_file(dtl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_dir:
|
||||
debugfs_remove_recursive(dtl_dir);
|
||||
err:
|
||||
return rc;
|
||||
}
|
||||
machine_arch_initcall(pseries, dtl_init);
|
||||
|
@ -129,7 +129,6 @@ static void probe_hcall_exit(void *ignored, unsigned long opcode, long retval,
|
||||
static int __init hcall_inst_init(void)
|
||||
{
|
||||
struct dentry *hcall_root;
|
||||
struct dentry *hcall_file;
|
||||
char cpu_name_buf[CPU_NAME_BUF_SIZE];
|
||||
int cpu;
|
||||
|
||||
@ -145,17 +144,12 @@ static int __init hcall_inst_init(void)
|
||||
}
|
||||
|
||||
hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);
|
||||
if (!hcall_root)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);
|
||||
hcall_file = debugfs_create_file(cpu_name_buf, 0444,
|
||||
hcall_root,
|
||||
per_cpu(hcall_stats, cpu),
|
||||
&hcall_inst_seq_fops);
|
||||
if (!hcall_file)
|
||||
return -ENOMEM;
|
||||
debugfs_create_file(cpu_name_buf, 0444, hcall_root,
|
||||
per_cpu(hcall_stats, cpu),
|
||||
&hcall_inst_seq_fops);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1998,24 +1998,11 @@ static int __init vpa_debugfs_init(void)
|
||||
return 0;
|
||||
|
||||
vpa_dir = debugfs_create_dir("vpa", powerpc_debugfs_root);
|
||||
if (!vpa_dir) {
|
||||
pr_warn("%s: can't create vpa root dir\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* set up the per-cpu vpa file*/
|
||||
for_each_possible_cpu(i) {
|
||||
struct dentry *d;
|
||||
|
||||
sprintf(name, "cpu-%ld", i);
|
||||
|
||||
d = debugfs_create_file(name, 0400, vpa_dir, (void *)i,
|
||||
&vpa_fops);
|
||||
if (!d) {
|
||||
pr_warn("%s: can't create per-cpu vpa file\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
debugfs_create_file(name, 0400, vpa_dir, (void *)i, &vpa_fops);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3,7 +3,7 @@
|
||||
# Makefile for the Linux SuperH-specific device drivers.
|
||||
#
|
||||
|
||||
obj-y += dma/
|
||||
obj-y += dma/ platform_early.o
|
||||
|
||||
obj-$(CONFIG_PCI) += pci/
|
||||
obj-$(CONFIG_SUPERHYWAY) += superhyway/
|
||||
|
347
arch/sh/drivers/platform_early.c
Normal file
347
arch/sh/drivers/platform_early.c
Normal file
@ -0,0 +1,347 @@
|
||||
// SPDX--License-Identifier: GPL-2.0
|
||||
|
||||
#include <asm/platform_early.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
static __initdata LIST_HEAD(sh_early_platform_driver_list);
|
||||
static __initdata LIST_HEAD(sh_early_platform_device_list);
|
||||
|
||||
static const struct platform_device_id *
|
||||
platform_match_id(const struct platform_device_id *id,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
while (id->name[0]) {
|
||||
if (strcmp(pdev->name, id->name) == 0) {
|
||||
pdev->id_entry = id;
|
||||
return id;
|
||||
}
|
||||
id++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int platform_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct platform_driver *pdrv = to_platform_driver(drv);
|
||||
|
||||
/* When driver_override is set, only bind to the matching driver */
|
||||
if (pdev->driver_override)
|
||||
return !strcmp(pdev->driver_override, drv->name);
|
||||
|
||||
/* Then try to match against the id table */
|
||||
if (pdrv->id_table)
|
||||
return platform_match_id(pdrv->id_table, pdev) != NULL;
|
||||
|
||||
/* fall-back to driver name match */
|
||||
return (strcmp(pdev->name, drv->name) == 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void device_pm_init_common(struct device *dev)
|
||||
{
|
||||
if (!dev->power.early_init) {
|
||||
spin_lock_init(&dev->power.lock);
|
||||
dev->power.qos = NULL;
|
||||
dev->power.early_init = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_runtime_early_init(struct device *dev)
|
||||
{
|
||||
dev->power.disable_depth = 1;
|
||||
device_pm_init_common(dev);
|
||||
}
|
||||
#else
|
||||
static void pm_runtime_early_init(struct device *dev) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* sh_early_platform_driver_register - register early platform driver
|
||||
* @epdrv: sh_early_platform driver structure
|
||||
* @buf: string passed from early_param()
|
||||
*
|
||||
* Helper function for sh_early_platform_init() / sh_early_platform_init_buffer()
|
||||
*/
|
||||
int __init sh_early_platform_driver_register(struct sh_early_platform_driver *epdrv,
|
||||
char *buf)
|
||||
{
|
||||
char *tmp;
|
||||
int n;
|
||||
|
||||
/* Simply add the driver to the end of the global list.
|
||||
* Drivers will by default be put on the list in compiled-in order.
|
||||
*/
|
||||
if (!epdrv->list.next) {
|
||||
INIT_LIST_HEAD(&epdrv->list);
|
||||
list_add_tail(&epdrv->list, &sh_early_platform_driver_list);
|
||||
}
|
||||
|
||||
/* If the user has specified device then make sure the driver
|
||||
* gets prioritized. The driver of the last device specified on
|
||||
* command line will be put first on the list.
|
||||
*/
|
||||
n = strlen(epdrv->pdrv->driver.name);
|
||||
if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
|
||||
list_move(&epdrv->list, &sh_early_platform_driver_list);
|
||||
|
||||
/* Allow passing parameters after device name */
|
||||
if (buf[n] == '\0' || buf[n] == ',')
|
||||
epdrv->requested_id = -1;
|
||||
else {
|
||||
epdrv->requested_id = simple_strtoul(&buf[n + 1],
|
||||
&tmp, 10);
|
||||
|
||||
if (buf[n] != '.' || (tmp == &buf[n + 1])) {
|
||||
epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
|
||||
n = 0;
|
||||
} else
|
||||
n += strcspn(&buf[n + 1], ",") + 1;
|
||||
}
|
||||
|
||||
if (buf[n] == ',')
|
||||
n++;
|
||||
|
||||
if (epdrv->bufsize) {
|
||||
memcpy(epdrv->buffer, &buf[n],
|
||||
min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
|
||||
epdrv->buffer[epdrv->bufsize - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sh_early_platform_add_devices - adds a number of early platform devices
|
||||
* @devs: array of early platform devices to add
|
||||
* @num: number of early platform devices in array
|
||||
*
|
||||
* Used by early architecture code to register early platform devices and
|
||||
* their platform data.
|
||||
*/
|
||||
void __init sh_early_platform_add_devices(struct platform_device **devs, int num)
|
||||
{
|
||||
struct device *dev;
|
||||
int i;
|
||||
|
||||
/* simply add the devices to list */
|
||||
for (i = 0; i < num; i++) {
|
||||
dev = &devs[i]->dev;
|
||||
|
||||
if (!dev->devres_head.next) {
|
||||
pm_runtime_early_init(dev);
|
||||
INIT_LIST_HEAD(&dev->devres_head);
|
||||
list_add_tail(&dev->devres_head,
|
||||
&sh_early_platform_device_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sh_early_platform_driver_register_all - register early platform drivers
|
||||
* @class_str: string to identify early platform driver class
|
||||
*
|
||||
* Used by architecture code to register all early platform drivers
|
||||
* for a certain class. If omitted then only early platform drivers
|
||||
* with matching kernel command line class parameters will be registered.
|
||||
*/
|
||||
void __init sh_early_platform_driver_register_all(char *class_str)
|
||||
{
|
||||
/* The "class_str" parameter may or may not be present on the kernel
|
||||
* command line. If it is present then there may be more than one
|
||||
* matching parameter.
|
||||
*
|
||||
* Since we register our early platform drivers using early_param()
|
||||
* we need to make sure that they also get registered in the case
|
||||
* when the parameter is missing from the kernel command line.
|
||||
*
|
||||
* We use parse_early_options() to make sure the early_param() gets
|
||||
* called at least once. The early_param() may be called more than
|
||||
* once since the name of the preferred device may be specified on
|
||||
* the kernel command line. sh_early_platform_driver_register() handles
|
||||
* this case for us.
|
||||
*/
|
||||
parse_early_options(class_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* sh_early_platform_match - find early platform device matching driver
|
||||
* @epdrv: early platform driver structure
|
||||
* @id: id to match against
|
||||
*/
|
||||
static struct platform_device * __init
|
||||
sh_early_platform_match(struct sh_early_platform_driver *epdrv, int id)
|
||||
{
|
||||
struct platform_device *pd;
|
||||
|
||||
list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
|
||||
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
|
||||
if (pd->id == id)
|
||||
return pd;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* sh_early_platform_left - check if early platform driver has matching devices
|
||||
* @epdrv: early platform driver structure
|
||||
* @id: return true if id or above exists
|
||||
*/
|
||||
static int __init sh_early_platform_left(struct sh_early_platform_driver *epdrv,
|
||||
int id)
|
||||
{
|
||||
struct platform_device *pd;
|
||||
|
||||
list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
|
||||
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
|
||||
if (pd->id >= id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sh_early_platform_driver_probe_id - probe drivers matching class_str and id
|
||||
* @class_str: string to identify early platform driver class
|
||||
* @id: id to match against
|
||||
* @nr_probe: number of platform devices to successfully probe before exiting
|
||||
*/
|
||||
static int __init sh_early_platform_driver_probe_id(char *class_str,
|
||||
int id,
|
||||
int nr_probe)
|
||||
{
|
||||
struct sh_early_platform_driver *epdrv;
|
||||
struct platform_device *match;
|
||||
int match_id;
|
||||
int n = 0;
|
||||
int left = 0;
|
||||
|
||||
list_for_each_entry(epdrv, &sh_early_platform_driver_list, list) {
|
||||
/* only use drivers matching our class_str */
|
||||
if (strcmp(class_str, epdrv->class_str))
|
||||
continue;
|
||||
|
||||
if (id == -2) {
|
||||
match_id = epdrv->requested_id;
|
||||
left = 1;
|
||||
|
||||
} else {
|
||||
match_id = id;
|
||||
left += sh_early_platform_left(epdrv, id);
|
||||
|
||||
/* skip requested id */
|
||||
switch (epdrv->requested_id) {
|
||||
case EARLY_PLATFORM_ID_ERROR:
|
||||
case EARLY_PLATFORM_ID_UNSET:
|
||||
break;
|
||||
default:
|
||||
if (epdrv->requested_id == id)
|
||||
match_id = EARLY_PLATFORM_ID_UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
switch (match_id) {
|
||||
case EARLY_PLATFORM_ID_ERROR:
|
||||
pr_warn("%s: unable to parse %s parameter\n",
|
||||
class_str, epdrv->pdrv->driver.name);
|
||||
/* fall-through */
|
||||
case EARLY_PLATFORM_ID_UNSET:
|
||||
match = NULL;
|
||||
break;
|
||||
default:
|
||||
match = sh_early_platform_match(epdrv, match_id);
|
||||
}
|
||||
|
||||
if (match) {
|
||||
/*
|
||||
* Set up a sensible init_name to enable
|
||||
* dev_name() and others to be used before the
|
||||
* rest of the driver core is initialized.
|
||||
*/
|
||||
if (!match->dev.init_name && slab_is_available()) {
|
||||
if (match->id != -1)
|
||||
match->dev.init_name =
|
||||
kasprintf(GFP_KERNEL, "%s.%d",
|
||||
match->name,
|
||||
match->id);
|
||||
else
|
||||
match->dev.init_name =
|
||||
kasprintf(GFP_KERNEL, "%s",
|
||||
match->name);
|
||||
|
||||
if (!match->dev.init_name)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (epdrv->pdrv->probe(match))
|
||||
pr_warn("%s: unable to probe %s early.\n",
|
||||
class_str, match->name);
|
||||
else
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n >= nr_probe)
|
||||
break;
|
||||
}
|
||||
|
||||
if (left)
|
||||
return n;
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* sh_early_platform_driver_probe - probe a class of registered drivers
|
||||
* @class_str: string to identify early platform driver class
|
||||
* @nr_probe: number of platform devices to successfully probe before exiting
|
||||
* @user_only: only probe user specified early platform devices
|
||||
*
|
||||
* Used by architecture code to probe registered early platform drivers
|
||||
* within a certain class. For probe to happen a registered early platform
|
||||
* device matching a registered early platform driver is needed.
|
||||
*/
|
||||
int __init sh_early_platform_driver_probe(char *class_str,
|
||||
int nr_probe,
|
||||
int user_only)
|
||||
{
|
||||
int k, n, i;
|
||||
|
||||
n = 0;
|
||||
for (i = -2; n < nr_probe; i++) {
|
||||
k = sh_early_platform_driver_probe_id(class_str, i, nr_probe - n);
|
||||
|
||||
if (k < 0)
|
||||
break;
|
||||
|
||||
n += k;
|
||||
|
||||
if (user_only)
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* sh_early_platform_cleanup - clean up early platform code
|
||||
*/
|
||||
static int __init sh_early_platform_cleanup(void)
|
||||
{
|
||||
struct platform_device *pd, *pd2;
|
||||
|
||||
/* clean up the devres list used to chain devices */
|
||||
list_for_each_entry_safe(pd, pd2, &sh_early_platform_device_list,
|
||||
dev.devres_head) {
|
||||
list_del(&pd->dev.devres_head);
|
||||
memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* This must happen once after all early devices are probed but before probing
|
||||
* real platform devices.
|
||||
*/
|
||||
subsys_initcall(sh_early_platform_cleanup);
|
61
arch/sh/include/asm/platform_early.h
Normal file
61
arch/sh/include/asm/platform_early.h
Normal file
@ -0,0 +1,61 @@
|
||||
/* SPDX--License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef __PLATFORM_EARLY__
|
||||
#define __PLATFORM_EARLY__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct sh_early_platform_driver {
|
||||
const char *class_str;
|
||||
struct platform_driver *pdrv;
|
||||
struct list_head list;
|
||||
int requested_id;
|
||||
char *buffer;
|
||||
int bufsize;
|
||||
};
|
||||
|
||||
#define EARLY_PLATFORM_ID_UNSET -2
|
||||
#define EARLY_PLATFORM_ID_ERROR -3
|
||||
|
||||
extern int sh_early_platform_driver_register(struct sh_early_platform_driver *epdrv,
|
||||
char *buf);
|
||||
extern void sh_early_platform_add_devices(struct platform_device **devs, int num);
|
||||
|
||||
static inline int is_sh_early_platform_device(struct platform_device *pdev)
|
||||
{
|
||||
return !pdev->dev.driver;
|
||||
}
|
||||
|
||||
extern void sh_early_platform_driver_register_all(char *class_str);
|
||||
extern int sh_early_platform_driver_probe(char *class_str,
|
||||
int nr_probe, int user_only);
|
||||
|
||||
#define sh_early_platform_init(class_string, platdrv) \
|
||||
sh_early_platform_init_buffer(class_string, platdrv, NULL, 0)
|
||||
|
||||
#ifndef MODULE
|
||||
#define sh_early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
|
||||
static __initdata struct sh_early_platform_driver early_driver = { \
|
||||
.class_str = class_string, \
|
||||
.buffer = buf, \
|
||||
.bufsize = bufsiz, \
|
||||
.pdrv = platdrv, \
|
||||
.requested_id = EARLY_PLATFORM_ID_UNSET, \
|
||||
}; \
|
||||
static int __init sh_early_platform_driver_setup_func(char *buffer) \
|
||||
{ \
|
||||
return sh_early_platform_driver_register(&early_driver, buffer); \
|
||||
} \
|
||||
early_param(class_string, sh_early_platform_driver_setup_func)
|
||||
#else /* MODULE */
|
||||
#define sh_early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
|
||||
static inline char *sh_early_platform_driver_setup_func(void) \
|
||||
{ \
|
||||
return bufsiz ? buf : NULL; \
|
||||
}
|
||||
#endif /* MODULE */
|
||||
|
||||
#endif /* __PLATFORM_EARLY__ */
|
@ -12,6 +12,7 @@
|
||||
#include <linux/sh_eth.h>
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -199,6 +200,6 @@ void __init plat_early_device_setup(void)
|
||||
/* enable CMT clock */
|
||||
__raw_writeb(__raw_readb(STBCR3) & ~0x10, STBCR3);
|
||||
|
||||
early_platform_add_devices(sh7619_early_devices,
|
||||
sh_early_platform_add_devices(sh7619_early_devices,
|
||||
ARRAY_SIZE(sh7619_early_devices));
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_sci.h>
|
||||
#include <linux/sh_timer.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -169,6 +170,6 @@ static struct platform_device *mxg_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(mxg_early_devices,
|
||||
sh_early_platform_add_devices(mxg_early_devices,
|
||||
ARRAY_SIZE(mxg_early_devices));
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/serial_sci.h>
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -412,6 +413,6 @@ void __init plat_early_device_setup(void)
|
||||
/* enable MTU2 clock */
|
||||
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
|
||||
|
||||
early_platform_add_devices(sh7201_early_devices,
|
||||
sh_early_platform_add_devices(sh7201_early_devices,
|
||||
ARRAY_SIZE(sh7201_early_devices));
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/serial_sci.h>
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -349,6 +350,6 @@ void __init plat_early_device_setup(void)
|
||||
/* enable MTU2 clock */
|
||||
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
|
||||
|
||||
early_platform_add_devices(sh7203_early_devices,
|
||||
sh_early_platform_add_devices(sh7203_early_devices,
|
||||
ARRAY_SIZE(sh7203_early_devices));
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/serial_sci.h>
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -285,6 +286,6 @@ void __init plat_early_device_setup(void)
|
||||
/* enable MTU2 clock */
|
||||
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
|
||||
|
||||
early_platform_add_devices(sh7206_early_devices,
|
||||
sh_early_platform_add_devices(sh7206_early_devices,
|
||||
ARRAY_SIZE(sh7206_early_devices));
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/usb/r8a66597.h>
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -546,6 +547,6 @@ static struct platform_device *sh7264_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7264_early_devices,
|
||||
sh_early_platform_add_devices(sh7264_early_devices,
|
||||
ARRAY_SIZE(sh7264_early_devices));
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/usb/r8a66597.h>
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -562,6 +563,6 @@ static struct platform_device *sh7269_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7269_early_devices,
|
||||
sh_early_platform_add_devices(sh7269_early_devices,
|
||||
ARRAY_SIZE(sh7269_early_devices));
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
/* All SH3 devices are equipped with IRQ0->5 (except sh7708) */
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/sh_intc.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <cpu/serial.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -178,7 +179,7 @@ static struct platform_device *sh7705_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7705_early_devices,
|
||||
sh_early_platform_add_devices(sh7705_early_devices,
|
||||
ARRAY_SIZE(sh7705_early_devices));
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/sh_intc.h>
|
||||
#include <cpu/serial.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -230,7 +231,7 @@ static struct platform_device *sh770x_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh770x_early_devices,
|
||||
sh_early_platform_add_devices(sh770x_early_devices,
|
||||
ARRAY_SIZE(sh770x_early_devices));
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/sh_intc.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -177,7 +178,7 @@ static struct platform_device *sh7710_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7710_early_devices,
|
||||
sh_early_platform_add_devices(sh7710_early_devices,
|
||||
ARRAY_SIZE(sh7710_early_devices));
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/sh_intc.h>
|
||||
#include <linux/usb/ohci_pdriver.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/platform_early.h>
|
||||
#include <cpu/serial.h>
|
||||
|
||||
static struct resource rtc_resources[] = {
|
||||
@ -211,7 +212,7 @@ static struct platform_device *sh7720_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7720_early_devices,
|
||||
sh_early_platform_add_devices(sh7720_early_devices,
|
||||
ARRAY_SIZE(sh7720_early_devices));
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/sh_intc.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
.scscr = SCSCR_REIE,
|
||||
@ -76,7 +77,7 @@ static struct platform_device *sh4202_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh4202_early_devices,
|
||||
sh_early_platform_add_devices(sh4202_early_devices,
|
||||
ARRAY_SIZE(sh4202_early_devices));
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/sh_intc.h>
|
||||
#include <linux/serial_sci.h>
|
||||
#include <generated/machtypes.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct resource rtc_resources[] = {
|
||||
[0] = {
|
||||
@ -161,15 +162,15 @@ void __init plat_early_device_setup(void)
|
||||
if (mach_is_rts7751r2d()) {
|
||||
scif_platform_data.scscr |= SCSCR_CKE1;
|
||||
dev[0] = &scif_device;
|
||||
early_platform_add_devices(dev, 1);
|
||||
sh_early_platform_add_devices(dev, 1);
|
||||
} else {
|
||||
dev[0] = &sci_device;
|
||||
early_platform_add_devices(dev, 1);
|
||||
sh_early_platform_add_devices(dev, 1);
|
||||
dev[0] = &scif_device;
|
||||
early_platform_add_devices(dev, 1);
|
||||
sh_early_platform_add_devices(dev, 1);
|
||||
}
|
||||
|
||||
early_platform_add_devices(sh7750_early_devices,
|
||||
sh_early_platform_add_devices(sh7750_early_devices,
|
||||
ARRAY_SIZE(sh7750_early_devices));
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/sh_intc.h>
|
||||
#include <linux/serial_sci.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
enum {
|
||||
UNUSED = 0,
|
||||
@ -271,7 +272,7 @@ static struct platform_device *sh7760_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7760_early_devices,
|
||||
sh_early_platform_add_devices(sh7760_early_devices,
|
||||
ARRAY_SIZE(sh7760_early_devices));
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/sh_intc.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
/* Serial */
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
@ -296,7 +297,7 @@ static struct platform_device *sh7343_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7343_early_devices,
|
||||
sh_early_platform_add_devices(sh7343_early_devices,
|
||||
ARRAY_SIZE(sh7343_early_devices));
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/sh_intc.h>
|
||||
#include <linux/usb/r8a66597.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
.scscr = SCSCR_REIE,
|
||||
@ -240,7 +241,7 @@ static struct platform_device *sh7366_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7366_early_devices,
|
||||
sh_early_platform_add_devices(sh7366_early_devices,
|
||||
ARRAY_SIZE(sh7366_early_devices));
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <asm/clock.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <asm/siu.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
#include <cpu/dma-register.h>
|
||||
#include <cpu/sh7722.h>
|
||||
@ -512,7 +513,7 @@ static struct platform_device *sh7722_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7722_early_devices,
|
||||
sh_early_platform_add_devices(sh7722_early_devices,
|
||||
ARRAY_SIZE(sh7722_early_devices));
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <asm/platform_early.h>
|
||||
#include <cpu/sh7723.h>
|
||||
|
||||
/* Serial */
|
||||
@ -410,7 +411,7 @@ static struct platform_device *sh7723_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7723_early_devices,
|
||||
sh_early_platform_add_devices(sh7723_early_devices,
|
||||
ARRAY_SIZE(sh7723_early_devices));
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <asm/suspend.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
#include <cpu/dma-register.h>
|
||||
#include <cpu/sh7724.h>
|
||||
@ -830,7 +831,7 @@ static struct platform_device *sh7724_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7724_early_devices,
|
||||
sh_early_platform_add_devices(sh7724_early_devices,
|
||||
ARRAY_SIZE(sh7724_early_devices));
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/platform_early.h>
|
||||
#include <cpu/sh7734.h>
|
||||
|
||||
/* SCIF */
|
||||
@ -280,7 +281,7 @@ static struct platform_device *sh7734_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7734_early_devices,
|
||||
sh_early_platform_add_devices(sh7734_early_devices,
|
||||
ARRAY_SIZE(sh7734_early_devices));
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/usb/ohci_pdriver.h>
|
||||
#include <cpu/dma-register.h>
|
||||
#include <cpu/sh7757.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct plat_sci_port scif2_platform_data = {
|
||||
.scscr = SCSCR_REIE,
|
||||
@ -767,7 +768,7 @@ static struct platform_device *sh7757_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7757_early_devices,
|
||||
sh_early_platform_add_devices(sh7757_early_devices,
|
||||
ARRAY_SIZE(sh7757_early_devices));
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/serial_sci.h>
|
||||
#include <linux/usb/ohci_pdriver.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
.scscr = SCSCR_REIE,
|
||||
@ -221,7 +222,7 @@ static struct platform_device *sh7763_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7763_early_devices,
|
||||
sh_early_platform_add_devices(sh7763_early_devices,
|
||||
ARRAY_SIZE(sh7763_early_devices));
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/sh_intc.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
.scscr = SCSCR_REIE | SCSCR_TOIE,
|
||||
@ -316,7 +317,7 @@ static struct platform_device *sh7770_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7770_early_devices,
|
||||
sh_early_platform_add_devices(sh7770_early_devices,
|
||||
ARRAY_SIZE(sh7770_early_devices));
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/sh_intc.h>
|
||||
#include <cpu/dma-register.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
.scscr = SCSCR_REIE | SCSCR_CKE1,
|
||||
@ -285,7 +286,7 @@ void __init plat_early_device_setup(void)
|
||||
scif1_platform_data.scscr &= ~SCSCR_CKE1;
|
||||
}
|
||||
|
||||
early_platform_add_devices(sh7780_early_devices,
|
||||
sh_early_platform_add_devices(sh7780_early_devices,
|
||||
ARRAY_SIZE(sh7780_early_devices));
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/sh_timer.h>
|
||||
#include <linux/sh_intc.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <asm/platform_early.h>
|
||||
#include <cpu/dma-register.h>
|
||||
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
@ -353,7 +354,7 @@ static struct platform_device *sh7785_early_devices[] __initdata = {
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7785_early_devices,
|
||||
sh_early_platform_add_devices(sh7785_early_devices,
|
||||
ARRAY_SIZE(sh7785_early_devices));
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/usb/ohci_pdriver.h>
|
||||
#include <cpu/dma-register.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
.scscr = SCSCR_REIE | SCSCR_CKE1,
|
||||
@ -834,6 +835,6 @@ arch_initcall(sh7786_devices_setup);
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh7786_early_devices,
|
||||
sh_early_platform_add_devices(sh7786_early_devices,
|
||||
ARRAY_SIZE(sh7786_early_devices));
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/sh_intc.h>
|
||||
#include <cpu/shx3.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
/*
|
||||
* This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
|
||||
@ -152,7 +153,7 @@ arch_initcall(shx3_devices_setup);
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(shx3_early_devices,
|
||||
sh_early_platform_add_devices(shx3_early_devices,
|
||||
ARRAY_SIZE(shx3_early_devices));
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sh_timer.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static struct plat_sci_port scif0_platform_data = {
|
||||
.flags = UPF_IOREMAP,
|
||||
@ -115,6 +116,6 @@ arch_initcall(sh5_devices_setup);
|
||||
|
||||
void __init plat_early_device_setup(void)
|
||||
{
|
||||
early_platform_add_devices(sh5_early_devices,
|
||||
sh_early_platform_add_devices(sh5_early_devices,
|
||||
ARRAY_SIZE(sh5_early_devices));
|
||||
}
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <asm/sparsemem.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
/*
|
||||
* Initialize loops_per_jiffy as 10000000 (1000MIPS).
|
||||
@ -328,7 +329,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
sh_mv_setup();
|
||||
|
||||
/* Let earlyprintk output early console messages */
|
||||
early_platform_driver_probe("earlyprintk", 1, 1);
|
||||
sh_early_platform_driver_probe("earlyprintk", 1, 1);
|
||||
|
||||
#ifdef CONFIG_OF_FLATTREE
|
||||
#ifdef CONFIG_USE_BUILTIN_DTB
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/platform_early.h>
|
||||
|
||||
static void __init sh_late_time_init(void)
|
||||
{
|
||||
@ -30,8 +31,8 @@ static void __init sh_late_time_init(void)
|
||||
* clocksource and the jiffies clocksource is used transparently
|
||||
* instead. No error handling is necessary here.
|
||||
*/
|
||||
early_platform_driver_register_all("earlytimer");
|
||||
early_platform_driver_probe("earlytimer", 2, 0);
|
||||
sh_early_platform_driver_register_all("earlytimer");
|
||||
sh_early_platform_driver_probe("earlytimer", 2, 0);
|
||||
}
|
||||
|
||||
void __init time_init(void)
|
||||
|
@ -45,6 +45,10 @@ early_param("sysfs.deprecated", sysfs_deprecated_setup);
|
||||
#endif
|
||||
|
||||
/* Device links support. */
|
||||
static LIST_HEAD(wait_for_suppliers);
|
||||
static DEFINE_MUTEX(wfs_lock);
|
||||
static LIST_HEAD(deferred_sync);
|
||||
static unsigned int defer_sync_state_count = 1;
|
||||
|
||||
#ifdef CONFIG_SRCU
|
||||
static DEFINE_MUTEX(device_links_lock);
|
||||
@ -127,6 +131,9 @@ static int device_is_dependent(struct device *dev, void *target)
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(link, &dev->links.consumers, s_node) {
|
||||
if (link->flags == (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
|
||||
continue;
|
||||
|
||||
if (link->consumer == target)
|
||||
return 1;
|
||||
|
||||
@ -196,8 +203,11 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
|
||||
device_pm_move_last(dev);
|
||||
|
||||
device_for_each_child(dev, NULL, device_reorder_to_tail);
|
||||
list_for_each_entry(link, &dev->links.consumers, s_node)
|
||||
list_for_each_entry(link, &dev->links.consumers, s_node) {
|
||||
if (link->flags == (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
|
||||
continue;
|
||||
device_reorder_to_tail(link->consumer, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -224,7 +234,8 @@ void device_pm_move_to_tail(struct device *dev)
|
||||
|
||||
#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \
|
||||
DL_FLAG_AUTOREMOVE_SUPPLIER | \
|
||||
DL_FLAG_AUTOPROBE_CONSUMER)
|
||||
DL_FLAG_AUTOPROBE_CONSUMER | \
|
||||
DL_FLAG_SYNC_STATE_ONLY)
|
||||
|
||||
#define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \
|
||||
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)
|
||||
@ -292,6 +303,8 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
|
||||
if (!consumer || !supplier || flags & ~DL_ADD_VALID_FLAGS ||
|
||||
(flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) ||
|
||||
(flags & DL_FLAG_SYNC_STATE_ONLY &&
|
||||
flags != DL_FLAG_SYNC_STATE_ONLY) ||
|
||||
(flags & DL_FLAG_AUTOPROBE_CONSUMER &&
|
||||
flags & (DL_FLAG_AUTOREMOVE_CONSUMER |
|
||||
DL_FLAG_AUTOREMOVE_SUPPLIER)))
|
||||
@ -312,11 +325,14 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
|
||||
/*
|
||||
* If the supplier has not been fully registered yet or there is a
|
||||
* reverse dependency between the consumer and the supplier already in
|
||||
* the graph, return NULL.
|
||||
* reverse (non-SYNC_STATE_ONLY) dependency between the consumer and
|
||||
* the supplier already in the graph, return NULL. If the link is a
|
||||
* SYNC_STATE_ONLY link, we don't check for reverse dependencies
|
||||
* because it only affects sync_state() callbacks.
|
||||
*/
|
||||
if (!device_pm_initialized(supplier)
|
||||
|| device_is_dependent(consumer, supplier)) {
|
||||
|| (!(flags & DL_FLAG_SYNC_STATE_ONLY) &&
|
||||
device_is_dependent(consumer, supplier))) {
|
||||
link = NULL;
|
||||
goto out;
|
||||
}
|
||||
@ -343,9 +359,14 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
}
|
||||
|
||||
if (flags & DL_FLAG_STATELESS) {
|
||||
link->flags |= DL_FLAG_STATELESS;
|
||||
kref_get(&link->kref);
|
||||
goto out;
|
||||
if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
|
||||
!(link->flags & DL_FLAG_STATELESS)) {
|
||||
link->flags |= DL_FLAG_STATELESS;
|
||||
goto reorder;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -367,6 +388,12 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
link->flags |= DL_FLAG_MANAGED;
|
||||
device_link_init_status(link, consumer, supplier);
|
||||
}
|
||||
if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
|
||||
!(flags & DL_FLAG_SYNC_STATE_ONLY)) {
|
||||
link->flags &= ~DL_FLAG_SYNC_STATE_ONLY;
|
||||
goto reorder;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -406,6 +433,13 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
flags & DL_FLAG_PM_RUNTIME)
|
||||
pm_runtime_resume(supplier);
|
||||
|
||||
if (flags & DL_FLAG_SYNC_STATE_ONLY) {
|
||||
dev_dbg(consumer,
|
||||
"Linked as a sync state only consumer to %s\n",
|
||||
dev_name(supplier));
|
||||
goto out;
|
||||
}
|
||||
reorder:
|
||||
/*
|
||||
* Move the consumer and all of the devices depending on it to the end
|
||||
* of dpm_list and the devices_kset list.
|
||||
@ -431,6 +465,70 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_link_add);
|
||||
|
||||
/**
|
||||
* device_link_wait_for_supplier - Add device to wait_for_suppliers list
|
||||
* @consumer: Consumer device
|
||||
*
|
||||
* Marks the @consumer device as waiting for suppliers to become available by
|
||||
* adding it to the wait_for_suppliers list. The consumer device will never be
|
||||
* probed until it's removed from the wait_for_suppliers list.
|
||||
*
|
||||
* The caller is responsible for adding the links to the supplier devices once
|
||||
* they are available and removing the @consumer device from the
|
||||
* wait_for_suppliers list once links to all the suppliers have been created.
|
||||
*
|
||||
* This function is NOT meant to be called from the probe function of the
|
||||
* consumer but rather from code that creates/adds the consumer device.
|
||||
*/
|
||||
static void device_link_wait_for_supplier(struct device *consumer,
|
||||
bool need_for_probe)
|
||||
{
|
||||
mutex_lock(&wfs_lock);
|
||||
list_add_tail(&consumer->links.needs_suppliers, &wait_for_suppliers);
|
||||
consumer->links.need_for_probe = need_for_probe;
|
||||
mutex_unlock(&wfs_lock);
|
||||
}
|
||||
|
||||
static void device_link_wait_for_mandatory_supplier(struct device *consumer)
|
||||
{
|
||||
device_link_wait_for_supplier(consumer, true);
|
||||
}
|
||||
|
||||
static void device_link_wait_for_optional_supplier(struct device *consumer)
|
||||
{
|
||||
device_link_wait_for_supplier(consumer, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* device_link_add_missing_supplier_links - Add links from consumer devices to
|
||||
* supplier devices, leaving any
|
||||
* consumer with inactive suppliers on
|
||||
* the wait_for_suppliers list
|
||||
*
|
||||
* Loops through all consumers waiting on suppliers and tries to add all their
|
||||
* supplier links. If that succeeds, the consumer device is removed from
|
||||
* wait_for_suppliers list. Otherwise, they are left in the wait_for_suppliers
|
||||
* list. Devices left on the wait_for_suppliers list will not be probed.
|
||||
*
|
||||
* The fwnode add_links callback is expected to return 0 if it has found and
|
||||
* added all the supplier links for the consumer device. It should return an
|
||||
* error if it isn't able to do so.
|
||||
*
|
||||
* The caller of device_link_wait_for_supplier() is expected to call this once
|
||||
* it's aware of potential suppliers becoming available.
|
||||
*/
|
||||
static void device_link_add_missing_supplier_links(void)
|
||||
{
|
||||
struct device *dev, *tmp;
|
||||
|
||||
mutex_lock(&wfs_lock);
|
||||
list_for_each_entry_safe(dev, tmp, &wait_for_suppliers,
|
||||
links.needs_suppliers)
|
||||
if (!fwnode_call_int_op(dev->fwnode, add_links, dev))
|
||||
list_del_init(&dev->links.needs_suppliers);
|
||||
mutex_unlock(&wfs_lock);
|
||||
}
|
||||
|
||||
static void device_link_free(struct device_link *link)
|
||||
{
|
||||
while (refcount_dec_not_one(&link->rpm_active))
|
||||
@ -565,10 +663,23 @@ int device_links_check_suppliers(struct device *dev)
|
||||
struct device_link *link;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Device waiting for supplier to become available is not allowed to
|
||||
* probe.
|
||||
*/
|
||||
mutex_lock(&wfs_lock);
|
||||
if (!list_empty(&dev->links.needs_suppliers) &&
|
||||
dev->links.need_for_probe) {
|
||||
mutex_unlock(&wfs_lock);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
mutex_unlock(&wfs_lock);
|
||||
|
||||
device_links_write_lock();
|
||||
|
||||
list_for_each_entry(link, &dev->links.suppliers, c_node) {
|
||||
if (!(link->flags & DL_FLAG_MANAGED))
|
||||
if (!(link->flags & DL_FLAG_MANAGED) ||
|
||||
link->flags & DL_FLAG_SYNC_STATE_ONLY)
|
||||
continue;
|
||||
|
||||
if (link->status != DL_STATE_AVAILABLE) {
|
||||
@ -584,6 +695,69 @@ int device_links_check_suppliers(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __device_links_supplier_sync_state(struct device *dev)
|
||||
{
|
||||
struct device_link *link;
|
||||
|
||||
if (dev->state_synced)
|
||||
return;
|
||||
|
||||
list_for_each_entry(link, &dev->links.consumers, s_node) {
|
||||
if (!(link->flags & DL_FLAG_MANAGED))
|
||||
continue;
|
||||
if (link->status != DL_STATE_ACTIVE)
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->bus->sync_state)
|
||||
dev->bus->sync_state(dev);
|
||||
else if (dev->driver && dev->driver->sync_state)
|
||||
dev->driver->sync_state(dev);
|
||||
|
||||
dev->state_synced = true;
|
||||
}
|
||||
|
||||
void device_links_supplier_sync_state_pause(void)
|
||||
{
|
||||
device_links_write_lock();
|
||||
defer_sync_state_count++;
|
||||
device_links_write_unlock();
|
||||
}
|
||||
|
||||
void device_links_supplier_sync_state_resume(void)
|
||||
{
|
||||
struct device *dev, *tmp;
|
||||
|
||||
device_links_write_lock();
|
||||
if (!defer_sync_state_count) {
|
||||
WARN(true, "Unmatched sync_state pause/resume!");
|
||||
goto out;
|
||||
}
|
||||
defer_sync_state_count--;
|
||||
if (defer_sync_state_count)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_sync) {
|
||||
__device_links_supplier_sync_state(dev);
|
||||
list_del_init(&dev->links.defer_sync);
|
||||
}
|
||||
out:
|
||||
device_links_write_unlock();
|
||||
}
|
||||
|
||||
static int sync_state_resume_initcall(void)
|
||||
{
|
||||
device_links_supplier_sync_state_resume();
|
||||
return 0;
|
||||
}
|
||||
late_initcall(sync_state_resume_initcall);
|
||||
|
||||
static void __device_links_supplier_defer_sync(struct device *sup)
|
||||
{
|
||||
if (list_empty(&sup->links.defer_sync))
|
||||
list_add_tail(&sup->links.defer_sync, &deferred_sync);
|
||||
}
|
||||
|
||||
/**
|
||||
* device_links_driver_bound - Update device links after probing its driver.
|
||||
* @dev: Device to update the links for.
|
||||
@ -599,6 +773,15 @@ void device_links_driver_bound(struct device *dev)
|
||||
{
|
||||
struct device_link *link;
|
||||
|
||||
/*
|
||||
* If a device probes successfully, it's expected to have created all
|
||||
* the device links it needs to or make new device links as it needs
|
||||
* them. So, it no longer needs to wait on any suppliers.
|
||||
*/
|
||||
mutex_lock(&wfs_lock);
|
||||
list_del_init(&dev->links.needs_suppliers);
|
||||
mutex_unlock(&wfs_lock);
|
||||
|
||||
device_links_write_lock();
|
||||
|
||||
list_for_each_entry(link, &dev->links.consumers, s_node) {
|
||||
@ -628,6 +811,11 @@ void device_links_driver_bound(struct device *dev)
|
||||
|
||||
WARN_ON(link->status != DL_STATE_CONSUMER_PROBE);
|
||||
WRITE_ONCE(link->status, DL_STATE_ACTIVE);
|
||||
|
||||
if (defer_sync_state_count)
|
||||
__device_links_supplier_defer_sync(link->supplier);
|
||||
else
|
||||
__device_links_supplier_sync_state(link->supplier);
|
||||
}
|
||||
|
||||
dev->links.status = DL_DEV_DRIVER_BOUND;
|
||||
@ -744,6 +932,7 @@ void device_links_driver_cleanup(struct device *dev)
|
||||
WRITE_ONCE(link->status, DL_STATE_DORMANT);
|
||||
}
|
||||
|
||||
list_del_init(&dev->links.defer_sync);
|
||||
__device_links_no_driver(dev);
|
||||
|
||||
device_links_write_unlock();
|
||||
@ -813,7 +1002,8 @@ void device_links_unbind_consumers(struct device *dev)
|
||||
list_for_each_entry(link, &dev->links.consumers, s_node) {
|
||||
enum device_link_state status;
|
||||
|
||||
if (!(link->flags & DL_FLAG_MANAGED))
|
||||
if (!(link->flags & DL_FLAG_MANAGED) ||
|
||||
link->flags & DL_FLAG_SYNC_STATE_ONLY)
|
||||
continue;
|
||||
|
||||
status = link->status;
|
||||
@ -849,6 +1039,10 @@ static void device_links_purge(struct device *dev)
|
||||
{
|
||||
struct device_link *link, *ln;
|
||||
|
||||
mutex_lock(&wfs_lock);
|
||||
list_del(&dev->links.needs_suppliers);
|
||||
mutex_unlock(&wfs_lock);
|
||||
|
||||
/*
|
||||
* Delete all of the remaining links from this device to any other
|
||||
* devices (either consumers or suppliers).
|
||||
@ -1713,6 +1907,8 @@ void device_initialize(struct device *dev)
|
||||
#endif
|
||||
INIT_LIST_HEAD(&dev->links.consumers);
|
||||
INIT_LIST_HEAD(&dev->links.suppliers);
|
||||
INIT_LIST_HEAD(&dev->links.needs_suppliers);
|
||||
INIT_LIST_HEAD(&dev->links.defer_sync);
|
||||
dev->links.status = DL_DEV_NO_DRIVER;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_initialize);
|
||||
@ -2101,7 +2297,7 @@ int device_add(struct device *dev)
|
||||
struct device *parent;
|
||||
struct kobject *kobj;
|
||||
struct class_interface *class_intf;
|
||||
int error = -EINVAL;
|
||||
int error = -EINVAL, fw_ret;
|
||||
struct kobject *glue_dir = NULL;
|
||||
|
||||
dev = get_device(dev);
|
||||
@ -2199,6 +2395,32 @@ int device_add(struct device *dev)
|
||||
BUS_NOTIFY_ADD_DEVICE, dev);
|
||||
|
||||
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
||||
|
||||
if (dev->fwnode && !dev->fwnode->dev)
|
||||
dev->fwnode->dev = dev;
|
||||
|
||||
/*
|
||||
* Check if any of the other devices (consumers) have been waiting for
|
||||
* this device (supplier) to be added so that they can create a device
|
||||
* link to it.
|
||||
*
|
||||
* This needs to happen after device_pm_add() because device_link_add()
|
||||
* requires the supplier be registered before it's called.
|
||||
*
|
||||
* But this also needs to happe before bus_probe_device() to make sure
|
||||
* waiting consumers can link to it before the driver is bound to the
|
||||
* device and the driver sync_state callback is called for this device.
|
||||
*/
|
||||
device_link_add_missing_supplier_links();
|
||||
|
||||
if (fwnode_has_op(dev->fwnode, add_links)) {
|
||||
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
|
||||
if (fw_ret == -ENODEV)
|
||||
device_link_wait_for_mandatory_supplier(dev);
|
||||
else if (fw_ret)
|
||||
device_link_wait_for_optional_supplier(dev);
|
||||
}
|
||||
|
||||
bus_probe_device(dev);
|
||||
if (parent)
|
||||
klist_add_tail(&dev->p->knode_parent,
|
||||
@ -2343,6 +2565,9 @@ void device_del(struct device *dev)
|
||||
kill_device(dev);
|
||||
device_unlock(dev);
|
||||
|
||||
if (dev->fwnode && dev->fwnode->dev == dev)
|
||||
dev->fwnode->dev = NULL;
|
||||
|
||||
/* Notify clients of device removal. This call must come
|
||||
* before dpm_sysfs_remove().
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Copyright (c) 2003 Manuel Estrada Sainz
|
||||
*
|
||||
* Please see Documentation/firmware_class/ for more information.
|
||||
* Please see Documentation/driver-api/firmware/ for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -504,6 +504,7 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
|
||||
path);
|
||||
continue;
|
||||
}
|
||||
dev_dbg(device, "Loading firmware from %s\n", path);
|
||||
if (decompress) {
|
||||
dev_dbg(device, "f/w decompressing %s\n",
|
||||
fw_priv->fw_name);
|
||||
|
@ -60,6 +60,7 @@ struct resource *platform_get_resource(struct platform_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(platform_get_resource);
|
||||
|
||||
#ifdef CONFIG_HAS_IOMEM
|
||||
/**
|
||||
* devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform
|
||||
* device
|
||||
@ -68,7 +69,6 @@ EXPORT_SYMBOL_GPL(platform_get_resource);
|
||||
* resource management
|
||||
* @index: resource index
|
||||
*/
|
||||
#ifdef CONFIG_HAS_IOMEM
|
||||
void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
|
||||
unsigned int index)
|
||||
{
|
||||
@ -78,9 +78,63 @@ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
|
||||
return devm_ioremap_resource(&pdev->dev, res);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
|
||||
|
||||
/**
|
||||
* devm_platform_ioremap_resource_wc - write-combined variant of
|
||||
* devm_platform_ioremap_resource()
|
||||
*
|
||||
* @pdev: platform device to use both for memory resource lookup as well as
|
||||
* resource management
|
||||
* @index: resource index
|
||||
*/
|
||||
void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev,
|
||||
unsigned int index)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, index);
|
||||
return devm_ioremap_resource_wc(&pdev->dev, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_platform_ioremap_resource_byname - call devm_ioremap_resource for
|
||||
* a platform device, retrieve the
|
||||
* resource by name
|
||||
*
|
||||
* @pdev: platform device to use both for memory resource lookup as well as
|
||||
* resource management
|
||||
* @name: name of the resource
|
||||
*/
|
||||
void __iomem *
|
||||
devm_platform_ioremap_resource_byname(struct platform_device *pdev,
|
||||
const char *name)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
|
||||
return devm_ioremap_resource(&pdev->dev, res);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
|
||||
#endif /* CONFIG_HAS_IOMEM */
|
||||
|
||||
static int __platform_get_irq(struct platform_device *dev, unsigned int num)
|
||||
/**
|
||||
* platform_get_irq_optional - get an optional IRQ for a device
|
||||
* @dev: platform device
|
||||
* @num: IRQ number index
|
||||
*
|
||||
* Gets an IRQ for a platform device. Device drivers should check the return
|
||||
* value for errors so as to not pass a negative integer value to the
|
||||
* request_irq() APIs. This is the same as platform_get_irq(), except that it
|
||||
* does not print an error message if an IRQ can not be obtained.
|
||||
*
|
||||
* Example:
|
||||
* int irq = platform_get_irq_optional(pdev, 0);
|
||||
* if (irq < 0)
|
||||
* return irq;
|
||||
*
|
||||
* Return: IRQ number on success, negative error number on failure.
|
||||
*/
|
||||
int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
|
||||
{
|
||||
#ifdef CONFIG_SPARC
|
||||
/* sparc does not have irqs represented as IORESOURCE_IRQ resources */
|
||||
@ -144,6 +198,7 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num)
|
||||
return -ENXIO;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(platform_get_irq_optional);
|
||||
|
||||
/**
|
||||
* platform_get_irq - get an IRQ for a device
|
||||
@ -165,7 +220,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __platform_get_irq(dev, num);
|
||||
ret = platform_get_irq_optional(dev, num);
|
||||
if (ret < 0 && ret != -EPROBE_DEFER)
|
||||
dev_err(&dev->dev, "IRQ index %u not found\n", num);
|
||||
|
||||
@ -173,29 +228,6 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(platform_get_irq);
|
||||
|
||||
/**
|
||||
* platform_get_irq_optional - get an optional IRQ for a device
|
||||
* @dev: platform device
|
||||
* @num: IRQ number index
|
||||
*
|
||||
* Gets an IRQ for a platform device. Device drivers should check the return
|
||||
* value for errors so as to not pass a negative integer value to the
|
||||
* request_irq() APIs. This is the same as platform_get_irq(), except that it
|
||||
* does not print an error message if an IRQ can not be obtained.
|
||||
*
|
||||
* Example:
|
||||
* int irq = platform_get_irq_optional(pdev, 0);
|
||||
* if (irq < 0)
|
||||
* return irq;
|
||||
*
|
||||
* Return: IRQ number on success, negative error number on failure.
|
||||
*/
|
||||
int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
|
||||
{
|
||||
return __platform_get_irq(dev, num);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(platform_get_irq_optional);
|
||||
|
||||
/**
|
||||
* platform_irq_count - Count the number of IRQs a platform device uses
|
||||
* @dev: platform device
|
||||
@ -206,7 +238,7 @@ int platform_irq_count(struct platform_device *dev)
|
||||
{
|
||||
int ret, nr = 0;
|
||||
|
||||
while ((ret = __platform_get_irq(dev, nr)) >= 0)
|
||||
while ((ret = platform_get_irq_optional(dev, nr)) >= 0)
|
||||
nr++;
|
||||
|
||||
if (ret == -EPROBE_DEFER)
|
||||
@ -1296,8 +1328,6 @@ int __init platform_bus_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
early_platform_cleanup();
|
||||
|
||||
error = device_register(&platform_bus);
|
||||
if (error) {
|
||||
put_device(&platform_bus);
|
||||
@ -1309,289 +1339,3 @@ int __init platform_bus_init(void)
|
||||
of_platform_register_reconfig_notifier();
|
||||
return error;
|
||||
}
|
||||
|
||||
static __initdata LIST_HEAD(early_platform_driver_list);
|
||||
static __initdata LIST_HEAD(early_platform_device_list);
|
||||
|
||||
/**
|
||||
* early_platform_driver_register - register early platform driver
|
||||
* @epdrv: early_platform driver structure
|
||||
* @buf: string passed from early_param()
|
||||
*
|
||||
* Helper function for early_platform_init() / early_platform_init_buffer()
|
||||
*/
|
||||
int __init early_platform_driver_register(struct early_platform_driver *epdrv,
|
||||
char *buf)
|
||||
{
|
||||
char *tmp;
|
||||
int n;
|
||||
|
||||
/* Simply add the driver to the end of the global list.
|
||||
* Drivers will by default be put on the list in compiled-in order.
|
||||
*/
|
||||
if (!epdrv->list.next) {
|
||||
INIT_LIST_HEAD(&epdrv->list);
|
||||
list_add_tail(&epdrv->list, &early_platform_driver_list);
|
||||
}
|
||||
|
||||
/* If the user has specified device then make sure the driver
|
||||
* gets prioritized. The driver of the last device specified on
|
||||
* command line will be put first on the list.
|
||||
*/
|
||||
n = strlen(epdrv->pdrv->driver.name);
|
||||
if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
|
||||
list_move(&epdrv->list, &early_platform_driver_list);
|
||||
|
||||
/* Allow passing parameters after device name */
|
||||
if (buf[n] == '\0' || buf[n] == ',')
|
||||
epdrv->requested_id = -1;
|
||||
else {
|
||||
epdrv->requested_id = simple_strtoul(&buf[n + 1],
|
||||
&tmp, 10);
|
||||
|
||||
if (buf[n] != '.' || (tmp == &buf[n + 1])) {
|
||||
epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
|
||||
n = 0;
|
||||
} else
|
||||
n += strcspn(&buf[n + 1], ",") + 1;
|
||||
}
|
||||
|
||||
if (buf[n] == ',')
|
||||
n++;
|
||||
|
||||
if (epdrv->bufsize) {
|
||||
memcpy(epdrv->buffer, &buf[n],
|
||||
min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
|
||||
epdrv->buffer[epdrv->bufsize - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_add_devices - adds a number of early platform devices
|
||||
* @devs: array of early platform devices to add
|
||||
* @num: number of early platform devices in array
|
||||
*
|
||||
* Used by early architecture code to register early platform devices and
|
||||
* their platform data.
|
||||
*/
|
||||
void __init early_platform_add_devices(struct platform_device **devs, int num)
|
||||
{
|
||||
struct device *dev;
|
||||
int i;
|
||||
|
||||
/* simply add the devices to list */
|
||||
for (i = 0; i < num; i++) {
|
||||
dev = &devs[i]->dev;
|
||||
|
||||
if (!dev->devres_head.next) {
|
||||
pm_runtime_early_init(dev);
|
||||
INIT_LIST_HEAD(&dev->devres_head);
|
||||
list_add_tail(&dev->devres_head,
|
||||
&early_platform_device_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_driver_register_all - register early platform drivers
|
||||
* @class_str: string to identify early platform driver class
|
||||
*
|
||||
* Used by architecture code to register all early platform drivers
|
||||
* for a certain class. If omitted then only early platform drivers
|
||||
* with matching kernel command line class parameters will be registered.
|
||||
*/
|
||||
void __init early_platform_driver_register_all(char *class_str)
|
||||
{
|
||||
/* The "class_str" parameter may or may not be present on the kernel
|
||||
* command line. If it is present then there may be more than one
|
||||
* matching parameter.
|
||||
*
|
||||
* Since we register our early platform drivers using early_param()
|
||||
* we need to make sure that they also get registered in the case
|
||||
* when the parameter is missing from the kernel command line.
|
||||
*
|
||||
* We use parse_early_options() to make sure the early_param() gets
|
||||
* called at least once. The early_param() may be called more than
|
||||
* once since the name of the preferred device may be specified on
|
||||
* the kernel command line. early_platform_driver_register() handles
|
||||
* this case for us.
|
||||
*/
|
||||
parse_early_options(class_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_match - find early platform device matching driver
|
||||
* @epdrv: early platform driver structure
|
||||
* @id: id to match against
|
||||
*/
|
||||
static struct platform_device * __init
|
||||
early_platform_match(struct early_platform_driver *epdrv, int id)
|
||||
{
|
||||
struct platform_device *pd;
|
||||
|
||||
list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
|
||||
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
|
||||
if (pd->id == id)
|
||||
return pd;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_left - check if early platform driver has matching devices
|
||||
* @epdrv: early platform driver structure
|
||||
* @id: return true if id or above exists
|
||||
*/
|
||||
static int __init early_platform_left(struct early_platform_driver *epdrv,
|
||||
int id)
|
||||
{
|
||||
struct platform_device *pd;
|
||||
|
||||
list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
|
||||
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
|
||||
if (pd->id >= id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_driver_probe_id - probe drivers matching class_str and id
|
||||
* @class_str: string to identify early platform driver class
|
||||
* @id: id to match against
|
||||
* @nr_probe: number of platform devices to successfully probe before exiting
|
||||
*/
|
||||
static int __init early_platform_driver_probe_id(char *class_str,
|
||||
int id,
|
||||
int nr_probe)
|
||||
{
|
||||
struct early_platform_driver *epdrv;
|
||||
struct platform_device *match;
|
||||
int match_id;
|
||||
int n = 0;
|
||||
int left = 0;
|
||||
|
||||
list_for_each_entry(epdrv, &early_platform_driver_list, list) {
|
||||
/* only use drivers matching our class_str */
|
||||
if (strcmp(class_str, epdrv->class_str))
|
||||
continue;
|
||||
|
||||
if (id == -2) {
|
||||
match_id = epdrv->requested_id;
|
||||
left = 1;
|
||||
|
||||
} else {
|
||||
match_id = id;
|
||||
left += early_platform_left(epdrv, id);
|
||||
|
||||
/* skip requested id */
|
||||
switch (epdrv->requested_id) {
|
||||
case EARLY_PLATFORM_ID_ERROR:
|
||||
case EARLY_PLATFORM_ID_UNSET:
|
||||
break;
|
||||
default:
|
||||
if (epdrv->requested_id == id)
|
||||
match_id = EARLY_PLATFORM_ID_UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
switch (match_id) {
|
||||
case EARLY_PLATFORM_ID_ERROR:
|
||||
pr_warn("%s: unable to parse %s parameter\n",
|
||||
class_str, epdrv->pdrv->driver.name);
|
||||
/* fall-through */
|
||||
case EARLY_PLATFORM_ID_UNSET:
|
||||
match = NULL;
|
||||
break;
|
||||
default:
|
||||
match = early_platform_match(epdrv, match_id);
|
||||
}
|
||||
|
||||
if (match) {
|
||||
/*
|
||||
* Set up a sensible init_name to enable
|
||||
* dev_name() and others to be used before the
|
||||
* rest of the driver core is initialized.
|
||||
*/
|
||||
if (!match->dev.init_name && slab_is_available()) {
|
||||
if (match->id != -1)
|
||||
match->dev.init_name =
|
||||
kasprintf(GFP_KERNEL, "%s.%d",
|
||||
match->name,
|
||||
match->id);
|
||||
else
|
||||
match->dev.init_name =
|
||||
kasprintf(GFP_KERNEL, "%s",
|
||||
match->name);
|
||||
|
||||
if (!match->dev.init_name)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (epdrv->pdrv->probe(match))
|
||||
pr_warn("%s: unable to probe %s early.\n",
|
||||
class_str, match->name);
|
||||
else
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n >= nr_probe)
|
||||
break;
|
||||
}
|
||||
|
||||
if (left)
|
||||
return n;
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_driver_probe - probe a class of registered drivers
|
||||
* @class_str: string to identify early platform driver class
|
||||
* @nr_probe: number of platform devices to successfully probe before exiting
|
||||
* @user_only: only probe user specified early platform devices
|
||||
*
|
||||
* Used by architecture code to probe registered early platform drivers
|
||||
* within a certain class. For probe to happen a registered early platform
|
||||
* device matching a registered early platform driver is needed.
|
||||
*/
|
||||
int __init early_platform_driver_probe(char *class_str,
|
||||
int nr_probe,
|
||||
int user_only)
|
||||
{
|
||||
int k, n, i;
|
||||
|
||||
n = 0;
|
||||
for (i = -2; n < nr_probe; i++) {
|
||||
k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
|
||||
|
||||
if (k < 0)
|
||||
break;
|
||||
|
||||
n += k;
|
||||
|
||||
if (user_only)
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_cleanup - clean up early platform code
|
||||
*/
|
||||
void __init early_platform_cleanup(void)
|
||||
{
|
||||
struct platform_device *pd, *pd2;
|
||||
|
||||
/* clean up the devres list used to chain devices */
|
||||
list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
|
||||
dev.devres_head) {
|
||||
list_del(&pd->dev.devres_head);
|
||||
memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,15 +104,12 @@ static const struct attribute_group soc_attr_group = {
|
||||
.is_visible = soc_attribute_mode,
|
||||
};
|
||||
|
||||
static const struct attribute_group *soc_attr_groups[] = {
|
||||
&soc_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void soc_release(struct device *dev)
|
||||
{
|
||||
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
||||
|
||||
ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
|
||||
kfree(soc_dev->dev.groups);
|
||||
kfree(soc_dev);
|
||||
}
|
||||
|
||||
@ -121,6 +118,7 @@ static struct soc_device_attribute *early_soc_dev_attr;
|
||||
struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr)
|
||||
{
|
||||
struct soc_device *soc_dev;
|
||||
const struct attribute_group **soc_attr_groups;
|
||||
int ret;
|
||||
|
||||
if (!soc_bus_type.p) {
|
||||
@ -136,10 +134,18 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
|
||||
goto out1;
|
||||
}
|
||||
|
||||
soc_attr_groups = kcalloc(3, sizeof(*soc_attr_groups), GFP_KERNEL);
|
||||
if (!soc_attr_groups) {
|
||||
ret = -ENOMEM;
|
||||
goto out2;
|
||||
}
|
||||
soc_attr_groups[0] = &soc_attr_group;
|
||||
soc_attr_groups[1] = soc_dev_attr->custom_attr_group;
|
||||
|
||||
/* Fetch a unique (reclaimable) SOC ID. */
|
||||
ret = ida_simple_get(&soc_ida, 0, 0, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto out2;
|
||||
goto out3;
|
||||
soc_dev->soc_dev_num = ret;
|
||||
|
||||
soc_dev->attr = soc_dev_attr;
|
||||
@ -150,15 +156,15 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
|
||||
dev_set_name(&soc_dev->dev, "soc%d", soc_dev->soc_dev_num);
|
||||
|
||||
ret = device_register(&soc_dev->dev);
|
||||
if (ret)
|
||||
goto out3;
|
||||
if (ret) {
|
||||
put_device(&soc_dev->dev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return soc_dev;
|
||||
|
||||
out3:
|
||||
ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
|
||||
put_device(&soc_dev->dev);
|
||||
soc_dev = NULL;
|
||||
kfree(soc_attr_groups);
|
||||
out2:
|
||||
kfree(soc_dev);
|
||||
out1:
|
||||
@ -169,8 +175,6 @@ EXPORT_SYMBOL_GPL(soc_device_register);
|
||||
/* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
|
||||
void soc_device_unregister(struct soc_device *soc_dev)
|
||||
{
|
||||
ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
|
||||
|
||||
device_unregister(&soc_dev->dev);
|
||||
early_soc_dev_attr = NULL;
|
||||
}
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#ifdef CONFIG_SUPERH
|
||||
#include <asm/platform_early.h>
|
||||
#endif
|
||||
|
||||
struct sh_cmt_device;
|
||||
|
||||
/*
|
||||
@ -1052,7 +1056,7 @@ static int sh_cmt_probe(struct platform_device *pdev)
|
||||
struct sh_cmt_device *cmt = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
if (!is_early_platform_device(pdev)) {
|
||||
if (!is_sh_early_platform_device(pdev)) {
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
}
|
||||
@ -1072,7 +1076,7 @@ static int sh_cmt_probe(struct platform_device *pdev)
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
if (is_early_platform_device(pdev))
|
||||
if (is_sh_early_platform_device(pdev))
|
||||
return 0;
|
||||
|
||||
out:
|
||||
@ -1109,7 +1113,10 @@ static void __exit sh_cmt_exit(void)
|
||||
platform_driver_unregister(&sh_cmt_device_driver);
|
||||
}
|
||||
|
||||
early_platform_init("earlytimer", &sh_cmt_device_driver);
|
||||
#ifdef CONFIG_SUPERH
|
||||
sh_early_platform_init("earlytimer", &sh_cmt_device_driver);
|
||||
#endif
|
||||
|
||||
subsys_initcall(sh_cmt_init);
|
||||
module_exit(sh_cmt_exit);
|
||||
|
||||
|
@ -23,6 +23,10 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#ifdef CONFIG_SUPERH
|
||||
#include <asm/platform_early.h>
|
||||
#endif
|
||||
|
||||
struct sh_mtu2_device;
|
||||
|
||||
struct sh_mtu2_channel {
|
||||
@ -442,7 +446,7 @@ static int sh_mtu2_probe(struct platform_device *pdev)
|
||||
struct sh_mtu2_device *mtu = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
if (!is_early_platform_device(pdev)) {
|
||||
if (!is_sh_early_platform_device(pdev)) {
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
}
|
||||
@ -462,7 +466,7 @@ static int sh_mtu2_probe(struct platform_device *pdev)
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
if (is_early_platform_device(pdev))
|
||||
if (is_sh_early_platform_device(pdev))
|
||||
return 0;
|
||||
|
||||
out:
|
||||
@ -511,7 +515,10 @@ static void __exit sh_mtu2_exit(void)
|
||||
platform_driver_unregister(&sh_mtu2_device_driver);
|
||||
}
|
||||
|
||||
early_platform_init("earlytimer", &sh_mtu2_device_driver);
|
||||
#ifdef CONFIG_SUPERH
|
||||
sh_early_platform_init("earlytimer", &sh_mtu2_device_driver);
|
||||
#endif
|
||||
|
||||
subsys_initcall(sh_mtu2_init);
|
||||
module_exit(sh_mtu2_exit);
|
||||
|
||||
|
@ -24,6 +24,10 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#ifdef CONFIG_SUPERH
|
||||
#include <asm/platform_early.h>
|
||||
#endif
|
||||
|
||||
enum sh_tmu_model {
|
||||
SH_TMU,
|
||||
SH_TMU_SH3,
|
||||
@ -595,7 +599,7 @@ static int sh_tmu_probe(struct platform_device *pdev)
|
||||
struct sh_tmu_device *tmu = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
if (!is_early_platform_device(pdev)) {
|
||||
if (!is_sh_early_platform_device(pdev)) {
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
}
|
||||
@ -615,7 +619,8 @@ static int sh_tmu_probe(struct platform_device *pdev)
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
if (is_early_platform_device(pdev))
|
||||
|
||||
if (is_sh_early_platform_device(pdev))
|
||||
return 0;
|
||||
|
||||
out:
|
||||
@ -665,7 +670,10 @@ static void __exit sh_tmu_exit(void)
|
||||
platform_driver_unregister(&sh_tmu_device_driver);
|
||||
}
|
||||
|
||||
early_platform_init("earlytimer", &sh_tmu_device_driver);
|
||||
#ifdef CONFIG_SUPERH
|
||||
sh_early_platform_init("earlytimer", &sh_tmu_device_driver);
|
||||
#endif
|
||||
|
||||
subsys_initcall(sh_tmu_init);
|
||||
module_exit(sh_tmu_exit);
|
||||
|
||||
|
@ -776,23 +776,12 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mvebu_pwm *mvpwm;
|
||||
struct resource *res;
|
||||
u32 set;
|
||||
|
||||
if (!of_device_is_compatible(mvchip->chip.of_node,
|
||||
"marvell,armada-370-gpio"))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* There are only two sets of PWM configuration registers for
|
||||
* all the GPIO lines on those SoCs which this driver reserves
|
||||
* for the first two GPIO chips. So if the resource is missing
|
||||
* we can't treat it as an error.
|
||||
*/
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm");
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
if (IS_ERR(mvchip->clk))
|
||||
return PTR_ERR(mvchip->clk);
|
||||
|
||||
@ -815,7 +804,13 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
mvchip->mvpwm = mvpwm;
|
||||
mvpwm->mvchip = mvchip;
|
||||
|
||||
mvpwm->membase = devm_ioremap_resource(dev, res);
|
||||
/*
|
||||
* There are only two sets of PWM configuration registers for
|
||||
* all the GPIO lines on those SoCs which this driver reserves
|
||||
* for the first two GPIO chips. So if the resource is missing
|
||||
* we can't treat it as an error.
|
||||
*/
|
||||
mvpwm->membase = devm_platform_ioremap_resource_byname(pdev, "pwm");
|
||||
if (IS_ERR(mvpwm->membase))
|
||||
return PTR_ERR(mvpwm->membase);
|
||||
|
||||
|
@ -450,7 +450,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
struct gpio_irq_chip *irq;
|
||||
struct tegra_gpio *gpio;
|
||||
struct device_node *np;
|
||||
struct resource *res;
|
||||
char **names;
|
||||
int err;
|
||||
|
||||
@ -460,8 +459,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
gpio->soc = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio");
|
||||
gpio->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
|
||||
if (IS_ERR(gpio->base))
|
||||
return PTR_ERR(gpio->base);
|
||||
|
||||
|
@ -5710,11 +5710,10 @@ static int mlx5_ib_rn_get_params(struct ib_device *device, u8 port_num,
|
||||
|
||||
static void delay_drop_debugfs_cleanup(struct mlx5_ib_dev *dev)
|
||||
{
|
||||
if (!dev->delay_drop.dbg)
|
||||
if (!dev->delay_drop.dir_debugfs)
|
||||
return;
|
||||
debugfs_remove_recursive(dev->delay_drop.dbg->dir_debugfs);
|
||||
kfree(dev->delay_drop.dbg);
|
||||
dev->delay_drop.dbg = NULL;
|
||||
debugfs_remove_recursive(dev->delay_drop.dir_debugfs);
|
||||
dev->delay_drop.dir_debugfs = NULL;
|
||||
}
|
||||
|
||||
static void cancel_delay_drop(struct mlx5_ib_dev *dev)
|
||||
@ -5765,52 +5764,22 @@ static const struct file_operations fops_delay_drop_timeout = {
|
||||
.read = delay_drop_timeout_read,
|
||||
};
|
||||
|
||||
static int delay_drop_debugfs_init(struct mlx5_ib_dev *dev)
|
||||
static void delay_drop_debugfs_init(struct mlx5_ib_dev *dev)
|
||||
{
|
||||
struct mlx5_ib_dbg_delay_drop *dbg;
|
||||
struct dentry *root;
|
||||
|
||||
if (!mlx5_debugfs_root)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
|
||||
if (!dbg)
|
||||
return -ENOMEM;
|
||||
root = debugfs_create_dir("delay_drop", dev->mdev->priv.dbg_root);
|
||||
dev->delay_drop.dir_debugfs = root;
|
||||
|
||||
dev->delay_drop.dbg = dbg;
|
||||
|
||||
dbg->dir_debugfs =
|
||||
debugfs_create_dir("delay_drop",
|
||||
dev->mdev->priv.dbg_root);
|
||||
if (!dbg->dir_debugfs)
|
||||
goto out_debugfs;
|
||||
|
||||
dbg->events_cnt_debugfs =
|
||||
debugfs_create_atomic_t("num_timeout_events", 0400,
|
||||
dbg->dir_debugfs,
|
||||
&dev->delay_drop.events_cnt);
|
||||
if (!dbg->events_cnt_debugfs)
|
||||
goto out_debugfs;
|
||||
|
||||
dbg->rqs_cnt_debugfs =
|
||||
debugfs_create_atomic_t("num_rqs", 0400,
|
||||
dbg->dir_debugfs,
|
||||
&dev->delay_drop.rqs_cnt);
|
||||
if (!dbg->rqs_cnt_debugfs)
|
||||
goto out_debugfs;
|
||||
|
||||
dbg->timeout_debugfs =
|
||||
debugfs_create_file("timeout", 0600,
|
||||
dbg->dir_debugfs,
|
||||
&dev->delay_drop,
|
||||
&fops_delay_drop_timeout);
|
||||
if (!dbg->timeout_debugfs)
|
||||
goto out_debugfs;
|
||||
|
||||
return 0;
|
||||
|
||||
out_debugfs:
|
||||
delay_drop_debugfs_cleanup(dev);
|
||||
return -ENOMEM;
|
||||
debugfs_create_atomic_t("num_timeout_events", 0400, root,
|
||||
&dev->delay_drop.events_cnt);
|
||||
debugfs_create_atomic_t("num_rqs", 0400, root,
|
||||
&dev->delay_drop.rqs_cnt);
|
||||
debugfs_create_file("timeout", 0600, root, &dev->delay_drop,
|
||||
&fops_delay_drop_timeout);
|
||||
}
|
||||
|
||||
static void init_delay_drop(struct mlx5_ib_dev *dev)
|
||||
@ -5826,8 +5795,7 @@ static void init_delay_drop(struct mlx5_ib_dev *dev)
|
||||
atomic_set(&dev->delay_drop.rqs_cnt, 0);
|
||||
atomic_set(&dev->delay_drop.events_cnt, 0);
|
||||
|
||||
if (delay_drop_debugfs_init(dev))
|
||||
mlx5_ib_warn(dev, "Failed to init delay drop debugfs\n");
|
||||
delay_drop_debugfs_init(dev);
|
||||
}
|
||||
|
||||
static void mlx5_ib_unbind_slave_port(struct mlx5_ib_dev *ibdev,
|
||||
|
@ -792,13 +792,6 @@ enum {
|
||||
MLX5_MAX_DELAY_DROP_TIMEOUT_MS = 100,
|
||||
};
|
||||
|
||||
struct mlx5_ib_dbg_delay_drop {
|
||||
struct dentry *dir_debugfs;
|
||||
struct dentry *rqs_cnt_debugfs;
|
||||
struct dentry *events_cnt_debugfs;
|
||||
struct dentry *timeout_debugfs;
|
||||
};
|
||||
|
||||
struct mlx5_ib_delay_drop {
|
||||
struct mlx5_ib_dev *dev;
|
||||
struct work_struct delay_drop_work;
|
||||
@ -808,7 +801,7 @@ struct mlx5_ib_delay_drop {
|
||||
bool activate;
|
||||
atomic_t events_cnt;
|
||||
atomic_t rqs_cnt;
|
||||
struct mlx5_ib_dbg_delay_drop *dbg;
|
||||
struct dentry *dir_debugfs;
|
||||
};
|
||||
|
||||
enum mlx5_ib_stages {
|
||||
|
@ -225,36 +225,16 @@ static const struct debugfs_reg32 fei_sys_regs[] = {
|
||||
|
||||
void c8sectpfe_debugfs_init(struct c8sectpfei *fei)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
|
||||
root = debugfs_create_dir("c8sectpfe", NULL);
|
||||
if (!root)
|
||||
goto err;
|
||||
|
||||
fei->root = root;
|
||||
|
||||
fei->regset = devm_kzalloc(fei->dev, sizeof(*fei->regset), GFP_KERNEL);
|
||||
if (!fei->regset)
|
||||
goto err;
|
||||
return;
|
||||
|
||||
fei->regset->regs = fei_sys_regs;
|
||||
fei->regset->nregs = ARRAY_SIZE(fei_sys_regs);
|
||||
fei->regset->base = fei->io;
|
||||
|
||||
file = debugfs_create_regset32("registers", S_IRUGO, root,
|
||||
fei->regset);
|
||||
if (!file) {
|
||||
dev_err(fei->dev,
|
||||
"%s not able to create 'registers' debugfs\n"
|
||||
, __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
debugfs_remove_recursive(root);
|
||||
fei->root = debugfs_create_dir("c8sectpfe", NULL);
|
||||
debugfs_create_regset32("registers", S_IRUGO, fei->root, fei->regset);
|
||||
}
|
||||
|
||||
void c8sectpfe_debugfs_exit(struct c8sectpfei *fei)
|
||||
|
@ -340,8 +340,6 @@ static const struct of_device_id sram_dt_ids[] = {
|
||||
static int sram_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sram_dev *sram;
|
||||
struct resource *res;
|
||||
size_t size;
|
||||
int ret;
|
||||
int (*init_func)(void);
|
||||
|
||||
@ -351,25 +349,14 @@ static int sram_probe(struct platform_device *pdev)
|
||||
|
||||
sram->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(sram->dev, "found no memory resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = resource_size(res);
|
||||
|
||||
if (!devm_request_mem_region(sram->dev, res->start, size, pdev->name)) {
|
||||
dev_err(sram->dev, "could not request region for resource\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node, "no-memory-wc"))
|
||||
sram->virt_base = devm_ioremap(sram->dev, res->start, size);
|
||||
sram->virt_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
else
|
||||
sram->virt_base = devm_ioremap_wc(sram->dev, res->start, size);
|
||||
if (!sram->virt_base)
|
||||
return -ENOMEM;
|
||||
sram->virt_base = devm_platform_ioremap_resource_wc(pdev, 0);
|
||||
if (IS_ERR(sram->virt_base)) {
|
||||
dev_err(&pdev->dev, "could not map SRAM registers\n");
|
||||
return PTR_ERR(sram->virt_base);
|
||||
}
|
||||
|
||||
sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
|
||||
NUMA_NO_NODE, NULL);
|
||||
@ -382,7 +369,8 @@ static int sram_probe(struct platform_device *pdev)
|
||||
else
|
||||
clk_prepare_enable(sram->clk);
|
||||
|
||||
ret = sram_reserve_regions(sram, res);
|
||||
ret = sram_reserve_regions(sram,
|
||||
platform_get_resource(pdev, IORESOURCE_MEM, 0));
|
||||
if (ret)
|
||||
goto err_disable_clk;
|
||||
|
||||
|
@ -583,11 +583,11 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
|
||||
|
||||
debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops);
|
||||
debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
|
||||
debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
|
||||
debugfs_create_x32("pending_events", S_IRUSR, root,
|
||||
(u32 *)&host->pending_events);
|
||||
debugfs_create_x32("completed_events", S_IRUSR, root,
|
||||
(u32 *)&host->completed_events);
|
||||
debugfs_create_u32("state", S_IRUSR, root, &host->state);
|
||||
debugfs_create_xul("pending_events", S_IRUSR, root,
|
||||
&host->pending_events);
|
||||
debugfs_create_xul("completed_events", S_IRUSR, root,
|
||||
&host->completed_events);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
|
@ -176,11 +176,11 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
|
||||
|
||||
debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);
|
||||
debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops);
|
||||
debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
|
||||
debugfs_create_x32("pending_events", S_IRUSR, root,
|
||||
(u32 *)&host->pending_events);
|
||||
debugfs_create_x32("completed_events", S_IRUSR, root,
|
||||
(u32 *)&host->completed_events);
|
||||
debugfs_create_u32("state", S_IRUSR, root, &host->state);
|
||||
debugfs_create_xul("pending_events", S_IRUSR, root,
|
||||
&host->pending_events);
|
||||
debugfs_create_xul("completed_events", S_IRUSR, root,
|
||||
&host->completed_events);
|
||||
}
|
||||
#endif /* defined(CONFIG_DEBUG_FS) */
|
||||
|
||||
|
@ -102,8 +102,8 @@ static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
|
||||
debugfs_create_blob("last_rx_msg", 0400, ser->debugfs_tty_dir,
|
||||
&ser->rx_blob);
|
||||
|
||||
debugfs_create_x32("ser_state", 0400, ser->debugfs_tty_dir,
|
||||
(u32 *)&ser->state);
|
||||
debugfs_create_xul("ser_state", 0400, ser->debugfs_tty_dir,
|
||||
&ser->state);
|
||||
|
||||
debugfs_create_x8("tty_status", 0400, ser->debugfs_tty_dir,
|
||||
&ser->tty_status);
|
||||
|
@ -354,13 +354,10 @@ static void pp_clear_ctx(struct pp_ctx *pp)
|
||||
static void pp_setup_dbgfs(struct pp_ctx *pp)
|
||||
{
|
||||
struct pci_dev *pdev = pp->ntb->pdev;
|
||||
void *ret;
|
||||
|
||||
pp->dbgfs_dir = debugfs_create_dir(pci_name(pdev), pp_dbgfs_topdir);
|
||||
|
||||
ret = debugfs_create_atomic_t("count", 0600, pp->dbgfs_dir, &pp->count);
|
||||
if (!ret)
|
||||
dev_warn(&pp->ntb->dev, "DebugFS unsupported\n");
|
||||
debugfs_create_atomic_t("count", 0600, pp->dbgfs_dir, &pp->count);
|
||||
}
|
||||
|
||||
static void pp_clear_dbgfs(struct pp_ctx *pp)
|
||||
|
@ -480,6 +480,7 @@ int of_platform_populate(struct device_node *root,
|
||||
pr_debug("%s()\n", __func__);
|
||||
pr_debug(" starting at: %pOF\n", root);
|
||||
|
||||
device_links_supplier_sync_state_pause();
|
||||
for_each_child_of_node(root, child) {
|
||||
rc = of_platform_bus_create(child, matches, lookup, parent, true);
|
||||
if (rc) {
|
||||
@ -487,6 +488,8 @@ int of_platform_populate(struct device_node *root,
|
||||
break;
|
||||
}
|
||||
}
|
||||
device_links_supplier_sync_state_resume();
|
||||
|
||||
of_node_set_flag(root, OF_POPULATED_BUS);
|
||||
|
||||
of_node_put(root);
|
||||
@ -518,6 +521,7 @@ static int __init of_platform_default_populate_init(void)
|
||||
if (!of_have_populated_dt())
|
||||
return -ENODEV;
|
||||
|
||||
device_links_supplier_sync_state_pause();
|
||||
/*
|
||||
* Handle certain compatibles explicitly, since we don't want to create
|
||||
* platform_devices for every node in /reserved-memory with a
|
||||
@ -538,6 +542,14 @@ static int __init of_platform_default_populate_init(void)
|
||||
return 0;
|
||||
}
|
||||
arch_initcall_sync(of_platform_default_populate_init);
|
||||
|
||||
static int __init of_platform_sync_state_init(void)
|
||||
{
|
||||
if (of_have_populated_dt())
|
||||
device_links_supplier_sync_state_resume();
|
||||
return 0;
|
||||
}
|
||||
late_initcall_sync(of_platform_sync_state_init);
|
||||
#endif
|
||||
|
||||
int of_platform_device_destroy(struct device *dev, void *data)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#include "of_private.h"
|
||||
|
||||
@ -985,6 +986,302 @@ of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
|
||||
return of_device_get_match_data(dev);
|
||||
}
|
||||
|
||||
static bool of_is_ancestor_of(struct device_node *test_ancestor,
|
||||
struct device_node *child)
|
||||
{
|
||||
of_node_get(child);
|
||||
while (child) {
|
||||
if (child == test_ancestor) {
|
||||
of_node_put(child);
|
||||
return false;
|
||||
}
|
||||
child = of_get_next_parent(child);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_link_to_phandle - Add device link to supplier from supplier phandle
|
||||
* @dev: consumer device
|
||||
* @sup_np: phandle to supplier device tree node
|
||||
*
|
||||
* Given a phandle to a supplier device tree node (@sup_np), this function
|
||||
* finds the device that owns the supplier device tree node and creates a
|
||||
* device link from @dev consumer device to the supplier device. This function
|
||||
* doesn't create device links for invalid scenarios such as trying to create a
|
||||
* link with a parent device as the consumer of its child device. In such
|
||||
* cases, it returns an error.
|
||||
*
|
||||
* Returns:
|
||||
* - 0 if link successfully created to supplier
|
||||
* - -EAGAIN if linking to the supplier should be reattempted
|
||||
* - -EINVAL if the supplier link is invalid and should not be created
|
||||
* - -ENODEV if there is no device that corresponds to the supplier phandle
|
||||
*/
|
||||
static int of_link_to_phandle(struct device *dev, struct device_node *sup_np,
|
||||
u32 dl_flags)
|
||||
{
|
||||
struct device *sup_dev;
|
||||
int ret = 0;
|
||||
struct device_node *tmp_np = sup_np;
|
||||
int is_populated;
|
||||
|
||||
of_node_get(sup_np);
|
||||
/*
|
||||
* Find the device node that contains the supplier phandle. It may be
|
||||
* @sup_np or it may be an ancestor of @sup_np.
|
||||
*/
|
||||
while (sup_np && !of_find_property(sup_np, "compatible", NULL))
|
||||
sup_np = of_get_next_parent(sup_np);
|
||||
if (!sup_np) {
|
||||
dev_dbg(dev, "Not linking to %pOFP - No device\n", tmp_np);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't allow linking a device node as a consumer of one of its
|
||||
* descendant nodes. By definition, a child node can't be a functional
|
||||
* dependency for the parent node.
|
||||
*/
|
||||
if (!of_is_ancestor_of(dev->of_node, sup_np)) {
|
||||
dev_dbg(dev, "Not linking to %pOFP - is descendant\n", sup_np);
|
||||
of_node_put(sup_np);
|
||||
return -EINVAL;
|
||||
}
|
||||
sup_dev = get_dev_from_fwnode(&sup_np->fwnode);
|
||||
is_populated = of_node_check_flag(sup_np, OF_POPULATED);
|
||||
of_node_put(sup_np);
|
||||
if (!sup_dev && is_populated) {
|
||||
/* Early device without struct device. */
|
||||
dev_dbg(dev, "Not linking to %pOFP - No struct device\n",
|
||||
sup_np);
|
||||
return -ENODEV;
|
||||
} else if (!sup_dev) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (!device_link_add(dev, sup_dev, dl_flags))
|
||||
ret = -EAGAIN;
|
||||
put_device(sup_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_prop_cells - Property parsing function for suppliers
|
||||
*
|
||||
* @np: Pointer to device tree node containing a list
|
||||
* @prop_name: Name of property to be parsed. Expected to hold phandle values
|
||||
* @index: For properties holding a list of phandles, this is the index
|
||||
* into the list.
|
||||
* @list_name: Property name that is known to contain list of phandle(s) to
|
||||
* supplier(s)
|
||||
* @cells_name: property name that specifies phandles' arguments count
|
||||
*
|
||||
* This is a helper function to parse properties that have a known fixed name
|
||||
* and are a list of phandles and phandle arguments.
|
||||
*
|
||||
* Returns:
|
||||
* - phandle node pointer with refcount incremented. Caller must of_node_put()
|
||||
* on it when done.
|
||||
* - NULL if no phandle found at index
|
||||
*/
|
||||
static struct device_node *parse_prop_cells(struct device_node *np,
|
||||
const char *prop_name, int index,
|
||||
const char *list_name,
|
||||
const char *cells_name)
|
||||
{
|
||||
struct of_phandle_args sup_args;
|
||||
|
||||
if (strcmp(prop_name, list_name))
|
||||
return NULL;
|
||||
|
||||
if (of_parse_phandle_with_args(np, list_name, cells_name, index,
|
||||
&sup_args))
|
||||
return NULL;
|
||||
|
||||
return sup_args.np;
|
||||
}
|
||||
|
||||
#define DEFINE_SIMPLE_PROP(fname, name, cells) \
|
||||
static struct device_node *parse_##fname(struct device_node *np, \
|
||||
const char *prop_name, int index) \
|
||||
{ \
|
||||
return parse_prop_cells(np, prop_name, index, name, cells); \
|
||||
}
|
||||
|
||||
static int strcmp_suffix(const char *str, const char *suffix)
|
||||
{
|
||||
unsigned int len, suffix_len;
|
||||
|
||||
len = strlen(str);
|
||||
suffix_len = strlen(suffix);
|
||||
if (len <= suffix_len)
|
||||
return -1;
|
||||
return strcmp(str + len - suffix_len, suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_suffix_prop_cells - Suffix property parsing function for suppliers
|
||||
*
|
||||
* @np: Pointer to device tree node containing a list
|
||||
* @prop_name: Name of property to be parsed. Expected to hold phandle values
|
||||
* @index: For properties holding a list of phandles, this is the index
|
||||
* into the list.
|
||||
* @suffix: Property suffix that is known to contain list of phandle(s) to
|
||||
* supplier(s)
|
||||
* @cells_name: property name that specifies phandles' arguments count
|
||||
*
|
||||
* This is a helper function to parse properties that have a known fixed suffix
|
||||
* and are a list of phandles and phandle arguments.
|
||||
*
|
||||
* Returns:
|
||||
* - phandle node pointer with refcount incremented. Caller must of_node_put()
|
||||
* on it when done.
|
||||
* - NULL if no phandle found at index
|
||||
*/
|
||||
static struct device_node *parse_suffix_prop_cells(struct device_node *np,
|
||||
const char *prop_name, int index,
|
||||
const char *suffix,
|
||||
const char *cells_name)
|
||||
{
|
||||
struct of_phandle_args sup_args;
|
||||
|
||||
if (strcmp_suffix(prop_name, suffix))
|
||||
return NULL;
|
||||
|
||||
if (of_parse_phandle_with_args(np, prop_name, cells_name, index,
|
||||
&sup_args))
|
||||
return NULL;
|
||||
|
||||
return sup_args.np;
|
||||
}
|
||||
|
||||
#define DEFINE_SUFFIX_PROP(fname, suffix, cells) \
|
||||
static struct device_node *parse_##fname(struct device_node *np, \
|
||||
const char *prop_name, int index) \
|
||||
{ \
|
||||
return parse_suffix_prop_cells(np, prop_name, index, suffix, cells); \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct supplier_bindings - Property parsing functions for suppliers
|
||||
*
|
||||
* @parse_prop: function name
|
||||
* parse_prop() finds the node corresponding to a supplier phandle
|
||||
* @parse_prop.np: Pointer to device node holding supplier phandle property
|
||||
* @parse_prop.prop_name: Name of property holding a phandle value
|
||||
* @parse_prop.index: For properties holding a list of phandles, this is the
|
||||
* index into the list
|
||||
*
|
||||
* Returns:
|
||||
* parse_prop() return values are
|
||||
* - phandle node pointer with refcount incremented. Caller must of_node_put()
|
||||
* on it when done.
|
||||
* - NULL if no phandle found at index
|
||||
*/
|
||||
struct supplier_bindings {
|
||||
struct device_node *(*parse_prop)(struct device_node *np,
|
||||
const char *prop_name, int index);
|
||||
};
|
||||
|
||||
DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells")
|
||||
DEFINE_SIMPLE_PROP(interconnects, "interconnects", "#interconnect-cells")
|
||||
DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells")
|
||||
DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells")
|
||||
DEFINE_SIMPLE_PROP(io_channels, "io-channel", "#io-channel-cells")
|
||||
DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
|
||||
|
||||
static const struct supplier_bindings of_supplier_bindings[] = {
|
||||
{ .parse_prop = parse_clocks, },
|
||||
{ .parse_prop = parse_interconnects, },
|
||||
{ .parse_prop = parse_iommus, },
|
||||
{ .parse_prop = parse_mboxes, },
|
||||
{ .parse_prop = parse_io_channels, },
|
||||
{ .parse_prop = parse_regulators, },
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* of_link_property - Create device links to suppliers listed in a property
|
||||
* @dev: Consumer device
|
||||
* @con_np: The consumer device tree node which contains the property
|
||||
* @prop_name: Name of property to be parsed
|
||||
*
|
||||
* This function checks if the property @prop_name that is present in the
|
||||
* @con_np device tree node is one of the known common device tree bindings
|
||||
* that list phandles to suppliers. If @prop_name isn't one, this function
|
||||
* doesn't do anything.
|
||||
*
|
||||
* If @prop_name is one, this function attempts to create device links from the
|
||||
* consumer device @dev to all the devices of the suppliers listed in
|
||||
* @prop_name.
|
||||
*
|
||||
* Any failed attempt to create a device link will NOT result in an immediate
|
||||
* return. of_link_property() must create links to all the available supplier
|
||||
* devices even when attempts to create a link to one or more suppliers fail.
|
||||
*/
|
||||
static int of_link_property(struct device *dev, struct device_node *con_np,
|
||||
const char *prop_name)
|
||||
{
|
||||
struct device_node *phandle;
|
||||
const struct supplier_bindings *s = of_supplier_bindings;
|
||||
unsigned int i = 0;
|
||||
bool matched = false;
|
||||
int ret = 0;
|
||||
u32 dl_flags;
|
||||
|
||||
if (dev->of_node == con_np)
|
||||
dl_flags = DL_FLAG_AUTOPROBE_CONSUMER;
|
||||
else
|
||||
dl_flags = DL_FLAG_SYNC_STATE_ONLY;
|
||||
|
||||
/* Do not stop at first failed link, link all available suppliers. */
|
||||
while (!matched && s->parse_prop) {
|
||||
while ((phandle = s->parse_prop(con_np, prop_name, i))) {
|
||||
matched = true;
|
||||
i++;
|
||||
if (of_link_to_phandle(dev, phandle, dl_flags)
|
||||
== -EAGAIN)
|
||||
ret = -EAGAIN;
|
||||
of_node_put(phandle);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int of_link_to_suppliers(struct device *dev,
|
||||
struct device_node *con_np)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct property *p;
|
||||
int ret = 0;
|
||||
|
||||
for_each_property_of_node(con_np, p)
|
||||
if (of_link_property(dev, con_np, p->name))
|
||||
ret = -ENODEV;
|
||||
|
||||
for_each_child_of_node(con_np, child)
|
||||
if (of_link_to_suppliers(dev, child) && !ret)
|
||||
ret = -EAGAIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool of_devlink;
|
||||
core_param(of_devlink, of_devlink, bool, 0);
|
||||
|
||||
static int of_fwnode_add_links(const struct fwnode_handle *fwnode,
|
||||
struct device *dev)
|
||||
{
|
||||
if (!of_devlink)
|
||||
return 0;
|
||||
|
||||
if (unlikely(!is_of_node(fwnode)))
|
||||
return 0;
|
||||
|
||||
return of_link_to_suppliers(dev, to_of_node(fwnode));
|
||||
}
|
||||
|
||||
const struct fwnode_operations of_fwnode_ops = {
|
||||
.get = of_fwnode_get,
|
||||
.put = of_fwnode_put,
|
||||
@ -1001,5 +1298,6 @@ const struct fwnode_operations of_fwnode_ops = {
|
||||
.graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
|
||||
.graph_get_port_parent = of_fwnode_graph_get_port_parent,
|
||||
.graph_parse_endpoint = of_fwnode_graph_parse_endpoint,
|
||||
.add_links = of_fwnode_add_links,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(of_fwnode_ops);
|
||||
|
@ -54,6 +54,7 @@
|
||||
|
||||
#ifdef CONFIG_SUPERH
|
||||
#include <asm/sh_bios.h>
|
||||
#include <asm/platform_early.h>
|
||||
#endif
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
@ -3090,6 +3091,7 @@ static struct console serial_console = {
|
||||
.data = &sci_uart_driver,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SUPERH
|
||||
static struct console early_serial_console = {
|
||||
.name = "early_ttySC",
|
||||
.write = serial_console_write,
|
||||
@ -3118,6 +3120,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev)
|
||||
register_console(&early_serial_console);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SCI_CONSOLE (&serial_console)
|
||||
|
||||
@ -3318,8 +3321,10 @@ static int sci_probe(struct platform_device *dev)
|
||||
* the special early probe. We don't have sufficient device state
|
||||
* to make it beyond this yet.
|
||||
*/
|
||||
if (is_early_platform_device(dev))
|
||||
#ifdef CONFIG_SUPERH
|
||||
if (is_sh_early_platform_device(dev))
|
||||
return sci_probe_earlyprintk(dev);
|
||||
#endif
|
||||
|
||||
if (dev->dev.of_node) {
|
||||
p = sci_parse_dt(dev, &dev_id);
|
||||
@ -3414,8 +3419,8 @@ static void __exit sci_exit(void)
|
||||
uart_unregister_driver(&sci_uart_driver);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
|
||||
early_platform_init_buffer("earlyprintk", &sci_driver,
|
||||
#if defined(CONFIG_SUPERH) && defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
|
||||
sh_early_platform_init_buffer("earlyprintk", &sci_driver,
|
||||
early_serial_buf, ARRAY_SIZE(early_serial_buf));
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
|
||||
|
@ -420,20 +420,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
|
||||
* This function creates a file in debugfs with the given name that
|
||||
* contains the value of the variable @value. If the @mode variable is so
|
||||
* set, it can be read from, and written to.
|
||||
*
|
||||
* This function will return a pointer to a dentry if it succeeds. This
|
||||
* pointer must be passed to the debugfs_remove() function when the file is
|
||||
* to be removed (no automatic cleanup happens if your module is unloaded,
|
||||
* you are responsible here.) If an error occurs, %ERR_PTR(-ERROR) will be
|
||||
* returned.
|
||||
*
|
||||
* If debugfs is not enabled in the kernel, the value %ERR_PTR(-ENODEV) will
|
||||
* be returned.
|
||||
*/
|
||||
struct dentry *debugfs_create_u8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value)
|
||||
void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
|
||||
u8 *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
|
||||
&fops_u8_ro, &fops_u8_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_u8);
|
||||
@ -465,20 +456,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
|
||||
* This function creates a file in debugfs with the given name that
|
||||
* contains the value of the variable @value. If the @mode variable is so
|
||||
* set, it can be read from, and written to.
|
||||
*
|
||||
* This function will return a pointer to a dentry if it succeeds. This
|
||||
* pointer must be passed to the debugfs_remove() function when the file is
|
||||
* to be removed (no automatic cleanup happens if your module is unloaded,
|
||||
* you are responsible here.) If an error occurs, %ERR_PTR(-ERROR) will be
|
||||
* returned.
|
||||
*
|
||||
* If debugfs is not enabled in the kernel, the value %ERR_PTR(-ENODEV) will
|
||||
* be returned.
|
||||
*/
|
||||
struct dentry *debugfs_create_u16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value)
|
||||
void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent,
|
||||
u16 *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
|
||||
&fops_u16_ro, &fops_u16_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_u16);
|
||||
@ -556,20 +538,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
|
||||
* This function creates a file in debugfs with the given name that
|
||||
* contains the value of the variable @value. If the @mode variable is so
|
||||
* set, it can be read from, and written to.
|
||||
*
|
||||
* This function will return a pointer to a dentry if it succeeds. This
|
||||
* pointer must be passed to the debugfs_remove() function when the file is
|
||||
* to be removed (no automatic cleanup happens if your module is unloaded,
|
||||
* you are responsible here.) If an error occurs, %ERR_PTR(-ERROR) will be
|
||||
* returned.
|
||||
*
|
||||
* If debugfs is not enabled in the kernel, the value %ERR_PTR(-ENODEV) will
|
||||
* be returned.
|
||||
*/
|
||||
struct dentry *debugfs_create_u64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value)
|
||||
void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent,
|
||||
u64 *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
|
||||
&fops_u64_ro, &fops_u64_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_u64);
|
||||
@ -660,10 +633,10 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
|
||||
* @value: a pointer to the variable that the file should read to and write
|
||||
* from.
|
||||
*/
|
||||
struct dentry *debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value)
|
||||
void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
|
||||
u8 *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
|
||||
&fops_x8_ro, &fops_x8_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_x8);
|
||||
@ -678,10 +651,10 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8);
|
||||
* @value: a pointer to the variable that the file should read to and write
|
||||
* from.
|
||||
*/
|
||||
struct dentry *debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value)
|
||||
void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent,
|
||||
u16 *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
|
||||
&fops_x16_ro, &fops_x16_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_x16);
|
||||
@ -696,10 +669,10 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16);
|
||||
* @value: a pointer to the variable that the file should read to and write
|
||||
* from.
|
||||
*/
|
||||
struct dentry *debugfs_create_x32(const char *name, umode_t mode,
|
||||
struct dentry *parent, u32 *value)
|
||||
void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent,
|
||||
u32 *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
|
||||
&fops_x32_ro, &fops_x32_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_x32);
|
||||
@ -714,10 +687,10 @@ EXPORT_SYMBOL_GPL(debugfs_create_x32);
|
||||
* @value: a pointer to the variable that the file should read to and write
|
||||
* from.
|
||||
*/
|
||||
struct dentry *debugfs_create_x64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value)
|
||||
void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent,
|
||||
u64 *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
|
||||
&fops_x64_ro, &fops_x64_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_x64);
|
||||
@ -748,12 +721,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n");
|
||||
* @value: a pointer to the variable that the file should read to and write
|
||||
* from.
|
||||
*/
|
||||
struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, size_t *value)
|
||||
void debugfs_create_size_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, size_t *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value,
|
||||
&fops_size_t, &fops_size_t_ro,
|
||||
&fops_size_t_wo);
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_size_t,
|
||||
&fops_size_t_ro, &fops_size_t_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_size_t);
|
||||
|
||||
@ -785,12 +757,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set,
|
||||
* @value: a pointer to the variable that the file should read to and write
|
||||
* from.
|
||||
*/
|
||||
struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, atomic_t *value)
|
||||
void debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, atomic_t *value)
|
||||
{
|
||||
return debugfs_create_mode_unsafe(name, mode, parent, value,
|
||||
&fops_atomic_t, &fops_atomic_t_ro,
|
||||
&fops_atomic_t_wo);
|
||||
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
|
||||
&fops_atomic_t_ro, &fops_atomic_t_wo);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_atomic_t);
|
||||
|
||||
|
@ -97,28 +97,28 @@ ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
|
||||
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
||||
struct dentry *new_dir, const char *new_name);
|
||||
|
||||
struct dentry *debugfs_create_u8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value);
|
||||
struct dentry *debugfs_create_u16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value);
|
||||
void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
|
||||
u8 *value);
|
||||
void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent,
|
||||
u16 *value);
|
||||
struct dentry *debugfs_create_u32(const char *name, umode_t mode,
|
||||
struct dentry *parent, u32 *value);
|
||||
struct dentry *debugfs_create_u64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value);
|
||||
void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent,
|
||||
u64 *value);
|
||||
struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
|
||||
struct dentry *parent, unsigned long *value);
|
||||
struct dentry *debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value);
|
||||
struct dentry *debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value);
|
||||
struct dentry *debugfs_create_x32(const char *name, umode_t mode,
|
||||
struct dentry *parent, u32 *value);
|
||||
struct dentry *debugfs_create_x64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value);
|
||||
struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, size_t *value);
|
||||
struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, atomic_t *value);
|
||||
void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
|
||||
u8 *value);
|
||||
void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent,
|
||||
u16 *value);
|
||||
void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent,
|
||||
u32 *value);
|
||||
void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent,
|
||||
u64 *value);
|
||||
void debugfs_create_size_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, size_t *value);
|
||||
void debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, atomic_t *value);
|
||||
struct dentry *debugfs_create_bool(const char *name, umode_t mode,
|
||||
struct dentry *parent, bool *value);
|
||||
|
||||
@ -244,19 +244,11 @@ static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentr
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct dentry *debugfs_create_u8(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u8 *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_u8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value) { }
|
||||
|
||||
static inline struct dentry *debugfs_create_u16(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u16 *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_u16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value) { }
|
||||
|
||||
static inline struct dentry *debugfs_create_u32(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
@ -265,12 +257,8 @@ static inline struct dentry *debugfs_create_u32(const char *name, umode_t mode,
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct dentry *debugfs_create_u64(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u64 *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_u64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value) { }
|
||||
|
||||
static inline struct dentry *debugfs_create_ulong(const char *name,
|
||||
umode_t mode,
|
||||
@ -280,46 +268,26 @@ static inline struct dentry *debugfs_create_ulong(const char *name,
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct dentry *debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u8 *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value) { }
|
||||
|
||||
static inline struct dentry *debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u16 *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value) { }
|
||||
|
||||
static inline struct dentry *debugfs_create_x32(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u32 *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_x32(const char *name, umode_t mode,
|
||||
struct dentry *parent, u32 *value) { }
|
||||
|
||||
static inline struct dentry *debugfs_create_x64(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u64 *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_x64(const char *name, umode_t mode,
|
||||
struct dentry *parent, u64 *value) { }
|
||||
|
||||
static inline struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
size_t *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_size_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, size_t *value)
|
||||
{ }
|
||||
|
||||
static inline struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent, atomic_t *value)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void debugfs_create_atomic_t(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
atomic_t *value)
|
||||
{ }
|
||||
|
||||
static inline struct dentry *debugfs_create_bool(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
@ -383,4 +351,25 @@ static inline ssize_t debugfs_write_file_bool(struct file *file,
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* debugfs_create_xul - create a debugfs file that is used to read and write an
|
||||
* unsigned long value, formatted in hexadecimal
|
||||
* @name: a pointer to a string containing the name of the file to create.
|
||||
* @mode: the permission that the file should have
|
||||
* @parent: a pointer to the parent dentry for this file. This should be a
|
||||
* directory dentry if set. If this parameter is %NULL, then the
|
||||
* file will be created in the root of the debugfs filesystem.
|
||||
* @value: a pointer to the variable that the file should read to and write
|
||||
* from.
|
||||
*/
|
||||
static inline void debugfs_create_xul(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
unsigned long *value)
|
||||
{
|
||||
if (sizeof(*value) == sizeof(u32))
|
||||
debugfs_create_x32(name, mode, parent, (u32 *)value);
|
||||
else
|
||||
debugfs_create_x64(name, mode, parent, (u64 *)value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -80,6 +80,13 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
|
||||
* that generate uevents to add the environment variables.
|
||||
* @probe: Called when a new device or driver add to this bus, and callback
|
||||
* the specific driver's probe to initial the matched device.
|
||||
* @sync_state: Called to sync device state to software state after all the
|
||||
* state tracking consumers linked to this device (present at
|
||||
* the time of late_initcall) have successfully bound to a
|
||||
* driver. If the device has no consumers, this function will
|
||||
* be called at late_initcall_sync level. If the device has
|
||||
* consumers that are never bound to a driver, this function
|
||||
* will never get called until they do.
|
||||
* @remove: Called when a device removed from this bus.
|
||||
* @shutdown: Called at shut-down time to quiesce the device.
|
||||
*
|
||||
@ -123,6 +130,7 @@ struct bus_type {
|
||||
int (*match)(struct device *dev, struct device_driver *drv);
|
||||
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
|
||||
int (*probe)(struct device *dev);
|
||||
void (*sync_state)(struct device *dev);
|
||||
int (*remove)(struct device *dev);
|
||||
void (*shutdown)(struct device *dev);
|
||||
|
||||
@ -340,6 +348,13 @@ enum probe_type {
|
||||
* @probe: Called to query the existence of a specific device,
|
||||
* whether this driver can work with it, and bind the driver
|
||||
* to a specific device.
|
||||
* @sync_state: Called to sync device state to software state after all the
|
||||
* state tracking consumers linked to this device (present at
|
||||
* the time of late_initcall) have successfully bound to a
|
||||
* driver. If the device has no consumers, this function will
|
||||
* be called at late_initcall_sync level. If the device has
|
||||
* consumers that are never bound to a driver, this function
|
||||
* will never get called until they do.
|
||||
* @remove: Called when the device is removed from the system to
|
||||
* unbind a device from this driver.
|
||||
* @shutdown: Called at shut-down time to quiesce the device.
|
||||
@ -379,6 +394,7 @@ struct device_driver {
|
||||
const struct acpi_device_id *acpi_match_table;
|
||||
|
||||
int (*probe) (struct device *dev);
|
||||
void (*sync_state)(struct device *dev);
|
||||
int (*remove) (struct device *dev);
|
||||
void (*shutdown) (struct device *dev);
|
||||
int (*suspend) (struct device *dev, pm_message_t state);
|
||||
@ -946,6 +962,8 @@ extern void devm_free_pages(struct device *dev, unsigned long addr);
|
||||
|
||||
void __iomem *devm_ioremap_resource(struct device *dev,
|
||||
const struct resource *res);
|
||||
void __iomem *devm_ioremap_resource_wc(struct device *dev,
|
||||
const struct resource *res);
|
||||
|
||||
void __iomem *devm_of_iomap(struct device *dev,
|
||||
struct device_node *node, int index,
|
||||
@ -1080,6 +1098,7 @@ enum device_link_state {
|
||||
* AUTOREMOVE_SUPPLIER: Remove the link automatically on supplier driver unbind.
|
||||
* AUTOPROBE_CONSUMER: Probe consumer driver automatically after supplier binds.
|
||||
* MANAGED: The core tracks presence of supplier/consumer drivers (internal).
|
||||
* SYNC_STATE_ONLY: Link only affects sync_state() behavior.
|
||||
*/
|
||||
#define DL_FLAG_STATELESS BIT(0)
|
||||
#define DL_FLAG_AUTOREMOVE_CONSUMER BIT(1)
|
||||
@ -1088,6 +1107,7 @@ enum device_link_state {
|
||||
#define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4)
|
||||
#define DL_FLAG_AUTOPROBE_CONSUMER BIT(5)
|
||||
#define DL_FLAG_MANAGED BIT(6)
|
||||
#define DL_FLAG_SYNC_STATE_ONLY BIT(7)
|
||||
|
||||
/**
|
||||
* struct device_link - Device link representation.
|
||||
@ -1135,11 +1155,18 @@ enum dl_dev_state {
|
||||
* struct dev_links_info - Device data related to device links.
|
||||
* @suppliers: List of links to supplier devices.
|
||||
* @consumers: List of links to consumer devices.
|
||||
* @needs_suppliers: Hook to global list of devices waiting for suppliers.
|
||||
* @defer_sync: Hook to global list of devices that have deferred sync_state.
|
||||
* @need_for_probe: If needs_suppliers is on a list, this indicates if the
|
||||
* suppliers are needed for probe or not.
|
||||
* @status: Driver status information.
|
||||
*/
|
||||
struct dev_links_info {
|
||||
struct list_head suppliers;
|
||||
struct list_head consumers;
|
||||
struct list_head needs_suppliers;
|
||||
struct list_head defer_sync;
|
||||
bool need_for_probe;
|
||||
enum dl_dev_state status;
|
||||
};
|
||||
|
||||
@ -1215,6 +1242,9 @@ struct dev_links_info {
|
||||
* @offline: Set after successful invocation of bus type's .offline().
|
||||
* @of_node_reused: Set if the device-tree node is shared with an ancestor
|
||||
* device.
|
||||
* @state_synced: The hardware state of this device has been synced to match
|
||||
* the software state of this device by calling the driver/bus
|
||||
* sync_state() callback.
|
||||
* @dma_coherent: this particular device is dma coherent, even if the
|
||||
* architecture supports non-coherent devices.
|
||||
*
|
||||
@ -1311,6 +1341,7 @@ struct device {
|
||||
bool offline_disabled:1;
|
||||
bool offline:1;
|
||||
bool of_node_reused:1;
|
||||
bool state_synced:1;
|
||||
#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \
|
||||
defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \
|
||||
defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL)
|
||||
@ -1653,6 +1684,8 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
struct device *supplier, u32 flags);
|
||||
void device_link_del(struct device_link *link);
|
||||
void device_link_remove(void *consumer, struct device *supplier);
|
||||
void device_links_supplier_sync_state_pause(void);
|
||||
void device_links_supplier_sync_state_resume(void);
|
||||
|
||||
#ifndef dev_fmt
|
||||
#define dev_fmt(fmt) fmt
|
||||
|
@ -17,6 +17,7 @@ struct device;
|
||||
struct fwnode_handle {
|
||||
struct fwnode_handle *secondary;
|
||||
const struct fwnode_operations *ops;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -65,6 +66,43 @@ struct fwnode_reference_args {
|
||||
* endpoint node.
|
||||
* @graph_get_port_parent: Return the parent node of a port node.
|
||||
* @graph_parse_endpoint: Parse endpoint for port and endpoint id.
|
||||
* @add_links: Called after the device corresponding to the fwnode is added
|
||||
* using device_add(). The function is expected to create device
|
||||
* links to all the suppliers of the device that are available at
|
||||
* the time this function is called. The function must NOT stop
|
||||
* at the first failed device link if other unlinked supplier
|
||||
* devices are present in the system. This is necessary for the
|
||||
* driver/bus sync_state() callbacks to work correctly.
|
||||
*
|
||||
* For example, say Device-C depends on suppliers Device-S1 and
|
||||
* Device-S2 and the dependency is listed in that order in the
|
||||
* firmware. Say, S1 gets populated from the firmware after
|
||||
* late_initcall_sync(). Say S2 is populated and probed way
|
||||
* before that in device_initcall(). When C is populated, if this
|
||||
* add_links() function doesn't continue past a "failed linking to
|
||||
* S1" and continue linking C to S2, then S2 will get a
|
||||
* sync_state() callback before C is probed. This is because from
|
||||
* the perspective of S2, C was never a consumer when its
|
||||
* sync_state() evaluation is done. To avoid this, the add_links()
|
||||
* function has to go through all available suppliers of the
|
||||
* device (that corresponds to this fwnode) and link to them
|
||||
* before returning.
|
||||
*
|
||||
* If some suppliers are not yet available (indicated by an error
|
||||
* return value), this function will be called again when other
|
||||
* devices are added to allow creating device links to any newly
|
||||
* available suppliers.
|
||||
*
|
||||
* Return 0 if device links have been successfully created to all
|
||||
* the suppliers this device needs to create device links to or if
|
||||
* the supplier information is not known.
|
||||
*
|
||||
* Return -ENODEV if and only if the suppliers needed for probing
|
||||
* the device are not yet available to create device links to.
|
||||
*
|
||||
* Return -EAGAIN if there are suppliers that need to be linked to
|
||||
* that are not yet available but none of those suppliers are
|
||||
* necessary for probing this device.
|
||||
*/
|
||||
struct fwnode_operations {
|
||||
struct fwnode_handle *(*get)(struct fwnode_handle *fwnode);
|
||||
@ -102,6 +140,8 @@ struct fwnode_operations {
|
||||
(*graph_get_port_parent)(struct fwnode_handle *fwnode);
|
||||
int (*graph_parse_endpoint)(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_endpoint *endpoint);
|
||||
int (*add_links)(const struct fwnode_handle *fwnode,
|
||||
struct device *dev);
|
||||
};
|
||||
|
||||
#define fwnode_has_op(fwnode, op) \
|
||||
@ -123,5 +163,6 @@ struct fwnode_operations {
|
||||
if (fwnode_has_op(fwnode, op)) \
|
||||
(fwnode)->ops->op(fwnode, ## __VA_ARGS__); \
|
||||
} while (false)
|
||||
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
|
||||
|
||||
#endif
|
||||
|
@ -57,6 +57,12 @@ platform_find_device_by_driver(struct device *start,
|
||||
extern void __iomem *
|
||||
devm_platform_ioremap_resource(struct platform_device *pdev,
|
||||
unsigned int index);
|
||||
extern void __iomem *
|
||||
devm_platform_ioremap_resource_wc(struct platform_device *pdev,
|
||||
unsigned int index);
|
||||
extern void __iomem *
|
||||
devm_platform_ioremap_resource_byname(struct platform_device *pdev,
|
||||
const char *name);
|
||||
extern int platform_get_irq(struct platform_device *, unsigned int);
|
||||
extern int platform_get_irq_optional(struct platform_device *, unsigned int);
|
||||
extern int platform_irq_count(struct platform_device *);
|
||||
@ -294,58 +300,6 @@ void platform_unregister_drivers(struct platform_driver * const *drivers,
|
||||
#define platform_register_drivers(drivers, count) \
|
||||
__platform_register_drivers(drivers, count, THIS_MODULE)
|
||||
|
||||
/* early platform driver interface */
|
||||
struct early_platform_driver {
|
||||
const char *class_str;
|
||||
struct platform_driver *pdrv;
|
||||
struct list_head list;
|
||||
int requested_id;
|
||||
char *buffer;
|
||||
int bufsize;
|
||||
};
|
||||
|
||||
#define EARLY_PLATFORM_ID_UNSET -2
|
||||
#define EARLY_PLATFORM_ID_ERROR -3
|
||||
|
||||
extern int early_platform_driver_register(struct early_platform_driver *epdrv,
|
||||
char *buf);
|
||||
extern void early_platform_add_devices(struct platform_device **devs, int num);
|
||||
|
||||
static inline int is_early_platform_device(struct platform_device *pdev)
|
||||
{
|
||||
return !pdev->dev.driver;
|
||||
}
|
||||
|
||||
extern void early_platform_driver_register_all(char *class_str);
|
||||
extern int early_platform_driver_probe(char *class_str,
|
||||
int nr_probe, int user_only);
|
||||
extern void early_platform_cleanup(void);
|
||||
|
||||
#define early_platform_init(class_string, platdrv) \
|
||||
early_platform_init_buffer(class_string, platdrv, NULL, 0)
|
||||
|
||||
#ifndef MODULE
|
||||
#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
|
||||
static __initdata struct early_platform_driver early_driver = { \
|
||||
.class_str = class_string, \
|
||||
.buffer = buf, \
|
||||
.bufsize = bufsiz, \
|
||||
.pdrv = platdrv, \
|
||||
.requested_id = EARLY_PLATFORM_ID_UNSET, \
|
||||
}; \
|
||||
static int __init early_platform_driver_setup_func(char *buffer) \
|
||||
{ \
|
||||
return early_platform_driver_register(&early_driver, buffer); \
|
||||
} \
|
||||
early_param(class_string, early_platform_driver_setup_func)
|
||||
#else /* MODULE */
|
||||
#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
|
||||
static inline char *early_platform_driver_setup_func(void) \
|
||||
{ \
|
||||
return bufsiz ? buf : NULL; \
|
||||
}
|
||||
#endif /* MODULE */
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
extern int platform_pm_suspend(struct device *dev);
|
||||
extern int platform_pm_resume(struct device *dev);
|
||||
@ -380,4 +334,16 @@ extern int platform_dma_configure(struct device *dev);
|
||||
#define USE_PLATFORM_PM_SLEEP_OPS
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SUPERH
|
||||
/*
|
||||
* REVISIT: This stub is needed for all non-SuperH users of early platform
|
||||
* drivers. It should go away once we introduce the new platform_device-based
|
||||
* early driver framework.
|
||||
*/
|
||||
static inline int is_sh_early_platform_device(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SUPERH */
|
||||
|
||||
#endif /* _PLATFORM_DEVICE_H_ */
|
||||
|
@ -15,6 +15,7 @@ struct soc_device_attribute {
|
||||
const char *serial_number;
|
||||
const char *soc_id;
|
||||
const void *data;
|
||||
const struct attribute_group *custom_attr_group;
|
||||
};
|
||||
|
||||
/**
|
||||
|
72
lib/devres.c
72
lib/devres.c
@ -114,6 +114,37 @@ void devm_iounmap(struct device *dev, void __iomem *addr)
|
||||
}
|
||||
EXPORT_SYMBOL(devm_iounmap);
|
||||
|
||||
static void __iomem *
|
||||
__devm_ioremap_resource(struct device *dev, const struct resource *res,
|
||||
enum devm_ioremap_type type)
|
||||
{
|
||||
resource_size_t size;
|
||||
void __iomem *dest_ptr;
|
||||
|
||||
BUG_ON(!dev);
|
||||
|
||||
if (!res || resource_type(res) != IORESOURCE_MEM) {
|
||||
dev_err(dev, "invalid resource\n");
|
||||
return IOMEM_ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
size = resource_size(res);
|
||||
|
||||
if (!devm_request_mem_region(dev, res->start, size, dev_name(dev))) {
|
||||
dev_err(dev, "can't request region for resource %pR\n", res);
|
||||
return IOMEM_ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
dest_ptr = __devm_ioremap(dev, res->start, size, type);
|
||||
if (!dest_ptr) {
|
||||
dev_err(dev, "ioremap failed for resource %pR\n", res);
|
||||
devm_release_mem_region(dev, res->start, size);
|
||||
dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return dest_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_ioremap_resource() - check, request region, and ioremap resource
|
||||
* @dev: generic device to handle the resource for
|
||||
@ -134,34 +165,25 @@ EXPORT_SYMBOL(devm_iounmap);
|
||||
void __iomem *devm_ioremap_resource(struct device *dev,
|
||||
const struct resource *res)
|
||||
{
|
||||
resource_size_t size;
|
||||
void __iomem *dest_ptr;
|
||||
|
||||
BUG_ON(!dev);
|
||||
|
||||
if (!res || resource_type(res) != IORESOURCE_MEM) {
|
||||
dev_err(dev, "invalid resource\n");
|
||||
return IOMEM_ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
size = resource_size(res);
|
||||
|
||||
if (!devm_request_mem_region(dev, res->start, size, dev_name(dev))) {
|
||||
dev_err(dev, "can't request region for resource %pR\n", res);
|
||||
return IOMEM_ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
dest_ptr = devm_ioremap(dev, res->start, size);
|
||||
if (!dest_ptr) {
|
||||
dev_err(dev, "ioremap failed for resource %pR\n", res);
|
||||
devm_release_mem_region(dev, res->start, size);
|
||||
dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return dest_ptr;
|
||||
return __devm_ioremap_resource(dev, res, DEVM_IOREMAP);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_ioremap_resource);
|
||||
|
||||
/**
|
||||
* devm_ioremap_resource_wc() - write-combined variant of
|
||||
* devm_ioremap_resource()
|
||||
* @dev: generic device to handle the resource for
|
||||
* @res: resource to be handled
|
||||
*
|
||||
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
|
||||
* on failure. Usage example:
|
||||
*/
|
||||
void __iomem *devm_ioremap_resource_wc(struct device *dev,
|
||||
const struct resource *res)
|
||||
{
|
||||
return __devm_ioremap_resource(dev, res, DEVM_IOREMAP_WC);
|
||||
}
|
||||
|
||||
/*
|
||||
* devm_of_iomap - Requests a resource and maps the memory mapped IO
|
||||
* for a given device_node managed by a given device
|
||||
|
@ -928,12 +928,7 @@ STA_OPS(he_capa);
|
||||
sta->debugfs_dir, sta, &sta_ ##name## _ops);
|
||||
|
||||
#define DEBUGFS_ADD_COUNTER(name, field) \
|
||||
if (sizeof(sta->field) == sizeof(u32)) \
|
||||
debugfs_create_u32(#name, 0400, sta->debugfs_dir, \
|
||||
(u32 *) &sta->field); \
|
||||
else \
|
||||
debugfs_create_u64(#name, 0400, sta->debugfs_dir, \
|
||||
(u64 *) &sta->field);
|
||||
debugfs_create_ulong(#name, 0400, sta->debugfs_dir, &sta->field);
|
||||
|
||||
void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
||||
{
|
||||
@ -978,14 +973,8 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
||||
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
DEBUGFS_ADD(airtime);
|
||||
|
||||
if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
|
||||
debugfs_create_x32("driver_buffered_tids", 0400,
|
||||
sta->debugfs_dir,
|
||||
(u32 *)&sta->driver_buffered_tids);
|
||||
else
|
||||
debugfs_create_x64("driver_buffered_tids", 0400,
|
||||
sta->debugfs_dir,
|
||||
(u64 *)&sta->driver_buffered_tids);
|
||||
debugfs_create_xul("driver_buffered_tids", 0400, sta->debugfs_dir,
|
||||
&sta->driver_buffered_tids);
|
||||
|
||||
drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs_dir);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user