layerscape: reverse changes to ndo_get_stats64

The NXP LSDK kernel backported changes for interface ndo_get_stats64
functions from mainline, this causes a compile error with
backports/mac80211, which expects the original 4.9 defintion.

As reversing the ndo_get_stats64 change signifcantly reduces the size of
patch 601, the patches that were aggregated into it have been
disaggregated.

Signed-off-by: Mathew McBride <matt@traverse.com.au>
This commit is contained in:
Mathew McBride 2017-10-24 11:49:00 +11:00 committed by Hauke Mehrtens
parent 6a457749a4
commit 1c4415a679
9 changed files with 650 additions and 2365 deletions

View file

@ -0,0 +1,78 @@
From 95b8bbff6ecf0692747622af16d917a67313f8cc Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Fri, 7 Oct 2016 22:04:33 -0400
Subject: [PATCH] net: centralize net_device min/max MTU checking
While looking into an MTU issue with sfc, I started noticing that almost
every NIC driver with an ndo_change_mtu function implemented almost
exactly the same range checks, and in many cases, that was the only
practical thing their ndo_change_mtu function was doing. Quite a few
drivers have either 68, 64, 60 or 46 as their minimum MTU value checked,
and then various sizes from 1500 to 65535 for their maximum MTU value. We
can remove a whole lot of redundant code here if we simple store min_mtu
and max_mtu in net_device, and check against those in net/core/dev.c's
dev_set_mtu().
In theory, there should be zero functional change with this patch, it just
puts the infrastructure in place. Subsequent patches will attempt to start
using said infrastructure, with theoretically zero change in
functionality.
CC: netdev@vger.kernel.org
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/linux/netdevice.h | 4 ++++
net/core/dev.c | 13 +++++++++++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 780e7171f548..2082b7d02a77 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1507,6 +1507,8 @@ enum netdev_priv_flags {
* @if_port: Selectable AUI, TP, ...
* @dma: DMA channel
* @mtu: Interface MTU value
+ * @min_mtu: Interface Minimum MTU value
+ * @max_mtu: Interface Maximum MTU value
* @type: Interface hardware type
* @hard_header_len: Maximum hardware header length.
* @min_header_len: Minimum hardware header length
@@ -1728,6 +1730,8 @@ struct net_device {
unsigned char dma;
unsigned int mtu;
+ unsigned int min_mtu;
+ unsigned int max_mtu;
unsigned short type;
unsigned short hard_header_len;
unsigned short min_header_len;
diff --git a/net/core/dev.c b/net/core/dev.c
index 2e04fd188081..c7ec56e8659a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6524,9 +6524,18 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
if (new_mtu == dev->mtu)
return 0;
- /* MTU must be positive. */
- if (new_mtu < 0)
+ /* MTU must be positive, and in range */
+ if (new_mtu < 0 || new_mtu < dev->min_mtu) {
+ net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n",
+ dev->name, new_mtu, dev->min_mtu);
return -EINVAL;
+ }
+
+ if (dev->max_mtu > 0 && new_mtu > dev->max_mtu) {
+ net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n",
+ dev->name, new_mtu, dev->min_mtu);
+ return -EINVAL;
+ }
if (!netif_device_present(dev))
return -ENODEV;
--
2.11.1

View file

@ -0,0 +1,125 @@
From d33bde3c487c722541ad359e1d22090a78df0c77 Mon Sep 17 00:00:00 2001
From: Zhao Qiang <qiang.zhao@nxp.com>
Date: Tue, 11 Jul 2017 16:47:18 +0800
Subject: [PATCH] add devm_alloc_percpu support
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
---
drivers/base/devres.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/device.h | 19 +++++++++++++++
2 files changed, 85 insertions(+)
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 8fc654f0807b..71d577025285 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/percpu.h>
#include "base.h"
@@ -985,3 +986,68 @@ void devm_free_pages(struct device *dev, unsigned long addr)
&devres));
}
EXPORT_SYMBOL_GPL(devm_free_pages);
+
+static void devm_percpu_release(struct device *dev, void *pdata)
+{
+ void __percpu *p;
+
+ p = *(void __percpu **)pdata;
+ free_percpu(p);
+}
+
+static int devm_percpu_match(struct device *dev, void *data, void *p)
+{
+ struct devres *devr = container_of(data, struct devres, data);
+
+ return *(void **)devr->data == p;
+}
+
+/**
+ * __devm_alloc_percpu - Resource-managed alloc_percpu
+ * @dev: Device to allocate per-cpu memory for
+ * @size: Size of per-cpu memory to allocate
+ * @align: Alignment of per-cpu memory to allocate
+ *
+ * Managed alloc_percpu. Per-cpu memory allocated with this function is
+ * automatically freed on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void __percpu *__devm_alloc_percpu(struct device *dev, size_t size,
+ size_t align)
+{
+ void *p;
+ void __percpu *pcpu;
+
+ pcpu = __alloc_percpu(size, align);
+ if (!pcpu)
+ return NULL;
+
+ p = devres_alloc(devm_percpu_release, sizeof(void *), GFP_KERNEL);
+ if (!p) {
+ free_percpu(pcpu);
+ return NULL;
+ }
+
+ *(void __percpu **)p = pcpu;
+
+ devres_add(dev, p);
+
+ return pcpu;
+}
+EXPORT_SYMBOL_GPL(__devm_alloc_percpu);
+
+/**
+ * devm_free_percpu - Resource-managed free_percpu
+ * @dev: Device this memory belongs to
+ * @pdata: Per-cpu memory to free
+ *
+ * Free memory allocated with devm_alloc_percpu().
+ */
+void devm_free_percpu(struct device *dev, void __percpu *pdata)
+{
+ WARN_ON(devres_destroy(dev, devm_percpu_release, devm_percpu_match,
+ (void *)pdata));
+}
+EXPORT_SYMBOL_GPL(devm_free_percpu);
diff --git a/include/linux/device.h b/include/linux/device.h
index bc41e87a969b..0a2135cbddc9 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -686,6 +686,25 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
int devm_add_action(struct device *dev, void (*action)(void *), void *data);
void devm_remove_action(struct device *dev, void (*action)(void *), void *data);
+/**
+ * devm_alloc_percpu - Resource-managed alloc_percpu
+ * @dev: Device to allocate per-cpu memory for
+ * @type: Type to allocate per-cpu memory for
+ *
+ * Managed alloc_percpu. Per-cpu memory allocated with this function is
+ * automatically freed on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+#define devm_alloc_percpu(dev, type) \
+ ((typeof(type) __percpu *)__devm_alloc_percpu((dev), sizeof(type), \
+ __alignof__(type)))
+
+void __percpu *__devm_alloc_percpu(struct device *dev, size_t size,
+ size_t align);
+void devm_free_percpu(struct device *dev, void __percpu *pdata);
+
static inline int devm_add_action_or_reset(struct device *dev,
void (*action)(void *), void *data)
{
--
2.11.1

View file

@ -0,0 +1,66 @@
From 9527ee5eb436ad773acc7320b372a5f4825a920d Mon Sep 17 00:00:00 2001
From: Madalin Bucur <madalin.bucur@freescale.com>
Date: Tue, 5 Jan 2016 12:12:07 +0200
Subject: [PATCH] net: readd skb_recycle()
Adding back skb_recycle() as it's used by the DPAA Ethernet driver.
This was removed from the upstream kernel because it was lacking users.
Signed-off-by: Madalin Bucur <madalin.bucur@freescale.com>
---
include/linux/skbuff.h | 1 +
net/core/skbuff.c | 26 ++++++++++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 32810f279f8e..a52a6fb0ac2e 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -902,6 +902,7 @@ void kfree_skb(struct sk_buff *skb);
void kfree_skb_list(struct sk_buff *segs);
void skb_tx_error(struct sk_buff *skb);
void consume_skb(struct sk_buff *skb);
+void skb_recycle(struct sk_buff *skb);
void __kfree_skb(struct sk_buff *skb);
extern struct kmem_cache *skbuff_head_cache;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index fe008f1bd930..ab1038083df2 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -825,6 +825,32 @@ void napi_consume_skb(struct sk_buff *skb, int budget)
}
EXPORT_SYMBOL(napi_consume_skb);
+/**
+ * skb_recycle - clean up an skb for reuse
+ * @skb: buffer
+ *
+ * Recycles the skb to be reused as a receive buffer. This
+ * function does any necessary reference count dropping, and
+ * cleans up the skbuff as if it just came from __alloc_skb().
+ */
+void skb_recycle(struct sk_buff *skb)
+{
+ struct skb_shared_info *shinfo;
+ u8 head_frag = skb->head_frag;
+
+ skb_release_head_state(skb);
+
+ shinfo = skb_shinfo(skb);
+ memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
+ atomic_set(&shinfo->dataref, 1);
+
+ memset(skb, 0, offsetof(struct sk_buff, tail));
+ skb->data = skb->head + NET_SKB_PAD;
+ skb->head_frag = head_frag;
+ skb_reset_tail_pointer(skb);
+}
+EXPORT_SYMBOL(skb_recycle);
+
/* Make sure a field is enclosed inside headers_start/headers_end section */
#define CHECK_SKB_FIELD(field) \
BUILD_BUG_ON(offsetof(struct sk_buff, field) < \
--
2.11.1

View file

@ -0,0 +1,47 @@
From eae03a91605fd7dccb1de11053efee87db398df3 Mon Sep 17 00:00:00 2001
From: Zhang Ying-22455 <ying.zhang22455@nxp.com>
Date: Fri, 1 Sep 2017 14:56:01 +0800
Subject: [PATCH] linux/core: export copy_skb_header() function
Signed-off-by: Camelia Groza camelia.groza@nxp.com
---
include/linux/skbuff.h | 1 +
net/core/skbuff.c | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index a52a6fb0ac2e..a0385f9bdd4e 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3063,6 +3063,7 @@ static inline void skb_free_datagram_locked(struct sock *sk,
}
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
+void copy_skb_header(struct sk_buff *new, const struct sk_buff *old);
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
int len, __wsum csum);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ab1038083df2..2684c49b9805 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1082,7 +1082,7 @@ static void skb_headers_offset_update(struct sk_buff *skb, int off)
skb->inner_mac_header += off;
}
-static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
+void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
{
__copy_skb_header(new, old);
@@ -1090,6 +1090,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
}
+EXPORT_SYMBOL(copy_skb_header);
static inline int skb_alloc_rx_flag(const struct sk_buff *skb)
{
--
2.11.1

View file

@ -0,0 +1,60 @@
From 3d33284eb087deb7f62639a2d2c03b9d0a3eeb34 Mon Sep 17 00:00:00 2001
From: Camelia Groza <camelia.groza@nxp.com>
Date: Mon, 11 Sep 2017 17:20:41 +0800
Subject: [PATCH] sdk_dpaa: update the xmit timestamp to avoid watchdog
timeouts
[core-linux part]
Update txq0's trans_start in order to prevent the netdev watchdog from
triggering too quickly. Since we set the LLTX flag, the stack won't update
the jiffies for other tx queues. Prevent the watchdog from checking the
other tx queues by adding the NETIF_HW_ACCEL_MQ flag.
Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
---
include/linux/netdev_features.h | 2 ++
net/sched/sch_generic.c | 7 +++++++
2 files changed, 9 insertions(+)
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 9c6c8ef2e9e7..90b4107ebeff 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -74,6 +74,7 @@ enum {
NETIF_F_BUSY_POLL_BIT, /* Busy poll */
NETIF_F_HW_TC_BIT, /* Offload TC infrastructure */
+ NETIF_F_HW_ACCEL_MQ_BIT, /* Hardware-accelerated multiqueue */
/*
* Add your fresh new feature above and remember to update
@@ -136,6 +137,7 @@ enum {
#define NETIF_F_HW_L2FW_DOFFLOAD __NETIF_F(HW_L2FW_DOFFLOAD)
#define NETIF_F_BUSY_POLL __NETIF_F(BUSY_POLL)
#define NETIF_F_HW_TC __NETIF_F(HW_TC)
+#define NETIF_F_HW_ACCEL_MQ __NETIF_F(HW_ACCEL_MQ)
#define for_each_netdev_feature(mask_addr, bit) \
for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 6cfb6e9038c2..3fab16cb7c58 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -309,6 +309,13 @@ static void dev_watchdog(unsigned long arg)
txq->trans_timeout++;
break;
}
+
+ /* Devices with HW_ACCEL_MQ have multiple txqs
+ * but update only the first one's transmission
+ * timestamp so avoid checking the rest.
+ */
+ if (dev->features & NETIF_F_HW_ACCEL_MQ)
+ break;
}
if (some_queue_timedout) {
--
2.11.1

View file

@ -0,0 +1,112 @@
From: Mathew McBride <matt@traverse.com.au>
Date: Tue, 24 Oct 2017 11:30:00 +1100
Subject: [PATCH] dpaa: backport use of 4.9 ndo_get_stats64
This patch changes the declarations of ndo_get_stats64 handlers
to the previous struct rtnl_link_stats64 * return type instead of
the mainline void return.
Suggested-by: Adrien Gallouët <adrien@gallouet.fr>
Signed-off-by: Mathew McBride <matt@traverse.com.au>
---
drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c | 5 +++--
drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h | 4 ++--
drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c | 3 ++-
drivers/staging/fsl-dpaa2/ethsw/switch.c | 4 ++--
drivers/staging/fsl-dpaa2/evb/evb.c | 4 ++--
5 files changed, 11 insertions(+), 9 deletions(-)
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
@@ -1296,7 +1296,7 @@ static int dpaa2_eth_set_addr(struct net
/** Fill in counters maintained by the GPP driver. These may be different from
* the hardware counters obtained by ethtool.
*/
-static void dpaa2_eth_get_stats(struct net_device *net_dev,
+static struct rtnl_link_stats64 *dpaa2_eth_get_stats(struct net_device *net_dev,
struct rtnl_link_stats64 *stats)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
@@ -1312,6 +1312,7 @@ static void dpaa2_eth_get_stats(struct n
for (j = 0; j < num; j++)
netstats[j] += cpustats[j];
}
+ return stats;
}
static int dpaa2_eth_change_mtu(struct net_device *net_dev, int mtu)
--- a/drivers/staging/fsl-dpaa2/ethsw/switch.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/switch.c
@@ -1094,7 +1094,7 @@ static int ethsw_port_fdb_del(struct ndm
return 0;
}
-void ethsw_port_get_stats(struct net_device *netdev,
+struct rtnl_link_stats64 *ethsw_port_get_stats(struct net_device *netdev,
struct rtnl_link_stats64 *storage)
{
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
@@ -1154,7 +1154,7 @@ void ethsw_port_get_stats(struct net_dev
if (err)
goto error;
- return;
+ return storage;
error:
netdev_err(netdev, "dpsw_if_get_counter err %d\n", err);
--- a/drivers/staging/fsl-dpaa2/evb/evb.c
+++ b/drivers/staging/fsl-dpaa2/evb/evb.c
@@ -765,7 +765,7 @@ static int evb_dellink(struct net_device
return 0;
}
-void evb_port_get_stats(struct net_device *netdev,
+struct rtnl_link_stats64 *evb_port_get_stats(struct net_device *netdev,
struct rtnl_link_stats64 *storage)
{
struct evb_port_priv *port_priv = netdev_priv(netdev);
@@ -842,7 +842,7 @@ void evb_port_get_stats(struct net_devic
if (unlikely(err))
goto error;
- return;
+ return storage;
error:
netdev_err(netdev, "dpdmux_if_get_counter err %d\n", err);
--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
@@ -239,8 +239,8 @@ EXPORT_SYMBOL(dpa_timeout);
* Calculates the statistics for the given device by adding the statistics
* collected by each CPU.
*/
-void __cold
-dpa_get_stats64(struct net_device *net_dev,
+struct rtnl_link_stats64 __cold
+*dpa_get_stats64(struct net_device *net_dev,
struct rtnl_link_stats64 *stats)
{
struct dpa_priv_s *priv = netdev_priv(net_dev);
@@ -258,6 +258,7 @@ dpa_get_stats64(struct net_device *net_d
for (j = 0; j < numstats; j++)
netstats[j] += cpustats[j];
}
+ return stats;
}
EXPORT_SYMBOL(dpa_get_stats64);
--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
@@ -140,8 +140,8 @@ int dpa_netdev_init(struct net_device *n
int __cold dpa_start(struct net_device *net_dev);
int __cold dpa_stop(struct net_device *net_dev);
void __cold dpa_timeout(struct net_device *net_dev);
-void __cold
-dpa_get_stats64(struct net_device *net_dev,
+struct rtnl_link_stats64 __cold
+*dpa_get_stats64(struct net_device *net_dev,
struct rtnl_link_stats64 *stats);
int dpa_change_mtu(struct net_device *net_dev, int new_mtu);
int dpa_ndo_init(struct net_device *net_dev);

View file

@ -0,0 +1,162 @@
From c97db7cc7778e34a53b42d58c766f0ec0e30d580 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Wed, 21 Sep 2016 14:57:19 +0800
Subject: [PATCH] base: soc: Introduce soc_device_match() interface
We keep running into cases where device drivers want to know the exact
version of the a SoC they are currently running on. In the past, this has
usually been done through a vendor specific API that can be called by a
driver, or by directly accessing some kind of version register that is
not part of the device itself but that belongs to a global register area
of the chip.
Common reasons for doing this include:
- A machine is not using devicetree or similar for passing data about
on-chip devices, but just announces their presence using boot-time
platform devices, and the machine code itself does not care about the
revision.
- There is existing firmware or boot loaders with existing DT binaries
with generic compatible strings that do not identify the particular
revision of each device, but the driver knows which SoC revisions
include which part.
- A prerelease version of a chip has some quirks and we are using the same
version of the bootloader and the DT blob on both the prerelease and the
final version. An update of the DT binding seems inappropriate because
that would involve maintaining multiple copies of the dts and/or
bootloader.
This patch introduces the soc_device_match() interface that is meant to
work like of_match_node() but instead of identifying the version of a
device, it identifies the SoC itself using a vendor-agnostic interface.
Unlike of_match_node(), we do not do an exact string compare but instead
use glob_match() to allow wildcards in strings.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/base/Kconfig | 1 +
drivers/base/soc.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/sys_soc.h | 3 +++
3 files changed, 70 insertions(+)
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index fdf44cac08e6..991b21e1f89b 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -235,6 +235,7 @@ config GENERIC_CPU_AUTOPROBE
config SOC_BUS
bool
+ select GLOB
source "drivers/base/regmap/Kconfig"
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 028cef377fd4..04ee597fc3a3 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -13,6 +13,7 @@
#include <linux/spinlock.h>
#include <linux/sys_soc.h>
#include <linux/err.h>
+#include <linux/glob.h>
static DEFINE_IDA(soc_ida);
@@ -168,3 +169,68 @@ static int __init soc_bus_register(void)
return bus_register(&soc_bus_type);
}
core_initcall(soc_bus_register);
+
+static int soc_device_match_one(struct device *dev, void *arg)
+{
+ struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+ const struct soc_device_attribute *match = arg;
+
+ if (match->machine &&
+ !glob_match(match->machine, soc_dev->attr->machine))
+ return 0;
+
+ if (match->family &&
+ !glob_match(match->family, soc_dev->attr->family))
+ return 0;
+
+ if (match->revision &&
+ !glob_match(match->revision, soc_dev->attr->revision))
+ return 0;
+
+ if (match->soc_id &&
+ !glob_match(match->soc_id, soc_dev->attr->soc_id))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * soc_device_match - identify the SoC in the machine
+ * @matches: zero-terminated array of possible matches
+ *
+ * returns the first matching entry of the argument array, or NULL
+ * if none of them match.
+ *
+ * This function is meant as a helper in place of of_match_node()
+ * in cases where either no device tree is available or the information
+ * in a device node is insufficient to identify a particular variant
+ * by its compatible strings or other properties. For new devices,
+ * the DT binding should always provide unique compatible strings
+ * that allow the use of of_match_node() instead.
+ *
+ * The calling function can use the .data entry of the
+ * soc_device_attribute to pass a structure or function pointer for
+ * each entry.
+ */
+const struct soc_device_attribute *soc_device_match(
+ const struct soc_device_attribute *matches)
+{
+ int ret = 0;
+
+ if (!matches)
+ return NULL;
+
+ while (!ret) {
+ if (!(matches->machine || matches->family ||
+ matches->revision || matches->soc_id))
+ break;
+ ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
+ soc_device_match_one);
+ if (!ret)
+ matches++;
+ else
+ return matches;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(soc_device_match);
diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
index 2739ccb69571..9f5eb06f9fd8 100644
--- a/include/linux/sys_soc.h
+++ b/include/linux/sys_soc.h
@@ -13,6 +13,7 @@ struct soc_device_attribute {
const char *family;
const char *revision;
const char *soc_id;
+ const void *data;
};
/**
@@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_device *soc_dev);
*/
struct device *soc_device_to_device(struct soc_device *soc);
+const struct soc_device_attribute *soc_device_match(
+ const struct soc_device_attribute *matches);
#endif /* __SOC_BUS_H */
--
2.11.1