* [PATCH v3 1/2] Driver core: add bus_find_device_by_fwnode
From: Silesh C V @ 2018-10-09 10:17 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki
Cc: linux-kernel, linux-arm-kernel, linux-i2c, linux-rdma, netdev,
devicetree, linux-spi, Mathieu Poirier, Wolfram Sang, Lijun Ou,
Wei Hu(Xavier), Yisen Zhuang, Salil Mehta, Srinivas Kandagatla,
Andrew Lunn, Florian Fainelli, Rob Herring, Frank Rowand,
Mark Brown, David S. Miller, Silesh C V
Some drivers need to find the device on a bus having a specific firmware
node. Currently, such drivers have their own implementations to do this.
Provide a helper similar to bus_find_device_by_name so that each driver
does not have to reinvent this.
Signed-off-by: Silesh C V <svellattu@mvista.com>
---
Changes since v2:
- make use of dev_fwnode in match_fwnode.
drivers/base/bus.c | 20 ++++++++++++++++++++
include/linux/device.h | 3 +++
2 files changed, 23 insertions(+)
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 8bfd27e..a2f39db 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -17,6 +17,7 @@
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/property.h>
#include "base.h"
#include "power/power.h"
@@ -373,6 +374,25 @@ struct device *bus_find_device_by_name(struct bus_type *bus,
}
EXPORT_SYMBOL_GPL(bus_find_device_by_name);
+static int match_fwnode(struct device *dev, void *fwnode)
+{
+ return dev_fwnode(dev) == fwnode;
+}
+
+/**
+ * bus_find_device_by_fwnode - device iterator for locating a particular device
+ * having a specific firmware node
+ * @bus: bus type
+ * @start: Device to begin with
+ * @fwnode: firmware node of the device to match
+ */
+struct device *bus_find_device_by_fwnode(struct bus_type *bus, struct device *start,
+ struct fwnode_handle *fwnode)
+{
+ return bus_find_device(bus, start, (void *)fwnode, match_fwnode);
+}
+EXPORT_SYMBOL_GPL(bus_find_device_by_fwnode);
+
/**
* subsys_find_device_by_id - find a device with a specific enumeration number
* @subsys: subsystem
diff --git a/include/linux/device.h b/include/linux/device.h
index 8f88254..09384f6 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -171,6 +171,9 @@ struct device *bus_find_device(struct bus_type *bus, struct device *start,
struct device *bus_find_device_by_name(struct bus_type *bus,
struct device *start,
const char *name);
+struct device *bus_find_device_by_fwnode(struct bus_type *bus,
+ struct device *start,
+ struct fwnode_handle *fwnode);
struct device *subsys_find_device_by_id(struct bus_type *bus, unsigned int id,
struct device *hint);
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
--
1.9.1
^ permalink raw reply related
* [PATCH v3 2/2] treewide: use bus_find_device_by_fwnode
From: Silesh C V @ 2018-10-09 10:17 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki
Cc: linux-kernel, linux-arm-kernel, linux-i2c, linux-rdma, netdev,
devicetree, linux-spi, Mathieu Poirier, Wolfram Sang, Lijun Ou,
Wei Hu(Xavier), Yisen Zhuang, Salil Mehta, Srinivas Kandagatla,
Andrew Lunn, Florian Fainelli, Rob Herring, Frank Rowand,
Mark Brown, David S. Miller, Silesh C V
In-Reply-To: <1539080245-25818-1-git-send-email-svellattu@mvista.com>
Use bus_find_device_by_fwnode helper to find the device having a
specific firmware node on a bus.
Signed-off-by: Silesh C V <svellattu@mvista.com>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changes since v2:
- Add Reviewed-by tags
drivers/hwtracing/coresight/of_coresight.c | 14 ++++----------
drivers/i2c/i2c-core-of.c | 9 ++-------
drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 8 +-------
drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c | 8 +-------
drivers/nvmem/core.c | 7 +------
drivers/of/of_mdio.c | 8 +-------
drivers/of/platform.c | 7 +------
drivers/spi/spi.c | 10 +++-------
8 files changed, 14 insertions(+), 57 deletions(-)
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
index 6880bee..8193b50 100644
--- a/drivers/hwtracing/coresight/of_coresight.c
+++ b/drivers/hwtracing/coresight/of_coresight.c
@@ -17,12 +17,6 @@
#include <linux/cpumask.h>
#include <asm/smp_plat.h>
-
-static int of_dev_node_match(struct device *dev, void *data)
-{
- return dev->of_node == data;
-}
-
static struct device *
of_coresight_get_endpoint_device(struct device_node *endpoint)
{
@@ -32,8 +26,8 @@ static int of_dev_node_match(struct device *dev, void *data)
* If we have a non-configurable replicator, it will be found on the
* platform bus.
*/
- dev = bus_find_device(&platform_bus_type, NULL,
- endpoint, of_dev_node_match);
+ dev = bus_find_device_by_fwnode(&platform_bus_type, NULL,
+ &endpoint->fwnode);
if (dev)
return dev;
@@ -41,8 +35,8 @@ static int of_dev_node_match(struct device *dev, void *data)
* We have a configurable component - circle through the AMBA bus
* looking for the device that matches the endpoint node.
*/
- return bus_find_device(&amba_bustype, NULL,
- endpoint, of_dev_node_match);
+ return bus_find_device_by_fwnode(&amba_bustype, NULL,
+ &endpoint->fwnode);
}
static void of_coresight_get_ports(const struct device_node *node,
diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
index 6cb7ad6..2b8ef8d 100644
--- a/drivers/i2c/i2c-core-of.c
+++ b/drivers/i2c/i2c-core-of.c
@@ -116,18 +116,13 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
of_node_put(bus);
}
-static int of_dev_node_match(struct device *dev, void *data)
-{
- return dev->of_node == data;
-}
-
/* must call put_device() when done with returned i2c_client device */
struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
{
struct device *dev;
struct i2c_client *client;
- dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
+ dev = bus_find_device_by_fwnode(&i2c_bus_type, NULL, &node->fwnode);
if (!dev)
return NULL;
@@ -145,7 +140,7 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
struct device *dev;
struct i2c_adapter *adapter;
- dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
+ dev = bus_find_device_by_fwnode(&i2c_bus_type, NULL, &node->fwnode);
if (!dev)
return NULL;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
index 081aa91..b0d418e 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
@@ -4832,19 +4832,13 @@ static void hns_roce_v1_cleanup_eq_table(struct hns_roce_dev *hr_dev)
};
MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match);
-static int hns_roce_node_match(struct device *dev, void *fwnode)
-{
- return dev->fwnode == fwnode;
-}
-
static struct
platform_device *hns_roce_find_pdev(struct fwnode_handle *fwnode)
{
struct device *dev;
/* get the 'device' corresponding to the matching 'fwnode' */
- dev = bus_find_device(&platform_bus_type, NULL,
- fwnode, hns_roce_node_match);
+ dev = bus_find_device_by_fwnode(&platform_bus_type, NULL, fwnode);
/* get the platform device */
return dev ? to_platform_device(dev) : NULL;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
index 16294cd..d5d7c88 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
@@ -758,17 +758,11 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
return (void *)misc_op;
}
-static int hns_dsaf_dev_match(struct device *dev, void *fwnode)
-{
- return dev->fwnode == fwnode;
-}
-
struct
platform_device *hns_dsaf_find_platform_device(struct fwnode_handle *fwnode)
{
struct device *dev;
- dev = bus_find_device(&platform_bus_type, NULL,
- fwnode, hns_dsaf_dev_match);
+ dev = bus_find_device_by_fwnode(&platform_bus_type, NULL, fwnode);
return dev ? to_platform_device(dev) : NULL;
}
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index aa16578..b62f236 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -262,11 +262,6 @@ static void nvmem_release(struct device *dev)
.name = "nvmem",
};
-static int of_nvmem_match(struct device *dev, void *nvmem_np)
-{
- return dev->of_node == nvmem_np;
-}
-
static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
{
struct device *d;
@@ -274,7 +269,7 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
if (!nvmem_np)
return NULL;
- d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match);
+ d = bus_find_device_by_fwnode(&nvmem_bus_type, NULL, &nvmem_np->fwnode);
if (!d)
return NULL;
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index e92391d..2906a6b 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -282,12 +282,6 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
}
EXPORT_SYMBOL(of_mdiobus_register);
-/* Helper function for of_phy_find_device */
-static int of_phy_match(struct device *dev, void *phy_np)
-{
- return dev->of_node == phy_np;
-}
-
/**
* of_phy_find_device - Give a PHY node, find the phy_device
* @phy_np: Pointer to the phy's device tree node
@@ -303,7 +297,7 @@ struct phy_device *of_phy_find_device(struct device_node *phy_np)
if (!phy_np)
return NULL;
- d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match);
+ d = bus_find_device_by_fwnode(&mdio_bus_type, NULL, &phy_np->fwnode);
if (d) {
mdiodev = to_mdio_device(d);
if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY)
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 6c59673..36dd58e 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -37,11 +37,6 @@
{} /* Empty terminated list */
};
-static int of_dev_node_match(struct device *dev, void *data)
-{
- return dev->of_node == data;
-}
-
/**
* of_find_device_by_node - Find the platform_device associated with a node
* @np: Pointer to device tree node
@@ -55,7 +50,7 @@ struct platform_device *of_find_device_by_node(struct device_node *np)
{
struct device *dev;
- dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match);
+ dev = bus_find_device_by_fwnode(&platform_bus_type, NULL, &np->fwnode);
return dev ? to_platform_device(dev) : NULL;
}
EXPORT_SYMBOL(of_find_device_by_node);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 9da0bc5..97128a5 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -3324,16 +3324,12 @@ int spi_write_then_read(struct spi_device *spi,
/*-------------------------------------------------------------------------*/
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
-static int __spi_of_device_match(struct device *dev, void *data)
-{
- return dev->of_node == data;
-}
-
/* must call put_device() when done with returned spi_device device */
static struct spi_device *of_find_spi_device_by_node(struct device_node *node)
{
- struct device *dev = bus_find_device(&spi_bus_type, NULL, node,
- __spi_of_device_match);
+ struct device *dev = bus_find_device_by_fwnode(&spi_bus_type, NULL,
+ &node->fwnode);
+
return dev ? to_spi_device(dev) : NULL;
}
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v3 1/2] Driver core: add bus_find_device_by_fwnode
From: Rafael J. Wysocki @ 2018-10-09 10:20 UTC (permalink / raw)
To: svellattu
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Linux Kernel Mailing List,
Linux ARM, linux-i2c, linux-rdma, netdev,
devicetree@vger.kernel.org, linux-spi, Mathieu Poirier,
Wolfram Sang, oulijun, xavier.huwei, yisen.zhuang, salil.mehta,
srinivas.kandagatla, Andrew Lunn, Florian Fainelli, Rob Herring,
Frank Rowand, Mark Brown
In-Reply-To: <1539080245-25818-1-git-send-email-svellattu@mvista.com>
On Tue, Oct 9, 2018 at 12:18 PM Silesh C V <svellattu@mvista.com> wrote:
>
> Some drivers need to find the device on a bus having a specific firmware
> node. Currently, such drivers have their own implementations to do this.
> Provide a helper similar to bus_find_device_by_name so that each driver
> does not have to reinvent this.
>
> Signed-off-by: Silesh C V <svellattu@mvista.com>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> Changes since v2:
> - make use of dev_fwnode in match_fwnode.
>
> drivers/base/bus.c | 20 ++++++++++++++++++++
> include/linux/device.h | 3 +++
> 2 files changed, 23 insertions(+)
>
> diff --git a/drivers/base/bus.c b/drivers/base/bus.c
> index 8bfd27e..a2f39db 100644
> --- a/drivers/base/bus.c
> +++ b/drivers/base/bus.c
> @@ -17,6 +17,7 @@
> #include <linux/string.h>
> #include <linux/mutex.h>
> #include <linux/sysfs.h>
> +#include <linux/property.h>
> #include "base.h"
> #include "power/power.h"
>
> @@ -373,6 +374,25 @@ struct device *bus_find_device_by_name(struct bus_type *bus,
> }
> EXPORT_SYMBOL_GPL(bus_find_device_by_name);
>
> +static int match_fwnode(struct device *dev, void *fwnode)
> +{
> + return dev_fwnode(dev) == fwnode;
> +}
> +
> +/**
> + * bus_find_device_by_fwnode - device iterator for locating a particular device
> + * having a specific firmware node
> + * @bus: bus type
> + * @start: Device to begin with
> + * @fwnode: firmware node of the device to match
> + */
> +struct device *bus_find_device_by_fwnode(struct bus_type *bus, struct device *start,
> + struct fwnode_handle *fwnode)
> +{
> + return bus_find_device(bus, start, (void *)fwnode, match_fwnode);
> +}
> +EXPORT_SYMBOL_GPL(bus_find_device_by_fwnode);
> +
> /**
> * subsys_find_device_by_id - find a device with a specific enumeration number
> * @subsys: subsystem
> diff --git a/include/linux/device.h b/include/linux/device.h
> index 8f88254..09384f6 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -171,6 +171,9 @@ struct device *bus_find_device(struct bus_type *bus, struct device *start,
> struct device *bus_find_device_by_name(struct bus_type *bus,
> struct device *start,
> const char *name);
> +struct device *bus_find_device_by_fwnode(struct bus_type *bus,
> + struct device *start,
> + struct fwnode_handle *fwnode);
> struct device *subsys_find_device_by_id(struct bus_type *bus, unsigned int id,
> struct device *hint);
> int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
> --
> 1.9.1
>
^ permalink raw reply
* Re: [PATCH v3 1/2] Driver core: add bus_find_device_by_fwnode
From: Rafael J. Wysocki @ 2018-10-09 17:39 UTC (permalink / raw)
To: Mathieu Poirier
Cc: svellattu, Greg Kroah-Hartman, Rafael J. Wysocki,
Linux Kernel Mailing List, Linux ARM, linux-i2c, linux-rdma,
netdev, devicetree@vger.kernel.org, linux-spi, Wolfram Sang,
oulijun, xavier.huwei, yisen.zhuang, salil.mehta,
Srini Kandagatla, Andrew Lunn, Florian Fainelli, Rob Herring,
Frank Rowand, Mark Brown <broonie
In-Reply-To: <20181009172726.GA2182@xps15>
On Tue, Oct 9, 2018 at 7:27 PM Mathieu Poirier
<mathieu.poirier@linaro.org> wrote:
>
> Hi Silesh,
>
> On Tue, Oct 09, 2018 at 03:47:24PM +0530, Silesh C V wrote:
> > Some drivers need to find the device on a bus having a specific firmware
> > node. Currently, such drivers have their own implementations to do this.
> > Provide a helper similar to bus_find_device_by_name so that each driver
> > does not have to reinvent this.
> >
> > Signed-off-by: Silesh C V <svellattu@mvista.com>
> > ---
> > Changes since v2:
> > - make use of dev_fwnode in match_fwnode.
> >
> > drivers/base/bus.c | 20 ++++++++++++++++++++
> > include/linux/device.h | 3 +++
> > 2 files changed, 23 insertions(+)
> >
> > diff --git a/drivers/base/bus.c b/drivers/base/bus.c
> > index 8bfd27e..a2f39db 100644
> > --- a/drivers/base/bus.c
> > +++ b/drivers/base/bus.c
> > @@ -17,6 +17,7 @@
> > #include <linux/string.h>
> > #include <linux/mutex.h>
> > #include <linux/sysfs.h>
> > +#include <linux/property.h>
> > #include "base.h"
> > #include "power/power.h"
> >
> > @@ -373,6 +374,25 @@ struct device *bus_find_device_by_name(struct bus_type *bus,
> > }
> > EXPORT_SYMBOL_GPL(bus_find_device_by_name);
> >
> > +static int match_fwnode(struct device *dev, void *fwnode)
> > +{
> > + return dev_fwnode(dev) == fwnode;
> > +}
> > +
> > +/**
> > + * bus_find_device_by_fwnode - device iterator for locating a particular device
> > + * having a specific firmware node
> > + * @bus: bus type
> > + * @start: Device to begin with
> > + * @fwnode: firmware node of the device to match
> > + */
> > +struct device *bus_find_device_by_fwnode(struct bus_type *bus, struct device *start,
> > + struct fwnode_handle *fwnode)
>
> I get the following when running checkpatch on your set:
>
> mpoirier@xps15:~/work/linaro/coresight/kernel-maint$ ./scripts/checkpatch.pl
> 0001-Driver-core-add-bus_find_device_by_fwnode.patch
> WARNING: line over 80 characters
Lines longer than 80 chars often are legitimate. No need to send
extra reports about those cases in general.
Thanks,
Rafael
^ permalink raw reply
* Re: [PATCH v3 2/2] treewide: use bus_find_device_by_fwnode
From: Mathieu Poirier @ 2018-10-09 17:44 UTC (permalink / raw)
To: Silesh C V
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, linux-kernel,
linux-arm-kernel, linux-i2c, linux-rdma, netdev, devicetree,
linux-spi, Wolfram Sang, Lijun Ou, Wei Hu(Xavier), Yisen Zhuang,
Salil Mehta, Srinivas Kandagatla, Andrew Lunn, Florian Fainelli,
Rob Herring, Frank Rowand, Mark Brown, David S. Miller
In-Reply-To: <1539080245-25818-2-git-send-email-svellattu@mvista.com>
On Tue, Oct 09, 2018 at 03:47:25PM +0530, Silesh C V wrote:
> Use bus_find_device_by_fwnode helper to find the device having a
> specific firmware node on a bus.
>
> Signed-off-by: Silesh C V <svellattu@mvista.com>
> Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> Changes since v2:
> - Add Reviewed-by tags
>
> drivers/hwtracing/coresight/of_coresight.c | 14 ++++----------
> drivers/i2c/i2c-core-of.c | 9 ++-------
> drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 8 +-------
> drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c | 8 +-------
> drivers/nvmem/core.c | 7 +------
> drivers/of/of_mdio.c | 8 +-------
> drivers/of/platform.c | 7 +------
> drivers/spi/spi.c | 10 +++-------
> 8 files changed, 14 insertions(+), 57 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
> index 6880bee..8193b50 100644
> --- a/drivers/hwtracing/coresight/of_coresight.c
> +++ b/drivers/hwtracing/coresight/of_coresight.c
> @@ -17,12 +17,6 @@
> #include <linux/cpumask.h>
> #include <asm/smp_plat.h>
>
> -
> -static int of_dev_node_match(struct device *dev, void *data)
> -{
> - return dev->of_node == data;
> -}
> -
> static struct device *
> of_coresight_get_endpoint_device(struct device_node *endpoint)
> {
> @@ -32,8 +26,8 @@ static int of_dev_node_match(struct device *dev, void *data)
> * If we have a non-configurable replicator, it will be found on the
> * platform bus.
> */
> - dev = bus_find_device(&platform_bus_type, NULL,
> - endpoint, of_dev_node_match);
> + dev = bus_find_device_by_fwnode(&platform_bus_type, NULL,
> + &endpoint->fwnode);
> if (dev)
> return dev;
>
> @@ -41,8 +35,8 @@ static int of_dev_node_match(struct device *dev, void *data)
> * We have a configurable component - circle through the AMBA bus
> * looking for the device that matches the endpoint node.
> */
> - return bus_find_device(&amba_bustype, NULL,
> - endpoint, of_dev_node_match);
> + return bus_find_device_by_fwnode(&amba_bustype, NULL,
> + &endpoint->fwnode);
This doesn't apply on linux-next. This late in the cycle you may want to rebase
your work on that tree.
Otherwise and for the coresight part:
Tested-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Mathieu
> }
>
> static void of_coresight_get_ports(const struct device_node *node,
> diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
> index 6cb7ad6..2b8ef8d 100644
> --- a/drivers/i2c/i2c-core-of.c
> +++ b/drivers/i2c/i2c-core-of.c
> @@ -116,18 +116,13 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
> of_node_put(bus);
> }
>
> -static int of_dev_node_match(struct device *dev, void *data)
> -{
> - return dev->of_node == data;
> -}
> -
> /* must call put_device() when done with returned i2c_client device */
> struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
> {
> struct device *dev;
> struct i2c_client *client;
>
> - dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
> + dev = bus_find_device_by_fwnode(&i2c_bus_type, NULL, &node->fwnode);
> if (!dev)
> return NULL;
>
> @@ -145,7 +140,7 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
> struct device *dev;
> struct i2c_adapter *adapter;
>
> - dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
> + dev = bus_find_device_by_fwnode(&i2c_bus_type, NULL, &node->fwnode);
> if (!dev)
> return NULL;
>
> diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
> index 081aa91..b0d418e 100644
> --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
> +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
> @@ -4832,19 +4832,13 @@ static void hns_roce_v1_cleanup_eq_table(struct hns_roce_dev *hr_dev)
> };
> MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match);
>
> -static int hns_roce_node_match(struct device *dev, void *fwnode)
> -{
> - return dev->fwnode == fwnode;
> -}
> -
> static struct
> platform_device *hns_roce_find_pdev(struct fwnode_handle *fwnode)
> {
> struct device *dev;
>
> /* get the 'device' corresponding to the matching 'fwnode' */
> - dev = bus_find_device(&platform_bus_type, NULL,
> - fwnode, hns_roce_node_match);
> + dev = bus_find_device_by_fwnode(&platform_bus_type, NULL, fwnode);
> /* get the platform device */
> return dev ? to_platform_device(dev) : NULL;
> }
> diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
> index 16294cd..d5d7c88 100644
> --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
> +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
> @@ -758,17 +758,11 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
> return (void *)misc_op;
> }
>
> -static int hns_dsaf_dev_match(struct device *dev, void *fwnode)
> -{
> - return dev->fwnode == fwnode;
> -}
> -
> struct
> platform_device *hns_dsaf_find_platform_device(struct fwnode_handle *fwnode)
> {
> struct device *dev;
>
> - dev = bus_find_device(&platform_bus_type, NULL,
> - fwnode, hns_dsaf_dev_match);
> + dev = bus_find_device_by_fwnode(&platform_bus_type, NULL, fwnode);
> return dev ? to_platform_device(dev) : NULL;
> }
> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> index aa16578..b62f236 100644
> --- a/drivers/nvmem/core.c
> +++ b/drivers/nvmem/core.c
> @@ -262,11 +262,6 @@ static void nvmem_release(struct device *dev)
> .name = "nvmem",
> };
>
> -static int of_nvmem_match(struct device *dev, void *nvmem_np)
> -{
> - return dev->of_node == nvmem_np;
> -}
> -
> static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
> {
> struct device *d;
> @@ -274,7 +269,7 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
> if (!nvmem_np)
> return NULL;
>
> - d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match);
> + d = bus_find_device_by_fwnode(&nvmem_bus_type, NULL, &nvmem_np->fwnode);
>
> if (!d)
> return NULL;
> diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
> index e92391d..2906a6b 100644
> --- a/drivers/of/of_mdio.c
> +++ b/drivers/of/of_mdio.c
> @@ -282,12 +282,6 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
> }
> EXPORT_SYMBOL(of_mdiobus_register);
>
> -/* Helper function for of_phy_find_device */
> -static int of_phy_match(struct device *dev, void *phy_np)
> -{
> - return dev->of_node == phy_np;
> -}
> -
> /**
> * of_phy_find_device - Give a PHY node, find the phy_device
> * @phy_np: Pointer to the phy's device tree node
> @@ -303,7 +297,7 @@ struct phy_device *of_phy_find_device(struct device_node *phy_np)
> if (!phy_np)
> return NULL;
>
> - d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match);
> + d = bus_find_device_by_fwnode(&mdio_bus_type, NULL, &phy_np->fwnode);
> if (d) {
> mdiodev = to_mdio_device(d);
> if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY)
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index 6c59673..36dd58e 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -37,11 +37,6 @@
> {} /* Empty terminated list */
> };
>
> -static int of_dev_node_match(struct device *dev, void *data)
> -{
> - return dev->of_node == data;
> -}
> -
> /**
> * of_find_device_by_node - Find the platform_device associated with a node
> * @np: Pointer to device tree node
> @@ -55,7 +50,7 @@ struct platform_device *of_find_device_by_node(struct device_node *np)
> {
> struct device *dev;
>
> - dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match);
> + dev = bus_find_device_by_fwnode(&platform_bus_type, NULL, &np->fwnode);
> return dev ? to_platform_device(dev) : NULL;
> }
> EXPORT_SYMBOL(of_find_device_by_node);
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 9da0bc5..97128a5 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -3324,16 +3324,12 @@ int spi_write_then_read(struct spi_device *spi,
> /*-------------------------------------------------------------------------*/
>
> #if IS_ENABLED(CONFIG_OF_DYNAMIC)
> -static int __spi_of_device_match(struct device *dev, void *data)
> -{
> - return dev->of_node == data;
> -}
> -
> /* must call put_device() when done with returned spi_device device */
> static struct spi_device *of_find_spi_device_by_node(struct device_node *node)
> {
> - struct device *dev = bus_find_device(&spi_bus_type, NULL, node,
> - __spi_of_device_match);
> + struct device *dev = bus_find_device_by_fwnode(&spi_bus_type, NULL,
> + &node->fwnode);
> +
> return dev ? to_spi_device(dev) : NULL;
> }
>
> --
> 1.9.1
>
^ permalink raw reply
* [PATCH v2 1/2] net/ncsi: Add NCSI Broadcom OEM command
From: Vijay Khemka @ 2018-10-09 17:48 UTC (permalink / raw)
To: Samuel Mendoza-Jonas, David S. Miller, netdev, linux-kernel
Cc: vijaykhemka, openbmc @ lists . ozlabs . org, Justin.Lee1, joel,
linux-aspeed
This patch adds OEM Broadcom commands and response handling. It also
defines OEM Get MAC Address handler to get and configure the device.
ncsi_oem_gma_handler_bcm: This handler send NCSI broadcom command for
getting mac address.
ncsi_rsp_handler_oem_bcm: This handles response received for all
broadcom OEM commands.
ncsi_rsp_handler_oem_bcm_gma: This handles get mac address response and
set it to device.
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
---
net/ncsi/Kconfig | 6 ++++
net/ncsi/internal.h | 8 +++++
net/ncsi/ncsi-manage.c | 70 +++++++++++++++++++++++++++++++++++++++++-
net/ncsi/ncsi-pkt.h | 8 +++++
net/ncsi/ncsi-rsp.c | 40 +++++++++++++++++++++++-
5 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/net/ncsi/Kconfig b/net/ncsi/Kconfig
index 08a8a6031fd7..7f2b46108a24 100644
--- a/net/ncsi/Kconfig
+++ b/net/ncsi/Kconfig
@@ -10,3 +10,9 @@ config NET_NCSI
support. Enable this only if your system connects to a network
device via NCSI and the ethernet driver you're using supports
the protocol explicitly.
+config NCSI_OEM_CMD_GET_MAC
+ bool "Get NCSI OEM MAC Address"
+ depends on NET_NCSI
+ ---help---
+ This allows to get MAC address from NCSI firmware and set them back to
+ controller.
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 3d0a33b874f5..45883b32790e 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -71,6 +71,13 @@ enum {
/* OEM Vendor Manufacture ID */
#define NCSI_OEM_MFR_MLX_ID 0x8119
#define NCSI_OEM_MFR_BCM_ID 0x113d
+/* Broadcom specific OEM Command */
+#define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */
+/* OEM Command payload lengths*/
+#define NCSI_OEM_BCM_CMD_GMA_LEN 12
+/* Mac address offset in OEM response */
+#define BCM_MAC_ADDR_OFFSET 28
+
struct ncsi_channel_version {
u32 version; /* Supported BCD encoded NCSI version */
@@ -240,6 +247,7 @@ enum {
ncsi_dev_state_probe_dp,
ncsi_dev_state_config_sp = 0x0301,
ncsi_dev_state_config_cis,
+ ncsi_dev_state_config_oem_gma,
ncsi_dev_state_config_clear_vids,
ncsi_dev_state_config_svf,
ncsi_dev_state_config_ev,
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 091284760d21..e5bfd9245b5d 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -635,6 +635,39 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc,
return 0;
}
+#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
+
+/* NCSI OEM Command APIs */
+static void ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca)
+{
+ int ret = 0;
+ unsigned char data[NCSI_OEM_BCM_CMD_GMA_LEN];
+
+ nca->payload = NCSI_OEM_BCM_CMD_GMA_LEN;
+
+ memset(data, 0, NCSI_OEM_BCM_CMD_GMA_LEN);
+ *(unsigned int *)data = ntohl(NCSI_OEM_MFR_BCM_ID);
+ data[5] = NCSI_OEM_BCM_CMD_GMA;
+
+ nca->data = data;
+
+ ret = ncsi_xmit_cmd(nca);
+ if (ret)
+ netdev_err(nca->ndp->ndev.dev,
+ "NCSI: Failed to transmit cmd 0x%x during configure\n",
+ nca->type);
+}
+
+/* OEM Command handlers initialization */
+static struct ncsi_oem_gma_handler {
+ unsigned int mfr_id;
+ void (*handler)(struct ncsi_cmd_arg *nca);
+} ncsi_oem_gma_handlers[] = {
+ { NCSI_OEM_MFR_BCM_ID, ncsi_oem_gma_handler_bcm }
+};
+
+#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
+
static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
{
struct ncsi_dev *nd = &ndp->ndev;
@@ -643,9 +676,10 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
struct ncsi_channel *nc = ndp->active_channel;
struct ncsi_channel *hot_nc = NULL;
struct ncsi_cmd_arg nca;
+ struct ncsi_oem_gma_handler *nch = NULL;
unsigned char index;
unsigned long flags;
- int ret;
+ int ret, i;
nca.ndp = ndp;
nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
@@ -685,6 +719,40 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
goto error;
}
+#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
+ nd->state = ncsi_dev_state_config_oem_gma;
+ break;
+ case ncsi_dev_state_config_oem_gma:
+ nca.type = NCSI_PKT_CMD_OEM;
+ nca.package = np->id;
+ nca.channel = nc->id;
+ ndp->pending_req_num = 1;
+
+ /* Check for manufacturer id and Find the handler */
+ for (i = 0; i < ARRAY_SIZE(ncsi_oem_gma_handlers); i++) {
+ if (ncsi_oem_gma_handlers[i].mfr_id ==
+ nc->version.mf_id) {
+ if (ncsi_oem_gma_handlers[i].handler)
+ nch = &ncsi_oem_gma_handlers[i];
+ else
+ nch = NULL;
+
+ break;
+ }
+ }
+
+ if (!nch) {
+ netdev_err(ndp->ndev.dev, "No handler available for GMA with MFR-ID (0x%x)\n",
+ nc->version.mf_id);
+ nd->state = ncsi_dev_state_config_clear_vids;
+ schedule_work(&ndp->work);
+ break;
+ }
+
+ /* Get Mac address from NCSI device */
+ nch->handler(&nca);
+#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
+
nd->state = ncsi_dev_state_config_clear_vids;
break;
case ncsi_dev_state_config_clear_vids:
diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h
index 0f2087c8d42a..4d3f06be38bd 100644
--- a/net/ncsi/ncsi-pkt.h
+++ b/net/ncsi/ncsi-pkt.h
@@ -165,6 +165,14 @@ struct ncsi_rsp_oem_pkt {
unsigned char data[]; /* Payload data */
};
+/* Broadcom Response Data */
+struct ncsi_rsp_oem_bcm_pkt {
+ unsigned char ver; /* Payload Version */
+ unsigned char type; /* OEM Command type */
+ __be16 len; /* Payload Length */
+ unsigned char data[]; /* Cmd specific Data */
+};
+
/* Get Link Status */
struct ncsi_rsp_gls_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index d66b34749027..31672e967db2 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -596,12 +596,50 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
return 0;
}
+/* Response handler for Broadcom command Get Mac Address */
+static int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr)
+{
+ struct ncsi_rsp_oem_pkt *rsp;
+ struct ncsi_dev_priv *ndp = nr->ndp;
+ struct net_device *ndev = ndp->ndev.dev;
+ int ret = 0;
+ const struct net_device_ops *ops = ndev->netdev_ops;
+ struct sockaddr saddr;
+
+ /* Get the response header */
+ rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
+
+ saddr.sa_family = ndev->type;
+ ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+ memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN);
+ ret = ops->ndo_set_mac_address(ndev, &saddr);
+ if (ret < 0)
+ netdev_warn(ndev, "NCSI: Writing mac address to device failed\n");
+
+ return ret;
+}
+
+/* Response handler for Broadcom card */
+static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr)
+{
+ struct ncsi_rsp_oem_pkt *rsp;
+ struct ncsi_rsp_oem_bcm_pkt *bcm;
+
+ /* Get the response header */
+ rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
+ bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data);
+
+ if (bcm->type == NCSI_OEM_BCM_CMD_GMA)
+ return ncsi_rsp_handler_oem_bcm_gma(nr);
+ return 0;
+}
+
static struct ncsi_rsp_oem_handler {
unsigned int mfr_id;
int (*handler)(struct ncsi_request *nr);
} ncsi_rsp_oem_handlers[] = {
{ NCSI_OEM_MFR_MLX_ID, NULL },
- { NCSI_OEM_MFR_BCM_ID, NULL }
+ { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm }
};
/* Response handler for OEM command */
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v3 1/2] Driver core: add bus_find_device_by_fwnode
From: Mathieu Poirier @ 2018-10-09 17:48 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Silesh C V, Greg KH, Linux Kernel Mailing List, linux-arm-kernel,
linux-i2c, linux-rdma, netdev, devicetree, linux-spi,
Wolfram Sang, Lijun Ou, Wei Hu(Xavier), Yisen Zhuang, Salil Mehta,
Srinivas Kandagatla, Andrew Lunn, Florian Fainelli, Rob Herring,
Frank Rowand, Mark Brown, David Miller <davem@
In-Reply-To: <CAJZ5v0gckkg0jyTc7=JYPpUruQQXL_FhEjm03-0mrFcxH60cHA@mail.gmail.com>
On Tue, 9 Oct 2018 at 11:39, Rafael J. Wysocki <rafael@kernel.org> wrote:
>
> On Tue, Oct 9, 2018 at 7:27 PM Mathieu Poirier
> <mathieu.poirier@linaro.org> wrote:
> >
> > Hi Silesh,
> >
> > On Tue, Oct 09, 2018 at 03:47:24PM +0530, Silesh C V wrote:
> > > Some drivers need to find the device on a bus having a specific firmware
> > > node. Currently, such drivers have their own implementations to do this.
> > > Provide a helper similar to bus_find_device_by_name so that each driver
> > > does not have to reinvent this.
> > >
> > > Signed-off-by: Silesh C V <svellattu@mvista.com>
> > > ---
> > > Changes since v2:
> > > - make use of dev_fwnode in match_fwnode.
> > >
> > > drivers/base/bus.c | 20 ++++++++++++++++++++
> > > include/linux/device.h | 3 +++
> > > 2 files changed, 23 insertions(+)
> > >
> > > diff --git a/drivers/base/bus.c b/drivers/base/bus.c
> > > index 8bfd27e..a2f39db 100644
> > > --- a/drivers/base/bus.c
> > > +++ b/drivers/base/bus.c
> > > @@ -17,6 +17,7 @@
> > > #include <linux/string.h>
> > > #include <linux/mutex.h>
> > > #include <linux/sysfs.h>
> > > +#include <linux/property.h>
> > > #include "base.h"
> > > #include "power/power.h"
> > >
> > > @@ -373,6 +374,25 @@ struct device *bus_find_device_by_name(struct bus_type *bus,
> > > }
> > > EXPORT_SYMBOL_GPL(bus_find_device_by_name);
> > >
> > > +static int match_fwnode(struct device *dev, void *fwnode)
> > > +{
> > > + return dev_fwnode(dev) == fwnode;
> > > +}
> > > +
> > > +/**
> > > + * bus_find_device_by_fwnode - device iterator for locating a particular device
> > > + * having a specific firmware node
> > > + * @bus: bus type
> > > + * @start: Device to begin with
> > > + * @fwnode: firmware node of the device to match
> > > + */
> > > +struct device *bus_find_device_by_fwnode(struct bus_type *bus, struct device *start,
> > > + struct fwnode_handle *fwnode)
> >
> > I get the following when running checkpatch on your set:
> >
> > mpoirier@xps15:~/work/linaro/coresight/kernel-maint$ ./scripts/checkpatch.pl
> > 0001-Driver-core-add-bus_find_device_by_fwnode.patch
> > WARNING: line over 80 characters
>
> Lines longer than 80 chars often are legitimate. No need to send
> extra reports about those cases in general.
In this case I don't see a reason not to abide to the guideline.
Wrapping the function declaration to 80 characters would be easy
without effecting code readability.
Mathieu
>
> Thanks,
> Rafael
^ permalink raw reply
* Re: [RESEND PATCH v2 0/5] net: phy: mscc: add support for VSC8584 and VSC8574 Microsemi quad-port PHYs
From: Paul Burton @ 2018-10-09 17:59 UTC (permalink / raw)
To: Quentin Schulz
Cc: alexandre.belloni@bootlin.com, ralf@linux-mips.org,
jhogan@kernel.org, robh+dt@kernel.org, mark.rutland@arm.com,
davem@davemloft.net, andrew@lunn.ch, f.fainelli@gmail.com,
allan.nielsen@microchip.com, linux-mips@linux-mips.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org, thomas.petazzoni@bootlin.com,
antoine.tenart@bootlin.com
In-Reply-To: <20181008101445.25946-1-quentin.schulz@bootlin.com>
Hi Quentin,
On Mon, Oct 08, 2018 at 12:14:40PM +0200, Quentin Schulz wrote:
> RESEND: rebased on top of latest net-next and on top of latest version of
> "net: phy: mscc: various improvements to Microsemi PHY driver" patch
> series.
>
>%
>
> I suggest patches 1 to 3 go through net tree and patches 4 and 5 go
> through MIPS tree. Patches going through net tree and those going through
> MIPS tree do not depend on one another.
Patches 4 & 5 applied to mips-next for 4.20, thanks!
Paul
^ permalink raw reply
* Re: re iproute2 - don't return error on success fix
From: Or Gerlitz @ 2018-10-09 10:54 UTC (permalink / raw)
To: Phil Sutter, Stephen Hemminger, David Ahern, Linux Netdev List,
Roi Dayan
In-Reply-To: <20181008124141.GB14666@orbyte.nwl.cc>
On Mon, Oct 8, 2018 at 3:41 PM Phil Sutter <phil@nwl.cc> wrote:
> > $ ./tc/tc filter add dev enp33s0f0 protocol ip parent ffff: flower
> > skip_sw ip_flags firstfrag action drop && echo "success" || echo
> > "failed"
> > RTNETLINK answers: Operation not supported
> > success
>
> Interestingly, your output lacks the "We have an error" message mine
> shows. So in your case, the call to rtnl_talk_iov() from
> tc_filter_modify() does not return < 0.
>
> In my case, commands always fail with 'skip_sw' since I only test on a
> dummy interface. So maybe we hit different error paths? Could you please
> check what happens for you in __rtnl_talk_iov()? I guess the "RTNETLINK
> answers:" message should come from rtnl_talk_error(). In my case it does
> at least, and I haven't found an alternative place where that message
> could come from.
I have applied the patch Vlad sent today and it solved the problem:
# ./tc/tc filter add dev enp33s0f0 protocol ip parent ffff: flower
skip_sw ip_flags firstfrag action drop && echo "success" || echo
"failed"
RTNETLINK answers: Operation not supported
We have an error talking to the kernel, -1
failed
^ permalink raw reply
* Re: [PATCH v3 1/2] Driver core: add bus_find_device_by_fwnode
From: Wolfram Sang @ 2018-10-09 11:02 UTC (permalink / raw)
To: Silesh C V
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, linux-kernel,
linux-arm-kernel, linux-i2c, linux-rdma, netdev, devicetree,
linux-spi, Mathieu Poirier, Lijun Ou, Wei Hu(Xavier),
Yisen Zhuang, Salil Mehta, Srinivas Kandagatla, Andrew Lunn,
Florian Fainelli, Rob Herring, Frank Rowand, Mark Brown,
David S. Miller
In-Reply-To: <1539080245-25818-1-git-send-email-svellattu@mvista.com>
[-- Attachment #1: Type: text/plain, Size: 822 bytes --]
On Tue, Oct 09, 2018 at 03:47:24PM +0530, Silesh C V wrote:
> Some drivers need to find the device on a bus having a specific firmware
> node. Currently, such drivers have their own implementations to do this.
> Provide a helper similar to bus_find_device_by_name so that each driver
> does not have to reinvent this.
>
> Signed-off-by: Silesh C V <svellattu@mvista.com>
Looks good in general, however:
We recently had this discussion in I2C world about using the parent if
the (logical) device has a NULL fw_node [1]. I don't know if the other
subsystems you modify use logical devices as well? If no, it seems we
need an additional check for the parent in the I2C core only. If yes,
this might be considered in your patchset?
Thanks,
Wolfram
[1] http://patchwork.ozlabs.org/patch/974584/
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] dt-bindings: Add bindings for aliases node
From: Brian Norris @ 2018-10-09 18:31 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Matthias Kaehlcke, Rob Herring, Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux Kernel Mailing List, linux-wireless, linux-spi, netdev,
swboyd, Florian Fainelli
In-Reply-To: <CAMuHMdWe5JYp5eC2PvuG4xEud908Crhm+BhrtxPJ4Uo1-LCc4g@mail.gmail.com>
On Tue, Oct 09, 2018 at 09:22:07AM +0200, Geert Uytterhoeven wrote:
> Please note these aliases become cumbersome once you start considering
> (dynamic) DT overlays. That's why I made them optional in the sh-sci
> serial driver, cfr. commit 7678f4c20fa7670f ("serial: sh-sci: Add support
> for dynamic instances").
Note that as I understand it, the entire point of documenting this sort
of thing is to help solidify the interface between a DT aware boot
program (e.g., bootloader) and a device tree which is provided
separately, to avoid memorizing node/path hierarchy. It doesn't need to
(and doesn't, as I read it) enforce an OS's device naming policy.
> Relevant parts of the commit description are:
>
> On DT platforms, the sh-sci driver requires the presence of "serialN"
> aliases in DT, from which instance IDs are derived. If a DT alias is
> missing, the drivers fails to probe the corresponding serial port.
>
> This becomes cumbersome when considering DT overlays, as currently
> there is no upstream support for dynamically updating the /aliases node
> in DT.
That part is not a DT spec problem :)
> Furthermore, even in the presence of such support, hardcoded
> instance IDs in independent overlays are prone to conflicts.
>
> Hence add support for dynamic instance IDs, to be used in the absence of
> a DT alias. This makes serial ports behave similar to I2C and SPI
> buses, which already support dynamic instances.
This seems to be a much different sort of problem. People always love
having predictable IDs given by the OS (myself included), but that's
just plain hard to do and impossible in some cases. I don't think that's
what this document is about though.
IOW, this document seems pretty consistent with the above: it doesn't
require the usage of aliases (and it seems silly to have a driver
*require* an alias) -- it just documents how one should name such an
alias if you expect multiple independent software components to
understand it.
> To clarify my point: R-Car M2-W has 4 different types of serial ports, for a
> total of 18 ports, and the two ports on a board labeled 0 and 1 may not
> correspond to the physical first two ports (what's "first" in a collection of
> 4 different types?).
>
> Aliases may be fine for referring to the main serial console (labeled
> port 0 on the device, too), and the primary Ethernet interface (so U-Boot
> knows where to add the "local-mac-address" property), but beyond that,
> I think they should be avoided.
That's fair enough. Just because the solution isn't an all-purpose tool
doesn't mean it shouldn't be documented. The general concept is already
in ePAPR, but it's just not very specific about property names.
> Just my two^H^H^Hfive €c.
Thanks,
Brian
>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v3 net-next] ravb: do not write 1 to reserved bits
From: Simon Horman @ 2018-10-09 11:53 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Sergei Shtylyov, David S. Miller, Magnus Damm, netdev,
Linux-Renesas
In-Reply-To: <CAMuHMdU_6uBpHOFshgxc61GOG1o1ibAoi5T1n_ZdYZ+=i8H5Sw@mail.gmail.com>
On Tue, Oct 09, 2018 at 11:28:40AM +0200, Geert Uytterhoeven wrote:
> Hi Sergei,
>
> On Tue, Sep 18, 2018 at 6:55 PM Sergei Shtylyov
> <sergei.shtylyov@cogentembedded.com> wrote:
> > On 09/18/2018 01:22 PM, Simon Horman wrote:
> > > From: Kazuya Mizuguchi <kazuya.mizuguchi.ks@renesas.com>
> > > EtherAVB hardware requires 0 to be written to status register bits in
> > > order to clear them, however, care must be taken not to:
> > >
> > > 1. Clear other bits, by writing zero to them
> > > 2. Write one to reserved bits
> > >
> > > This patch corrects the ravb driver with respect to the second point above.
> > > This is done by defining reserved bit masks for the affected registers and,
> > > after auditing the code, ensure all sites that may write a one to a
> > > reserved bit use are suitably masked.
> > >
> > > Signed-off-by: Kazuya Mizuguchi <kazuya.mizuguchi.ks@renesas.com>
> > > Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> > [...]
> >
> > Reviewed-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> >
> > > diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
> > > index 1470fc12282b..9b6bf557a2f5 100644
> > > --- a/drivers/net/ethernet/renesas/ravb.h
> > > +++ b/drivers/net/ethernet/renesas/ravb.h
> > > @@ -428,6 +428,7 @@ enum EIS_BIT {
> > > EIS_CULF1 = 0x00000080,
> > > EIS_TFFF = 0x00000100,
> > > EIS_QFS = 0x00010000,
> > > + EIS_RESERVED = (GENMASK(31, 17) | GENMASK(15, 11)),
> >
> > Well, I'm not a big fan of BIT() and GENMASK() -- they still lack a macro
> > to #define a bit/field value. But if you prefer to use them, OK, let's be so...
>
> FIELD_PREP()?
>
> Perhaps the other bit definitions should be converted to BIT()?
> That way it becomes much easier to match valid EIS_* bits with EIS_RESERVED.
+1
^ permalink raw reply
* Re: [PATCH v8 10/15] octeontx2-af: Reconfig MSIX base with IOVA
From: Arnd Bergmann @ 2018-10-09 12:00 UTC (permalink / raw)
To: Sunil Kovvuri; +Cc: Networking, David Miller, linux-soc, gakula, sgoutham
In-Reply-To: <CA+sq2Cc_oxj6cexz1XuJ02vSvPEdjxRcetig5Z0tceHvEWWNig@mail.gmail.com>
On Tue, Oct 9, 2018 at 11:20 AM Sunil Kovvuri <sunil.kovvuri@gmail.com> wrote:
>
> On Tue, Oct 9, 2018 at 1:27 PM Arnd Bergmann <arnd@arndb.de> wrote:
> >
> > On Tue, Oct 9, 2018 at 9:03 AM Sunil Kovvuri <sunil.kovvuri@gmail.com> wrote:
> > > On Mon, Oct 8, 2018 at 5:38 PM Arnd Bergmann <arnd@arndb.de> wrote:
> > > > On Sun, Oct 7, 2018 at 5:01 PM <sunil.kovvuri@gmail.com> wrote:
> > I think if you enable CONFIG_DEBUG_VIRTUAL, the virt_to_page()
> > above should trigger a warning in
> >
> > phys_addr_t __virt_to_phys(unsigned long x)
> > {
> > WARN(!__is_lm_address(x),
> > "virt_to_phys used for non-linear address: %pK (%pS)\n",
> > (void *)x,
> > (void *)x);
> >
> > return __virt_to_phys_nodebug(x);
> > }
> >
> > Can you verify that?
> >
> > Arnd
>
> No, it isn't, as for 64bit systems CONFIG_SPARSEMEM_VMEMMAP is enabled.
But that is also user-selectable, right? It still seems to be really
fragile to rely on non-documented behavior of virt_to_phys()
here, if that only works for some configurations.
> But is there any alternative to what is being done ?
I'm not completely sure, but there may be a way to do this correctly
using the iommu API instead of the dma-mapping API. What you do
here is fairly rare, but not unprecedented.
Arnd
^ permalink raw reply
* Re: [PATCH] ath10k: htt_rx: Fix signedness bug in ath10k_update_per_peer_tx_stats
From: Gustavo A. R. Silva @ 2018-10-09 19:19 UTC (permalink / raw)
To: Anilkumar Kolli
Cc: Ben Greear, Kalle Valo, David S. Miller, ath10k, linux-wireless,
netdev, linux-kernel, linux-wireless-owner
In-Reply-To: <af44d03892b3d51df391760af7af0382@codeaurora.org>
>
> I have sent a patch to address this,
> https://patchwork.kernel.org/patch/10611943/
>
That's great.
Thanks for letting me know. :)
--
Gustavo
^ permalink raw reply
* Re: [PATCH net-next] rxrpc: Remove set but not used variable 'ioc'
From: YueHaibing @ 2018-10-09 12:04 UTC (permalink / raw)
To: David Howells; +Cc: davem, linux-afs, netdev, kernel-janitors
In-Reply-To: <11853.1539079996@warthog.procyon.org.uk>
On 2018/10/9 18:13, David Howells wrote:
> YueHaibing <yuehaibing@huawei.com> wrote:
>
>> net/rxrpc/output.c: In function 'rxrpc_reject_packets':
>> net/rxrpc/output.c:527:11: warning:
>> variable 'ioc' set but not used [-Wunused-but-set-variable]
>>
>> It never used since introduction in
>
> I wonder why my compiler doesn't show this warning.
Just use make W=1
>
> Anyway, NAK: just removing the variable is the wrong fix - you need to look at
> the code more closely. The actual fix is to pass it to kernel_sendmsg()
> instead of 2.
I didn't notice this, Thank you for correction.
>
> But thanks anyway! Do you want to respin your patch?
Sure, I will fix it.
>
>> commit ece64fec164f ("rxrpc: Emit BUSY packets when supposed to rather than ABORTs")
>
> Btw, this should be a 'Fixes: <commit> ("subject")' line and the patch needs
> to go to net, not net-next.
>
> David
>
> .
>
^ permalink raw reply
* icmp redirect sent when an active ipsec child_sa exist
From: Marco Berizzi @ 2018-10-09 12:09 UTC (permalink / raw)
To: netdev
Hi Folks,
I'm running strongSwan on Slackware with linux 4.18
This is the output from 'ip route show':
default via isp_router dev eth0 metric 1
10.0.0.0/8 via 10.68.63.3 dev eth1
10.68.63.0/26 dev eth1 proto kernel scope link src 10.68.63.62
127.0.0.0/8 dev lo scope link
172.16.0.0/12 via 10.68.63.3 dev eth1
192.168.0.0/16 via 10.68.63.3 dev eth1
and 'ip a s':
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 [trimmed]
link/ether fc:4d:d4:2e:dc:6a brd ff:ff:ff:ff:ff:ff
inet 10.68.63.62/26 brd 10.68.63.63 scope global eth1
valid_lft forever preferred_lft forever
Connected to the eth1 there is also a 10.68.63.55 host:
the default gateway for this host is 10.68.63.62
This is the relevant configuration from stronSwan:
children {
networks {
local_ts = 10.68.63.54/31
remote_ts = 10.82.43.0/24
start_action = trap
}
}
The value trap installs a trap policy, which is going
to trigger the tunnel as soon as matching traffic will
be detected.
When I issue a ping from 10.68.63.55 host to a 10.82.43.0/24
network's host, I get this behaviour:
12:24:40.219185 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 43, length 64
12:24:41.235072 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 44, length 64
12:24:42.251095 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 45, length 64
12:24:43.267007 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 46, length 64
12:24:44.282948 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 47, length 64
12:24:45.298873 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 48, length 64
12:24:46.314840 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 49, length 64
12:24:47.330767 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 50, length 64
12:24:48.346708 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 51, length 64
12:24:49.362627 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 52, length 64
12:24:49.362686 IP (tos 0xc0, ttl 64, id 11631, offset 0, flags [none], proto ICMP (1), length 112)
10.68.63.62 > 10.68.63.55: ICMP redirect 10.82.43.10 to host 10.68.63.3, length 92
IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 52, length 64
12:24:50.379051 IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 53, length 64
12:24:50.379113 IP (tos 0xc0, ttl 64, id 12190, offset 0, flags [none], proto ICMP (1), length 112)
10.68.63.62 > 10.68.63.55: ICMP redirect 10.82.43.10 to host 10.68.63.3, length 92
IP (tos 0x0, ttl 62, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 53, length 64
12:24:51.398707 IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
10.68.63.55 > 10.82.43.10: ICMP echo request, id 12199, seq 54, length 64
Linux is sending those icmp redirects *after* the
CHILD_SA has been established. When the CHILD_SA
is not yet established linux will not send any icmp
redirect.
Is this the expected behavior?
Obviously if I remove the following static route:
10.0.0.0/8 via 10.68.63.3 dev eth1
linux will not send anymore the icmp redirect.
Any feedback are welcome.
Thanks in advance
^ permalink raw reply
* [PATCH v2 lora-next 0/4] migration to regmap and clk framework
From: Ben Whitten @ 2018-10-09 12:52 UTC (permalink / raw)
To: afaerber; +Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
Ben Whitten
This series completes the sx1301 migration to regmap by replaceing the SPI
burst read and write with regmap raw reads and writes, this solution is a work
around until there is regmap_noinc_read/write API merged as it sepends on the
fact that we have the regcache turned off.
regmap_noinc_read is available in 4.19 however a write varient isn't.
The various fields of the sx1301 are converted to regmap to pass the read
modify write down to the regmap layer and reduce our code.
The downside is that in the cases of the hand optimised multiple field writes
at once within one register, however if it is desirable these can be replaced
with regmap_update_bits.
Apply the same regmap treatment for the radio device and allow it to register as
a clock provider, this clock is enabled when the lora link is brought up as it
is required prior to calibration of the concentrator.
modprobe lora-sx125x
lora-dev: init
sx1301 spi0.0: SX1301 module probed
sx125x_con spi0.0-a: SX125x version: 21
sx125x_con spi0.0-a: SX125x module probed
sx125x_con spi0.0-b: SX125x version: 21
sx125x_con spi0.0-b: registering clkout
sx125x_con spi0.0-b: SX125x module probed
ip link set lora0 up
sx125x_con spi0.0-b: enabling clkout
Ben Whitten (4):
net: lora: sx1301: convert burst spi functions to regmap raw
net: lora: sx1301: convert to using regmap fields for bit ops
net: lora: sx125x: convert to regmap fields
net: lora: sx125x sx1301: allow radio to register as a clk provider
drivers/net/lora/sx125x.c | 159 ++++++++++++++++++++++++++--
drivers/net/lora/sx1301.c | 265 ++++++++++++++++------------------------------
drivers/net/lora/sx1301.h | 50 ++++++++-
3 files changed, 287 insertions(+), 187 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH v2 lora-next 1/4] net: lora: sx1301: convert burst spi functions to regmap raw
From: Ben Whitten @ 2018-10-09 12:52 UTC (permalink / raw)
To: afaerber; +Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
Ben Whitten
In-Reply-To: <1539089532-2481-1-git-send-email-ben.whitten@lairdtech.com>
As we have caching disabled we can access the regmap using raw for our
firmware reading and writing bursts.
We also remove the now defunct spi element from the structure as this
completes the move to regmap.
Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
drivers/net/lora/sx1301.c | 26 +++++++++++++++++---------
drivers/net/lora/sx1301.h | 2 --
2 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index fd29258..5ab0e2d 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -76,19 +76,28 @@ static struct regmap_config sx1301_regmap_config = {
static int sx1301_read_burst(struct sx1301_priv *priv, u8 reg, u8 *val, size_t len)
{
- u8 addr = reg & 0x7f;
- return spi_write_then_read(priv->spi, &addr, 1, val, len);
+ size_t max;
+
+ max = regmap_get_raw_read_max(priv->regmap);
+ if (max && max < len) {
+ dev_err(priv->dev, "Burst greater then max raw read\n");
+ return -EINVAL;
+ }
+
+ return regmap_raw_read(priv->regmap, reg, val, len);
}
static int sx1301_write_burst(struct sx1301_priv *priv, u8 reg, const u8 *val, size_t len)
{
- u8 addr = reg | BIT(7);
- struct spi_transfer xfr[2] = {
- { .tx_buf = &addr, .len = 1 },
- { .tx_buf = val, .len = len },
- };
+ size_t max;
+
+ max = regmap_get_raw_write_max(priv->regmap);
+ if (max && max < len) {
+ dev_err(priv->dev, "Burst greater then max raw write\n");
+ return -EINVAL;
+ }
- return spi_sync_transfer(priv->spi, xfr, 2);
+ return regmap_raw_write(priv->regmap, reg, val, len);
}
static int sx1301_soft_reset(struct sx1301_priv *priv)
@@ -566,7 +575,6 @@ static int sx1301_probe(struct spi_device *spi)
spi_set_drvdata(spi, netdev);
priv->dev = &spi->dev;
- priv->spi = spi;
priv->regmap = devm_regmap_init_spi(spi, &sx1301_regmap_config);
if (IS_ERR(priv->regmap)) {
diff --git a/drivers/net/lora/sx1301.h b/drivers/net/lora/sx1301.h
index e939c02..e6400f8 100644
--- a/drivers/net/lora/sx1301.h
+++ b/drivers/net/lora/sx1301.h
@@ -12,7 +12,6 @@
#include <linux/regmap.h>
#include <linux/gpio/consumer.h>
#include <linux/lora/dev.h>
-#include <linux/spi/spi.h>
#define SX1301_CHIP_VERSION 103
@@ -64,7 +63,6 @@
struct sx1301_priv {
struct lora_dev_priv lora;
struct device *dev;
- struct spi_device *spi;
struct gpio_desc *rst_gpio;
struct regmap *regmap;
};
--
2.7.4
^ permalink raw reply related
* [PATCH v2 lora-next 2/4] net: lora: sx1301: convert to using regmap fields for bit ops
From: Ben Whitten @ 2018-10-09 12:52 UTC (permalink / raw)
To: afaerber; +Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
Ben Whitten
In-Reply-To: <1539089532-2481-1-git-send-email-ben.whitten@lairdtech.com>
From: Ben Whitten <ben.whitten@gmail.com>
We convert to using regmap fields to allow bit access to the registers
where regmap handles the read update write.
Signed-off-by: Ben Whitten <ben.whitten@gmail.com>
---
drivers/net/lora/sx1301.c | 240 +++++++++++++---------------------------------
drivers/net/lora/sx1301.h | 46 +++++++++
2 files changed, 113 insertions(+), 173 deletions(-)
diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index 5ab0e2d..eb89af6 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -24,27 +24,6 @@
#include "sx1301.h"
-#define REG_PAGE_RESET_SOFT_RESET BIT(7)
-
-#define REG_16_GLOBAL_EN BIT(3)
-
-#define REG_17_CLK32M_EN BIT(0)
-
-#define REG_0_105_FORCE_HOST_RADIO_CTRL BIT(1)
-#define REG_0_105_FORCE_HOST_FE_CTRL BIT(2)
-#define REG_0_105_FORCE_DEC_FILTER_GAIN BIT(3)
-
-#define REG_0_MCU_RST_0 BIT(0)
-#define REG_0_MCU_RST_1 BIT(1)
-#define REG_0_MCU_SELECT_MUX_0 BIT(2)
-#define REG_0_MCU_SELECT_MUX_1 BIT(3)
-
-#define REG_2_43_RADIO_A_EN BIT(0)
-#define REG_2_43_RADIO_B_EN BIT(1)
-#define REG_2_43_RADIO_RST BIT(2)
-
-#define REG_EMERGENCY_FORCE_HOST_CTRL BIT(0)
-
static const struct regmap_range_cfg sx1301_regmap_ranges[] = {
{
.name = "Pages",
@@ -74,6 +53,12 @@ static struct regmap_config sx1301_regmap_config = {
.max_register = SX1301_MAX_REGISTER,
};
+static int sx1301_field_write(struct sx1301_priv *priv,
+ enum sx1301_fields field_id, u8 val)
+{
+ return regmap_field_write(priv->regmap_fields[field_id], val);
+}
+
static int sx1301_read_burst(struct sx1301_priv *priv, u8 reg, u8 *val, size_t len)
{
size_t max;
@@ -100,11 +85,6 @@ static int sx1301_write_burst(struct sx1301_priv *priv, u8 reg, const u8 *val, s
return regmap_raw_write(priv->regmap, reg, val, len);
}
-static int sx1301_soft_reset(struct sx1301_priv *priv)
-{
- return regmap_write(priv->regmap, SX1301_PAGE, REG_PAGE_RESET_SOFT_RESET);
-}
-
static int sx1301_agc_ram_read(struct sx1301_priv *priv, u8 addr, unsigned int *val)
{
int ret;
@@ -146,7 +126,7 @@ static int sx1301_arb_ram_read(struct sx1301_priv *priv, u8 addr, unsigned int *
static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct firmware *fw)
{
u8 *buf;
- u8 rst, select_mux;
+ enum sx1301_fields rst, select_mux;
unsigned int val;
int ret;
@@ -157,29 +137,26 @@ static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct
switch (mcu) {
case 0:
- rst = REG_0_MCU_RST_0;
- select_mux = REG_0_MCU_SELECT_MUX_0;
+ rst = F_MCU_RST_0;
+ select_mux = F_MCU_SELECT_MUX_0;
break;
case 1:
- rst = REG_0_MCU_RST_1;
- select_mux = REG_0_MCU_SELECT_MUX_1;
+ rst = F_MCU_RST_1;
+ select_mux = F_MCU_SELECT_MUX_1;
break;
default:
return -EINVAL;
}
- ret = regmap_read(priv->regmap, SX1301_MCU_CTRL, &val);
+ ret = sx1301_field_write(priv, rst, 1);
if (ret) {
- dev_err(priv->dev, "MCU read failed\n");
+ dev_err(priv->dev, "MCU reset failed\n");
return ret;
}
- val |= rst;
- val &= ~select_mux;
-
- ret = regmap_write(priv->regmap, SX1301_MCU_CTRL, val);
+ ret = sx1301_field_write(priv, select_mux, 0);
if (ret) {
- dev_err(priv->dev, "MCU reset / select mux write failed\n");
+ dev_err(priv->dev, "MCU RAM select mux failed\n");
return ret;
}
@@ -220,17 +197,9 @@ static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct
kfree(buf);
- ret = regmap_read(priv->regmap, SX1301_MCU_CTRL, &val);
+ ret = sx1301_field_write(priv, select_mux, 1);
if (ret) {
- dev_err(priv->dev, "MCU read (1) failed\n");
- return ret;
- }
-
- val |= select_mux;
-
- ret = regmap_write(priv->regmap, SX1301_MCU_CTRL, val);
- if (ret) {
- dev_err(priv->dev, "MCU reset / select mux write (1) failed\n");
+ dev_err(priv->dev, "MCU RAM release mux failed\n");
return ret;
}
@@ -256,17 +225,9 @@ static int sx1301_agc_calibrate(struct sx1301_priv *priv)
return ret;
}
- ret = regmap_read(priv->regmap, SX1301_FORCE_CTRL, &val);
+ ret = sx1301_field_write(priv, F_FORCE_HOST_RADIO_CTRL, 0);
if (ret) {
- dev_err(priv->dev, "0|105 read failed\n");
- return ret;
- }
-
- val &= ~REG_0_105_FORCE_HOST_RADIO_CTRL;
-
- ret = regmap_write(priv->regmap, SX1301_FORCE_CTRL, val);
- if (ret) {
- dev_err(priv->dev, "0|105 write failed\n");
+ dev_err(priv->dev, "force host control failed\n");
return ret;
}
@@ -280,17 +241,9 @@ static int sx1301_agc_calibrate(struct sx1301_priv *priv)
return ret;
}
- ret = regmap_read(priv->regmap, SX1301_MCU_CTRL, &val);
+ ret = sx1301_field_write(priv, F_MCU_RST_1, 0);
if (ret) {
- dev_err(priv->dev, "MCU read (0) failed\n");
- return ret;
- }
-
- val &= ~REG_0_MCU_RST_1;
-
- ret = regmap_write(priv->regmap, SX1301_MCU_CTRL, val);
- if (ret) {
- dev_err(priv->dev, "MCU write (0) failed\n");
+ dev_err(priv->dev, "MCU 1 reset failed\n");
return ret;
}
@@ -308,34 +261,18 @@ static int sx1301_agc_calibrate(struct sx1301_priv *priv)
return -ENXIO;
}
- ret = regmap_read(priv->regmap, SX1301_EMERGENCY_FORCE_HOST_CTRL, &val);
+ ret = sx1301_field_write(priv, F_EMERGENCY_FORCE_HOST_CTRL, 0);
if (ret) {
- dev_err(priv->dev, "emergency force read failed\n");
- return ret;
- }
-
- val &= ~REG_EMERGENCY_FORCE_HOST_CTRL;
-
- ret = regmap_write(priv->regmap, SX1301_EMERGENCY_FORCE_HOST_CTRL, val);
- if (ret) {
- dev_err(priv->dev, "emergency force write failed\n");
+ dev_err(priv->dev, "emergency force failed\n");
return ret;
}
dev_err(priv->dev, "starting calibration...\n");
msleep(2300);
- ret = regmap_read(priv->regmap, SX1301_EMERGENCY_FORCE_HOST_CTRL, &val);
- if (ret) {
- dev_err(priv->dev, "emergency force read (1) failed\n");
- return ret;
- }
-
- val |= REG_EMERGENCY_FORCE_HOST_CTRL;
-
- ret = regmap_write(priv->regmap, SX1301_EMERGENCY_FORCE_HOST_CTRL, val);
+ ret = sx1301_field_write(priv, F_EMERGENCY_FORCE_HOST_CTRL, 1);
if (ret) {
- dev_err(priv->dev, "emergency force write (1) failed\n");
+ dev_err(priv->dev, "emergency force release failed\n");
return ret;
}
@@ -382,19 +319,15 @@ static int sx1301_load_all_firmware(struct sx1301_priv *priv)
if (ret)
return ret;
- ret = regmap_read(priv->regmap, SX1301_FORCE_CTRL, &val);
- if (ret) {
- dev_err(priv->dev, "0|105 read failed\n");
+ ret = sx1301_field_write(priv, F_FORCE_HOST_RADIO_CTRL, 0);
+ if (ret)
return ret;
- }
-
- val &= ~(REG_0_105_FORCE_HOST_RADIO_CTRL | REG_0_105_FORCE_HOST_FE_CTRL | REG_0_105_FORCE_DEC_FILTER_GAIN);
-
- ret = regmap_write(priv->regmap, SX1301_FORCE_CTRL, val);
- if (ret) {
- dev_err(priv->dev, "0|105 write failed\n");
+ ret = sx1301_field_write(priv, F_FORCE_HOST_FE_CTRL, 0);
+ if (ret)
+ return ret;
+ ret = sx1301_field_write(priv, F_FORCE_DEC_FILTER_GAIN, 0);
+ if (ret)
return ret;
- }
ret = regmap_write(priv->regmap, SX1301_CHRS, 0);
if (ret) {
@@ -402,17 +335,15 @@ static int sx1301_load_all_firmware(struct sx1301_priv *priv)
return ret;
}
- ret = regmap_read(priv->regmap, SX1301_MCU_CTRL, &val);
+ ret = sx1301_field_write(priv, F_MCU_RST_0, 0);
if (ret) {
- dev_err(priv->dev, "MCU read (0) failed\n");
+ dev_err(priv->dev, "MCU 0 release failed\n");
return ret;
}
- val &= ~(REG_0_MCU_RST_1 | REG_0_MCU_RST_0);
-
- ret = regmap_write(priv->regmap, SX1301_MCU_CTRL, val);
+ ret = sx1301_field_write(priv, F_MCU_RST_1, 0);
if (ret) {
- dev_err(priv->dev, "MCU write (0) failed\n");
+ dev_err(priv->dev, "MCU 1 release failed\n");
return ret;
}
@@ -464,7 +395,6 @@ static netdev_tx_t sx130x_loradev_start_xmit(struct sk_buff *skb, struct net_dev
static int sx130x_loradev_open(struct net_device *netdev)
{
struct sx1301_priv *priv = netdev_priv(netdev);
- unsigned int val;
int ret;
netdev_dbg(netdev, "%s", __func__);
@@ -474,31 +404,15 @@ static int sx130x_loradev_open(struct net_device *netdev)
return -ENXIO;
}
- ret = regmap_read(priv->regmap, SX1301_GEN, &val);
+ ret = sx1301_field_write(priv, F_GLOBAL_EN, 1);
if (ret) {
- netdev_err(netdev, "16 read (1) failed\n");
+ dev_err(priv->dev, "enable global clocks failed\n");
return ret;
}
- val |= REG_16_GLOBAL_EN;
-
- ret = regmap_write(priv->regmap, SX1301_GEN, val);
+ ret = sx1301_field_write(priv, F_CLK32M_EN, 1);
if (ret) {
- netdev_err(netdev, "16 write (1) failed\n");
- return ret;
- }
-
- ret = regmap_read(priv->regmap, SX1301_CKEN, &val);
- if (ret) {
- netdev_err(netdev, "17 read (1) failed\n");
- return ret;
- }
-
- val |= REG_17_CLK32M_EN;
-
- ret = regmap_write(priv->regmap, SX1301_CKEN, val);
- if (ret) {
- netdev_err(netdev, "17 write (1) failed\n");
+ dev_err(priv->dev, "enable 32M clock failed\n");
return ret;
}
@@ -545,6 +459,7 @@ static int sx1301_probe(struct spi_device *spi)
struct sx1301_priv *priv;
struct gpio_desc *rst;
int ret;
+ int i;
unsigned int ver;
unsigned int val;
@@ -583,6 +498,19 @@ static int sx1301_probe(struct spi_device *spi)
return ret;
}
+ for (i = 0; i < ARRAY_SIZE(sx1301_regmap_fields); i++) {
+ const struct reg_field *reg_fields = sx1301_regmap_fields;
+
+ priv->regmap_fields[i] = devm_regmap_field_alloc(&spi->dev,
+ priv->regmap,
+ reg_fields[i]);
+ if (IS_ERR(priv->regmap_fields[i])) {
+ ret = PTR_ERR(priv->regmap_fields[i]);
+ dev_err(&spi->dev, "Cannot allocate regmap field: %d\n", ret);
+ return ret;
+ }
+ }
+
ret = regmap_read(priv->regmap, SX1301_VER, &ver);
if (ret) {
dev_err(&spi->dev, "version read failed\n");
@@ -600,83 +528,49 @@ static int sx1301_probe(struct spi_device *spi)
return ret;
}
- ret = sx1301_soft_reset(priv);
+ ret = sx1301_field_write(priv, F_SOFT_RESET, 1);
if (ret) {
dev_err(&spi->dev, "soft reset failed\n");
return ret;
}
- ret = regmap_read(priv->regmap, SX1301_GEN, &val);
+ ret = sx1301_field_write(priv, F_GLOBAL_EN, 0);
if (ret) {
- dev_err(&spi->dev, "16 read failed\n");
+ dev_err(&spi->dev, "gate global clocks failed\n");
return ret;
}
- val &= ~REG_16_GLOBAL_EN;
-
- ret = regmap_write(priv->regmap, SX1301_GEN, val);
- if (ret) {
- dev_err(&spi->dev, "16 write failed\n");
- return ret;
- }
-
- ret = regmap_read(priv->regmap, SX1301_CKEN, &val);
+ ret = sx1301_field_write(priv, F_CLK32M_EN, 0);
if (ret) {
- dev_err(&spi->dev, "17 read failed\n");
+ dev_err(&spi->dev, "gate 32M clock failed\n");
return ret;
}
- val &= ~REG_17_CLK32M_EN;
-
- ret = regmap_write(priv->regmap, SX1301_CKEN, val);
+ ret = sx1301_field_write(priv, F_RADIO_A_EN, 1);
if (ret) {
- dev_err(&spi->dev, "17 write failed\n");
+ dev_err(&spi->dev, "radio a enable failed\n");
return ret;
}
- ret = regmap_read(priv->regmap, SX1301_RADIO_CFG, &val);
- if (ret) {
- dev_err(&spi->dev, "2|43 read failed\n");
- return ret;
- }
-
- val |= REG_2_43_RADIO_B_EN | REG_2_43_RADIO_A_EN;
-
- ret = regmap_write(priv->regmap, SX1301_RADIO_CFG, val);
+ ret = sx1301_field_write(priv, F_RADIO_B_EN, 1);
if (ret) {
- dev_err(&spi->dev, "2|43 write failed\n");
+ dev_err(&spi->dev, "radio b enable failed\n");
return ret;
}
msleep(500);
- ret = regmap_read(priv->regmap, SX1301_RADIO_CFG, &val);
+ ret = sx1301_field_write(priv, F_RADIO_RST, 1);
if (ret) {
- dev_err(&spi->dev, "2|43 read failed\n");
- return ret;
- }
-
- val |= REG_2_43_RADIO_RST;
-
- ret = regmap_write(priv->regmap, SX1301_RADIO_CFG, val);
- if (ret) {
- dev_err(&spi->dev, "2|43 write failed\n");
+ dev_err(&spi->dev, "radio asert reset failed\n");
return ret;
}
msleep(5);
- ret = regmap_read(priv->regmap, SX1301_RADIO_CFG, &val);
- if (ret) {
- dev_err(&spi->dev, "2|43 read failed\n");
- return ret;
- }
-
- val &= ~REG_2_43_RADIO_RST;
-
- ret = regmap_write(priv->regmap, SX1301_RADIO_CFG, val);
+ ret = sx1301_field_write(priv, F_RADIO_RST, 0);
if (ret) {
- dev_err(&spi->dev, "2|43 write failed\n");
+ dev_err(&spi->dev, "radio deasert reset failed\n");
return ret;
}
diff --git a/drivers/net/lora/sx1301.h b/drivers/net/lora/sx1301.h
index e6400f8..0bbd948 100644
--- a/drivers/net/lora/sx1301.h
+++ b/drivers/net/lora/sx1301.h
@@ -60,11 +60,57 @@
#define SX1301_MAX_REGISTER (SX1301_PAGE_BASE(3) + 0x7F)
+enum sx1301_fields {
+ F_SOFT_RESET,
+ F_GLOBAL_EN,
+ F_CLK32M_EN,
+ F_RADIO_A_EN,
+ F_RADIO_B_EN,
+ F_RADIO_RST,
+
+ F_MCU_RST_0,
+ F_MCU_RST_1,
+ F_MCU_SELECT_MUX_0,
+ F_MCU_SELECT_MUX_1,
+
+ F_FORCE_HOST_RADIO_CTRL,
+ F_FORCE_HOST_FE_CTRL,
+ F_FORCE_DEC_FILTER_GAIN,
+
+ F_EMERGENCY_FORCE_HOST_CTRL,
+};
+
+static const struct reg_field sx1301_regmap_fields[] = {
+ /* PAGE */
+ [F_SOFT_RESET] = REG_FIELD(SX1301_PAGE, 7, 7),
+ /* GEN */
+ [F_GLOBAL_EN] = REG_FIELD(SX1301_GEN, 3, 3),
+ /* CKEN */
+ [F_CLK32M_EN] = REG_FIELD(SX1301_CKEN, 0, 0),
+ /* RADIO_CFG */
+ [F_RADIO_A_EN] = REG_FIELD(SX1301_RADIO_CFG, 0, 0),
+ [F_RADIO_B_EN] = REG_FIELD(SX1301_RADIO_CFG, 1, 1),
+ [F_RADIO_RST] = REG_FIELD(SX1301_RADIO_CFG, 2, 2),
+ /* MCU_CTRL */
+ [F_MCU_RST_0] = REG_FIELD(SX1301_MCU_CTRL, 0, 0),
+ [F_MCU_RST_1] = REG_FIELD(SX1301_MCU_CTRL, 1, 1),
+ [F_MCU_SELECT_MUX_0] = REG_FIELD(SX1301_MCU_CTRL, 2, 2),
+ [F_MCU_SELECT_MUX_1] = REG_FIELD(SX1301_MCU_CTRL, 3, 3),
+ /* FORCE_CTRL */
+ [F_FORCE_HOST_RADIO_CTRL] = REG_FIELD(SX1301_FORCE_CTRL, 1, 1),
+ [F_FORCE_HOST_FE_CTRL] = REG_FIELD(SX1301_FORCE_CTRL, 2, 2),
+ [F_FORCE_DEC_FILTER_GAIN] = REG_FIELD(SX1301_FORCE_CTRL, 3, 3),
+ /* EMERGENCY_FORCE_HOST_CTRL */
+ [F_EMERGENCY_FORCE_HOST_CTRL] =
+ REG_FIELD(SX1301_EMERGENCY_FORCE_HOST_CTRL, 0, 0),
+};
+
struct sx1301_priv {
struct lora_dev_priv lora;
struct device *dev;
struct gpio_desc *rst_gpio;
struct regmap *regmap;
+ struct regmap_field *regmap_fields[ARRAY_SIZE(sx1301_regmap_fields)];
};
int __init sx130x_radio_init(void);
--
2.7.4
^ permalink raw reply related
* [PATCH v2 lora-next 3/4] net: lora: sx125x: convert to regmap fields
From: Ben Whitten @ 2018-10-09 12:52 UTC (permalink / raw)
To: afaerber; +Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
Ben Whitten
In-Reply-To: <1539089532-2481-1-git-send-email-ben.whitten@lairdtech.com>
From: Ben Whitten <ben.whitten@gmail.com>
We convert to using regmap fields to allow regmap to take care of read
modify writes and bit shifting for ofset fields.
Signed-off-by: Ben Whitten <ben.whitten@gmail.com>
---
drivers/net/lora/sx125x.c | 59 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 51 insertions(+), 8 deletions(-)
diff --git a/drivers/net/lora/sx125x.c b/drivers/net/lora/sx125x.c
index dc13d1a..36b61b1 100644
--- a/drivers/net/lora/sx125x.c
+++ b/drivers/net/lora/sx125x.c
@@ -25,11 +25,25 @@
#include "sx125x.h"
-#define REG_CLK_SELECT_TX_DAC_CLK_SELECT_CLK_IN BIT(0)
-#define REG_CLK_SELECT_CLK_OUT BIT(1)
+enum sx125x_fields {
+ F_CLK_OUT,
+ F_TX_DAC_CLK_SEL,
+ F_SX1257_XOSC_GM_STARTUP,
+ F_SX1257_XOSC_DISABLE_CORE,
+};
+
+static const struct reg_field sx125x_regmap_fields[] = {
+ /* CLK_SELECT */
+ [F_CLK_OUT] = REG_FIELD(SX125X_CLK_SELECT, 1, 1),
+ [F_TX_DAC_CLK_SEL] = REG_FIELD(SX125X_CLK_SELECT, 0, 0),
+ /* XOSC */ /* TODO maybe make this dynamic */
+ [F_SX1257_XOSC_GM_STARTUP] = REG_FIELD(SX1257_XOSC, 0, 3),
+ [F_SX1257_XOSC_DISABLE_CORE] = REG_FIELD(SX1257_XOSC, 5, 5),
+};
struct sx125x_priv {
struct regmap *regmap;
+ struct regmap_field *regmap_fields[ARRAY_SIZE(sx125x_regmap_fields)];
};
static struct regmap_config __maybe_unused sx125x_regmap_config = {
@@ -44,11 +58,18 @@ static struct regmap_config __maybe_unused sx125x_regmap_config = {
.max_register = SX125X_MAX_REGISTER,
};
+static int sx125x_field_write(struct sx125x_priv *priv,
+ enum sx125x_fields field_id, u8 val)
+{
+ return regmap_field_write(priv->regmap_fields[field_id], val);
+}
+
static int __maybe_unused sx125x_regmap_probe(struct device *dev, struct regmap *regmap, unsigned int radio)
{
struct sx125x_priv *priv;
unsigned int val;
int ret;
+ int i;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -56,6 +77,18 @@ static int __maybe_unused sx125x_regmap_probe(struct device *dev, struct regmap
dev_set_drvdata(dev, priv);
priv->regmap = regmap;
+ for (i = 0; i < ARRAY_SIZE(sx125x_regmap_fields); i++) {
+ const struct reg_field *reg_fields = sx125x_regmap_fields;
+
+ priv->regmap_fields[i] = devm_regmap_field_alloc(dev,
+ priv->regmap,
+ reg_fields[i]);
+ if (IS_ERR(priv->regmap_fields[i])) {
+ ret = PTR_ERR(priv->regmap_fields[i]);
+ dev_err(dev, "Cannot allocate regmap field: %d\n", ret);
+ return ret;
+ }
+ }
if (true) {
ret = regmap_read(priv->regmap, SX1255_VERSION, &val);
@@ -66,24 +99,34 @@ static int __maybe_unused sx125x_regmap_probe(struct device *dev, struct regmap
dev_info(dev, "SX125x version: %02x\n", val);
}
- val = REG_CLK_SELECT_TX_DAC_CLK_SELECT_CLK_IN;
if (radio == 1) { /* HACK */
- val |= REG_CLK_SELECT_CLK_OUT;
+ ret = sx125x_field_write(priv, F_CLK_OUT, 1);
+ if (ret) {
+ dev_err(dev, "enabling clock output failed\n");
+ return ret;
+ }
+
dev_info(dev, "enabling clock output\n");
}
- ret = regmap_write(priv->regmap, SX125X_CLK_SELECT, val);
+ ret = sx125x_field_write(priv, F_TX_DAC_CLK_SEL, 1);
if (ret) {
- dev_err(dev, "clk write failed\n");
+ dev_err(dev, "clock select failed\n");
return ret;
}
dev_dbg(dev, "clk written\n");
if (true) {
- ret = regmap_write(priv->regmap, SX1257_XOSC, 13 + 2 * 16);
+ ret = sx125x_field_write(priv, F_SX1257_XOSC_DISABLE_CORE, 1);
+ if (ret) {
+ dev_err(dev, "xosc disable failed\n");
+ return ret;
+ }
+
+ ret = sx125x_field_write(priv, F_SX1257_XOSC_GM_STARTUP, 13);
if (ret) {
- dev_err(dev, "xosc write failed\n");
+ dev_err(dev, "xosc startup adjust failed\n");
return ret;
}
}
--
2.7.4
^ permalink raw reply related
* [PATCH v2 lora-next 4/4] net: lora: sx125x sx1301: allow radio to register as a clk provider
From: Ben Whitten @ 2018-10-09 12:52 UTC (permalink / raw)
To: afaerber; +Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
Ben Whitten
In-Reply-To: <1539089532-2481-1-git-send-email-ben.whitten@lairdtech.com>
From: Ben Whitten <ben.whitten@gmail.com>
The 32M is run from the radio, before we just enabled it based on
the radio number but now we can use the clk framework to request the
clk is started when we need it.
The 32M clock produced from the radio is really a gated version of
tcxo which is a fixed clock provided by hardware, and isn't captured
in this patch.
The sx1301 brings the clock up prior to calibration once the radios
have probed themselves.
A sample dts showing the clk link:
sx1301: sx1301@0 {
...
clocks = <&radio1 0>;
clock-names = "clk32m";
radio-spi {
radio0: radio-a@0 {
...
};
radio1: radio-b@1 {
#clock-cells = <0>;
clock-output-names = "clk32m";
};
};
};
Signed-off-by: Ben Whitten <ben.whitten@gmail.com>
---
drivers/net/lora/sx125x.c | 112 ++++++++++++++++++++++++++++++++++++++++++----
drivers/net/lora/sx1301.c | 13 ++++++
drivers/net/lora/sx1301.h | 2 +
3 files changed, 119 insertions(+), 8 deletions(-)
diff --git a/drivers/net/lora/sx125x.c b/drivers/net/lora/sx125x.c
index 36b61b1..b7ca782 100644
--- a/drivers/net/lora/sx125x.c
+++ b/drivers/net/lora/sx125x.c
@@ -9,6 +9,8 @@
* Copyright (c) 2013 Semtech-Cycleo
*/
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -42,10 +44,16 @@ static const struct reg_field sx125x_regmap_fields[] = {
};
struct sx125x_priv {
+ struct clk *clkout;
+ struct clk_hw clkout_hw;
+
+ struct device *dev;
struct regmap *regmap;
struct regmap_field *regmap_fields[ARRAY_SIZE(sx125x_regmap_fields)];
};
+#define to_clkout(_hw) container_of(_hw, struct sx125x_priv, clkout_hw)
+
static struct regmap_config __maybe_unused sx125x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -64,6 +72,96 @@ static int sx125x_field_write(struct sx125x_priv *priv,
return regmap_field_write(priv->regmap_fields[field_id], val);
}
+static int sx125x_field_read(struct sx125x_priv *priv,
+ enum sx125x_fields field_id, unsigned int *val)
+{
+ return regmap_field_read(priv->regmap_fields[field_id], val);
+}
+
+static int sx125x_clkout_enable(struct clk_hw *hw)
+{
+ struct sx125x_priv *priv = to_clkout(hw);
+
+ dev_info(priv->dev, "enabling clkout\n");
+ return sx125x_field_write(priv, F_CLK_OUT, 1);
+}
+
+static void sx125x_clkout_disable(struct clk_hw *hw)
+{
+ struct sx125x_priv *priv = to_clkout(hw);
+ int ret;
+
+ dev_info(priv->dev, "disabling clkout\n");
+ ret = sx125x_field_write(priv, F_CLK_OUT, 0);
+ if (ret)
+ dev_err(priv->dev, "error disabling clkout\n");
+}
+
+static int sx125x_clkout_is_enabled(struct clk_hw *hw)
+{
+ struct sx125x_priv *priv = to_clkout(hw);
+ unsigned int enabled;
+ int ret;
+
+ ret = sx125x_field_read(priv, F_CLK_OUT, &enabled);
+ if (ret) {
+ dev_err(priv->dev, "error reading clk enable\n");
+ return 0;
+ }
+ return enabled;
+}
+
+static const struct clk_ops sx125x_clkout_ops = {
+ .enable = sx125x_clkout_enable,
+ .disable = sx125x_clkout_disable,
+ .is_enabled = sx125x_clkout_is_enabled,
+};
+
+static int sx125x_register_clock_provider(struct sx125x_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct clk_init_data init;
+ const char *parent;
+ int ret;
+
+ /* Disable CLKOUT */
+ ret = sx125x_field_write(priv, F_CLK_OUT, 0);
+ if (ret) {
+ dev_err(dev, "unable to disable clkout\n");
+ return ret;
+ }
+
+ /* Register clock provider if expected in DTB */
+ if (!of_find_property(dev->of_node, "#clock-cells", NULL))
+ return 0;
+
+ dev_info(dev, "registering clkout\n");
+
+ parent = of_clk_get_parent_name(dev->of_node, 0);
+ if (!parent) {
+ dev_err(dev, "Unable to find parent clk\n");
+ return -ENODEV;
+ }
+
+ init.ops = &sx125x_clkout_ops;
+ init.flags = CLK_IS_BASIC;
+ init.parent_names = &parent;
+ init.num_parents = 1;
+ priv->clkout_hw.init = &init;
+
+ of_property_read_string_index(dev->of_node, "clock-output-names", 0,
+ &init.name);
+
+ priv->clkout = devm_clk_register(dev, &priv->clkout_hw);
+ if (IS_ERR(priv->clkout)) {
+ dev_err(dev, "failed to register clkout\n");
+ return PTR_ERR(priv->clkout);
+ }
+ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get,
+ &priv->clkout_hw);
+ return ret;
+}
+
static int __maybe_unused sx125x_regmap_probe(struct device *dev, struct regmap *regmap, unsigned int radio)
{
struct sx125x_priv *priv;
@@ -76,6 +174,7 @@ static int __maybe_unused sx125x_regmap_probe(struct device *dev, struct regmap
return -ENOMEM;
dev_set_drvdata(dev, priv);
+ priv->dev = dev;
priv->regmap = regmap;
for (i = 0; i < ARRAY_SIZE(sx125x_regmap_fields); i++) {
const struct reg_field *reg_fields = sx125x_regmap_fields;
@@ -99,16 +198,13 @@ static int __maybe_unused sx125x_regmap_probe(struct device *dev, struct regmap
dev_info(dev, "SX125x version: %02x\n", val);
}
- if (radio == 1) { /* HACK */
- ret = sx125x_field_write(priv, F_CLK_OUT, 1);
- if (ret) {
- dev_err(dev, "enabling clock output failed\n");
- return ret;
- }
-
- dev_info(dev, "enabling clock output\n");
+ ret = sx125x_register_clock_provider(priv);
+ if (ret) {
+ dev_err(dev, "failed to register clkout provider: %d\n", ret);
+ return ret;
}
+ /* TODO Only needs setting on radio on the TX path */
ret = sx125x_field_write(priv, F_TX_DAC_CLK_SEL, 1);
if (ret) {
dev_err(dev, "clock select failed\n");
diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index eb89af6..44a7d0b 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -10,6 +10,7 @@
*/
#include <linux/bitops.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/lora.h>
@@ -404,6 +405,18 @@ static int sx130x_loradev_open(struct net_device *netdev)
return -ENXIO;
}
+ priv->clk32m = devm_clk_get(priv->dev, "clk32m");
+ if (IS_ERR(priv->clk32m)) {
+ dev_err(priv->dev, "failed to get clk32m\n");
+ return PTR_ERR(priv->clk32m);
+ }
+
+ ret = clk_prepare_enable(priv->clk32m);
+ if (ret) {
+ dev_err(priv->dev, "failed to enable clk32m: %d\n", ret);
+ return ret;
+ }
+
ret = sx1301_field_write(priv, F_GLOBAL_EN, 1);
if (ret) {
dev_err(priv->dev, "enable global clocks failed\n");
diff --git a/drivers/net/lora/sx1301.h b/drivers/net/lora/sx1301.h
index 0bbd948..a1a2e38 100644
--- a/drivers/net/lora/sx1301.h
+++ b/drivers/net/lora/sx1301.h
@@ -9,6 +9,7 @@
#ifndef _SX1301_
#define _SX1301_
+#include <linux/clk.h>
#include <linux/regmap.h>
#include <linux/gpio/consumer.h>
#include <linux/lora/dev.h>
@@ -108,6 +109,7 @@ static const struct reg_field sx1301_regmap_fields[] = {
struct sx1301_priv {
struct lora_dev_priv lora;
struct device *dev;
+ struct clk *clk32m;
struct gpio_desc *rst_gpio;
struct regmap *regmap;
struct regmap_field *regmap_fields[ARRAY_SIZE(sx1301_regmap_fields)];
--
2.7.4
^ permalink raw reply related
* Re: [RFC PATCH 02/11] dt-bindings: phy: add cpsw port interface mode selection phy bindings
From: Grygorii Strashko @ 2018-10-09 20:10 UTC (permalink / raw)
To: Tony Lindgren
Cc: David S. Miller, netdev, Rob Herring, Kishon Vijay Abraham I,
Sekhar Nori, linux-kernel, linux-omap, devicetree
In-Reply-To: <20181009144000.GL5662@atomide.com>
On 10/09/2018 09:40 AM, Tony Lindgren wrote:
> * Grygorii Strashko <grygorii.strashko@ti.com> [181008 23:54]:
>> +Examples:
>> + phy_gmii_sel: phy-gmii-sel {
>> + compatible = "ti,am3352-phy-gmii-sel";
>> + syscon-scm = <&scm_conf>;
>> + #phy-cells = <2>;
>> + };
>
> Now that this driver can live in it's proper place in the
right
> dts, you may want to consider just using standard reg
> property for it instead of the syscon-scm. And also get
> rid of the syscon reads and writes.
Could you help clarify how to get syscon in this case?
syscon_node_to_regmap(dev->parent->of_node)?
Also, there are could be more then one gmii_sel registers in SCM in the future,
so I hidden offsets in of_match data.
As result, "reg" not needed at all now.
--
regards,
-grygorii
^ permalink raw reply
* Re: [PATCH bpf-next 3/6] bpf: add MAP_LOOKUP_AND_DELETE_ELEM syscall
From: Mauricio Vasquez @ 2018-10-09 12:56 UTC (permalink / raw)
To: Song Liu; +Cc: Alexei Starovoitov, Daniel Borkmann, Networking
In-Reply-To: <CAPhsuW4xb=srya5ghyjvKtcnTTYvje-c=vbJa-abUBj6CjC6_A@mail.gmail.com>
On 10/08/2018 08:13 PM, Song Liu wrote:
> On Mon, Oct 8, 2018 at 12:12 PM Mauricio Vasquez B
> <mauricio.vasquez@polito.it> wrote:
>> The following patch implements a bpf queue/stack maps that
>> provides the peek/pop/push functions. There is not a direct
>> relationship between those functions and the current maps
>> syscalls, hence a new MAP_LOOKUP_AND_DELETE_ELEM syscall is added,
>> this is mapped to the pop operation in the queue/stack maps
>> and it is still to implement in other kind of maps.
> Do we need this system call for other maps (non-stack/queue)?
> If not, maybe we can just call it POP, and only implement it for
> stack and queue?
>
Yes, this system call could also benefit other maps. The first idea was
to add pop/push/peek system calls as well, but them Alexei realized it
was too specific for queue/stack maps and we decided to go ahead with
this solution that is more general.
>> Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
>> ---
>> include/linux/bpf.h | 1 +
>> include/uapi/linux/bpf.h | 1 +
>> kernel/bpf/syscall.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 83 insertions(+)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index 027697b6a22f..98c7eeb6d138 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -39,6 +39,7 @@ struct bpf_map_ops {
>> void *(*map_lookup_elem)(struct bpf_map *map, void *key);
>> int (*map_update_elem)(struct bpf_map *map, void *key, void *value, u64 flags);
>> int (*map_delete_elem)(struct bpf_map *map, void *key);
>> + void *(*map_lookup_and_delete_elem)(struct bpf_map *map, void *key);
>>
>> /* funcs called by prog_array and perf_event_array map */
>> void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file,
>> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
>> index f9187b41dff6..3bb94aa2d408 100644
>> --- a/include/uapi/linux/bpf.h
>> +++ b/include/uapi/linux/bpf.h
>> @@ -103,6 +103,7 @@ enum bpf_cmd {
>> BPF_BTF_LOAD,
>> BPF_BTF_GET_FD_BY_ID,
>> BPF_TASK_FD_QUERY,
>> + BPF_MAP_LOOKUP_AND_DELETE_ELEM,
>> };
>>
>> enum bpf_map_type {
>> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> index eb75e8af73ff..c33d9303f72f 100644
>> --- a/kernel/bpf/syscall.c
>> +++ b/kernel/bpf/syscall.c
>> @@ -975,6 +975,84 @@ static int map_get_next_key(union bpf_attr *attr)
>> return err;
>> }
>>
>> +#define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD value
>> +
>> +static int map_lookup_and_delete_elem(union bpf_attr *attr)
>> +{
>> + void __user *ukey = u64_to_user_ptr(attr->key);
>> + void __user *uvalue = u64_to_user_ptr(attr->value);
>> + int ufd = attr->map_fd;
>> + struct bpf_map *map;
>> + void *key, *value, *ptr;
>> + u32 value_size;
>> + struct fd f;
>> + int err;
>> +
>> + if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
>> + return -EINVAL;
>> +
>> + f = fdget(ufd);
>> + map = __bpf_map_get(f);
>> + if (IS_ERR(map))
>> + return PTR_ERR(map);
>> +
>> + if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
>> + err = -EPERM;
>> + goto err_put;
>> + }
>> +
>> + key = __bpf_copy_key(ukey, map->key_size);
>> + if (IS_ERR(key)) {
>> + err = PTR_ERR(key);
>> + goto err_put;
>> + }
>> +
>> + value_size = map->value_size;
>> +
>> + err = -ENOMEM;
>> + value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
>> + if (!value)
>> + goto free_key;
>> +
>> + err = -EFAULT;
>> + if (copy_from_user(value, uvalue, value_size) != 0)
>> + goto free_value;
>> +
>> + /* must increment bpf_prog_active to avoid kprobe+bpf triggering from
>> + * inside bpf map update or delete otherwise deadlocks are possible
>> + */
>> + preempt_disable();
>> + __this_cpu_inc(bpf_prog_active);
>> + if (!map->ops->map_lookup_and_delete_elem) {
> Why do have have this check here? Shouldn't it be check much earlier?
> If we really need it here, we need at least add the following:
In this particular patch the check can be done much earlier, but in next
patch we need it on this position, so I leave it here to avoid moving
around on next patch.
> __this_cpu_dec(bpf_prog_active);
> preempt_enable();
You are right, I missed that. Will fix for next version.
>
>
>> + err = -ENOTSUPP;
>> + goto free_value;
>> + }
>> + rcu_read_lock();
>> + ptr = map->ops->map_lookup_and_delete_elem(map, key);
>> + if (ptr)
>> + memcpy(value, ptr, value_size);
>> + rcu_read_unlock();
>> + err = ptr ? 0 : -ENOENT;
>> + __this_cpu_dec(bpf_prog_active);
>> + preempt_enable();
>> +
>> + if (err)
>> + goto free_value;
>> +
>> + if (copy_to_user(uvalue, value, value_size) != 0)
>> + goto free_value;
>> +
>> + err = 0;
>> +
>> +free_value:
>> + kfree(value);
>> +free_key:
>> + kfree(key);
>> +err_put:
>> + fdput(f);
>> + return err;
>> +}
>> +
>> static const struct bpf_prog_ops * const bpf_prog_types[] = {
>> #define BPF_PROG_TYPE(_id, _name) \
>> [_id] = & _name ## _prog_ops,
>> @@ -2448,6 +2526,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
>> case BPF_TASK_FD_QUERY:
>> err = bpf_task_fd_query(&attr, uattr);
>> break;
>> + case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
>> + err = map_lookup_and_delete_elem(&attr);
>> + break;
>> default:
>> err = -EINVAL;
>> break;
>>
^ permalink raw reply
* Re: [RFC PATCH 03/11] phy: ti: introduce phy-gmii-sel driver
From: Grygorii Strashko @ 2018-10-09 20:22 UTC (permalink / raw)
To: Andrew Lunn
Cc: David S. Miller, netdev, Tony Lindgren, Rob Herring,
Kishon Vijay Abraham I, Sekhar Nori, linux-kernel, linux-omap,
devicetree
In-Reply-To: <20181009003935.GA23588@lunn.ch>
Hi Andrew,
On 10/08/2018 07:39 PM, Andrew Lunn wrote:
> On Mon, Oct 08, 2018 at 06:49:41PM -0500, Grygorii Strashko wrote:
>> +static int phy_gmii_sel_mode(struct phy *phy, phy_interface_t intf_mode)
>> +{
>> + struct phy_gmii_sel_phy_priv *if_phy = phy_get_drvdata(phy);
>> + const struct phy_gmii_sel_soc_data *soc_data = if_phy->priv->soc_data;
>> + struct device *dev = if_phy->priv->dev;
>> + struct regmap_field *regfield;
>> + int ret, rgmii_id = 0;
>> + u32 mode = 0;
>> +
>> + if_phy->phy_if_mode = intf_mode;
>> +
>> + switch (if_phy->phy_if_mode) {
>> + case PHY_INTERFACE_MODE_RMII:
>> + mode = AM33XX_GMII_SEL_MODE_RMII;
>> + break;
>> +
>> + case PHY_INTERFACE_MODE_RGMII:
>> + mode = AM33XX_GMII_SEL_MODE_RGMII;
>> + break;
>> +
>> + case PHY_INTERFACE_MODE_RGMII_ID:
>> + case PHY_INTERFACE_MODE_RGMII_RXID:
>> + case PHY_INTERFACE_MODE_RGMII_TXID:
>> + mode = AM33XX_GMII_SEL_MODE_RGMII;
>> + rgmii_id = 1;
>> + break;
>
> Hi Grygorii
>
> It looks like the MAC can do AM33XX_GMII_SEL_MODE_RGMII and
> AM33XX_GMII_SEL_MODE_RGMII_ID. I don't think it can do
> AM33XX_GMII_SEL_MODE_RGMII_RXID or AM33XX_GMII_SEL_MODE_RGMII_TXID?
Sry, but would prefer not to thought this logic as part of this series as i moved it here
unchanged rom cpsw-phy-sel.c (except adding possibility to update only supported field)
and any changes here would require separate review (including all existing TI DT boards)
and testing.
I
> would prefer it return -EINVAL when asked to do something it cannot
> do.
Just to clarify rgmii_id = 1 means *disable* CPSW Internal Delay Mode.
>
>> +
>> + default:
>> + dev_warn(dev,
>> + "port%u: unsupported mode: \"%s\". Defaulting to MII.\n",
>> + if_phy->id, phy_modes(rgmii_id));
>> + /* fall through */
>
> Returning -EINVAL would be better. Otherwise the DT might never get
> fixed.
ok
>
>> + case PHY_INTERFACE_MODE_MII:
>> + mode = AM33XX_GMII_SEL_MODE_MII;
>> + break;
>> + };
>> +
>> + dev_dbg(dev, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n",
>> + __func__, if_phy->id, mode, rgmii_id,
>> + if_phy->rmii_clock_external);
>> +
>> + regfield = if_phy->fields[PHY_GMII_SEL_PORT_MODE];
>> + ret = regmap_field_write(regfield, mode);
>> +
>> + if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE) &&
>> + if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE]) {
>> + regfield = if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE];
>> + ret |= regmap_field_write(regfield, rgmii_id);
>> + }
>> +
>> + if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
>> + if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN]) {
>> + regfield = if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN];
>> + ret |= regmap_field_write(regfield,
>> + if_phy->rmii_clock_external);
>> + }
>> +
>> + if (ret) {
>> + dev_err(dev, "port%u: set mode fail %d", if_phy->id, ret);
>> + return -EIO;
>> + }
>
> I would prefer each write had its own error check. The fact you don't
> return ret means you know ret could be -EINVAL|-EOIO, making
> -EMORECOFFEE.
:) right, sry.
--
regards,
-grygorii
^ permalink raw reply
* Re: [PATCH bpf-next 4/6] bpf: add queue and stack maps
From: Mauricio Vasquez @ 2018-10-09 13:05 UTC (permalink / raw)
To: Song Liu; +Cc: Alexei Starovoitov, Daniel Borkmann, Networking
In-Reply-To: <CAPhsuW6B_VJ8t8VoDhmk=H9J6PwkczscPqsB4fW_cFr1K72z6g@mail.gmail.com>
On 10/08/2018 08:36 PM, Song Liu wrote:
> On Mon, Oct 8, 2018 at 12:12 PM Mauricio Vasquez B
> <mauricio.vasquez@polito.it> wrote:
>> Queue/stack maps implement a FIFO/LIFO data storage for ebpf programs.
>> These maps support peek, pop and push operations that are exposed to eBPF
>> programs through the new bpf_map[peek/pop/push] helpers. Those operations
>> are exposed to userspace applications through the already existing
>> syscalls in the following way:
>>
>> BPF_MAP_LOOKUP_ELEM -> peek
>> BPF_MAP_LOOKUP_AND_DELETE_ELEM -> pop
>> BPF_MAP_UPDATE_ELEM -> push
>>
>> Queue/stack maps are implemented using a buffer, tail and head indexes,
>> hence BPF_F_NO_PREALLOC is not supported.
>>
>> As opposite to other maps, queue and stack do not use RCU for protecting
>> maps values, the bpf_map[peek/pop] have a ARG_PTR_TO_UNINIT_MAP_VALUE
>> argument that is a pointer to a memory zone where to save the value of a
>> map. Basically the same as ARG_PTR_TO_UNINIT_MEM, but the size has not
>> be passed as an extra argument.
>>
>> Our main motivation for implementing queue/stack maps was to keep track
>> of a pool of elements, like network ports in a SNAT, however we forsee
>> other use cases, like for exampling saving last N kernel events in a map
>> and then analysing from userspace.
>>
>> Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
>> ---
>> include/linux/bpf.h | 7 +
>> include/linux/bpf_types.h | 2
>> include/uapi/linux/bpf.h | 35 ++++-
>> kernel/bpf/Makefile | 2
>> kernel/bpf/core.c | 3
>> kernel/bpf/helpers.c | 43 ++++++
>> kernel/bpf/queue_stack_maps.c | 288 +++++++++++++++++++++++++++++++++++++++++
>> kernel/bpf/syscall.c | 30 +++-
>> kernel/bpf/verifier.c | 28 +++-
>> net/core/filter.c | 6 +
>> 10 files changed, 426 insertions(+), 18 deletions(-)
>> create mode 100644 kernel/bpf/queue_stack_maps.c
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index 98c7eeb6d138..cad3bc5cffd1 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -40,6 +40,9 @@ struct bpf_map_ops {
>> int (*map_update_elem)(struct bpf_map *map, void *key, void *value, u64 flags);
>> int (*map_delete_elem)(struct bpf_map *map, void *key);
>> void *(*map_lookup_and_delete_elem)(struct bpf_map *map, void *key);
>> + int (*map_push_elem)(struct bpf_map *map, void *value, u64 flags);
>> + int (*map_pop_elem)(struct bpf_map *map, void *value);
>> + int (*map_peek_elem)(struct bpf_map *map, void *value);
>>
>> /* funcs called by prog_array and perf_event_array map */
>> void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file,
>> @@ -139,6 +142,7 @@ enum bpf_arg_type {
>> ARG_CONST_MAP_PTR, /* const argument used as pointer to bpf_map */
>> ARG_PTR_TO_MAP_KEY, /* pointer to stack used as map key */
>> ARG_PTR_TO_MAP_VALUE, /* pointer to stack used as map value */
>> + ARG_PTR_TO_UNINIT_MAP_VALUE, /* pointer to valid memory used to store a map value */
> How about we put ARG_PTR_TO_UNINIT_MAP_VALUE and related logic to a
> separate patch?
I thought it too, but this is a really small change (6 additions, 3
deletions). Does it worth a separated patch?
>
>> /* the following constraints used to prototype bpf_memcmp() and other
>> * functions that access data on eBPF program stack
>> @@ -825,6 +829,9 @@ static inline int bpf_fd_reuseport_array_update_elem(struct bpf_map *map,
>> extern const struct bpf_func_proto bpf_map_lookup_elem_proto;
>> extern const struct bpf_func_proto bpf_map_update_elem_proto;
>> extern const struct bpf_func_proto bpf_map_delete_elem_proto;
>> +extern const struct bpf_func_proto bpf_map_push_elem_proto;
>> +extern const struct bpf_func_proto bpf_map_pop_elem_proto;
>> +extern const struct bpf_func_proto bpf_map_peek_elem_proto;
>>
>> extern const struct bpf_func_proto bpf_get_prandom_u32_proto;
>> extern const struct bpf_func_proto bpf_get_smp_processor_id_proto;
>> diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
>> index 658509daacd4..a2ec73aa1ec7 100644
>> --- a/include/linux/bpf_types.h
>> +++ b/include/linux/bpf_types.h
>> @@ -69,3 +69,5 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_XSKMAP, xsk_map_ops)
>> BPF_MAP_TYPE(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, reuseport_array_ops)
>> #endif
>> #endif
>> +BPF_MAP_TYPE(BPF_MAP_TYPE_QUEUE, queue_map_ops)
>> +BPF_MAP_TYPE(BPF_MAP_TYPE_STACK, stack_map_ops)
>> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
>> index 3bb94aa2d408..bfa042273fad 100644
>> --- a/include/uapi/linux/bpf.h
>> +++ b/include/uapi/linux/bpf.h
>> @@ -129,6 +129,8 @@ enum bpf_map_type {
>> BPF_MAP_TYPE_CGROUP_STORAGE,
>> BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
>> BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
>> + BPF_MAP_TYPE_QUEUE,
>> + BPF_MAP_TYPE_STACK,
>> };
>>
>> enum bpf_prog_type {
>> @@ -463,6 +465,28 @@ union bpf_attr {
>> * Return
>> * 0 on success, or a negative error in case of failure.
>> *
>> + * int bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags)
>> + * Description
>> + * Push an element *value* in *map*. *flags* is one of:
>> + *
>> + * **BPF_EXIST**
>> + * If the queue/stack is full, the oldest element is removed to
>> + * make room for this.
>> + * Return
>> + * 0 on success, or a negative error in case of failure.
>> + *
>> + * int bpf_map_pop_elem(struct bpf_map *map, void *value)
>> + * Description
>> + * Pop an element from *map*.
>> + * Return
>> + * 0 on success, or a negative error in case of failure.
>> + *
>> + * int bpf_map_peek_elem(struct bpf_map *map, void *value)
>> + * Description
>> + * Get an element from *map* without removing it.
>> + * Return
>> + * 0 on success, or a negative error in case of failure.
>> + *
>> * int bpf_probe_read(void *dst, u32 size, const void *src)
>> * Description
>> * For tracing programs, safely attempt to read *size* bytes from
>> @@ -790,14 +814,14 @@ union bpf_attr {
>> *
>> * int ret;
>> * struct bpf_tunnel_key key = {};
>> - *
>> + *
>> * ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
>> * if (ret < 0)
>> * return TC_ACT_SHOT; // drop packet
>> - *
>> + *
>> * if (key.remote_ipv4 != 0x0a000001)
>> * return TC_ACT_SHOT; // drop packet
>> - *
>> + *
>> * return TC_ACT_OK; // accept packet
>> *
>> * This interface can also be used with all encapsulation devices
>> @@ -2304,7 +2328,10 @@ union bpf_attr {
>> FN(skb_ancestor_cgroup_id), \
>> FN(sk_lookup_tcp), \
>> FN(sk_lookup_udp), \
>> - FN(sk_release),
>> + FN(sk_release), \
>> + FN(map_push_elem), \
>> + FN(map_pop_elem), \
>> + FN(map_peek_elem),
>>
>> /* integer value in 'imm' field of BPF_CALL instruction selects which helper
>> * function eBPF program intends to call
>> diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
>> index 0488b8258321..17afae9e65f3 100644
>> --- a/kernel/bpf/Makefile
>> +++ b/kernel/bpf/Makefile
>> @@ -3,7 +3,7 @@ obj-y := core.o
>>
>> obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o
>> obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o
>> -obj-$(CONFIG_BPF_SYSCALL) += local_storage.o
>> +obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o
>> obj-$(CONFIG_BPF_SYSCALL) += disasm.o
>> obj-$(CONFIG_BPF_SYSCALL) += btf.o
>> ifeq ($(CONFIG_NET),y)
>> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
>> index 3f5bf1af0826..8d2db076d123 100644
>> --- a/kernel/bpf/core.c
>> +++ b/kernel/bpf/core.c
>> @@ -1783,6 +1783,9 @@ BPF_CALL_0(bpf_user_rnd_u32)
>> const struct bpf_func_proto bpf_map_lookup_elem_proto __weak;
>> const struct bpf_func_proto bpf_map_update_elem_proto __weak;
>> const struct bpf_func_proto bpf_map_delete_elem_proto __weak;
>> +const struct bpf_func_proto bpf_map_push_elem_proto __weak;
>> +const struct bpf_func_proto bpf_map_pop_elem_proto __weak;
>> +const struct bpf_func_proto bpf_map_peek_elem_proto __weak;
>>
>> const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;
>> const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak;
>> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
>> index 6502115e8f55..ab0d5e3f9892 100644
>> --- a/kernel/bpf/helpers.c
>> +++ b/kernel/bpf/helpers.c
>> @@ -76,6 +76,49 @@ const struct bpf_func_proto bpf_map_delete_elem_proto = {
>> .arg2_type = ARG_PTR_TO_MAP_KEY,
>> };
>>
>> +BPF_CALL_3(bpf_map_push_elem, struct bpf_map *, map, void *, value, u64, flags)
>> +{
>> + return map->ops->map_push_elem(map, value, flags);
>> +}
>> +
>> +const struct bpf_func_proto bpf_map_push_elem_proto = {
>> + .func = bpf_map_push_elem,
>> + .gpl_only = false,
>> + .pkt_access = true,
>> + .ret_type = RET_INTEGER,
>> + .arg1_type = ARG_CONST_MAP_PTR,
>> + .arg2_type = ARG_PTR_TO_MAP_VALUE,
>> + .arg3_type = ARG_ANYTHING,
>> +};
>> +
>> +BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value)
>> +{
>> + return map->ops->map_pop_elem(map, value);
>> +}
>> +
>> +const struct bpf_func_proto bpf_map_pop_elem_proto = {
>> + .func = bpf_map_pop_elem,
>> + .gpl_only = false,
>> + .pkt_access = true,
>> + .ret_type = RET_INTEGER,
>> + .arg1_type = ARG_CONST_MAP_PTR,
>> + .arg2_type = ARG_PTR_TO_UNINIT_MAP_VALUE,
>> +};
>> +
>> +BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
>> +{
>> + return map->ops->map_peek_elem(map, value);
>> +}
>> +
>> +const struct bpf_func_proto bpf_map_peek_elem_proto = {
>> + .func = bpf_map_pop_elem,
>> + .gpl_only = false,
>> + .pkt_access = true,
>> + .ret_type = RET_INTEGER,
>> + .arg1_type = ARG_CONST_MAP_PTR,
>> + .arg2_type = ARG_PTR_TO_UNINIT_MAP_VALUE,
>> +};
>> +
>> const struct bpf_func_proto bpf_get_prandom_u32_proto = {
>> .func = bpf_user_rnd_u32,
>> .gpl_only = false,
>> diff --git a/kernel/bpf/queue_stack_maps.c b/kernel/bpf/queue_stack_maps.c
>> new file mode 100644
>> index 000000000000..12a93fb37449
>> --- /dev/null
>> +++ b/kernel/bpf/queue_stack_maps.c
>> @@ -0,0 +1,288 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * queue_stack_maps.c: BPF queue and stack maps
>> + *
>> + * Copyright (c) 2018 Politecnico di Torino
>> + */
>> +#include <linux/bpf.h>
>> +#include <linux/list.h>
>> +#include <linux/slab.h>
>> +#include "percpu_freelist.h"
>> +
>> +#define QUEUE_STACK_CREATE_FLAG_MASK \
>> + (BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)
>> +
>> +
>> +struct bpf_queue_stack {
>> + struct bpf_map map;
>> + raw_spinlock_t lock;
>> + u32 head, tail;
>> + u32 size; /* max_entries + 1 */
>> +
>> + char elements[0] __aligned(8);
>> +};
>> +
>> +static struct bpf_queue_stack *bpf_queue_stack(struct bpf_map *map)
>> +{
>> + return container_of(map, struct bpf_queue_stack, map);
>> +}
>> +
>> +static bool queue_stack_map_is_empty(struct bpf_queue_stack *qs)
>> +{
>> + return qs->head == qs->tail;
>> +}
>> +
>> +static bool queue_stack_map_is_full(struct bpf_queue_stack *qs)
>> +{
>> + u32 head = qs->head + 1;
>> +
>> + if (unlikely(head >= qs->size))
>> + head = 0;
>> +
>> + return head == qs->tail;
>> +}
>> +
>> +/* Called from syscall */
>> +static int queue_stack_map_alloc_check(union bpf_attr *attr)
>> +{
>> + /* check sanity of attributes */
>> + if (attr->max_entries == 0 || attr->key_size != 0 ||
>> + attr->map_flags & ~QUEUE_STACK_CREATE_FLAG_MASK)
>> + return -EINVAL;
>> +
>> + if (attr->value_size > KMALLOC_MAX_SIZE)
>> + /* if value_size is bigger, the user space won't be able to
>> + * access the elements.
>> + */
>> + return -E2BIG;
>> +
>> + return 0;
>> +}
>> +
>> +static struct bpf_map *queue_stack_map_alloc(union bpf_attr *attr)
>> +{
>> + int ret, numa_node = bpf_map_attr_numa_node(attr);
>> + struct bpf_queue_stack *qs;
>> + u32 size, value_size;
>> + u64 queue_size, cost;
>> +
>> + size = attr->max_entries + 1;
>> + value_size = attr->value_size;
>> +
>> + queue_size = sizeof(*qs) + (u64) value_size * size;
>> +
>> + cost = queue_size;
>> + if (cost >= U32_MAX - PAGE_SIZE)
>> + return ERR_PTR(-E2BIG);
>> +
>> + cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
>> +
>> + ret = bpf_map_precharge_memlock(cost);
>> + if (ret < 0)
>> + return ERR_PTR(ret);
>> +
>> + qs = bpf_map_area_alloc(queue_size, numa_node);
>> + if (!qs)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + memset(qs, 0, sizeof(*qs));
>> +
>> + bpf_map_init_from_attr(&qs->map, attr);
>> +
>> + qs->map.pages = cost;
>> + qs->size = size;
>> +
>> + raw_spin_lock_init(&qs->lock);
>> +
>> + return &qs->map;
>> +}
>> +
>> +/* Called when map->refcnt goes to zero, either from workqueue or from syscall */
>> +static void queue_stack_map_free(struct bpf_map *map)
>> +{
>> + struct bpf_queue_stack *qs = bpf_queue_stack(map);
>> +
>> + /* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0,
>> + * so the programs (can be more than one that used this map) were
>> + * disconnected from events. Wait for outstanding critical sections in
>> + * these programs to complete
>> + */
>> + synchronize_rcu();
>> +
>> + bpf_map_area_free(qs);
>> +}
>> +
>> +static int __queue_map_get(struct bpf_map *map, void *value, bool delete)
>> +{
>> + struct bpf_queue_stack *qs = bpf_queue_stack(map);
>> + unsigned long flags;
>> + int err = 0;
>> + void *ptr;
>> +
>> + raw_spin_lock_irqsave(&qs->lock, flags);
>> +
>> + if (queue_stack_map_is_empty(qs)) {
>> + err = -ENOENT;
>> + goto out;
>> + }
>> +
>> + ptr = &qs->elements[qs->tail * qs->map.value_size];
>> + memcpy(value, ptr, qs->map.value_size);
>> +
>> + if (delete) {
>> + if (unlikely(++qs->tail >= qs->size))
>> + qs->tail = 0;
>> + }
>> +
>> +out:
>> + raw_spin_unlock_irqrestore(&qs->lock, flags);
>> + return err;
>> +}
>> +
>> +
>> +static int __stack_map_get(struct bpf_map *map, void *value, bool delete)
>> +{
>> + struct bpf_queue_stack *qs = bpf_queue_stack(map);
>> + unsigned long flags;
>> + int err = 0;
>> + void *ptr;
>> + u32 index;
>> +
>> + raw_spin_lock_irqsave(&qs->lock, flags);
>> +
>> + if (queue_stack_map_is_empty(qs)) {
>> + err = -ENOENT;
>> + goto out;
>> + }
>> +
>> + index = qs->head - 1;
>> + if (unlikely(index >= qs->size))
>> + index = qs->size - 1;
>> +
>> + ptr = &qs->elements[index * qs->map.value_size];
>> + memcpy(value, ptr, qs->map.value_size);
>> +
>> + if (delete)
>> + qs->head = index;
>> +
>> +out:
>> + raw_spin_unlock_irqrestore(&qs->lock, flags);
>> + return err;
>> +}
>> +
>> +/* Called from syscall or from eBPF program */
>> +static int queue_map_peek_elem(struct bpf_map *map, void *value)
>> +{
>> + return __queue_map_get(map, value, false);
>> +}
>> +
>> +/* Called from syscall or from eBPF program */
>> +static int stack_map_peek_elem(struct bpf_map *map, void *value)
>> +{
>> + return __stack_map_get(map, value, false);
>> +}
>> +
>> +/* Called from syscall or from eBPF program */
>> +static int queue_map_pop_elem(struct bpf_map *map, void *value)
>> +{
>> + return __queue_map_get(map, value, true);
>> +}
>> +
>> +/* Called from syscall or from eBPF program */
>> +static int stack_map_pop_elem(struct bpf_map *map, void *value)
>> +{
>> + return __stack_map_get(map, value, true);
>> +}
>> +
>> +/* Called from syscall or from eBPF program */
>> +static int queue_stack_map_push_elem(struct bpf_map *map, void *value,
>> + u64 flags)
>> +{
>> + struct bpf_queue_stack *qs = bpf_queue_stack(map);
>> + unsigned long irq_flags;
>> + int err = 0;
>> + void *dst;
>> +
>> + /* BPF_EXIST is used to force making room for a new element in case the
>> + * map is full
>> + */
>> + bool replace = (flags & BPF_EXIST);
>> +
>> + /* Check supported flags for queue and stack maps */
>> + if (flags & BPF_NOEXIST || flags > BPF_EXIST)
>> + return -EINVAL;
>> +
>> + raw_spin_lock_irqsave(&qs->lock, irq_flags);
>> +
>> + if (queue_stack_map_is_full(qs)) {
>> + if (!replace) {
>> + err = -E2BIG;
>> + goto out;
>> + }
>> + /* advance tail pointer to overwrite oldest element */
>> + if (unlikely(++qs->tail >= qs->size))
>> + qs->tail = 0;
>> + }
>> +
>> + dst = &qs->elements[qs->head * qs->map.value_size];
>> + memcpy(dst, value, qs->map.value_size);
>> +
>> + if (unlikely(++qs->head >= qs->size))
>> + qs->head = 0;
>> +
>> +out:
>> + raw_spin_unlock_irqrestore(&qs->lock, irq_flags);
>> + return err;
>> +}
>> +
>> +/* Called from syscall or from eBPF program */
>> +static void *queue_stack_map_lookup_elem(struct bpf_map *map, void *key)
>> +{
>> + return NULL;
>> +}
>> +
>> +/* Called from syscall or from eBPF program */
>> +static int queue_stack_map_update_elem(struct bpf_map *map, void *key,
>> + void *value, u64 flags)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +/* Called from syscall or from eBPF program */
>> +static int queue_stack_map_delete_elem(struct bpf_map *map, void *key)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +/* Called from syscall */
>> +static int queue_stack_map_get_next_key(struct bpf_map *map, void *key,
>> + void *next_key)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +const struct bpf_map_ops queue_map_ops = {
>> + .map_alloc_check = queue_stack_map_alloc_check,
>> + .map_alloc = queue_stack_map_alloc,
>> + .map_free = queue_stack_map_free,
>> + .map_lookup_elem = queue_stack_map_lookup_elem,
>> + .map_update_elem = queue_stack_map_update_elem,
>> + .map_delete_elem = queue_stack_map_delete_elem,
>> + .map_push_elem = queue_stack_map_push_elem,
>> + .map_pop_elem = queue_map_pop_elem,
>> + .map_peek_elem = queue_map_peek_elem,
>> + .map_get_next_key = queue_stack_map_get_next_key,
>> +};
>> +
>> +const struct bpf_map_ops stack_map_ops = {
>> + .map_alloc_check = queue_stack_map_alloc_check,
>> + .map_alloc = queue_stack_map_alloc,
>> + .map_free = queue_stack_map_free,
>> + .map_lookup_elem = queue_stack_map_lookup_elem,
>> + .map_update_elem = queue_stack_map_update_elem,
>> + .map_delete_elem = queue_stack_map_delete_elem,
>> + .map_push_elem = queue_stack_map_push_elem,
>> + .map_pop_elem = stack_map_pop_elem,
>> + .map_peek_elem = stack_map_peek_elem,
>> + .map_get_next_key = queue_stack_map_get_next_key,
>> +};
>> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> index c33d9303f72f..c135d205fd09 100644
>> --- a/kernel/bpf/syscall.c
>> +++ b/kernel/bpf/syscall.c
>> @@ -727,6 +727,9 @@ static int map_lookup_elem(union bpf_attr *attr)
>> err = bpf_fd_htab_map_lookup_elem(map, key, value);
>> } else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
>> err = bpf_fd_reuseport_array_lookup_elem(map, key, value);
>> + } else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
>> + map->map_type == BPF_MAP_TYPE_STACK) {
>> + err = map->ops->map_peek_elem(map, value);
>> } else {
>> rcu_read_lock();
>> ptr = map->ops->map_lookup_elem(map, key);
>> @@ -841,6 +844,9 @@ static int map_update_elem(union bpf_attr *attr)
>> /* rcu_read_lock() is not needed */
>> err = bpf_fd_reuseport_array_update_elem(map, key, value,
>> attr->flags);
>> + } else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
>> + map->map_type == BPF_MAP_TYPE_STACK) {
>> + err = map->ops->map_push_elem(map, value, attr->flags);
>> } else {
>> rcu_read_lock();
>> err = map->ops->map_update_elem(map, key, value, attr->flags);
>> @@ -1023,16 +1029,22 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr)
>> */
>> preempt_disable();
>> __this_cpu_inc(bpf_prog_active);
>> - if (!map->ops->map_lookup_and_delete_elem) {
>> - err = -ENOTSUPP;
>> - goto free_value;
>> + if (map->map_type == BPF_MAP_TYPE_QUEUE ||
>> + map->map_type == BPF_MAP_TYPE_STACK) {
>> + err = map->ops->map_pop_elem(map, value);
>> + } else {
>> + if (!map->ops->map_lookup_and_delete_elem) {
>> + err = -ENOTSUPP;
>> + goto free_value;
> similar to previous patch: either we move this check, or we add
> __this_cpu_dec() and preempt_enable().
In this case the check cannot be moved, I'll change it to fix the
problem and make it more readable.
>
> Thanks,
> Song
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox