Merge tag 'driver-core-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 27 Nov 2019 19:06:20 +0000 (11:06 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 27 Nov 2019 19:06:20 +0000 (11:06 -0800)
Pull driver core updates from Greg KH:
 "Here is the "big" set of driver core patches for 5.5-rc1

  There's a few minor cleanups and fixes in here, but the majority of
  the patches in here fall into two buckets:

   - debugfs api cleanups and fixes

   - driver core device link support for boot dependancy issues

  The debugfs api cleanups are working to slowly refactor the debugfs
  apis so that it is even harder to use incorrectly. That work has been
  happening for the past few kernel releases and will continue over
  time, it's a long-term project/goal

  The driver core device link support missed 5.4 by just a bit, so it's
  been sitting and baking for many months now. It's from Saravana Kannan
  to help resolve the problems that DT-based systems have at boot time
  with dependancy graphs and kernel modules. Turns out that no one has
  actually tried to build a generic arm64 kernel with loads of modules
  and have it "just work" for a variety of platforms (like a distro
  kernel). The big problem turned out to be a lack of dependency
  information between different areas of DT entries, and the work here
  resolves that problem and now allows devices to boot properly, and
  quicker than a monolith kernel.

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

* tag 'driver-core-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (68 commits)
  tracing: Remove unnecessary DEBUG_FS dependency
  of: property: Add device link support for interrupt-parent, dmas and -gpio(s)
  debugfs: Fix !DEBUG_FS debugfs_create_automount
  of: property: Add device link support for "iommu-map"
  of: property: Fix the semantics of of_is_ancestor_of()
  i2c: of: Populate fwnode in of_i2c_get_board_info()
  drivers: base: Fix Kconfig indentation
  firmware_loader: Fix labels with comma for builtin firmware
  driver core: Allow device link operations inside sync_state()
  driver core: platform: Declare ret variable only once
  cpu-topology: declare parse_acpi_topology in <linux/arch_topology.h>
  crypto: hisilicon: no need to check return value of debugfs_create functions
  driver core: platform: use the correct callback type for bus_find_device
  firmware_class: make firmware caching configurable
  driver core: Clarify documentation for fwnode_operations.add_links()
  mailbox: tegra: Fix superfluous IRQ error message
  net: caif: Fix debugfs on 64-bit platforms
  mac80211: Use debugfs_create_xul() helper
  media: c8sectpfe: no need to check return value of debugfs_create functions
  of: property: Add device link support for iommus, mboxes and io-channels
  ...

77 files changed:
Documentation/admin-guide/kernel-parameters.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/driver-api/device_link.rst
Documentation/driver-api/driver-model/devres.rst
Documentation/driver-api/driver-model/driver.rst
Documentation/filesystems/debugfs.txt
arch/powerpc/platforms/pseries/dtl.c
arch/powerpc/platforms/pseries/hvCall_inst.c
arch/powerpc/platforms/pseries/lpar.c
arch/sh/drivers/Makefile
arch/sh/drivers/platform_early.c [new file with mode: 0644]
arch/sh/include/asm/platform_early.h [new file with mode: 0644]
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-mxg.c
arch/sh/kernel/cpu/sh2a/setup-sh7201.c
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh2a/setup-sh7264.c
arch/sh/kernel/cpu/sh2a/setup-sh7269.c
arch/sh/kernel/cpu/sh3/setup-sh3.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/setup-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7734.c
arch/sh/kernel/cpu/sh4a/setup-sh7757.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7770.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpu/sh5/setup-sh5.c
arch/sh/kernel/setup.c
arch/sh/kernel/time.c
drivers/base/core.c
drivers/base/firmware_loader/Kconfig
drivers/base/firmware_loader/builtin/Makefile
drivers/base/firmware_loader/main.c
drivers/base/platform.c
drivers/base/soc.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-tegra186.c
drivers/i2c/i2c-core-of.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/mailbox/tegra-hsp.c
drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.c
drivers/misc/sram.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/dw_mmc.c
drivers/net/caif/caif_serial.c
drivers/ntb/test/ntb_pingpong.c
drivers/of/platform.c
drivers/of/property.c
drivers/tty/serial/sh-sci.c
fs/debugfs/file.c
include/linux/arch_topology.h
include/linux/debugfs.h
include/linux/device.h
include/linux/fwnode.h
include/linux/platform_device.h
include/linux/sys_soc.h
kernel/trace/Kconfig
lib/devres.c
net/mac80211/debugfs_sta.c

index d05d531b4ec9f3f4288845cc3e84296b009b1942..6d421694d98e9e2f528877949fc2ca1e40802650 100644 (file)
@@ -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.
index 1fda057434c3d0e3fcfb63def9da6e5f84146037..b25b47a47acd89a0303ff64e5fa6fa6d052e8ff4 100644 (file)
                        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.
index 1b5020ec6517b06ae01e0f57db976bc41ce81d5b..bc2d89af88ce2da221cfac37dee585dd4c11ca42 100644 (file)
@@ -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()`.)
index a100bef5495284d93ee487a7b2ad44985869497d..4ab193319d8c60bcea4ed41d29587ca32fc9fabe 100644 (file)
@@ -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
index 11d281506a0415219e945c49684b2977ea873d7e..baa6a85c82871b40f9aa43bd505efc89febedeb2 100644 (file)
@@ -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
index 9e27c843d00ea0602e391f760c05764066a544c0..dc497b96fa4ff54dc6b84cbf2951391a369473c0 100644 (file)
@@ -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.
index 2b87480f2837ae3241cd2acacd50f31ce5461bcb..eab8aa293743b421fba23cb266a2843d7e489033 100644 (file)
@@ -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);
index bcc1b67417a84b066d65ac9e37a851acf893e10d..c40c62ec432e277f4cfebcf979ce2d4fc9881ac4 100644 (file)
@@ -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;
index f87a5c64e24dcf534de83255baf8d7bbd441433f..f9f57c55655ecf1f12d8f9f6d46953ce7d365d6b 100644 (file)
@@ -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;
index 3e93b434e6048edea4e27c3c2577ffeb30c22667..56b0acace6e7c81092ba615d24d60ba50b95f162 100644 (file)
@@ -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/
diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c
new file mode 100644 (file)
index 0000000..f6d1484
--- /dev/null
@@ -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);
diff --git a/arch/sh/include/asm/platform_early.h b/arch/sh/include/asm/platform_early.h
new file mode 100644 (file)
index 0000000..fc80213
--- /dev/null
@@ -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__ */
index f5b6841ef7e1cd3783918e216b3c4b7471024157..b1c877b6a4207fefe73b02516fd87d03d7664c5e 100644 (file)
@@ -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));
 }
index 52350ad0b0a26a23e7158485bc6b63f0f6d93da6..cefa07924c16dbedf2737c06b641b6af0a22b43e 100644 (file)
@@ -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));
 }
index b51ed761ae087977e4bb4d3721636d830f67542f..28f1bebf340565db791824a7f0ae4d748f6e8d06 100644 (file)
@@ -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));
 }
index 89b3e49fc2503673e5d5cf81ca82c4c6a1a9dcd2..4839f3aaeb4c21542dd1aa5beae7c0e444d7da6d 100644 (file)
@@ -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));
 }
index 36ff3a3139dabe1e98be6d60e32b0e56a1623d14..68add5af4cc56e3f5d1bfcebf14f660226fbe121 100644 (file)
@@ -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));
 }
index d199618d877c070b2a4176d32027ea96a12f330a..8a1cb613dd2e0478517c07e164f9431cefd16cce 100644 (file)
@@ -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));
 }
index 9095c960b4558d90c9037c1a5849412d531c9519..8b1ef3028320c75b67aff32bc96ae9553b23c2ae 100644 (file)
@@ -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));
 }
index 8058c01cf09dfd187d8b29ed48eb241cd6739836..cf2a3f09fee44348a09795239af82707757792f7 100644 (file)
@@ -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) */
 
index e19d1ce7b6ad1f09730f0a676b55c9c8c6e76ba6..0544134b3f20c631514377700ef48bda2c7117b4 100644 (file)
@@ -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));
 }
 
index 5c5144bee6bcc7ced870ccd785042b7c534eb224..4947f57748bc123208183eb778e9366cbaf70c60 100644 (file)
@@ -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));
 }
 
index 4776e2495738fde54720a9cbd5508672f727f7fa..3819107615794b085031d7e4bf93218c3a400fc2 100644 (file)
@@ -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));
 }
 
index 1d4c34e7b7db98ced3eafe368c3ff87dc1689ede..425d067dae9bafc327367c9bf20c8c308ec1e067 100644 (file)
@@ -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));
 }
 
index a40ef35d101a9cb232ef69990aa1a1a329371e3b..e6737f3d0df25267e1c8daa3e63af39c85831ac0 100644 (file)
@@ -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));
 }
 
index b37bda66a532e8ddff486941114793db29bb62fa..19c8f1d69071c37ed036939c1b2c36a62631d496 100644 (file)
@@ -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));
 }
 
index 86845da859979da93e64c6e3da51b43f91fd7390..14212f5d803cd44a56a73f4af060bb9610a28c0d 100644 (file)
@@ -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));
 }
 
index a15e25690b5f96a3a78e3dead849228e5eafac77..b6015188fab1f1b58a11101c8b73c8567c11f5db 100644 (file)
@@ -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));
 }
 
index 7bd2776441ba0981701dbb2b97122fa9ed32ff93..6676beef053e59e29db75eb58c23c1cb4fb1d133 100644 (file)
@@ -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));
 }
 
index 1ce65f88f060e7350041dba893388a3d8eef05e2..0c6757ef63f42c4db50276c23ab551f61a7677ab 100644 (file)
@@ -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));
 }
 
index edb6499506625a74e2b52b7efc233653d08047d6..83ae1ad4a86e86b710cf5872d9fd68693f41557c 100644 (file)
@@ -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));
 }
 
index 3e9825031d3d76801a73f26b7675740743f2561d..0d990ab1ba2a9ed743e0fa9fa1d627352e141312 100644 (file)
@@ -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));
 }
 
index 06a91569697a7c697a2a6f4d92b6bf749690efb9..9911da794358d0b5b000c59439979e01ad9df638 100644 (file)
@@ -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));
 }
 
index 2501ce656511b061bbe843831e31a7d77a955641..67e330b7ea4621e98ea5d7c11cea9fc260d82530 100644 (file)
@@ -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));
 }
 
index 419c5efe4a17fee24308ff77df5707bedeff6fe3..b0608664785f5016e8990e7b614e287eb42bf123 100644 (file)
@@ -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));
 }
 
index 5fb4cf9b58c691110ad41bff5dcc55f53e6e00e1..5efec6ceb04d5cc9e4f28dcd2f977b9b1f5181d8 100644 (file)
@@ -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));
 }
 
index ab7d6b715865b54c07052660dfb960b4455bf832..c818b788ecb05a54f454a8ef6db86dd0ca50d48d 100644 (file)
@@ -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));
 }
 
index a438da47285d6ceea28a5ff3c6609e2c93eb3e98..3b4a414d60a91c733eeaced87349cade611687d4 100644 (file)
@@ -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));
 }
 
index d894165a0ef6fb8ed16a94bd437501381e4b5ae9..4b0db8259e3d708205c6bdd2fde413a4c3a04608 100644 (file)
@@ -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));
 }
index 14aa4552bc45b5f75753f8aa2445f7795cd92467..7014d6d199b3e64a67f6444c81bf75a9d2db921d 100644 (file)
@@ -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));
 }
 
index 41c1673afc0b4301a6e4b56b4530c01411fe614d..dc8476d67244069e8b6088b4bdf95a41ff96a2c8 100644 (file)
@@ -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));
 }
index 6ef341f6cfee9ce1aa91349b9f54a5d4f555204e..d232cfa01877efd615fb5f2c1c7f950cb783787c 100644 (file)
@@ -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
index e16b2cd269a331f911a02a35de7170e67922a382..821a09cbd6054f6d089d6f3062531b7325a7135d 100644 (file)
@@ -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)
index 7bd9cd366d41193638c858076755eec4ab1c67e6..42a67245643234a8fb23614feb1d7a5f60f7c0c9 100644 (file)
@@ -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,128 @@ int device_links_check_suppliers(struct device *dev)
        return ret;
 }
 
+/**
+ * __device_links_queue_sync_state - Queue a device for sync_state() callback
+ * @dev: Device to call sync_state() on
+ * @list: List head to queue the @dev on
+ *
+ * Queues a device for a sync_state() callback when the device links write lock
+ * isn't held. This allows the sync_state() execution flow to use device links
+ * APIs.  The caller must ensure this function is called with
+ * device_links_write_lock() held.
+ *
+ * This function does a get_device() to make sure the device is not freed while
+ * on this list.
+ *
+ * So the caller must also ensure that device_links_flush_sync_list() is called
+ * as soon as the caller releases device_links_write_lock().  This is necessary
+ * to make sure the sync_state() is called in a timely fashion and the
+ * put_device() is called on this device.
+ */
+static void __device_links_queue_sync_state(struct device *dev,
+                                           struct list_head *list)
+{
+       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;
+       }
+
+       /*
+        * Set the flag here to avoid adding the same device to a list more
+        * than once. This can happen if new consumers get added to the device
+        * and probed before the list is flushed.
+        */
+       dev->state_synced = true;
+
+       if (WARN_ON(!list_empty(&dev->links.defer_sync)))
+               return;
+
+       get_device(dev);
+       list_add_tail(&dev->links.defer_sync, list);
+}
+
+/**
+ * device_links_flush_sync_list - Call sync_state() on a list of devices
+ * @list: List of devices to call sync_state() on
+ *
+ * Calls sync_state() on all the devices that have been queued for it. This
+ * function is used in conjunction with __device_links_queue_sync_state().
+ */
+static void device_links_flush_sync_list(struct list_head *list)
+{
+       struct device *dev, *tmp;
+
+       list_for_each_entry_safe(dev, tmp, list, links.defer_sync) {
+               list_del_init(&dev->links.defer_sync);
+
+               device_lock(dev);
+
+               if (dev->bus->sync_state)
+                       dev->bus->sync_state(dev);
+               else if (dev->driver && dev->driver->sync_state)
+                       dev->driver->sync_state(dev);
+
+               device_unlock(dev);
+
+               put_device(dev);
+       }
+}
+
+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;
+       LIST_HEAD(sync_list);
+
+       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) {
+               /*
+                * Delete from deferred_sync list before queuing it to
+                * sync_list because defer_sync is used for both lists.
+                */
+               list_del_init(&dev->links.defer_sync);
+               __device_links_queue_sync_state(dev, &sync_list);
+       }
+out:
+       device_links_write_unlock();
+
+       device_links_flush_sync_list(&sync_list);
+}
+
+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.
@@ -598,6 +831,16 @@ int device_links_check_suppliers(struct device *dev)
 void device_links_driver_bound(struct device *dev)
 {
        struct device_link *link;
+       LIST_HEAD(sync_list);
+
+       /*
+        * 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();
 
@@ -628,11 +871,19 @@ 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_queue_sync_state(link->supplier,
+                                                       &sync_list);
        }
 
        dev->links.status = DL_DEV_DRIVER_BOUND;
 
        device_links_write_unlock();
+
+       device_links_flush_sync_list(&sync_list);
 }
 
 static void device_link_drop_managed(struct device_link *link)
@@ -744,6 +995,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 +1065,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 +1102,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 +1970,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 +2360,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 +2458,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 +2628,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().
         */
index 3f9e274e2ed325ad1fc59523aa1d368e201acb03..5b24f39592557d082ecf999b23e0aa20528b88a7 100644 (file)
@@ -148,7 +148,7 @@ config FW_LOADER_USER_HELPER_FALLBACK
          to be used for all firmware requests which explicitly do not disable a
          a fallback mechanism. Firmware calls which do prohibit a fallback
          mechanism is request_firmware_direct(). This option is kept for
-          backward compatibility purposes given this precise mechanism can also
+         backward compatibility purposes given this precise mechanism can also
          be enabled by setting the proc sysctl value to true:
 
               /proc/sys/kernel/firmware_config/force_sysfs_fallback
@@ -169,5 +169,17 @@ config FW_LOADER_COMPRESS
          be compressed with either none or crc32 integrity check type (pass
          "-C crc32" option to xz command).
 
+config FW_CACHE
+       bool "Enable firmware caching during suspend"
+       depends on PM_SLEEP
+       default y if PM_SLEEP
+       help
+         Because firmware caching generates uevent messages that are sent
+         over a netlink socket, it can prevent suspend on many platforms.
+         It is also not always useful, so on such platforms we have the
+         option.
+
+         If unsure, say Y.
+
 endif # FW_LOADER
 endmenu
index 37e5ae387400abbf984a90d67b72ee246460c32b..4a66888e7253d34d00674824d7fab6593dd794fd 100644 (file)
@@ -8,7 +8,8 @@ fwdir := $(addprefix $(srctree)/,$(filter-out /%,$(fwdir)))$(filter /%,$(fwdir))
 obj-y  := $(addsuffix .gen.o, $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE)))
 
 FWNAME    = $(patsubst $(obj)/%.gen.S,%,$@)
-FWSTR     = $(subst /,_,$(subst .,_,$(subst -,_,$(FWNAME))))
+comma     := ,
+FWSTR     = $(subst $(comma),_,$(subst /,_,$(subst .,_,$(subst -,_,$(FWNAME)))))
 ASM_WORD  = $(if $(CONFIG_64BIT),.quad,.long)
 ASM_ALIGN = $(if $(CONFIG_64BIT),3,2)
 PROGBITS  = $(if $(CONFIG_ARM),%,@)progbits
index bf44c79beae92b23fbc63b011da722abcc88f040..249add8c5e05666f8e1fd5b2f69f6c69c0901a20 100644 (file)
@@ -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.
  *
  */
 
@@ -51,7 +51,7 @@ struct firmware_cache {
        struct list_head head;
        int state;
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
        /*
         * Names of firmware images which have been cached successfully
         * will be added into the below list so that device uncache
@@ -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);
@@ -556,7 +557,7 @@ static void fw_set_page_data(struct fw_priv *fw_priv, struct firmware *fw)
                 (unsigned int)fw_priv->size);
 }
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
 static void fw_name_devm_release(struct device *dev, void *res)
 {
        struct fw_name_devm *fwn = res;
@@ -1046,7 +1047,7 @@ request_firmware_nowait(
 }
 EXPORT_SYMBOL(request_firmware_nowait);
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
 static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
 
 /**
index b230beb6ccb41ba8beb5fbaf87972f69b94a33e3..7c532548b0a62d8d0ac99d8d052de4a8d045ef18 100644 (file)
@@ -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 */
@@ -89,9 +143,9 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num)
        return dev->archdata.irqs[num];
 #else
        struct resource *r;
-       if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
-               int ret;
+       int ret;
 
+       if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
                ret = of_irq_get(dev->dev.of_node, num);
                if (ret > 0 || ret == -EPROBE_DEFER)
                        return ret;
@@ -100,8 +154,6 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num)
        r = platform_get_resource(dev, IORESOURCE_IRQ, num);
        if (has_acpi_companion(&dev->dev)) {
                if (r && r->flags & IORESOURCE_DISABLED) {
-                       int ret;
-
                        ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r);
                        if (ret)
                                return ret;
@@ -134,8 +186,7 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num)
         * allows a common code path across either kind of resource.
         */
        if (num == 0 && has_acpi_companion(&dev->dev)) {
-               int ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num);
-
+               ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num);
                /* Our callers expect -ENXIO for missing IRQs. */
                if (ret >= 0 || ret == -EPROBE_DEFER)
                        return ret;
@@ -144,6 +195,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 +217,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 +225,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 +235,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)
@@ -245,10 +274,9 @@ static int __platform_get_irq_byname(struct platform_device *dev,
                                     const char *name)
 {
        struct resource *r;
+       int ret;
 
        if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
-               int ret;
-
                ret = of_irq_get_byname(dev->dev.of_node, name);
                if (ret > 0 || ret == -EPROBE_DEFER)
                        return ret;
@@ -1278,6 +1306,11 @@ struct bus_type platform_bus_type = {
 };
 EXPORT_SYMBOL_GPL(platform_bus_type);
 
+static inline int __platform_match(struct device *dev, const void *drv)
+{
+       return platform_match(dev, (struct device_driver *)drv);
+}
+
 /**
  * platform_find_device_by_driver - Find a platform device with a given
  * driver.
@@ -1288,7 +1321,7 @@ struct device *platform_find_device_by_driver(struct device *start,
                                              const struct device_driver *drv)
 {
        return bus_find_device(&platform_bus_type, start, drv,
-                              (void *)platform_match);
+                              __platform_match);
 }
 EXPORT_SYMBOL_GPL(platform_find_device_by_driver);
 
@@ -1296,8 +1329,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 +1340,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));
-       }
-}
-
index 7c0c5ca5953d20b63b849ec537ba999a328f212a..4af11a423475e5bb818d3b36b2410e25861b786a 100644 (file)
@@ -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;
 }
index ef773db080e903002b693b41b961a2d48e0f5e53..9cde50cb322008a02a1d38c56f68a9a07f923fac 100644 (file)
 #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);
 
index 62812f80b5cc0916d3a38146ac6b3b75c4b9915f..64526e50d471c1f096b372a69fbaee1d2948da4b 100644 (file)
 #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 {
@@ -448,7 +452,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);
        }
@@ -468,7 +472,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:
@@ -517,7 +521,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);
 
index 8c4f3753b36ecbec88cb4be5091264e44f6a1934..d49690d1553670e65bede80e78e2e07e648b5ecd 100644 (file)
 #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);
 
index 6c06876943412bc974999e247d6ffcd91301a7a3..2f0f50336b9a1544b2d5aec5a77e8c34627b1c13 100644 (file)
@@ -773,23 +773,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);
 
@@ -812,7 +801,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);
 
index a9058fda187e3abda62d447a2ed5930c30328c7e..ef40fbe923cf30d4678eb8a6533869face7f95c4 100644 (file)
@@ -407,7 +407,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        unsigned int i, j, offset;
        struct gpio_irq_chip *irq;
        struct tegra_gpio *gpio;
-       struct resource *res;
        char **names;
        int err;
 
@@ -417,8 +416,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);
 
index 7eb41990bd6deff1271c388395614c7d85fa54ad..e4d296b40baae48019425bb1a8999c7bf7727833 100644 (file)
@@ -50,6 +50,7 @@ int of_i2c_get_board_info(struct device *dev, struct device_node *node,
 
        info->addr = addr;
        info->of_node = node;
+       info->fwnode = of_fwnode_handle(node);
 
        if (of_property_read_bool(node, "host-notify"))
                info->flags |= I2C_CLIENT_HOST_NOTIFY;
index 97b26e9a5234b6bfb122a1e3697f4e377411ec8d..51100350b688058dc782306a57fa81abd907612f 100644 (file)
@@ -5701,11 +5701,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)
@@ -5756,52 +5755,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;
-
-       dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
-       if (!dbg)
-               return -ENOMEM;
-
-       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;
 
-       return 0;
+       root = debugfs_create_dir("delay_drop", dev->mdev->priv.dbg_root);
+       dev->delay_drop.dir_debugfs = root;
 
-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)
@@ -5817,8 +5786,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,
index b983e385a8c507bc33afb6cf7db7efa2855d0aee..03af54b53bf71401a556a941db644468c7823582 100644 (file)
@@ -799,13 +799,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;
@@ -815,7 +808,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 {
index 4c5ba35d48d435e61d2161cf4070f1f50c299eb0..834b35dc3b1378bca2a99ea7401af2f38410d0b8 100644 (file)
@@ -657,7 +657,7 @@ static int tegra_hsp_probe(struct platform_device *pdev)
        hsp->num_db = (value >> HSP_nDB_SHIFT) & HSP_nINT_MASK;
        hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
 
-       err = platform_get_irq_byname(pdev, "doorbell");
+       err = platform_get_irq_byname_optional(pdev, "doorbell");
        if (err >= 0)
                hsp->doorbell_irq = err;
 
@@ -677,7 +677,7 @@ static int tegra_hsp_probe(struct platform_device *pdev)
                        if (!name)
                                return -ENOMEM;
 
-                       err = platform_get_irq_byname(pdev, name);
+                       err = platform_get_irq_byname_optional(pdev, name);
                        if (err >= 0) {
                                hsp->shared_irqs[i] = err;
                                count++;
index 8f0ddcbeed9df6ef79198ada0a869543e836042f..301fa10f419b6a7c9a1b50d759fd0fbbfc0f7692 100644 (file)
@@ -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)
index f30448bf3a6316b4cace786477a04aea54c302de..6c1a23cb3e8c0fa8ef1f5bf8b871a10c763fa894 100644 (file)
@@ -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;
 
index 581b99f9e113edafc0ec6e52eb4fede0b8bd81b8..6f065bb5c55a7e0f54ed6bc85f3d6c9570190f81 100644 (file)
@@ -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)
index bf0048ebbda356a7b03e7f3f56849718ac7ca54d..fc9d4d000f97e4342bd0b19ae8834382c9e11289 100644 (file)
@@ -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) */
 
index 40b079162804fb0c7d43d000392abb5c60448c37..bd40b114d6cd72143aa11fd557259854ceb412ce 100644 (file)
@@ -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);
index 65865e460ab87eb4847db95a3600007c88cf19a4..04dd46647db361c35a2a01c41a480a5165b231b2 100644 (file)
@@ -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)
index b47a2292fe8e8904a653ad295404c8d56282c9df..d93891a05f6033638916d7eda0a560110dcaf4ef 100644 (file)
@@ -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)
index e8202f61a5d930996ec2af0e43f3017bf22a13bb..477966d2421a130ede0b06b291e3ca32c42ef66a 100644 (file)
@@ -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"
 
@@ -999,6 +1000,320 @@ 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 true;
+               }
+               child = of_get_next_parent(child);
+       }
+       return false;
+}
+
+/**
+ * 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_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL)
+DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells")
+DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
+DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
+DEFINE_SUFFIX_PROP(gpios, "-gpios", "#gpio-cells")
+
+static struct device_node *parse_iommu_maps(struct device_node *np,
+                                           const char *prop_name, int index)
+{
+       if (strcmp(prop_name, "iommu-map"))
+               return NULL;
+
+       return of_parse_phandle(np, prop_name, (index * 4) + 1);
+}
+
+static const struct supplier_bindings of_supplier_bindings[] = {
+       { .parse_prop = parse_clocks, },
+       { .parse_prop = parse_interconnects, },
+       { .parse_prop = parse_iommus, },
+       { .parse_prop = parse_iommu_maps, },
+       { .parse_prop = parse_mboxes, },
+       { .parse_prop = parse_io_channels, },
+       { .parse_prop = parse_interrupt_parent, },
+       { .parse_prop = parse_dmas, },
+       { .parse_prop = parse_regulators, },
+       { .parse_prop = parse_gpio, },
+       { .parse_prop = parse_gpios, },
+       {}
+};
+
+/**
+ * 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,
@@ -1017,5 +1332,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);
index 22e5d4e13714e8635a54b74ab6c5f02f2c05bb2a..58bf9d496ba596dd59056a4ab4cb04863d75ac82 100644 (file)
@@ -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
index 87846aad594b70ec06d6437b9c9bd3e56b6b43fd..dede25247b81f72a2f8aeca2f1c42e8f67683459 100644 (file)
@@ -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);
 
index 42f2b512609499bebc2f71e75ccca74d420b0a83..3015ecbb90b131691fe3bcda3f59351f93694589 100644 (file)
@@ -57,6 +57,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu);
 void update_siblings_masks(unsigned int cpu);
 void remove_cpu_topology(unsigned int cpuid);
 void reset_cpu_topology(void);
+int parse_acpi_topology(void);
 #endif
 
 #endif /* _LINUX_ARCH_TOPOLOGY_H_ */
index 58424eb3b3291ae3183506d5d951ab425dccb51c..bf9b6cafa4c26a680df1e9bfbd9b175a66e63807 100644 (file)
@@ -54,6 +54,8 @@ static const struct file_operations __fops = {                                \
        .llseek  = no_llseek,                                           \
 }
 
+typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *);
+
 #if defined(CONFIG_DEBUG_FS)
 
 struct dentry *debugfs_lookup(const char *name, struct dentry *parent);
@@ -75,7 +77,6 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
 struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
                                      const char *dest);
 
-typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *);
 struct dentry *debugfs_create_automount(const char *name,
                                        struct dentry *parent,
                                        debugfs_automount_t f,
@@ -97,28 +98,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);
 
@@ -203,7 +204,7 @@ static inline struct dentry *debugfs_create_symlink(const char *name,
 
 static inline struct dentry *debugfs_create_automount(const char *name,
                                        struct dentry *parent,
-                                       struct vfsmount *(*f)(void *),
+                                       debugfs_automount_t f,
                                        void *data)
 {
        return ERR_PTR(-ENODEV);
@@ -244,19 +245,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 +258,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 +269,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 +352,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
index 297239a08bb77c7474c21695a8ef406cd582e78a..f05c5b92e61f535abcfd1d11fd6e8165a8ae840f 100644 (file)
@@ -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
index 9d9dc444d7873c8f523452b09f23ff515e7173a3..8feeb94b8acc79e48f6897c21b2822cff56e11fc 100644 (file)
@@ -17,6 +17,7 @@ struct device;
 struct fwnode_handle {
        struct fwnode_handle *secondary;
        const struct fwnode_operations *ops;
+       struct device *dev;
 };
 
 /**
@@ -67,6 +68,44 @@ 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 known suppliers of this device or if the supplier
+ *             information is not known.
+ *
+ *             Return -ENODEV if the suppliers needed for probing this device
+ *             have not been registered yet (because device links can only be
+ *             created to devices registered with the driver core).
+ *
+ *             Return -EAGAIN if some of the suppliers of this device have not
+ *             been registered yet, but none of those suppliers are necessary
+ *             for probing the device.
  */
 struct fwnode_operations {
        struct fwnode_handle *(*get)(struct fwnode_handle *fwnode);
@@ -106,6 +145,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)                              \
@@ -127,5 +168,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
index f2688404d1cd73d3423d3443304a975306f4e0a1..276a03c246919ee57be5495808a4043c7abdcaac 100644 (file)
@@ -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_ */
index 48ceea867dd65274cb0d17eb4a536439ac4d40d2..d9b3cf0f410c8cfb509a4c1a4d6c83fde6fe33c6 100644 (file)
@@ -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;
 };
 
 /**
index e08527f50d2a91f91077922eeae61b30a150dfa1..382628b9b75980e0408edeed9ecfbc2d165cd2d4 100644 (file)
@@ -106,7 +106,6 @@ config PREEMPTIRQ_TRACEPOINTS
 
 config TRACING
        bool
-       select DEBUG_FS
        select RING_BUFFER
        select STACKTRACE if STACKTRACE_SUPPORT
        select TRACEPOINTS
index 6a0e9bd6524aecc06e2e1f3f3da202ec95374202..97fb44e5b4d6dce8a4a2f9d484f1f6ed1d431ed4 100644 (file)
@@ -114,25 +114,9 @@ void devm_iounmap(struct device *dev, void __iomem *addr)
 }
 EXPORT_SYMBOL(devm_iounmap);
 
-/**
- * devm_ioremap_resource() - check, request region, and ioremap resource
- * @dev: generic device to handle the resource for
- * @res: resource to be handled
- *
- * Checks that a resource is a valid memory region, requests the memory
- * region and ioremaps it. All operations are managed and will be undone
- * on driver detach.
- *
- * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
- * on failure. Usage example:
- *
- *     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- *     base = devm_ioremap_resource(&pdev->dev, res);
- *     if (IS_ERR(base))
- *             return PTR_ERR(base);
- */
-void __iomem *devm_ioremap_resource(struct device *dev,
-                                   const struct resource *res)
+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;
@@ -151,7 +135,7 @@ void __iomem *devm_ioremap_resource(struct device *dev,
                return IOMEM_ERR_PTR(-EBUSY);
        }
 
-       dest_ptr = devm_ioremap(dev, res->start, size);
+       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);
@@ -160,8 +144,46 @@ void __iomem *devm_ioremap_resource(struct device *dev,
 
        return dest_ptr;
 }
+
+/**
+ * devm_ioremap_resource() - check, request region, and ioremap resource
+ * @dev: generic device to handle the resource for
+ * @res: resource to be handled
+ *
+ * Checks that a resource is a valid memory region, requests the memory
+ * region and ioremaps it. All operations are managed and will be undone
+ * on driver detach.
+ *
+ * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
+ * on failure. Usage example:
+ *
+ *     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ *     base = devm_ioremap_resource(&pdev->dev, res);
+ *     if (IS_ERR(base))
+ *             return PTR_ERR(base);
+ */
+void __iomem *devm_ioremap_resource(struct device *dev,
+                                   const struct resource *res)
+{
+       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
index 0185e6e5e5d1f4a730812032a9d5459ca3766bab..b3c9001d1f43d92a87104738b2de972a7e5425e2 100644 (file)
@@ -951,12 +951,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)
 {
@@ -1001,14 +996,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);
 }