Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v3 net-next 9/9] dt-bindings: net: stmmac: Add the bindings documentation for XGMAC2.
From: Rob Herring @ 2018-08-07 17:36 UTC (permalink / raw)
  To: Jose Abreu
  Cc: netdev, David S. Miller, Joao Pinto, Giuseppe Cavallaro,
	Alexandre Torgue, Sergei Shtylyov, devicetree
In-Reply-To: <782f85bb556f1f1d8b4eb0b803092ecb4a2c98a8.1533311285.git.joabreu@synopsys.com>

On Fri, Aug 03, 2018 at 04:50:27PM +0100, Jose Abreu wrote:
> Adds the documentation for XGMAC2 DT bindings.
> 
> Signed-off-by: Jose Abreu <joabreu@synopsys.com>
> Cc: David S. Miller <davem@davemloft.net>
> Cc: Joao Pinto <jpinto@synopsys.com>
> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> Cc: Alexandre Torgue <alexandre.torgue@st.com>
> Cc: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> Cc: devicetree@vger.kernel.org
> Cc: Rob Herring <robh+dt@kernel.org>
> ---
> Changes from v1:
> 	- Correct header, now we also support 2.5/10G.
> 	- Add missing '>' (Sergei)
> ---
>  Documentation/devicetree/bindings/net/stmmac.txt | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt
> index 3a28a5d8857d..a32fd590ce8f 100644
> --- a/Documentation/devicetree/bindings/net/stmmac.txt
> +++ b/Documentation/devicetree/bindings/net/stmmac.txt
> @@ -1,7 +1,8 @@
> -* STMicroelectronics 10/100/1000 Ethernet driver (GMAC)
> +* STMicroelectronics 10/100/1000/2500/10000 Ethernet driver (GMAC/XGMAC)

Bindings don't describe drivers.

>  
>  Required properties:
> -- compatible: Should be "snps,dwmac-<ip_version>", "snps,dwmac"
> +- compatible: Should be "snps,dwmac-<ip_version>", "snps,dwmac" or
> +	"snps,dwxgmac-<ip_version>", "snps,dwxgmac".
>  	For backwards compatibility: "st,spear600-gmac" is also supported.
>  - reg: Address and length of the register set for the device
>  - interrupt-parent: Should be the phandle for the interrupt controller
> -- 
> 2.7.4
> 
> 

^ permalink raw reply

* [PATCH lora-next 10/10] net: lora: sx1301: convert all firmware to regmap
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

The last stage in the probe function loads the final firmwares to
the sx1301.

Signed-off-by: Ben Whitten <ben.whitten@gmail.com>
---
 drivers/net/lora/sx1301.c | 67 ++++++++++++++++++++---------------------------
 1 file changed, 28 insertions(+), 39 deletions(-)

diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index 21b3f9a..7f4bfa1 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -663,16 +663,15 @@ static int sx1301_agc_calibrate(struct sx1301_priv *priv)
 	return 0;
 }
 
-static int sx1301_load_all_firmware(struct spi_device *spi)
+static int sx1301_load_all_firmware(struct sx1301_priv *priv)
 {
-	struct sx1301_priv *priv = spi_get_drvdata(spi);
 	const struct firmware *fw;
 	u8 val;
 	int ret;
 
 	ret = request_firmware(&fw, "sx1301_arb.bin", priv->dev);
 	if (ret) {
-		dev_err(priv->dev, "arb firmware file load failed\n");
+		dev_err(priv->dev, "ARB firmware file load failed\n");
 		return ret;
 	}
 
@@ -683,7 +682,7 @@ static int sx1301_load_all_firmware(struct spi_device *spi)
 
 	ret = request_firmware(&fw, "sx1301_agc.bin", priv->dev);
 	if (ret) {
-		dev_err(priv->dev, "agc firmware file load failed\n");
+		dev_err(priv->dev, "AGC firmware file load failed\n");
 		return ret;
 	}
 
@@ -692,63 +691,53 @@ static int sx1301_load_all_firmware(struct spi_device *spi)
 	if (ret)
 		return ret;
 
-	ret = sx1301_page_read(spi, 0, 105, &val);
-	if (ret) {
-		dev_err(&spi->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 = sx1301_page_write(spi, 0, 105, val);
-	if (ret) {
-		dev_err(&spi->dev, "0|105 write failed\n");
+	ret = sx1301_field_write(priv, F_FORCE_HOST_FE_CTRL, 0);
+	if (ret)
 		return ret;
-	}
-
-	ret = sx1301_page_write(spi, 0, REG_0_RADIO_SELECT, 0);
-	if (ret) {
-		dev_err(&spi->dev, "radio select write failed\n");
+	ret = sx1301_field_write(priv, F_FORCE_DEC_FILTER_GAIN, 0);
+	if (ret)
 		return ret;
-	}
 
-	ret = sx1301_page_read(spi, 0, REG_0_MCU, &val);
-	if (ret) {
-		dev_err(&spi->dev, "MCU read (0) failed\n");
+	ret = regmap_write(priv->regmap, SX1301_CHRS, 0);
+	if (ret)
 		return ret;
-	}
-
-	val &= ~(REG_0_MCU_RST_1 | REG_0_MCU_RST_0);
 
-	ret = sx1301_page_write(spi, 0, REG_0_MCU, val);
-	if (ret) {
-		dev_err(&spi->dev, "MCU write (0) failed\n");
+	/* Release the CPUs */
+	ret = sx1301_field_write(priv, F_MCU_RST_0, 0);
+	if (ret)
+		return ret;
+	ret = sx1301_field_write(priv, F_MCU_RST_1, 0);
+	if (ret)
 		return ret;
-	}
 
 	ret = sx1301_agc_ram_read(priv, 0x20, &val);
 	if (ret) {
-		dev_err(&spi->dev, "AGC RAM data read failed\n");
+		dev_err(priv->dev, "AGC RAM data read failed\n");
 		return ret;
 	}
 
-	dev_info(&spi->dev, "AGC firmware version %u\n", (unsigned)val);
+	dev_info(priv->dev, "AGC firmware version %u\n", (unsigned)val);
 
-	if (val != 4) {
-		dev_err(&spi->dev, "unexpected firmware version, expecting %u\n", 4);
+	if (val != SX1301_MCU_AGC_FW_VERSION) {
+		dev_err(priv->dev, "unexpected firmware version, expecting %u\n",
+				SX1301_MCU_AGC_FW_VERSION);
 		return -ENXIO;
 	}
 
 	ret = sx1301_arb_ram_read(priv, 0x20, &val);
 	if (ret) {
-		dev_err(&spi->dev, "ARB RAM data read failed\n");
+		dev_err(priv->dev, "ARB RAM data read failed\n");
 		return ret;
 	}
 
-	dev_info(&spi->dev, "ARB firmware version %u\n", (unsigned)val);
+	dev_info(priv->dev, "ARB firmware version %u\n", (unsigned)val);
 
-	if (val != 1) {
-		dev_err(&spi->dev, "unexpected firmware version, expecting %u\n", 1);
+	if (val != SX1301_MCU_ARB_FW_VERSION) {
+		dev_err(priv->dev, "unexpected firmware version, expecting %u\n",
+				SX1301_MCU_ARB_FW_VERSION);
 		return -ENXIO;
 	}
 
@@ -942,7 +931,7 @@ static int sx1301_probe(struct spi_device *spi)
 
 	/* TODO */
 
-	ret = sx1301_load_all_firmware(spi);
+	ret = sx1301_load_all_firmware(priv);
 	if (ret)
 		return ret;
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 09/10] net: lora: sx1301: convert agc calibrate to regmap functions
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

We convert the AGC calibration function over to regmap and take the
opportunity to make the expected firmware versions defines.
Switch to taking a pointer to our private data.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/sx1301.c | 101 ++++++++++++----------------------------------
 1 file changed, 26 insertions(+), 75 deletions(-)

diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index f84a6ce..21b3f9a 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -589,123 +589,74 @@ static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct
 	return 0;
 }
 
-static int sx1301_agc_calibrate(struct spi_device *spi)
+static int sx1301_agc_calibrate(struct sx1301_priv *priv)
 {
 	const struct firmware *fw;
-	struct sx1301_priv *priv = spi_get_drvdata(spi);
 	u8 val;
 	int ret;
+	unsigned int cal;
 
 	ret = request_firmware(&fw, "sx1301_agc_calibration.bin", priv->dev);
 	if (ret) {
-		dev_err(&spi->dev, "agc cal firmware file load failed\n");
+		dev_err(priv->dev, "AGC CAL firmware file load failed\n");
 		return ret;
 	}
 
 	ret = sx1301_load_firmware(priv, 1, fw);
 	release_firmware(fw);
 	if (ret) {
-		dev_err(&spi->dev, "agc cal firmware load failed\n");
-		return ret;
-	}
-
-	ret = sx1301_page_read(spi, 0, 105, &val);
-	if (ret) {
-		dev_err(&spi->dev, "0|105 read failed\n");
+		dev_err(priv->dev, "AGC CAL firmware load failed\n");
 		return ret;
 	}
 
-	val &= ~REG_0_105_FORCE_HOST_RADIO_CTRL;
-
-	ret = sx1301_page_write(spi, 0, 105, val);
-	if (ret) {
-		dev_err(&spi->dev, "0|105 write failed\n");
+	ret = sx1301_field_write(priv, F_FORCE_HOST_RADIO_CTRL, 0);
+	if (ret)
 		return ret;
-	}
 
 	val = BIT(4); /* with DAC gain=3 */
 	if (false)
 		val |= BIT(5); /* SX1255 */
 
-	ret = sx1301_page_write(spi, 0, REG_0_RADIO_SELECT, val);
-	if (ret) {
-		dev_err(&spi->dev, "radio select write failed\n");
-		return ret;
-	}
-
-	ret = sx1301_page_read(spi, 0, REG_0_MCU, &val);
-	if (ret) {
-		dev_err(&spi->dev, "MCU read (0) failed\n");
+	ret = regmap_write(priv->regmap, SX1301_CHRS, val);
+	if (ret)
 		return ret;
-	}
-
-	val &= ~REG_0_MCU_RST_1;
 
-	ret = sx1301_page_write(spi, 0, REG_0_MCU, val);
-	if (ret) {
-		dev_err(&spi->dev, "MCU write (0) failed\n");
+	ret = sx1301_field_write(priv, F_MCU_RST_1, 0);
+	if (ret)
 		return ret;
-	}
 
 	ret = sx1301_agc_ram_read(priv, 0x20, &val);
 	if (ret) {
-		dev_err(&spi->dev, "AGC RAM data read failed\n");
+		dev_err(priv->dev, "AGC RAM data read failed\n");
 		return ret;
 	}
 
-	dev_info(&spi->dev, "AGC calibration firmware version %u\n", (unsigned)val);
+	dev_info(priv->dev, "AGC calibration firmware version %u\n", (unsigned)val);
 
-	if (val != 2) {
-		dev_err(&spi->dev, "unexpected firmware version, expecting %u\n", 2);
+	if (val != SX1301_MCU_AGC_CAL_FW_VERSION) {
+		dev_err(priv->dev, "unexpected firmware version, expecting %u\n",
+				SX1301_MCU_AGC_CAL_FW_VERSION);
 		return -ENXIO;
 	}
 
-	ret = sx1301_page_switch(spi, 3);
-	if (ret) {
-		dev_err(&spi->dev, "page switch 3 failed\n");
-		return ret;
-	}
-
-	ret = sx1301_read(priv, REG_EMERGENCY_FORCE, &val);
-	if (ret) {
-		dev_err(&spi->dev, "emergency force read failed\n");
-		return ret;
-	}
-
-	val &= ~REG_EMERGENCY_FORCE_HOST_CTRL;
-
-	ret = sx1301_write(priv, REG_EMERGENCY_FORCE, val);
-	if (ret) {
-		dev_err(&spi->dev, "emergency force write failed\n");
+	ret = sx1301_field_write(priv, F_EMERGENCY_FORCE_HOST_CTRL, 0);
+	if (ret)
 		return ret;
-	}
 
-	dev_err(&spi->dev, "starting calibration...\n");
+	dev_err(priv->dev, "starting calibration...\n");
 	msleep(2300);
 
-	ret = sx1301_read(priv, REG_EMERGENCY_FORCE, &val);
-	if (ret) {
-		dev_err(&spi->dev, "emergency force read (1) failed\n");
-		return ret;
-	}
-
-	val |= REG_EMERGENCY_FORCE_HOST_CTRL;
-
-	ret = sx1301_write(priv, REG_EMERGENCY_FORCE, val);
-	if (ret) {
-		dev_err(&spi->dev, "emergency force write (1) failed\n");
+	ret = sx1301_field_write(priv, F_EMERGENCY_FORCE_HOST_CTRL, 1);
+	if (ret)
 		return ret;
-	}
 
-	ret = sx1301_read(priv, REG_MCU_AGC_STATUS, &val);
-	if (ret) {
-		dev_err(&spi->dev, "AGC status read failed\n");
+	ret = regmap_read(priv->regmap, SX1301_AGCSTS, &cal);
+	if (ret)
 		return ret;
-	}
 
-	dev_info(&spi->dev, "AGC status: %02x\n", (unsigned)val);
-	if ((val & (BIT(7) | BIT(0))) != (BIT(7) | BIT(0))) {
-		dev_err(&spi->dev, "AGC calibration failed\n");
+	dev_info(priv->dev, "AGC status: %02x\n", cal);
+	if ((cal & (BIT(7) | BIT(0))) != (BIT(7) | BIT(0))) {
+		dev_err(priv->dev, "AGC calibration failed\n");
 		return -ENXIO;
 	}
 
@@ -985,7 +936,7 @@ static int sx1301_probe(struct spi_device *spi)
 
 	/* calibration */
 
-	ret = sx1301_agc_calibrate(spi);
+	ret = sx1301_agc_calibrate(priv);
 	if (ret)
 		return ret;
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 08/10] net: lora: sx1301: convert read and write to priv pointer
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

Convert the next layer of read and writes to our private pointer,
once again compatiblity later in the page read and write layer.
The page functions will be removed with this full stack as page switches
are handled by regmap automatically.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/sx1301.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index ab45b5b..f84a6ce 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -318,9 +318,8 @@ static int sx1301_read_burst(struct sx1301_priv *priv, u8 reg, u8 *val, size_t l
 	return spi_write_then_read(priv->spi, &addr, 1, val, len);
 }
 
-static int sx1301_read(struct spi_device *spi, u8 reg, u8 *val)
+static int sx1301_read(struct sx1301_priv *priv, u8 reg, u8 *val)
 {
-	struct sx1301_priv *priv = spi_get_drvdata(spi);
 	return sx1301_read_burst(priv, reg, val, 1);
 }
 
@@ -335,9 +334,8 @@ static int sx1301_write_burst(struct sx1301_priv *priv, u8 reg, const u8 *val, s
 	return spi_sync_transfer(priv->spi, xfr, 2);
 }
 
-static int sx1301_write(struct spi_device *spi, u8 reg, u8 val)
+static int sx1301_write(struct sx1301_priv *priv, u8 reg, u8 val)
 {
-	struct sx1301_priv *priv = spi_get_drvdata(spi);
 	return sx1301_write_burst(priv, reg, &val, 1);
 }
 
@@ -350,7 +348,7 @@ static int sx1301_page_switch(struct spi_device *spi, u8 page)
 		return 0;
 
 	dev_dbg(&spi->dev, "switching to page %u\n", (unsigned)page);
-	ret = sx1301_write(spi, REG_PAGE_RESET, page & 0x3);
+	ret = sx1301_write(priv, REG_PAGE_RESET, page & 0x3);
 	if (ret) {
 		dev_err(&spi->dev, "switching to page %u failed\n", (unsigned)page);
 		return ret;
@@ -364,23 +362,25 @@ static int sx1301_page_switch(struct spi_device *spi, u8 page)
 static int sx1301_page_read(struct spi_device *spi, u8 page, u8 reg, u8 *val)
 {
 	int ret;
+	struct sx1301_priv *priv = spi_get_drvdata(spi);
 
 	ret = sx1301_page_switch(spi, page);
 	if (ret)
 		return ret;
 
-	return sx1301_read(spi, reg, val);
+	return sx1301_read(priv, reg, val);
 }
 
 static int sx1301_page_write(struct spi_device *spi, u8 page, u8 reg, u8 val)
 {
 	int ret;
+	struct sx1301_priv *priv = spi_get_drvdata(spi);
 
 	ret = sx1301_page_switch(spi, page);
 	if (ret)
 		return ret;
 
-	return sx1301_write(spi, reg, val);
+	return sx1301_write(priv, reg, val);
 }
 
 #define REG_RADIO_X_DATA		0
@@ -666,7 +666,7 @@ static int sx1301_agc_calibrate(struct spi_device *spi)
 		return ret;
 	}
 
-	ret = sx1301_read(spi, REG_EMERGENCY_FORCE, &val);
+	ret = sx1301_read(priv, REG_EMERGENCY_FORCE, &val);
 	if (ret) {
 		dev_err(&spi->dev, "emergency force read failed\n");
 		return ret;
@@ -674,7 +674,7 @@ static int sx1301_agc_calibrate(struct spi_device *spi)
 
 	val &= ~REG_EMERGENCY_FORCE_HOST_CTRL;
 
-	ret = sx1301_write(spi, REG_EMERGENCY_FORCE, val);
+	ret = sx1301_write(priv, REG_EMERGENCY_FORCE, val);
 	if (ret) {
 		dev_err(&spi->dev, "emergency force write failed\n");
 		return ret;
@@ -683,7 +683,7 @@ static int sx1301_agc_calibrate(struct spi_device *spi)
 	dev_err(&spi->dev, "starting calibration...\n");
 	msleep(2300);
 
-	ret = sx1301_read(spi, REG_EMERGENCY_FORCE, &val);
+	ret = sx1301_read(priv, REG_EMERGENCY_FORCE, &val);
 	if (ret) {
 		dev_err(&spi->dev, "emergency force read (1) failed\n");
 		return ret;
@@ -691,13 +691,13 @@ static int sx1301_agc_calibrate(struct spi_device *spi)
 
 	val |= REG_EMERGENCY_FORCE_HOST_CTRL;
 
-	ret = sx1301_write(spi, REG_EMERGENCY_FORCE, val);
+	ret = sx1301_write(priv, REG_EMERGENCY_FORCE, val);
 	if (ret) {
 		dev_err(&spi->dev, "emergency force write (1) failed\n");
 		return ret;
 	}
 
-	ret = sx1301_read(spi, REG_MCU_AGC_STATUS, &val);
+	ret = sx1301_read(priv, REG_MCU_AGC_STATUS, &val);
 	if (ret) {
 		dev_err(&spi->dev, "AGC status read failed\n");
 		return ret;
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 07/10] net: lora: sx1301: convert read and write burst to take priv data
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

As part of standardising on passing our priv data around we convert read
and write burst to take the priv data, there is a small compat step
needed in the old _read and _write functions and will be removed in the
next step.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/sx1301.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index 4cec524..ab45b5b 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -312,18 +312,19 @@ static int sx1301_field_write(struct sx1301_priv *priv,
 	return regmap_field_write(priv->regmap_fields[field_id], val);
 }
 
-static int sx1301_read_burst(struct spi_device *spi, u8 reg, u8 *val, size_t len)
+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(spi, &addr, 1, val, len);
+	return spi_write_then_read(priv->spi, &addr, 1, val, len);
 }
 
 static int sx1301_read(struct spi_device *spi, u8 reg, u8 *val)
 {
-	return sx1301_read_burst(spi, reg, val, 1);
+	struct sx1301_priv *priv = spi_get_drvdata(spi);
+	return sx1301_read_burst(priv, reg, val, 1);
 }
 
-static int sx1301_write_burst(struct spi_device *spi, u8 reg, const u8 *val, size_t 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] = {
@@ -331,12 +332,13 @@ static int sx1301_write_burst(struct spi_device *spi, u8 reg, const u8 *val, siz
 		{ .tx_buf = val, .len = len },
 	};
 
-	return spi_sync_transfer(spi, xfr, 2);
+	return spi_sync_transfer(priv->spi, xfr, 2);
 }
 
 static int sx1301_write(struct spi_device *spi, u8 reg, u8 val)
 {
-	return sx1301_write_burst(spi, reg, &val, 1);
+	struct sx1301_priv *priv = spi_get_drvdata(spi);
+	return sx1301_write_burst(priv, reg, &val, 1);
 }
 
 static int sx1301_page_switch(struct spi_device *spi, u8 page)
@@ -551,7 +553,7 @@ static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct
 	if (ret)
 		return ret;
 
-	ret = sx1301_write_burst(priv->spi, REG_MCU_PROM_DATA, fw->data, fw->size);
+	ret = sx1301_write_burst(priv, REG_MCU_PROM_DATA, fw->data, fw->size);
 	if (ret) {
 		dev_err(priv->dev, "MCU prom data write failed\n");
 		return ret;
@@ -567,7 +569,7 @@ static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct
 	if (!buf)
 		return -ENOMEM;
 
-	ret = sx1301_read_burst(priv->spi, REG_MCU_PROM_DATA, buf, fw->size);
+	ret = sx1301_read_burst(priv, REG_MCU_PROM_DATA, buf, fw->size);
 	if (ret) {
 		dev_err(priv->dev, "MCU prom data read failed\n");
 		return ret;
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 06/10] net: lora: sx1301: simplify firmware loading and convert
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

As part of changing our internal pointers to our priv data we add the
spi_device temporarily for downstream burst read/writes.
Just pass firmware pointer to the load and remove redundant size checks,
as both MCUs have the same program size add a define.

Use devm_kzalloc for automatic cleanup on failure to load firmware,
manually cleaup this memory on success.

Convert firmware loading to regmap functions.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/sx1301.c | 109 ++++++++++++++++------------------------------
 1 file changed, 37 insertions(+), 72 deletions(-)

diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index 249551b..4cec524 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -284,6 +284,7 @@ struct spi_sx1301 {
 
 struct sx1301_priv {
 	struct device *dev;
+	struct spi_device *spi;
 	struct lora_priv lora;
 	struct gpio_desc *rst_gpio;
 	u8 cur_page;
@@ -515,93 +516,73 @@ static int sx1301_arb_ram_read(struct sx1301_priv *priv, u8 addr, u8 *val)
 	return 0;
 }
 
-static int sx1301_load_firmware(struct spi_device *spi, int mcu, const u8 *data, size_t len)
+static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct firmware *fw)
 {
 	u8 *buf;
-	u8 val, rst, select_mux;
 	int ret;
+	unsigned int read;
+	enum sx1301_fields rst, select_mux;
 
-	if (len > 8192)
+	if (fw->size > SX1301_MCU_FW_BYTE)
 		return -EINVAL;
 
 	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 = sx1301_page_read(spi, 0, REG_0_MCU, &val);
-	if (ret) {
-		dev_err(&spi->dev, "MCU read failed\n");
+	ret = sx1301_field_write(priv, rst, 1);
+	if (ret)
 		return ret;
-	}
-
-	val |= rst;
-	val &= ~select_mux;
-
-	ret = sx1301_page_write(spi, 0, REG_0_MCU, val);
-	if (ret) {
-		dev_err(&spi->dev, "MCU reset / select mux write failed\n");
+	ret = sx1301_field_write(priv, select_mux, 0);
+	if (ret)
 		return ret;
-	}
 
-	ret = sx1301_write(spi, REG_MCU_PROM_ADDR, 0);
-	if (ret) {
-		dev_err(&spi->dev, "MCU prom addr write failed\n");
+	/* Load firmware into the data register */
+	ret = regmap_write(priv->regmap, SX1301_MPA, 0);
+	if (ret)
 		return ret;
-	}
 
-	ret = sx1301_write_burst(spi, REG_MCU_PROM_DATA, data, len);
+	ret = sx1301_write_burst(priv->spi, REG_MCU_PROM_DATA, fw->data, fw->size);
 	if (ret) {
-		dev_err(&spi->dev, "MCU prom data write failed\n");
+		dev_err(priv->dev, "MCU prom data write failed\n");
 		return ret;
 	}
 
-	ret = sx1301_read(spi, REG_MCU_PROM_DATA, &val);
+	ret = regmap_read(priv->regmap, SX1301_MPD, &read);
 	if (ret) {
-		dev_err(&spi->dev, "MCU prom data dummy read failed\n");
+		dev_err(priv->dev, "MCU prom data dummy read failed\n");
 		return ret;
 	}
 
-	buf = kzalloc(len, GFP_KERNEL);
+	buf = devm_kzalloc(priv->dev, fw->size, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
-	ret = sx1301_read_burst(spi, REG_MCU_PROM_DATA, buf, len);
+	ret = sx1301_read_burst(priv->spi, REG_MCU_PROM_DATA, buf, fw->size);
 	if (ret) {
-		dev_err(&spi->dev, "MCU prom data read failed\n");
-		kfree(buf);
+		dev_err(priv->dev, "MCU prom data read failed\n");
 		return ret;
 	}
 
-	if (memcmp(data, buf, len)) {
-		dev_err(&spi->dev, "MCU prom data read does not match data written\n");
-		kfree(buf);
+	if (memcmp(fw->data, buf, fw->size)) {
+		dev_err(priv->dev, "MCU prom data read does not match data written\n");
 		return -ENXIO;
 	}
 
-	kfree(buf);
+	devm_kfree(priv->dev, buf);
 
-	ret = sx1301_page_read(spi, 0, REG_0_MCU, &val);
-	if (ret) {
-		dev_err(&spi->dev, "MCU read (1) failed\n");
-		return ret;
-	}
-
-	val |= select_mux;
-
-	ret = sx1301_page_write(spi, 0, REG_0_MCU, val);
-	if (ret) {
-		dev_err(&spi->dev, "MCU reset / select mux write (1) failed\n");
+	ret = sx1301_field_write(priv, select_mux, 1);
+	if (ret)
 		return ret;
-	}
 
 	return 0;
 }
@@ -613,18 +594,13 @@ static int sx1301_agc_calibrate(struct spi_device *spi)
 	u8 val;
 	int ret;
 
-	ret = request_firmware(&fw, "sx1301_agc_calibration.bin", &spi->dev);
+	ret = request_firmware(&fw, "sx1301_agc_calibration.bin", priv->dev);
 	if (ret) {
 		dev_err(&spi->dev, "agc cal firmware file load failed\n");
 		return ret;
 	}
 
-	if (fw->size != 8192) {
-		dev_err(&spi->dev, "unexpected agc cal firmware size\n");
-		return -EINVAL;
-	}
-
-	ret = sx1301_load_firmware(spi, 1, fw->data, fw->size);
+	ret = sx1301_load_firmware(priv, 1, fw);
 	release_firmware(fw);
 	if (ret) {
 		dev_err(&spi->dev, "agc cal firmware load failed\n");
@@ -741,36 +717,24 @@ static int sx1301_load_all_firmware(struct spi_device *spi)
 	u8 val;
 	int ret;
 
-	ret = request_firmware(&fw, "sx1301_arb.bin", &spi->dev);
+	ret = request_firmware(&fw, "sx1301_arb.bin", priv->dev);
 	if (ret) {
-		dev_err(&spi->dev, "arb firmware file load failed\n");
+		dev_err(priv->dev, "arb firmware file load failed\n");
 		return ret;
 	}
 
-	if (fw->size != 8192) {
-		dev_err(&spi->dev, "unexpected arb firmware size\n");
-		release_firmware(fw);
-		return -EINVAL;
-	}
-
-	ret = sx1301_load_firmware(spi, 0, fw->data, fw->size);
+	ret = sx1301_load_firmware(priv, 0, fw);
 	release_firmware(fw);
 	if (ret)
 		return ret;
 
-	ret = request_firmware(&fw, "sx1301_agc.bin", &spi->dev);
+	ret = request_firmware(&fw, "sx1301_agc.bin", priv->dev);
 	if (ret) {
-		dev_err(&spi->dev, "agc firmware file load failed\n");
+		dev_err(priv->dev, "agc firmware file load failed\n");
 		return ret;
 	}
 
-	if (fw->size != 8192) {
-		dev_err(&spi->dev, "unexpected agc firmware size\n");
-		release_firmware(fw);
-		return -EINVAL;
-	}
-
-	ret = sx1301_load_firmware(spi, 1, fw->data, fw->size);
+	ret = sx1301_load_firmware(priv, 1, fw);
 	release_firmware(fw);
 	if (ret)
 		return ret;
@@ -886,6 +850,7 @@ static int sx1301_probe(struct spi_device *spi)
 	spi_set_drvdata(spi, netdev);
 	SET_NETDEV_DEV(netdev, &spi->dev);
 	priv->dev = &spi->dev;
+	priv->spi = spi;
 
 	priv->regmap = devm_regmap_init_spi(spi, &sx1301_regmap_config);
 	if (IS_ERR(priv->regmap)) {
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 05/10] net: lora: sx1301: add device to private data and convert ram reads
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

It's easier to simply add a pointer to our device to our private data,
this way we can avoid passing around our spi_device and instead just
pass private data which is more flexible.

As its a two line change its coupled with converting AGC and ARB ram reads
to regmap functions.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/sx1301.c | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index 118e8d8..249551b 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -283,6 +283,7 @@ struct spi_sx1301 {
 };
 
 struct sx1301_priv {
+	struct device *dev;
 	struct lora_priv lora;
 	struct gpio_desc *rst_gpio;
 	u8 cur_page;
@@ -472,40 +473,44 @@ static int sx1301_radio_spi_transfer_one(struct spi_controller *ctrl,
 	return 0;
 }
 
-static int sx1301_agc_ram_read(struct spi_device *spi, u8 addr, u8 *val)
+static int sx1301_agc_ram_read(struct sx1301_priv *priv, u8 addr, u8 *val)
 {
 	int ret;
+	unsigned int read;
 
-	ret = sx1301_page_write(spi, 2, REG_2_DBG_AGC_MCU_RAM_ADDR, addr);
+	ret = regmap_write(priv->regmap, SX1301_DBG_AGC_MCU_RAM_ADDR, addr);
 	if (ret) {
-		dev_err(&spi->dev, "AGC RAM addr write failed\n");
+		dev_err(priv->dev, "AGC RAM addr write failed\n");
 		return ret;
 	}
 
-	ret = sx1301_page_read(spi, 2, REG_2_DBG_AGC_MCU_RAM_DATA, val);
+	ret = regmap_read(priv->regmap, SX1301_DBG_AGC_MCU_RAM_DATA, &read);
 	if (ret) {
-		dev_err(&spi->dev, "AGC RAM data read failed\n");
+		dev_err(priv->dev, "AGC RAM data read failed\n");
 		return ret;
 	}
+	*val = read;
 
 	return 0;
 }
 
-static int sx1301_arb_ram_read(struct spi_device *spi, u8 addr, u8 *val)
+static int sx1301_arb_ram_read(struct sx1301_priv *priv, u8 addr, u8 *val)
 {
 	int ret;
+	unsigned int read;
 
-	ret = sx1301_page_write(spi, 2, REG_2_DBG_ARB_MCU_RAM_ADDR, addr);
+	ret = regmap_write(priv->regmap, SX1301_DBG_ARB_MCU_RAM_ADDR, addr);
 	if (ret) {
-		dev_err(&spi->dev, "ARB RAM addr write failed\n");
+		dev_err(priv->dev, "ARB RAM addr write failed\n");
 		return ret;
 	}
 
-	ret = sx1301_page_read(spi, 2, REG_2_DBG_ARB_MCU_RAM_DATA, val);
+	ret = regmap_read(priv->regmap, SX1301_DBG_ARB_MCU_RAM_DATA, &read);
 	if (ret) {
-		dev_err(&spi->dev, "ARB RAM data read failed\n");
+		dev_err(priv->dev, "ARB RAM data read failed\n");
 		return ret;
 	}
+	*val = read;
 
 	return 0;
 }
@@ -604,6 +609,7 @@ static int sx1301_load_firmware(struct spi_device *spi, int mcu, const u8 *data,
 static int sx1301_agc_calibrate(struct spi_device *spi)
 {
 	const struct firmware *fw;
+	struct sx1301_priv *priv = spi_get_drvdata(spi);
 	u8 val;
 	int ret;
 
@@ -663,7 +669,7 @@ static int sx1301_agc_calibrate(struct spi_device *spi)
 		return ret;
 	}
 
-	ret = sx1301_agc_ram_read(spi, 0x20, &val);
+	ret = sx1301_agc_ram_read(priv, 0x20, &val);
 	if (ret) {
 		dev_err(&spi->dev, "AGC RAM data read failed\n");
 		return ret;
@@ -730,6 +736,7 @@ static int sx1301_agc_calibrate(struct spi_device *spi)
 
 static int sx1301_load_all_firmware(struct spi_device *spi)
 {
+	struct sx1301_priv *priv = spi_get_drvdata(spi);
 	const struct firmware *fw;
 	u8 val;
 	int ret;
@@ -802,7 +809,7 @@ static int sx1301_load_all_firmware(struct spi_device *spi)
 		return ret;
 	}
 
-	ret = sx1301_agc_ram_read(spi, 0x20, &val);
+	ret = sx1301_agc_ram_read(priv, 0x20, &val);
 	if (ret) {
 		dev_err(&spi->dev, "AGC RAM data read failed\n");
 		return ret;
@@ -815,7 +822,7 @@ static int sx1301_load_all_firmware(struct spi_device *spi)
 		return -ENXIO;
 	}
 
-	ret = sx1301_arb_ram_read(spi, 0x20, &val);
+	ret = sx1301_arb_ram_read(priv, 0x20, &val);
 	if (ret) {
 		dev_err(&spi->dev, "ARB RAM data read failed\n");
 		return ret;
@@ -878,6 +885,7 @@ static int sx1301_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, netdev);
 	SET_NETDEV_DEV(netdev, &spi->dev);
+	priv->dev = &spi->dev;
 
 	priv->regmap = devm_regmap_init_spi(spi, &sx1301_regmap_config);
 	if (IS_ERR(priv->regmap)) {
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 04/10] net: lora: sx1301: convert probe function to regmap access
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

Keeping change sets small we convert the probe function over to regmap
and regmap_field access for initialisation.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/sx1301.c | 155 +++++++++-------------------------------------
 drivers/net/lora/sx1301.h |   7 +++
 2 files changed, 35 insertions(+), 127 deletions(-)

diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index 54bfc31..118e8d8 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -379,11 +379,6 @@ static int sx1301_page_write(struct spi_device *spi, u8 page, u8 reg, u8 val)
 	return sx1301_write(spi, reg, val);
 }
 
-static int sx1301_soft_reset(struct spi_device *spi)
-{
-	return sx1301_write(spi, REG_PAGE_RESET, REG_PAGE_RESET_SOFT_RESET);
-}
-
 #define REG_RADIO_X_DATA		0
 #define REG_RADIO_X_DATA_READBACK	1
 #define REG_RADIO_X_ADDR		2
@@ -854,7 +849,6 @@ static int sx1301_probe(struct spi_device *spi)
 	int ret;
 	int i;
 	unsigned int ver;
-	u8 val;
 
 	rst = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(rst))
@@ -911,96 +905,46 @@ static int sx1301_probe(struct spi_device *spi)
 		return ret;
 	}
 
-	if (ver != 103) {
+	if (ver != SX1301_CHIP_VERSION) {
 		dev_err(&spi->dev, "unexpected version: %u\n", ver);
 		return -ENXIO;
 	}
 
-	ret = sx1301_write(spi, REG_PAGE_RESET, 0);
+	ret = regmap_write(priv->regmap, SX1301_PAGE, 0);
 	if (ret) {
 		dev_err(&spi->dev, "page/reset write failed\n");
 		return ret;
 	}
 
-	ret = sx1301_soft_reset(spi);
+	ret = sx1301_field_write(priv, F_SOFT_RESET, 1);
 	if (ret) {
 		dev_err(&spi->dev, "soft reset failed\n");
 		return ret;
 	}
 
-	ret = sx1301_read(spi, 16, &val);
-	if (ret) {
-		dev_err(&spi->dev, "16 read failed\n");
-		return ret;
-	}
-
-	val &= ~REG_16_GLOBAL_EN;
-
-	ret = sx1301_write(spi, 16, val);
-	if (ret) {
-		dev_err(&spi->dev, "16 write failed\n");
-		return ret;
-	}
-
-	ret = sx1301_read(spi, 17, &val);
-	if (ret) {
-		dev_err(&spi->dev, "17 read failed\n");
-		return ret;
-	}
-
-	val &= ~REG_17_CLK32M_EN;
-
-	ret = sx1301_write(spi, 17, val);
-	if (ret) {
-		dev_err(&spi->dev, "17 write failed\n");
-		return ret;
-	}
-
-	ret = sx1301_page_read(spi, 2, 43, &val);
-	if (ret) {
-		dev_err(&spi->dev, "2|43 read failed\n");
+	/* gate clocks */
+	ret = sx1301_field_write(priv, F_GLOBAL_EN, 0);
+	if (ret)
 		return ret;
-	}
-
-	val |= REG_2_43_RADIO_B_EN | REG_2_43_RADIO_A_EN;
-
-	ret = sx1301_page_write(spi, 2, 43, val);
-	if (ret) {
-		dev_err(&spi->dev, "2|43 write failed\n");
+	ret = sx1301_field_write(priv, F_CLK32M_EN, 0);
+	if (ret)
 		return ret;
-	}
 
-	msleep(500);
-
-	ret = sx1301_page_read(spi, 2, 43, &val);
-	if (ret) {
-		dev_err(&spi->dev, "2|43 read failed\n");
+	/* switch on and reset the radios (also starts the 32 MHz XTAL) */
+	ret = sx1301_field_write(priv, F_RADIO_A_EN, 1);
+	if (ret)
 		return ret;
-	}
-
-	val |= REG_2_43_RADIO_RST;
-
-	ret = sx1301_page_write(spi, 2, 43, val);
-	if (ret) {
-		dev_err(&spi->dev, "2|43 write failed\n");
+	ret = sx1301_field_write(priv, F_RADIO_B_EN, 1);
+	if (ret)
 		return ret;
-	}
-
-	msleep(5);
-
-	ret = sx1301_page_read(spi, 2, 43, &val);
-	if (ret) {
-		dev_err(&spi->dev, "2|43 read failed\n");
+	mdelay(500);
+	ret = sx1301_field_write(priv, F_RADIO_RST, 1);
+	if (ret)
 		return ret;
-	}
-
-	val &= ~REG_2_43_RADIO_RST;
-
-	ret = sx1301_page_write(spi, 2, 43, val);
-	if (ret) {
-		dev_err(&spi->dev, "2|43 write failed\n");
+	mdelay(5);
+	ret = sx1301_field_write(priv, F_RADIO_RST, 0);
+	if (ret)
 		return ret;
-	}
 
 	/* radio A */
 
@@ -1047,65 +991,22 @@ static int sx1301_probe(struct spi_device *spi)
 	}
 
 	/* GPIO */
-
-	ret = sx1301_read(spi, REG_GPIO_MODE, &val);
-	if (ret) {
-		dev_err(&spi->dev, "GPIO mode read failed\n");
-		return ret;
-	}
-
-	val |= GENMASK(4, 0);
-
-	ret = sx1301_write(spi, REG_GPIO_MODE, val);
-	if (ret) {
-		dev_err(&spi->dev, "GPIO mode write failed\n");
-		return ret;
-	}
-
-	ret = sx1301_read(spi, REG_GPIO_SELECT_OUTPUT, &val);
-	if (ret) {
-		dev_err(&spi->dev, "GPIO select output read failed\n");
+	ret = regmap_write(priv->regmap, SX1301_GPMODE, 0x1F);
+	if (ret)
 		return ret;
-	}
-
-	val &= ~GENMASK(3, 0);
-	val |= 2;
-
-	ret = sx1301_write(spi, REG_GPIO_SELECT_OUTPUT, val);
-	if (ret) {
-		dev_err(&spi->dev, "GPIO select output write failed\n");
+	ret = regmap_write(priv->regmap, SX1301_GPSO, 0x2);
+	if (ret)
 		return ret;
-	}
 
 	/* TODO LBT */
 
-	ret = sx1301_read(spi, 16, &val);
-	if (ret) {
-		dev_err(&spi->dev, "16 read (1) failed\n");
-		return ret;
-	}
-
-	val |= REG_16_GLOBAL_EN;
-
-	ret = sx1301_write(spi, 16, val);
-	if (ret) {
-		dev_err(&spi->dev, "16 write (1) failed\n");
-		return ret;
-	}
-
-	ret = sx1301_read(spi, 17, &val);
-	if (ret) {
-		dev_err(&spi->dev, "17 read (1) failed\n");
+	/* start clocks */
+	ret = sx1301_field_write(priv, F_GLOBAL_EN, 1);
+	if (ret)
 		return ret;
-	}
-
-	val |= REG_17_CLK32M_EN;
-
-	ret = sx1301_write(spi, 17, val);
-	if (ret) {
-		dev_err(&spi->dev, "17 write (1) failed\n");
+	ret = sx1301_field_write(priv, F_CLK32M_EN, 1);
+	if (ret)
 		return ret;
-	}
 
 	/* calibration */
 
diff --git a/drivers/net/lora/sx1301.h b/drivers/net/lora/sx1301.h
index abfb7b5..0e84703 100644
--- a/drivers/net/lora/sx1301.h
+++ b/drivers/net/lora/sx1301.h
@@ -8,6 +8,13 @@
 #ifndef _SX1301_
 #define _SX1301_
 
+#define SX1301_CHIP_VERSION 103
+
+#define SX1301_MCU_FW_BYTE 8192
+#define SX1301_MCU_ARB_FW_VERSION 1
+#define SX1301_MCU_AGC_FW_VERSION 4
+#define SX1301_MCU_AGC_CAL_FW_VERSION 2
+
 /* Page independent */
 #define SX1301_PAGE     0x00
 #define SX1301_VER      0x01
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 03/10] net: lora: sx1301: convert to devm registration of netdev
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

We allow the devres framework handle the clean removal of resources on
teardown of the device, in this case the SPI device, saving lengthy
unwind code and improving clarity.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/sx1301.c | 87 +++++++++++++++++------------------------------
 1 file changed, 31 insertions(+), 56 deletions(-)

diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index 49958f0..54bfc31 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -869,9 +869,13 @@ static int sx1301_probe(struct spi_device *spi)
 	spi_setup(spi);
 
 	netdev = alloc_loradev(sizeof(*priv));
-	if (!netdev) {
-		ret = -ENOMEM;
-		goto err_alloc_loradev;
+	if (!netdev)
+		return -ENOMEM;
+
+	ret = devm_lora_register_netdev(&spi->dev, netdev);
+	if (ret) {
+		free_loradev(netdev);
+		return ret;
 	}
 
 	priv = netdev_priv(netdev);
@@ -885,7 +889,7 @@ static int sx1301_probe(struct spi_device *spi)
 	if (IS_ERR(priv->regmap)) {
 		ret = PTR_ERR(priv->regmap);
 		dev_err(&spi->dev, "Regmap allocation failed: %d\n", ret);
-		return err_regmap;
+		return ret;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(sx1301_reg_fields); i++) {
@@ -897,38 +901,37 @@ static int sx1301_probe(struct spi_device *spi)
 		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);
-			goto err_regmap;
+			return ret;
 		}
 	}
 
 	ret = regmap_read(priv->regmap, SX1301_VER, &ver);
 	if (ret) {
 		dev_err(&spi->dev, "version read failed\n");
-		goto err_version;
+		return ret;
 	}
 
 	if (ver != 103) {
 		dev_err(&spi->dev, "unexpected version: %u\n", ver);
-		ret = -ENXIO;
-		goto err_version;
+		return -ENXIO;
 	}
 
 	ret = sx1301_write(spi, REG_PAGE_RESET, 0);
 	if (ret) {
 		dev_err(&spi->dev, "page/reset write failed\n");
-		goto err_init_page;
+		return ret;
 	}
 
 	ret = sx1301_soft_reset(spi);
 	if (ret) {
 		dev_err(&spi->dev, "soft reset failed\n");
-		goto err_soft_reset;
+		return ret;
 	}
 
 	ret = sx1301_read(spi, 16, &val);
 	if (ret) {
 		dev_err(&spi->dev, "16 read failed\n");
-		goto err_read_global_en_0;
+		return ret;
 	}
 
 	val &= ~REG_16_GLOBAL_EN;
@@ -936,13 +939,13 @@ static int sx1301_probe(struct spi_device *spi)
 	ret = sx1301_write(spi, 16, val);
 	if (ret) {
 		dev_err(&spi->dev, "16 write failed\n");
-		goto err_write_global_en_0;
+		return ret;
 	}
 
 	ret = sx1301_read(spi, 17, &val);
 	if (ret) {
 		dev_err(&spi->dev, "17 read failed\n");
-		goto err_read_clk32m_0;
+		return ret;
 	}
 
 	val &= ~REG_17_CLK32M_EN;
@@ -950,7 +953,7 @@ static int sx1301_probe(struct spi_device *spi)
 	ret = sx1301_write(spi, 17, val);
 	if (ret) {
 		dev_err(&spi->dev, "17 write failed\n");
-		goto err_write_clk32m_0;
+		return ret;
 	}
 
 	ret = sx1301_page_read(spi, 2, 43, &val);
@@ -1003,8 +1006,7 @@ static int sx1301_probe(struct spi_device *spi)
 
 	priv->radio_a_ctrl = spi_alloc_master(&spi->dev, sizeof(*radio));
 	if (!priv->radio_a_ctrl) {
-		ret = -ENOMEM;
-		goto err_radio_a_alloc;
+		return -ENOMEM;
 	}
 
 	sx1301_radio_setup(priv->radio_a_ctrl);
@@ -1019,15 +1021,14 @@ static int sx1301_probe(struct spi_device *spi)
 	if (ret) {
 		dev_err(&spi->dev, "radio A SPI register failed\n");
 		spi_controller_put(priv->radio_a_ctrl);
-		goto err_radio_a_register;
+		return ret;
 	}
 
 	/* radio B */
 
 	priv->radio_b_ctrl = spi_alloc_master(&spi->dev, sizeof(*radio));
 	if (!priv->radio_b_ctrl) {
-		ret = -ENOMEM;
-		goto err_radio_b_alloc;
+		return -ENOMEM;
 	}
 
 	sx1301_radio_setup(priv->radio_b_ctrl);
@@ -1042,7 +1043,7 @@ static int sx1301_probe(struct spi_device *spi)
 	if (ret) {
 		dev_err(&spi->dev, "radio B SPI register failed\n");
 		spi_controller_put(priv->radio_b_ctrl);
-		goto err_radio_b_register;
+		return ret;
 	}
 
 	/* GPIO */
@@ -1050,7 +1051,7 @@ static int sx1301_probe(struct spi_device *spi)
 	ret = sx1301_read(spi, REG_GPIO_MODE, &val);
 	if (ret) {
 		dev_err(&spi->dev, "GPIO mode read failed\n");
-		goto err_read_gpio_mode;
+		return ret;
 	}
 
 	val |= GENMASK(4, 0);
@@ -1058,13 +1059,13 @@ static int sx1301_probe(struct spi_device *spi)
 	ret = sx1301_write(spi, REG_GPIO_MODE, val);
 	if (ret) {
 		dev_err(&spi->dev, "GPIO mode write failed\n");
-		goto err_write_gpio_mode;
+		return ret;
 	}
 
 	ret = sx1301_read(spi, REG_GPIO_SELECT_OUTPUT, &val);
 	if (ret) {
 		dev_err(&spi->dev, "GPIO select output read failed\n");
-		goto err_read_gpio_select_output;
+		return ret;
 	}
 
 	val &= ~GENMASK(3, 0);
@@ -1073,7 +1074,7 @@ static int sx1301_probe(struct spi_device *spi)
 	ret = sx1301_write(spi, REG_GPIO_SELECT_OUTPUT, val);
 	if (ret) {
 		dev_err(&spi->dev, "GPIO select output write failed\n");
-		goto err_write_gpio_select_output;
+		return ret;
 	}
 
 	/* TODO LBT */
@@ -1081,7 +1082,7 @@ static int sx1301_probe(struct spi_device *spi)
 	ret = sx1301_read(spi, 16, &val);
 	if (ret) {
 		dev_err(&spi->dev, "16 read (1) failed\n");
-		goto err_read_global_en_1;
+		return ret;
 	}
 
 	val |= REG_16_GLOBAL_EN;
@@ -1089,13 +1090,13 @@ static int sx1301_probe(struct spi_device *spi)
 	ret = sx1301_write(spi, 16, val);
 	if (ret) {
 		dev_err(&spi->dev, "16 write (1) failed\n");
-		goto err_write_global_en_1;
+		return ret;
 	}
 
 	ret = sx1301_read(spi, 17, &val);
 	if (ret) {
 		dev_err(&spi->dev, "17 read (1) failed\n");
-		goto err_read_clk32m_1;
+		return ret;
 	}
 
 	val |= REG_17_CLK32M_EN;
@@ -1103,50 +1104,24 @@ static int sx1301_probe(struct spi_device *spi)
 	ret = sx1301_write(spi, 17, val);
 	if (ret) {
 		dev_err(&spi->dev, "17 write (1) failed\n");
-		goto err_write_clk32m_1;
+		return ret;
 	}
 
 	/* calibration */
 
 	ret = sx1301_agc_calibrate(spi);
 	if (ret)
-		goto err_agc_calibrate;
+		return ret;
 
 	/* TODO */
 
 	ret = sx1301_load_all_firmware(spi);
 	if (ret)
-		goto err_load_firmware;
+		return ret;
 
 	dev_info(&spi->dev, "SX1301 module probed\n");
 
 	return 0;
-
-err_load_firmware:
-err_agc_calibrate:
-err_write_clk32m_1:
-err_read_clk32m_1:
-err_write_global_en_1:
-err_read_global_en_1:
-err_write_gpio_select_output:
-err_read_gpio_select_output:
-err_write_gpio_mode:
-err_read_gpio_mode:
-err_radio_b_register:
-err_radio_b_alloc:
-err_radio_a_register:
-err_radio_a_alloc:
-err_write_clk32m_0:
-err_read_clk32m_0:
-err_write_global_en_0:
-err_read_global_en_0:
-err_soft_reset:
-err_init_page:
-err_version:
-err_regmap:
-	free_loradev(netdev);
-err_alloc_loradev:
-	return ret;
 }
 
 static int sx1301_remove(struct spi_device *spi)
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 02/10] net: lora: add methods for devm registration
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

Follow the devm model so that we can avoid lengthy unwind code.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/dev.c   | 20 ++++++++++++++++++++
 include/linux/lora/dev.h |  1 +
 2 files changed, 21 insertions(+)

diff --git a/drivers/net/lora/dev.c b/drivers/net/lora/dev.c
index 8c01106..69a8b52 100644
--- a/drivers/net/lora/dev.c
+++ b/drivers/net/lora/dev.c
@@ -84,6 +84,26 @@ void free_loradev(struct net_device *dev)
 }
 EXPORT_SYMBOL_GPL(free_loradev);
 
+static void devm_lora_unregister(struct device *dev, void *res)
+{
+	free_loradev(*(struct net_device **)res);
+}
+
+int devm_lora_register_netdev(struct device *dev, struct net_device *net)
+{
+	struct net_device **ptr;
+
+	ptr = devres_alloc(devm_lora_unregister, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	*ptr = net;
+	devres_add(dev, ptr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devm_lora_register_netdev);
+
 static struct rtnl_link_ops lora_link_ops __read_mostly = {
 	.kind = "lora",
 	.setup = lora_setup,
diff --git a/include/linux/lora/dev.h b/include/linux/lora/dev.h
index 153f9b2..3f871c6 100644
--- a/include/linux/lora/dev.h
+++ b/include/linux/lora/dev.h
@@ -32,6 +32,7 @@ static inline int lora_strtoeui(const char *str, lora_eui *val)
 
 struct net_device *alloc_loradev(int sizeof_priv);
 void free_loradev(struct net_device *dev);
+int devm_lora_register_netdev(struct device *dev, struct net_device *net);
 int register_loradev(struct net_device *dev);
 void unregister_loradev(struct net_device *dev);
 int open_loradev(struct net_device *dev);
-- 
2.7.4

^ permalink raw reply related

* [RFC] spi: add spi multiplexing functions for dt
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

Like I2C busses SPI devices can also sit behind multiplexers.
This patch adds is based off the I2C implementation and allows
description in the devicetree.

Signed-off-by: Ben Whitten <ben.whitten@gmail.com>
---
 drivers/spi/Kconfig     |  10 +++
 drivers/spi/Makefile    |   3 +
 drivers/spi/spi-mux.c   | 181 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/spi-mux.h |  55 +++++++++++++++
 4 files changed, 249 insertions(+)
 create mode 100644 drivers/spi/spi-mux.c
 create mode 100644 include/linux/spi-mux.h

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a75f2a2..58eba70 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -51,6 +51,16 @@ config SPI_MASTER
 
 if SPI_MASTER
 
+config SPI_MUX
+	tristate "SPI bus multiplexing support"
+	help
+	  Say Y here if you want the SPI core to support the ability to
+	  handle multiplexed SPI bus topologies, by presenting each
+	  multiplexed segment as an SPI controller.
+
+	  This support is also available as a module.  If so, the module
+	  will be called spi-mux.
+
 comment "SPI Master Controller Drivers"
 
 config SPI_ALTERA
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 8e0cda7..ef525fe 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -109,6 +109,9 @@ obj-$(CONFIG_SPI_XLP)			+= spi-xlp.o
 obj-$(CONFIG_SPI_XTENSA_XTFPGA)		+= spi-xtensa-xtfpga.o
 obj-$(CONFIG_SPI_ZYNQMP_GQSPI)		+= spi-zynqmp-gqspi.o
 
+# SPI muxs
+obj-$(CONFIG_SPI_MUX)			+= spi-mux.o
+
 # SPI slave protocol handlers
 obj-$(CONFIG_SPI_SLAVE_TIME)		+= spi-slave-time.o
 obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL)	+= spi-slave-system-control.o
diff --git a/drivers/spi/spi-mux.c b/drivers/spi/spi-mux.c
new file mode 100644
index 0000000..a2008c1
--- /dev/null
+++ b/drivers/spi/spi-mux.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for an SPI multiplexer
+ *
+ * Copyright (c) 2018   Ben Whitten
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/spi-mux.h>
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+struct spi_mux_priv {
+	struct spi_controller *controller;
+	struct spi_mux_core *muxc;
+	u32 chan_id;
+};
+
+struct spi_mux_core *spi_mux_alloc(struct spi_controller *parent,
+				   struct device *dev,
+				   int max_controllers,
+				   int sizeof_priv,
+				   int (*select)(struct spi_mux_core *, u32),
+				   int (*deselect)(struct spi_mux_core *, u32),
+				   int (*transfer_one_message)
+					(struct spi_controller *controller,
+					 struct spi_message *msg))
+{
+	struct spi_mux_core *muxc;
+
+	muxc = devm_kzalloc(dev, sizeof(*muxc)
+			    + max_controllers * sizeof(muxc->controller[0])
+			    + sizeof_priv, GFP_KERNEL);
+	if (!muxc)
+		return NULL;
+	if (sizeof_priv)
+		muxc->priv = &muxc->controller[max_controllers];
+
+	muxc->parent = parent;
+	muxc->dev = dev;
+
+	muxc->select = select;
+	muxc->deselect = deselect;
+	muxc->transfer_one_message = transfer_one_message;
+	muxc->max_controllers = max_controllers;
+
+	return muxc;
+}
+EXPORT_SYMBOL_GPL(spi_mux_alloc);
+
+u32 spi_mux_get_chan_id(struct spi_controller *controller)
+{
+	struct spi_mux_priv *priv = spi_controller_get_devdata(controller);
+
+	return priv->chan_id;
+}
+EXPORT_SYMBOL_GPL(spi_mux_get_chan_id);
+
+static int spi_mux_transfer_one_message(struct spi_controller *controller,
+					struct spi_message *msg)
+{
+	struct spi_mux_priv *priv = spi_controller_get_devdata(controller);
+	struct spi_mux_core *muxc = priv->muxc;
+	struct spi_device *spi = to_spi_device(muxc->dev);
+	int ret;
+
+	ret = muxc->select(muxc, priv->chan_id);
+	if (ret < 0)
+		return ret;
+
+	/* If we have a custom transfer, use it */
+	if (muxc->transfer_one_message)
+		ret = muxc->transfer_one_message(controller, msg);
+	else
+		ret = spi_sync(spi, msg);
+
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	return ret;
+}
+
+static int spi_mux_add_controller(struct spi_mux_core *muxc, u32 chan_id)
+{
+	struct spi_controller *controller;
+	struct spi_mux_priv *priv;
+	int ret;
+
+	if (muxc->num_controllers >= muxc->max_controllers) {
+		dev_err(muxc->dev, "No room for more spi-mux controllers");
+		return -EINVAL;
+	}
+
+	controller = spi_alloc_master(muxc->dev, sizeof(*priv));
+	if (!controller)
+		return -ENOMEM;
+	priv = spi_controller_get_devdata(controller);
+
+	/* Setup private controller data */
+	priv->muxc = muxc;
+	priv->controller = controller;
+	priv->chan_id = chan_id;
+
+	priv->controller->transfer_one_message = spi_mux_transfer_one_message;
+
+	/* Look for the child of this controller */
+	if (muxc->dev->of_node) {
+		struct device_node *dev_node = muxc->dev->of_node;
+		struct device_node *mux_node, *child = NULL;
+		u32 reg;
+
+		mux_node = of_get_child_by_name(dev_node, "spi-mux");
+		if (!mux_node)
+			mux_node = of_node_get(dev_node);
+
+		for_each_child_of_node(mux_node, child) {
+			ret = of_property_read_u32(child, "reg", &reg);
+			if (ret)
+				continue;
+			if (chan_id == reg)
+				break;
+		}
+
+		priv->controller->dev.of_node = child;
+		of_node_put(mux_node);
+	}
+
+	ret = devm_spi_register_controller(muxc->dev, priv->controller);
+	if (ret) {
+		spi_controller_put(priv->controller);
+		dev_err(muxc->dev, "Problem registering spi controller: %d\n",
+			ret);
+		return ret;
+	}
+
+	muxc->controller[muxc->num_controllers++] = priv->controller;
+
+	return ret;
+}
+
+static void spi_mux_del_controllers(struct spi_mux_core *muxc)
+{
+	struct spi_controller *controller =
+	    muxc->controller[--muxc->num_controllers];
+	struct device_node *np = controller->dev.of_node;
+
+	muxc->controller[muxc->num_controllers] = NULL;
+	of_node_put(np);
+}
+
+static void devm_spi_mux_del_controllers(struct device *dev, void *res)
+{
+	spi_mux_del_controllers(*(struct spi_mux_core **)res);
+}
+
+int devm_spi_mux_add_controller(struct spi_mux_core *muxc, u32 chan_id)
+{
+	struct spi_mux_core **ptr;
+	int ret;
+
+	ptr = devres_alloc(devm_spi_mux_del_controllers, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	ret = spi_mux_add_controller(muxc, chan_id);
+	if (!ret) {
+		*ptr = muxc;
+		devres_add(muxc->dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devm_spi_mux_add_controller);
+
+MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
+MODULE_DESCRIPTION("SPI driver for multiplexed SPI busses");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/spi-mux.h b/include/linux/spi-mux.h
new file mode 100644
index 0000000..5978f86
--- /dev/null
+++ b/include/linux/spi-mux.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for an SPI multiplexer
+ *
+ * Copyright (c) 2018   Ben Whitten
+ */
+
+#ifndef _LINUX_SPI_MUX_H_
+#define _LINUX_SPI_MUX_H_
+
+#ifdef __KERNEL__
+
+struct spi_mux_core {
+	struct spi_controller *parent;
+	struct device *dev;
+
+	void *priv;
+
+	int (*select)(struct spi_mux_core *, u32 chan_id);
+	int (*deselect)(struct spi_mux_core *, u32 chan_id);
+	int (*transfer_one_message)(struct spi_controller *controller,
+				    struct spi_message *msg);
+
+	int num_controllers;
+	int max_controllers;
+	struct spi_controller *controller[0];
+};
+
+struct spi_mux_core *spi_mux_alloc(struct spi_controller *parent,
+				   struct device *dev,
+				   int max_controllers,
+				   int sizeof_priv,
+				   int (*select)(struct spi_mux_core *, u32),
+				   int (*deselect)(struct spi_mux_core *, u32),
+				   int (*transfer_one_message)
+					(struct spi_controller *controller,
+					 struct spi_message *msg));
+
+static inline void *spi_mux_priv(struct spi_mux_core *muxc)
+{
+	return muxc->priv;
+}
+
+u32 spi_mux_get_chan_id(struct spi_controller *controller);
+
+/*
+ * Called to create an spi bus on a multiplexed bus segment.
+ * The chan_id parameter is passed to the select and deselect
+ * callback functions to perform hardware-specific mux control.
+ */
+int devm_spi_mux_add_controller(struct spi_mux_core *muxc, u32 chan_id);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SPI_MUX_H_ */
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 01/10] net: lora: sx1301: add register, bit-fields, and helpers for regmap
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten
In-Reply-To: <1533663131-16313-1-git-send-email-ben.whitten@gmail.com>

From: Ben Whitten <ben.whitten@lairdtech.com>

The register and bit-field definitions are taken from the SX1301
datasheet version 2.01 dated June 2014 with the revision information
'First released version'.

The reset state and RW capability of each field is not reflected in this
patch however from the datasheet:
"Bits and registers that are not documented are reserved. They may
include calibration values. It is important not to modify these bits and
registers. If specific bits must be changed in a register with reserved
bits, the register must be read first, specific bits modified while
masking reserved bits and then the register can be written."

Then goes on to state:
"Reserved bits should be written with their reset state, they may be
read different states."

Caching is currently disabled.

The version is read back using regmap_read to verify regmap operation,
in doing so needs to be moved after priv and regmap allocation.

Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
---
 drivers/net/lora/Kconfig  |   1 +
 drivers/net/lora/sx1301.c | 282 +++++++++++++++++++++++++++++++++++++++++++---
 drivers/net/lora/sx1301.h | 169 +++++++++++++++++++++++++++
 3 files changed, 439 insertions(+), 13 deletions(-)
 create mode 100644 drivers/net/lora/sx1301.h

diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig
index bb57a01..79d23f2 100644
--- a/drivers/net/lora/Kconfig
+++ b/drivers/net/lora/Kconfig
@@ -49,6 +49,7 @@ config LORA_SX1301
 	tristate "Semtech SX1301 SPI driver"
 	default y
 	depends on SPI
+	select REGMAP_SPI
 	help
 	  Semtech SX1301
 
diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index 5342b61..49958f0 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -3,6 +3,7 @@
  * Semtech SX1301 LoRa concentrator
  *
  * Copyright (c) 2018 Andreas Färber
+ * Copyright (c) 2018 Ben Whitten
  *
  * Based on SX1301 HAL code:
  * Copyright (c) 2013 Semtech-Cycleo
@@ -19,6 +20,9 @@
 #include <linux/of_gpio.h>
 #include <linux/lora/dev.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include "sx1301.h"
 
 #define REG_PAGE_RESET			0
 #define REG_VERSION			1
@@ -65,6 +69,213 @@
 
 #define REG_EMERGENCY_FORCE_HOST_CTRL	BIT(0)
 
+enum sx1301_fields {
+	F_SOFT_RESET,
+	F_START_BIST0,
+	F_START_BIST1,
+	F_BIST0_FINISHED,
+	F_BIST1_FINISHED,
+	F_GLOBAL_EN,
+	F_CLK32M_EN,
+	F_RADIO_A_EN,
+	F_RADIO_B_EN,
+	F_RADIO_RST,
+
+	F_RX_INVERT_IQ,
+	F_MODEM_INVERT_IQ,
+	F_MBWSSF_MODEM_INVERT_IQ,
+	F_RX_EDGE_SELECT,
+	F_MISC_RADIO_EN,
+	F_FSK_MODEM_INVERT_IQ,
+
+	F_RSSI_BB_FILTER_ALPHA,
+	F_RSSI_DEC_FILTER_ALPHA,
+	F_RSSI_CHANN_FILTER_ALPHA,
+
+	F_DEC_GAIN_OFFSET,
+	F_CHAN_GAIN_OFFSET,
+
+	F_LLR_SCALE,
+	F_SNR_AVG_CST,
+
+	F_CORR_NUM_SAME_PEAK,
+	F_CORR_MAC_GAIN,
+
+	F_FSK_CH_BW_EXPO,
+	F_FSK_RSSI_LENGTH,
+	F_FSK_RX_INVERT,
+	F_FSK_PKT_MODE,
+
+	F_FSK_PSIZE,
+	F_FSK_CRC_EN,
+	F_FSK_DCFREE_ENC,
+	F_FSK_CRC_IBM,
+
+	F_FSK_ERROR_OSR_TOL,
+	F_FSK_RADIO_SELECT,
+
+	F_TX_MODE,
+	F_TX_ZERO_PAD,
+	F_TX_EDGE_SELECT,
+	F_TX_EDGE_SELECT_TOP,
+
+	F_TX_GAIN,
+	F_TX_CHIRP_LOW_PASS,
+	F_TX_FCC_WIDEBAND,
+	F_TX_SWAP_IQ,
+
+	F_FSK_TX_GAUSSIAN_EN,
+	F_FSK_TX_GAUSSIAN_SELECT_BT,
+	F_FSK_TX_PATTERN_EN,
+	F_FSK_TX_PREAMBLE_SEQ,
+	F_FSK_TX_PSIZE,
+
+	F_FORCE_HOST_RADIO_CTRL,
+	F_FORCE_HOST_FE_CTRL,
+	F_FORCE_DEC_FILTER_GAIN,
+
+	F_MCU_RST_0,
+	F_MCU_RST_1,
+	F_MCU_SELECT_MUX_0,
+	F_MCU_SELECT_MUX_1,
+	F_MCU_CORRUPTION_DETECTED_0,
+	F_MCU_CORRUPTION_DETECTED_1,
+	F_MCU_SELECT_EDGE_0,
+	F_MCU_SELECT_EDGE_1,
+
+	F_EMERGENCY_FORCE_HOST_CTRL,
+};
+
+static const struct reg_field sx1301_reg_fields[] = {
+	/* PAGE */
+	[F_SOFT_RESET]		= REG_FIELD(SX1301_PAGE, 7, 7),
+	/* BIST */
+	[F_START_BIST0]		= REG_FIELD(SX1301_BIST, 0, 0),
+	[F_START_BIST1]		= REG_FIELD(SX1301_BIST, 1, 1),
+	/* BIST_S */
+	[F_BIST0_FINISHED]	= REG_FIELD(SX1301_BIST_S, 0, 0),
+	[F_BIST1_FINISHED]	= REG_FIELD(SX1301_BIST_S, 1, 1),
+	/* 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),
+
+	/* IQCFG */
+	[F_RX_INVERT_IQ]	= REG_FIELD(SX1301_IQCFG, 0, 0),
+	[F_MODEM_INVERT_IQ]	= REG_FIELD(SX1301_IQCFG, 1, 1),
+	[F_MBWSSF_MODEM_INVERT_IQ]	= REG_FIELD(SX1301_IQCFG, 2, 2),
+	[F_RX_EDGE_SELECT]	= REG_FIELD(SX1301_IQCFG, 3, 3),
+	[F_MISC_RADIO_EN]	= REG_FIELD(SX1301_IQCFG, 4, 4),
+	[F_FSK_MODEM_INVERT_IQ]	= REG_FIELD(SX1301_IQCFG, 5, 5),
+
+	/* RSSI_X_FILTER_ALPHA */
+	[F_RSSI_BB_FILTER_ALPHA] =
+		REG_FIELD(SX1301_RSSI_BB_FILTER_ALPHA, 0, 4),
+	[F_RSSI_DEC_FILTER_ALPHA] =
+		REG_FIELD(SX1301_RSSI_DEC_FILTER_ALPHA, 0, 4),
+	[F_RSSI_CHANN_FILTER_ALPHA] =
+		REG_FIELD(SX1301_RSSI_CHANN_FILTER_ALPHA, 0, 4),
+
+	/* GAIN_OFFSET */
+	[F_DEC_GAIN_OFFSET]	= REG_FIELD(SX1301_GAIN_OFFSET, 0, 3),
+	[F_CHAN_GAIN_OFFSET]	= REG_FIELD(SX1301_GAIN_OFFSET, 4, 7),
+
+	/* MISC_CFG1 */
+	[F_LLR_SCALE]		= REG_FIELD(SX1301_MISC_CFG1, 0, 3),
+	[F_SNR_AVG_CST]		= REG_FIELD(SX1301_MISC_CFG1, 4, 5),
+
+	/* CORR_CFG */
+	[F_CORR_NUM_SAME_PEAK]	= REG_FIELD(SX1301_CORR_CFG, 0, 3),
+	[F_CORR_MAC_GAIN]	= REG_FIELD(SX1301_CORR_CFG, 4, 6),
+
+	/* FSK_CFG1 */
+	[F_FSK_CH_BW_EXPO]	= REG_FIELD(SX1301_FSK_CFG1, 0, 2),
+	[F_FSK_RSSI_LENGTH]	= REG_FIELD(SX1301_FSK_CFG1, 3, 5),
+	[F_FSK_RX_INVERT]	= REG_FIELD(SX1301_FSK_CFG1, 6, 6),
+	[F_FSK_PKT_MODE]	= REG_FIELD(SX1301_FSK_CFG1, 7, 7),
+
+	/* FSK_CFG2 */
+	[F_FSK_PSIZE]		= REG_FIELD(SX1301_FSK_CFG2, 0, 2),
+	[F_FSK_CRC_EN]		= REG_FIELD(SX1301_FSK_CFG2, 3, 3),
+	[F_FSK_DCFREE_ENC]	= REG_FIELD(SX1301_FSK_CFG2, 4, 5),
+	[F_FSK_CRC_IBM]		= REG_FIELD(SX1301_FSK_CFG2, 6, 6),
+
+	/* FSK_ERROR_OSR_TOL */
+	[F_FSK_ERROR_OSR_TOL]	= REG_FIELD(SX1301_FSK_ERROR_OSR_TOL, 0, 4),
+	[F_FSK_RADIO_SELECT]	= REG_FIELD(SX1301_FSK_ERROR_OSR_TOL, 7, 7),
+
+	/* TX_CFG1 */
+	[F_TX_MODE]		= REG_FIELD(SX1301_TX_CFG1, 0, 0),
+	[F_TX_ZERO_PAD]		= REG_FIELD(SX1301_TX_CFG1, 1, 4),
+	[F_TX_EDGE_SELECT]	= REG_FIELD(SX1301_TX_CFG1, 5, 5),
+	[F_TX_EDGE_SELECT_TOP]	= REG_FIELD(SX1301_TX_CFG1, 6, 6),
+
+	/* TX_CFG2 */
+	[F_TX_GAIN]		= REG_FIELD(SX1301_TX_CFG2, 0, 1),
+	[F_TX_CHIRP_LOW_PASS]	= REG_FIELD(SX1301_TX_CFG2, 2, 4),
+	[F_TX_FCC_WIDEBAND]	= REG_FIELD(SX1301_TX_CFG2, 5, 6),
+	[F_TX_SWAP_IQ]		= REG_FIELD(SX1301_TX_CFG2, 7, 7),
+
+	/* FSK_TX */
+	[F_FSK_TX_GAUSSIAN_EN]	= REG_FIELD(SX1301_FSK_TX, 0, 0),
+	[F_FSK_TX_GAUSSIAN_SELECT_BT]	= REG_FIELD(SX1301_FSK_TX, 1, 2),
+	[F_FSK_TX_PATTERN_EN]	= REG_FIELD(SX1301_FSK_TX, 3, 3),
+	[F_FSK_TX_PREAMBLE_SEQ]	= REG_FIELD(SX1301_FSK_TX, 4, 4),
+	[F_FSK_TX_PSIZE]	= REG_FIELD(SX1301_FSK_TX, 5, 7),
+
+	/* 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),
+
+	/* 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),
+	[F_MCU_CORRUPTION_DETECTED_0] = REG_FIELD(SX1301_MCU_CTRL, 4, 4),
+	[F_MCU_CORRUPTION_DETECTED_1] = REG_FIELD(SX1301_MCU_CTRL, 5, 5),
+	[F_MCU_SELECT_EDGE_0]	= REG_FIELD(SX1301_MCU_CTRL, 6, 6),
+	[F_MCU_SELECT_EDGE_1]	= REG_FIELD(SX1301_MCU_CTRL, 7, 7),
+
+	/* EMERGENCY_FORCE_HOST_CTRL */
+	[F_EMERGENCY_FORCE_HOST_CTRL] =
+		REG_FIELD(SX1301_EMERGENCY_FORCE_HOST_CTRL, 0, 0),
+};
+
+static const struct regmap_range_cfg sx1301_ranges[] = {
+	{
+		.name = "Pages",
+
+		.range_min = SX1301_VIRT_BASE,
+		.range_max = SX1301_MAX_REGISTER,
+
+		.selector_reg = SX1301_PAGE,
+		.selector_mask = 0x3,
+
+		.window_start = 0,
+		.window_len = SX1301_PAGE_LEN,
+	},
+};
+
+static struct regmap_config sx1301_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.cache_type = REGCACHE_NONE,
+
+	.read_flag_mask = 0,
+	.write_flag_mask = BIT(7),
+
+	.ranges = sx1301_ranges,
+	.num_ranges = ARRAY_SIZE(sx1301_ranges),
+	.max_register = SX1301_MAX_REGISTER,
+};
+
 struct spi_sx1301 {
 	struct spi_device *parent;
 	u8 page;
@@ -76,8 +287,29 @@ struct sx1301_priv {
 	struct gpio_desc *rst_gpio;
 	u8 cur_page;
 	struct spi_controller *radio_a_ctrl, *radio_b_ctrl;
+	struct regmap		*regmap;
+	struct regmap_field	*regmap_fields[ARRAY_SIZE(sx1301_reg_fields)];
 };
 
+static int sx1301_field_read(struct sx1301_priv *priv,
+		enum sx1301_fields field_id)
+{
+	int ret;
+	int val;
+
+	ret = regmap_field_read(priv->regmap_fields[field_id], &val);
+	if (ret)
+		return ret;
+
+	return val;
+}
+
+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 spi_device *spi, u8 reg, u8 *val, size_t len)
 {
 	u8 addr = reg & 0x7f;
@@ -620,6 +852,8 @@ static int sx1301_probe(struct spi_device *spi)
 	struct spi_sx1301 *radio;
 	struct gpio_desc *rst;
 	int ret;
+	int i;
+	unsigned int ver;
 	u8 val;
 
 	rst = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
@@ -634,18 +868,6 @@ static int sx1301_probe(struct spi_device *spi)
 	spi->bits_per_word = 8;
 	spi_setup(spi);
 
-	ret = sx1301_read(spi, REG_VERSION, &val);
-	if (ret) {
-		dev_err(&spi->dev, "version read failed\n");
-		goto err_version;
-	}
-
-	if (val != 103) {
-		dev_err(&spi->dev, "unexpected version: %u\n", val);
-		ret = -ENXIO;
-		goto err_version;
-	}
-
 	netdev = alloc_loradev(sizeof(*priv));
 	if (!netdev) {
 		ret = -ENOMEM;
@@ -659,6 +881,38 @@ static int sx1301_probe(struct spi_device *spi)
 	spi_set_drvdata(spi, netdev);
 	SET_NETDEV_DEV(netdev, &spi->dev);
 
+	priv->regmap = devm_regmap_init_spi(spi, &sx1301_regmap_config);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&spi->dev, "Regmap allocation failed: %d\n", ret);
+		return err_regmap;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sx1301_reg_fields); i++) {
+		const struct reg_field *reg_fields = sx1301_reg_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);
+			goto err_regmap;
+		}
+	}
+
+	ret = regmap_read(priv->regmap, SX1301_VER, &ver);
+	if (ret) {
+		dev_err(&spi->dev, "version read failed\n");
+		goto err_version;
+	}
+
+	if (ver != 103) {
+		dev_err(&spi->dev, "unexpected version: %u\n", ver);
+		ret = -ENXIO;
+		goto err_version;
+	}
+
 	ret = sx1301_write(spi, REG_PAGE_RESET, 0);
 	if (ret) {
 		dev_err(&spi->dev, "page/reset write failed\n");
@@ -888,9 +1142,10 @@ static int sx1301_probe(struct spi_device *spi)
 err_read_global_en_0:
 err_soft_reset:
 err_init_page:
+err_version:
+err_regmap:
 	free_loradev(netdev);
 err_alloc_loradev:
-err_version:
 	return ret;
 }
 
@@ -927,4 +1182,5 @@ module_spi_driver(sx1301_spi_driver);
 
 MODULE_DESCRIPTION("SX1301 SPI driver");
 MODULE_AUTHOR("Andreas Färber <afaerber@suse.de>");
+MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/lora/sx1301.h b/drivers/net/lora/sx1301.h
new file mode 100644
index 0000000..abfb7b5
--- /dev/null
+++ b/drivers/net/lora/sx1301.h
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Semtech SX1301 lora concentrator
+ *
+ * Copyright (c) 2018   Ben Whitten
+ */
+
+#ifndef _SX1301_
+#define _SX1301_
+
+/* Page independent */
+#define SX1301_PAGE     0x00
+#define SX1301_VER      0x01
+#define SX1301_RDBAL    0x02
+#define SX1301_RDBAH    0x03
+#define SX1301_RDBD     0x04
+#define SX1301_TDBA     0x05
+#define SX1301_TDBD     0x06
+#define SX1301_MPA      0x09
+#define SX1301_MPD      0x0A
+#define SX1301_RPNS     0x0B
+#define SX1301_RPAPL    0x0C
+#define SX1301_RPAPH    0x0D
+#define SX1301_RPS      0x0E
+#define SX1301_RPPS     0x0F
+#define SX1301_GEN      0x10
+#define SX1301_CKEN     0x11
+#define SX1301_BIST     0x12
+#define SX1301_BIST_S   0x13
+#define SX1301_GPSI     0x1B
+#define SX1301_GPSO     0x1C
+#define SX1301_GPMODE   0x1D
+#define SX1301_GPREGI   0x1E
+#define SX1301_GPREGO   0x1F
+#define SX1301_AGCSTS   0x20
+#define SX1301_ARBSTS   0x7D
+#define SX1301_ID       0x7F
+
+#define SX1301_VIRT_BASE    0x100
+#define SX1301_PAGE_LEN     0x80
+#define SX1301_PAGE_BASE(n) (SX1301_VIRT_BASE + (SX1301_PAGE_LEN * n))
+
+/* Page 0 */
+#define SX1301_IQCFG        (SX1301_PAGE_BASE(0) + 0x21)
+#define SX1301_DECCFG       (SX1301_PAGE_BASE(0) + 0x22)
+#define SX1301_CHRS         (SX1301_PAGE_BASE(0) + 0x23)
+#define SX1301_IF0L         (SX1301_PAGE_BASE(0) + 0x24)
+#define SX1301_IF0H         (SX1301_PAGE_BASE(0) + 0x25)
+#define SX1301_IF1L         (SX1301_PAGE_BASE(0) + 0x26)
+#define SX1301_IF1H         (SX1301_PAGE_BASE(0) + 0x27)
+#define SX1301_IF2L         (SX1301_PAGE_BASE(0) + 0x28)
+#define SX1301_IF2H         (SX1301_PAGE_BASE(0) + 0x29)
+#define SX1301_IF3L         (SX1301_PAGE_BASE(0) + 0x2A)
+#define SX1301_IF3H         (SX1301_PAGE_BASE(0) + 0x2B)
+#define SX1301_IF4L         (SX1301_PAGE_BASE(0) + 0x2C)
+#define SX1301_IF4H         (SX1301_PAGE_BASE(0) + 0x2D)
+#define SX1301_IF5L         (SX1301_PAGE_BASE(0) + 0x2E)
+#define SX1301_IF5H         (SX1301_PAGE_BASE(0) + 0x2F)
+#define SX1301_IF6L         (SX1301_PAGE_BASE(0) + 0x30)
+#define SX1301_IF6H         (SX1301_PAGE_BASE(0) + 0x31)
+#define SX1301_IF7L         (SX1301_PAGE_BASE(0) + 0x32)
+#define SX1301_IF7H         (SX1301_PAGE_BASE(0) + 0x33)
+#define SX1301_IF8L         (SX1301_PAGE_BASE(0) + 0x34)
+#define SX1301_IF8H         (SX1301_PAGE_BASE(0) + 0x35)
+#define SX1301_IF9L         (SX1301_PAGE_BASE(0) + 0x36)
+#define SX1301_IF9H         (SX1301_PAGE_BASE(0) + 0x37)
+#define SX1301_COR0DETEN    (SX1301_PAGE_BASE(0) + 0x41)
+#define SX1301_COR1DETEN    (SX1301_PAGE_BASE(0) + 0x42)
+#define SX1301_COR2DETEN    (SX1301_PAGE_BASE(0) + 0x43)
+#define SX1301_COR3DETEN    (SX1301_PAGE_BASE(0) + 0x44)
+#define SX1301_COR4DETEN    (SX1301_PAGE_BASE(0) + 0x45)
+#define SX1301_COR5DETEN    (SX1301_PAGE_BASE(0) + 0x46)
+#define SX1301_COR6DETEN    (SX1301_PAGE_BASE(0) + 0x47)
+#define SX1301_COR7DETEN    (SX1301_PAGE_BASE(0) + 0x48)
+#define SX1301_CORR_CFG	    (SX1301_PAGE_BASE(0) + 0x4E)
+#define SX1301_MODEM_START_RDX4_L (SX1301_PAGE_BASE(0) + 0x51)
+#define SX1301_MODEM_START_RDX4_H (SX1301_PAGE_BASE(0) + 0x52)
+#define SX1301_MODEM_START_SF12_RDX4_L (SX1301_PAGE_BASE(0) + 0x53)
+#define SX1301_MODEM_START_SF12_RDX4_H (SX1301_PAGE_BASE(0) + 0x54)
+#define SX1301_TIMTRAK2     (SX1301_PAGE_BASE(0) + 0x5D)
+#define SX1301_PRSYMBNBL    (SX1301_PAGE_BASE(0) + 0x60)
+#define SX1301_PRSYMBNBH    (SX1301_PAGE_BASE(0) + 0x61)
+#define SX1301_MISC_CFG1    (SX1301_PAGE_BASE(0) + 0x63)
+#define SX1301_MISC_CFG2    (SX1301_PAGE_BASE(0) + 0x64)
+#define SX1301_HEADER_CFG1  (SX1301_PAGE_BASE(0) + 0x65)
+#define SX1301_HEADER_CFG2  (SX1301_PAGE_BASE(0) + 0x66)
+#define SX1301_GAIN_OFFSET  (SX1301_PAGE_BASE(0) + 0x68)
+#define SX1301_FORCE_CTRL   (SX1301_PAGE_BASE(0) + 0x69)
+#define SX1301_MCU_CTRL     (SX1301_PAGE_BASE(0) + 0x6A)
+#define SX1301_CHANN_SELECT_RSSI	(SX1301_PAGE_BASE(0) + 0x6B)
+#define SX1301_RSSI_BB_DEFAULT_VALUE	(SX1301_PAGE_BASE(0) + 0x6C)
+#define SX1301_RSSI_DEC_DEFAULT_VALUE	(SX1301_PAGE_BASE(0) + 0x6D)
+#define SX1301_RSSI_CHANN_DEFAULT_VALUE (SX1301_PAGE_BASE(0) + 0x6E)
+#define SX1301_RSSI_BB_FILTER_ALPHA	(SX1301_PAGE_BASE(0) + 0x6F)
+#define SX1301_RSSI_DEC_FILTER_ALPHA	(SX1301_PAGE_BASE(0) + 0x70)
+#define SX1301_RSSI_CHANN_FILTER_ALPHA	(SX1301_PAGE_BASE(0) + 0x71)
+
+/* Page 1 */
+#define SX1301_TXTRIG               (SX1301_PAGE_BASE(1) + 0x21)
+#define SX1301_TX_OFFSET_I          (SX1301_PAGE_BASE(1) + 0x27)
+#define SX1301_TX_OFFSET_Q          (SX1301_PAGE_BASE(1) + 0x28)
+#define SX1301_TX_CFG1              (SX1301_PAGE_BASE(1) + 0x29)
+#define SX1301_TX_CFG2              (SX1301_PAGE_BASE(1) + 0x2A)
+#define SX1301_BHIMPCFG1            (SX1301_PAGE_BASE(1) + 0x2B)
+#define SX1301_BHIMPCFG2            (SX1301_PAGE_BASE(1) + 0x2C)
+#define SX1301_BHSYNCPOS            (SX1301_PAGE_BASE(1) + 0x2E)
+#define SX1301_BHPRSYMNBL           (SX1301_PAGE_BASE(1) + 0x2F)
+#define SX1301_MBWSSF_MISC_CFG1     (SX1301_PAGE_BASE(1) + 0x3A)
+#define SX1301_MBWSSF_MISC_CFG2     (SX1301_PAGE_BASE(1) + 0x3B)
+#define SX1301_MBWSSF_MISC_CFG3     (SX1301_PAGE_BASE(1) + 0x3C)
+#define SX1301_MBWSSF_MISC_CFG4     (SX1301_PAGE_BASE(1) + 0x3D)
+#define SX1301_TX_STATUS            (SX1301_PAGE_BASE(1) + 0x3E)
+#define SX1301_FSK_CFG1             (SX1301_PAGE_BASE(1) + 0x3F)
+#define SX1301_FSK_CFG2             (SX1301_PAGE_BASE(1) + 0x40)
+#define SX1301_FSK_ERROR_OSR_TOL    (SX1301_PAGE_BASE(1) + 0x41)
+#define SX1301_FSK_BR_RATIOL        (SX1301_PAGE_BASE(1) + 0x42)
+#define SX1301_FSK_BR_RATIOH        (SX1301_PAGE_BASE(1) + 0x43)
+#define SX1301_FSK_REF_PATTERN_0    (SX1301_PAGE_BASE(1) + 0x44)
+#define SX1301_FSK_REF_PATTERN_1    (SX1301_PAGE_BASE(1) + 0x45)
+#define SX1301_FSK_REF_PATTERN_2    (SX1301_PAGE_BASE(1) + 0x46)
+#define SX1301_FSK_REF_PATTERN_3    (SX1301_PAGE_BASE(1) + 0x47)
+#define SX1301_FSK_REF_PATTERN_4    (SX1301_PAGE_BASE(1) + 0x48)
+#define SX1301_FSK_REF_PATTERN_5    (SX1301_PAGE_BASE(1) + 0x49)
+#define SX1301_FSK_REF_PATTERN_6    (SX1301_PAGE_BASE(1) + 0x4A)
+#define SX1301_FSK_REF_PATTERN_7    (SX1301_PAGE_BASE(1) + 0x4B)
+#define SX1301_FSK_PKT_LENGTH       (SX1301_PAGE_BASE(1) + 0x4C)
+#define SX1301_FSK_TX		    (SX1301_PAGE_BASE(1) + 0x4D)
+#define SX1301_FSK_AAFC             (SX1301_PAGE_BASE(1) + 0x52)
+#define SX1301_FSK_PATTERN_TIMEOUT_CFGL (SX1301_PAGE_BASE(1) + 0x53)
+#define SX1301_FSK_PATTERN_TIMEOUT_CFGH (SX1301_PAGE_BASE(1) + 0x54)
+
+/* Page 2 */
+#define SX1301_RADIO_A_SPI_DATA     (SX1301_PAGE_BASE(2) + 0x21)
+#define SX1301_RADIO_A_SPI_DATA_RB  (SX1301_PAGE_BASE(2) + 0x22)
+#define SX1301_RADIO_A_SPI_ADDR     (SX1301_PAGE_BASE(2) + 0x23)
+#define SX1301_RADIO_A_SPI_CS       (SX1301_PAGE_BASE(2) + 0x25)
+#define SX1301_RADIO_B_SPI_DATA     (SX1301_PAGE_BASE(2) + 0x26)
+#define SX1301_RADIO_B_SPI_DATA_RB  (SX1301_PAGE_BASE(2) + 0x27)
+#define SX1301_RADIO_B_SPI_ADDR     (SX1301_PAGE_BASE(2) + 0x28)
+#define SX1301_RADIO_B_SPI_CS       (SX1301_PAGE_BASE(2) + 0x2A)
+#define SX1301_RADIO_CFG            (SX1301_PAGE_BASE(2) + 0x2B)
+#define SX1301_PA_GAIN              (SX1301_PAGE_BASE(2) + 0x2C)
+#define SX1301_FE_A_CTRL_LUT        (SX1301_PAGE_BASE(2) + 0x2D)
+#define SX1301_FE_B_CTRL_LUT        (SX1301_PAGE_BASE(2) + 0x2E)
+#define SX1301_VALID_HEADER_COUNTER_M_WSSF  (SX1301_PAGE_BASE(2) + 0x38)
+#define SX1301_VALID_HEADER_COUNTER_FSK     (SX1301_PAGE_BASE(2) + 0x39)
+#define SX1301_VALID_PACKET_COUNTER_MB_SSF  (SX1301_PAGE_BASE(2) + 0x3A)
+#define SX1301_VALID_PACKET_COUNTER_FSK     (SX1301_PAGE_BASE(2) + 0x3B)
+#define SX1301_CHANN_RSSI           (SX1301_PAGE_BASE(2) + 0x3C)
+#define SX1301_BB_RSSI              (SX1301_PAGE_BASE(2) + 0x3D)
+#define SX1301_DEC_RSSI             (SX1301_PAGE_BASE(2) + 0x3E)
+#define SX1301_DBG_MCU_DATA         (SX1301_PAGE_BASE(2) + 0x3F)
+#define SX1301_DBG_ARB_MCU_RAM_DATA (SX1301_PAGE_BASE(2) + 0x40)
+#define SX1301_DBG_AGC_MCU_RAM_DATA (SX1301_PAGE_BASE(2) + 0x41)
+#define SX1301_TIMESTAMP_0          (SX1301_PAGE_BASE(2) + 0x46)
+#define SX1301_TIMESTAMP_1          (SX1301_PAGE_BASE(2) + 0x47)
+#define SX1301_TIMESTAMP_2          (SX1301_PAGE_BASE(2) + 0x48)
+#define SX1301_TIMESTAMP_3          (SX1301_PAGE_BASE(2) + 0x49)
+#define SX1301_DBG_ARB_MCU_RAM_ADDR (SX1301_PAGE_BASE(2) + 0x50)
+#define SX1301_DBG_AGC_MCU_RAM_ADDR (SX1301_PAGE_BASE(2) + 0x51)
+#define SX1301_SPI_MASTER_CFG       (SX1301_PAGE_BASE(2) + 0x52)
+#define SX1301_GPS_CFG              (SX1301_PAGE_BASE(2) + 0x59)
+
+/* Page 3 */
+#define SX1301_EMERGENCY_FORCE_HOST_CTRL (SX1301_PAGE_BASE(3) + 0x7F)
+
+#define SX1301_MAX_REGISTER         (SX1301_PAGE_BASE(3) + 0x7F)
+
+#endif
-- 
2.7.4

^ permalink raw reply related

* [PATCH lora-next 00/10] Conversing sx1301 to regmap and regfield
From: Ben Whitten @ 2018-08-07 17:32 UTC (permalink / raw)
  To: afaerber, starnight, hasnain.virk; +Cc: netdev, Ben Whitten

This series converts the majority of sx1301 code to using regmap and regfield
system.
The SPI subsystem is as yet untouched but will be converted to a regmap_bus
in a future series with sx1257 conversions.

Interestingly the initial state did not work for me as I was getting kernel
oopses somewhere todo with sx1301_page_read on my hardware.
Since conversion to regmap the sx1301 initialises properly, sx1257 still oopses
because of the SPI bus read but presumably will go away with regmap_bus.

Ben Whitten (10):
  net: lora: sx1301: add register, bit-fields, and helpers for regmap
  net: lora: add methods for devm registration
  net: lora: sx1301: convert to devm registration of netdev
  net: lora: sx1301: convert probe function to regmap access
  net: lora: sx1301: add device to private data and convert ram reads
  net: lora: sx1301: simplify firmware loading and convert
  net: lora: sx1301: convert read and write burst to take priv data
  net: lora: sx1301: convert read and write to priv pointer
  net: lora: sx1301: convert agc calibrate to regmap functions
  net: lora: sx1301: convert all firmware to regmap

 drivers/net/lora/Kconfig  |   1 +
 drivers/net/lora/dev.c    |  20 ++
 drivers/net/lora/sx1301.c | 803 ++++++++++++++++++++++++----------------------
 drivers/net/lora/sx1301.h | 176 ++++++++++
 include/linux/lora/dev.h  |   1 +
 5 files changed, 623 insertions(+), 378 deletions(-)
 create mode 100644 drivers/net/lora/sx1301.h

-- 
2.7.4

^ permalink raw reply

* Re: [PATCH v3 net-next 5/9] net: stmmac: Add MDIO related functions for XGMAC2
From: Florian Fainelli @ 2018-08-07 17:31 UTC (permalink / raw)
  To: Jose Abreu, netdev
  Cc: David S. Miller, Joao Pinto, Giuseppe Cavallaro, Alexandre Torgue,
	Andrew Lunn
In-Reply-To: <3a097ddf-cff1-460f-2c63-7347274c1ee5@synopsys.com>

On 08/07/2018 06:35 AM, Jose Abreu wrote:
> Hi Florian,
> 
> On 06-08-2018 16:25, Florian Fainelli wrote:
>> On August 6, 2018 12:59:54 AM PDT, Jose Abreu <Jose.Abreu@synopsys.com> wrote:
>>> On 03-08-2018 20:06, Florian Fainelli wrote:
>>>> On 08/03/2018 08:50 AM, Jose Abreu wrote:
>>>>> Add the MDIO related funcionalities for the new IP block XGMAC2.
>>>>>
>>>>> Signed-off-by: Jose Abreu <joabreu@synopsys.com>
>>>>> Cc: David S. Miller <davem@davemloft.net>
>>>>> Cc: Joao Pinto <jpinto@synopsys.com>
>>>>> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
>>>>> Cc: Alexandre Torgue <alexandre.torgue@st.com>
>>>>> Cc: Andrew Lunn <andrew@lunn.ch>
>>>>> ---
>>>>> +satic int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int
>>> phyaddr,
>>>>> +				    int phyreg, u32 *hw_addr)
>>>>> +{
>>>>> +	unsigned int mii_data = priv->hw->mii.data;
>>>>> +	u32 tmp;
>>>>> +
>>>>> +	/* HW does not support C22 addr >= 4 */
>>>>> +	if (phyaddr >= 4)
>>>>> +		return -ENODEV;
>>>> It would be nice if this could be moved at probe time so you don't
>>> have
>>>> to wait until you connect to the PHY, read its PHY OUI and find out
>>> it
>>>> has a MDIO address >= 4. Not a blocker, but something that could be
>>>> improved further on.
>>>>
>>>> In premise you could even scan the MDIO bus' device tree node, and
>>> find
>>>> that out ahead of time.
>>> Oh, but I use phylib ... I only provide the read/write callbacks
>>> so I think we should avoid duplicating the code that's already in
>>> the phylib ... No?
>> You can always extract the code that scans a MDIO bus into a helper function and make it parametrized with a callback of some kind. In that case I would be fine with you open coding the MDIO bus scan to find out if there is an address >= 4.
> 
> Sorry but I dont' think thats the best solution because
> of_mdiobus_register() already scans the bus. Duplicating this
> should be avoided, no?

I suggested you extract the code into a helper to avoid the duplication.

> 
> Note all of this is probably never needed because stmmac just
> picks the first phy it finds, if phy_addr is not specified ...

No, it's much more involved than that, there are several modes in which
MDIO on stmmac can be instantiated:

- platform data instantiation, which uses a loop and finds the first
available address
- Device Tree which will scan the MDIO bus' node child nodes and create
PHYs for valid nodes

It feels a bit late to check for PHY address >= 4 during the first read,
because it won't be obvious to somehow why this fails, but if that
fulfills your needs, keep it that way.

> 
>>
>>>>> +	/* Wait until any existing MII operation is complete */
>>>>> +	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
>>>>> +			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
>>>>> +		return -EBUSY;
>>>>> +
>>>>> +	/* Set port as Clause 22 */
>>>>> +	tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
>>>>> +	tmp |= BIT(phyaddr);
>>>> Since the registers are being Read/Modify/Write here, don't you need
>>> to
>>>> clear the previous address bits as well?
>>>>
>>>> You probably did not encounter any problems in your testing if you
>>> had
>>>> only one PHY on the MDIO bus, but this is not something that is
>>>> necessarily true, e.g: if you have an Ethernet switch, several MDIO
>>> bus
>>>> addresses are going to be responding.
>>>>
>>>> Your MDIO bus implementation must be able to support one transaction
>>>> with one PHY address and the next transaction with another PHY
>>> address ,
>>>> etc...
>>>>
>>>> That is something that should be easy to fix and be resubmitted as
>>> part
>>>> of v4.
>>> I'm not following you here... I only set/unset the bit for the
>>> corresponding phyaddr that phylib wants to read/write. Why would
>>> I clear the remaining addresses?
>> Because this is all about transactions, the HW must be in a state that it will be able to perform that transaction correctly. So here for instance if you needed to support a C45 transaction you would have to clear that bit for that particular PHY address. Since you don't appear to support those yet then yes the code appears fine though it would not hurt if you did clear all other PHY's c22 bits to make it clear what this does.
> 
> I can't test C45 right now but I will in a near future. In that
> case then we will need to support C22 and C45 so I may want to
> only set one bit for a specific phy that only supports c22.

We are really talking about adding something like:

	reg &= ~(MASK);

before setting the bit, anyhow, if you want to do that later on when you
add C45 support, be my guest...
-- 
Florian

^ permalink raw reply

* Re: [PATCH v6 1/9] PCI: Check for PCIe downtraining conditions
From: David Miller @ 2018-08-07 19:44 UTC (permalink / raw)
  To: mr.nuke.me
  Cc: linux-pci, bhelgaas, jakub.kicinski, keith.busch, alex_gagniuc,
	austin_bolen, shyam_iyer, ariel.elior, everest-linux-l2,
	michael.chan, ganeshgr, jeffrey.t.kirsher, tariqt, saeedm, leon,
	dirk.vandermerwe, netdev, linux-kernel, intel-wired-lan,
	linux-rdma, oss-drivers
In-Reply-To: <20180806232600.25694-1-mr.nuke.me@gmail.com>

From: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Date: Mon,  6 Aug 2018 18:25:35 -0500

> PCIe downtraining happens when both the device and PCIe port are
> capable of a larger bus width or higher speed than negotiated.
> Downtraining might be indicative of other problems in the system, and
> identifying this from userspace is neither intuitive, nor
> straightforward.
> 
> The easiest way to detect this is with pcie_print_link_status(),
> since the bottleneck is usually the link that is downtrained. It's not
> a perfect solution, but it works extremely well in most cases.
> 
> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>

Feel free to merge this entire series via the PCI tree.

For the series:

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* Re: [PATCH] net: thunderx: check for failed allocation lmac->dmacs
From: David Miller @ 2018-08-07 19:38 UTC (permalink / raw)
  To: colin.king
  Cc: sgoutham, rric, linux-arm-kernel, netdev, kernel-janitors,
	linux-kernel
In-Reply-To: <20180806165045.15707-1-colin.king@canonical.com>

From: Colin King <colin.king@canonical.com>
Date: Mon,  6 Aug 2018 17:50:45 +0100

> From: Colin Ian King <colin.king@canonical.com>
> 
> The allocation of lmac->dmacs is not being checked for allocation
> failure. Add the check.
> 
> Fixes: 3a34ecfd9d3f ("net: thunderx: add MAC address filter tracking for LMAC")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>

Applied.

^ permalink raw reply

* Re: [PATCH net-next v2] tcp: propagate gso_segs to the new skb built in tcp collapse
From: David Miller @ 2018-08-07 19:32 UTC (permalink / raw)
  To: laoar.shao; +Cc: edumazet, netdev, linux-kernel
In-Reply-To: <1533464707-11777-1-git-send-email-laoar.shao@gmail.com>

From: Yafang Shao <laoar.shao@gmail.com>
Date: Sun,  5 Aug 2018 18:25:07 +0800

> The gso_segs of the new built SKB in tcp collapse is inited to 0,
> that makes us hard to know the accurate segments number of this new SKB.
> We'd better propagate the gso_segs of the collapsed SKB to the new built
> one, so when this SKB is dropped (for example when doing tcp prune) the
> sk_drops will be added to the correct value.
> 
> If the collapsed SKB is fully copied to the new built one, we just add its
> gso_segs to the new SKB.
> While if the collapsed SKB is partially copied to the new built SKB,
> we have to caculate how many segments are copied.
> Furthemore, we have to reset the gso_segs of this SKB if is is partially
> copied, so in the next round when the left segments are copied it could
> propagate the correct value.
> 
> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>

Eric, please review.

If partial copies are common, I wonder how much sense it makes to try to
avoid the DIV_ROUND_UP() operations.

^ permalink raw reply

* [PATCH 2/3] net: dsa: b53: Add support for Broadcom Omega SoC internal switch
From: Arun Parameswaran @ 2018-08-07 17:02 UTC (permalink / raw)
  To: David S. Miller, Florian Fainelli, Andrew Lunn, Vivien Didelot,
	Rob Herring, Mark Rutland
  Cc: netdev, devicetree, linux-kernel, bcm-kernel-feedback-list,
	Arun Parameswaran
In-Reply-To: <1533661364-15381-1-git-send-email-arun.parameswaran@broadcom.com>

Add support for the Broadcom Omega SoC internal ethernet switch
to the b53 srab driver in the DSA framework.

Signed-off-by: Arun Parameswaran <arun.parameswaran@broadcom.com>
---
 drivers/net/dsa/b53/b53_srab.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c
index 8247481..91de2ba 100644
--- a/drivers/net/dsa/b53/b53_srab.c
+++ b/drivers/net/dsa/b53/b53_srab.c
@@ -374,6 +374,7 @@ static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
 	{ .compatible = "brcm,bcm88312-srab", .data = (void *)BCM58XX_DEVICE_ID },
 	{ .compatible = "brcm,cygnus-srab", .data = (void *)BCM583XX_DEVICE_ID },
 	{ .compatible = "brcm,nsp-srab", .data = (void *)BCM58XX_DEVICE_ID },
+	{ .compatible = "brcm,omega-srab", .data = (void *)BCM583XX_DEVICE_ID },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, b53_srab_of_match);
-- 
1.9.1

^ permalink raw reply related

* [PATCH net v2] dccp: fix undefined behavior with 'cwnd' shift in ccid2_cwnd_restart()
From: Alexey Kodanev @ 2018-08-07 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Gerrit Renker, David Miller, dccp, Alexey Kodanev

The shift of 'cwnd' with '(now - hc->tx_lsndtime) / hc->tx_rto' value
can lead to undefined behavior [1].

In order to fix this use a gradual shift of the window with a 'while'
loop, similar to what tcp_cwnd_restart() is doing.

When comparing delta and RTO there is a minor difference between TCP
and DCCP, the last one also invokes dccp_cwnd_restart() and reduces
'cwnd' if delta equals RTO. That case is preserved in this change.

[1]:
[40850.963623] UBSAN: Undefined behaviour in net/dccp/ccids/ccid2.c:237:7
[40851.043858] shift exponent 67 is too large for 32-bit type 'unsigned int'
[40851.127163] CPU: 3 PID: 15940 Comm: netstress Tainted: G        W   E     4.18.0-rc7.x86_64 #1
...
[40851.377176] Call Trace:
[40851.408503]  dump_stack+0xf1/0x17b
[40851.451331]  ? show_regs_print_info+0x5/0x5
[40851.503555]  ubsan_epilogue+0x9/0x7c
[40851.548363]  __ubsan_handle_shift_out_of_bounds+0x25b/0x2b4
[40851.617109]  ? __ubsan_handle_load_invalid_value+0x18f/0x18f
[40851.686796]  ? xfrm4_output_finish+0x80/0x80
[40851.739827]  ? lock_downgrade+0x6d0/0x6d0
[40851.789744]  ? xfrm4_prepare_output+0x160/0x160
[40851.845912]  ? ip_queue_xmit+0x810/0x1db0
[40851.895845]  ? ccid2_hc_tx_packet_sent+0xd36/0x10a0 [dccp]
[40851.963530]  ccid2_hc_tx_packet_sent+0xd36/0x10a0 [dccp]
[40852.029063]  dccp_xmit_packet+0x1d3/0x720 [dccp]
[40852.086254]  dccp_write_xmit+0x116/0x1d0 [dccp]
[40852.142412]  dccp_sendmsg+0x428/0xb20 [dccp]
[40852.195454]  ? inet_dccp_listen+0x200/0x200 [dccp]
[40852.254833]  ? sched_clock+0x5/0x10
[40852.298508]  ? sched_clock+0x5/0x10
[40852.342194]  ? inet_create+0xdf0/0xdf0
[40852.388988]  sock_sendmsg+0xd9/0x160
...

Fixes: 113ced1f52e5 ("dccp ccid-2: Perform congestion-window validation")
Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
---

v2: instead of checking the value with min(), use gradual shifting,
    similar to tcp_cwnd_restart().

 net/dccp/ccids/ccid2.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 2b75df4..842a9c7 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -229,14 +229,16 @@ static void ccid2_cwnd_restart(struct sock *sk, const u32 now)
 	struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
 	u32 cwnd = hc->tx_cwnd, restart_cwnd,
 	    iwnd = rfc3390_bytes_to_packets(dccp_sk(sk)->dccps_mss_cache);
+	s32 delta = now - hc->tx_lsndtime;
 
 	hc->tx_ssthresh = max(hc->tx_ssthresh, (cwnd >> 1) + (cwnd >> 2));
 
 	/* don't reduce cwnd below the initial window (IW) */
 	restart_cwnd = min(cwnd, iwnd);
-	cwnd >>= (now - hc->tx_lsndtime) / hc->tx_rto;
-	hc->tx_cwnd = max(cwnd, restart_cwnd);
 
+	while ((delta -= hc->tx_rto) >= 0 && cwnd > restart_cwnd)
+		cwnd >>= 1;
+	hc->tx_cwnd = max(cwnd, restart_cwnd);
 	hc->tx_cwnd_stamp = now;
 	hc->tx_cwnd_used  = 0;
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH net-next] selftests: forwarding: gre_multipath: Update next-hop statistics match criteria
From: Nir Dotan @ 2018-08-07 16:41 UTC (permalink / raw)
  To: netdev; +Cc: davem, mlxsw, Nir Dotan

gre_multipath test was using egress vlan_id matching on flows, for the
purpose of collecting next-hops statistics, later to be compared
against configured weights.
As matching on vlan_id on egress direction is not supported on all HW
devices, change the match criteria to use destination IP.

Signed-off-by: Nir Dotan <nird@mellanox.com>
Acked-by: Petr Machata <petrm@mellanox.com>
---
 tools/testing/selftests/net/forwarding/gre_multipath.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/net/forwarding/gre_multipath.sh b/tools/testing/selftests/net/forwarding/gre_multipath.sh
index 3b1e047..cca2baa 100755
--- a/tools/testing/selftests/net/forwarding/gre_multipath.sh
+++ b/tools/testing/selftests/net/forwarding/gre_multipath.sh
@@ -95,10 +95,10 @@ sw1_create()
 	   nexthop dev g1b
 
 	tc qdisc add dev $ul1 clsact
-	tc filter add dev $ul1 egress pref 111 prot 802.1q \
-	   flower vlan_id 111 action pass
-	tc filter add dev $ul1 egress pref 222 prot 802.1q \
-	   flower vlan_id 222 action pass
+	tc filter add dev $ul1 egress pref 111 prot ipv4 \
+	   flower dst_ip 192.0.2.66 action pass
+	tc filter add dev $ul1 egress pref 222 prot ipv4 \
+	   flower dst_ip 192.0.2.82 action pass
 }
 
 sw1_destroy()
-- 
2.8.4

^ permalink raw reply related

* Re: [PATCH net-next 12/14] net: sched: act_mirred: remove dependency on rtnl lock
From: Jiri Pirko @ 2018-08-07 16:36 UTC (permalink / raw)
  To: Vlad Buslov
  Cc: netdev, davem, jhs, xiyou.wangcong, pablo, kadlec, fw, ast,
	daniel, edumazet, keescook, marcelo.leitner
In-Reply-To: <1533538465-23199-13-git-send-email-vladbu@mellanox.com>

Mon, Aug 06, 2018 at 08:54:23AM CEST, vladbu@mellanox.com wrote:

[...]

>diff --git a/include/net/tc_act/tc_tunnel_key.h b/include/net/tc_act/tc_tunnel_key.h
>index 46b8c7f1c8d5..e6e475d788c6 100644
>--- a/include/net/tc_act/tc_tunnel_key.h
>+++ b/include/net/tc_act/tc_tunnel_key.h
>@@ -30,26 +30,47 @@ struct tcf_tunnel_key {
> 
> static inline bool is_tcf_tunnel_set(const struct tc_action *a)
> {
>+	bool ret = false;
> #ifdef CONFIG_NET_CLS_ACT
> 	struct tcf_tunnel_key *t = to_tunnel_key(a);
>-	struct tcf_tunnel_key_params *params = rtnl_dereference(t->params);
>+	struct tcf_tunnel_key_params *params;
> 
>+	rcu_read_lock();
>+	params = rcu_dereference(t->params);
> 	if (a->ops && a->ops->type == TCA_ACT_TUNNEL_KEY)
>-		return params->tcft_action == TCA_TUNNEL_KEY_ACT_SET;
>+		ret = params->tcft_action == TCA_TUNNEL_KEY_ACT_SET;
>+	rcu_read_unlock();
> #endif
>-	return false;
>+	return ret;
> }
> 
> static inline bool is_tcf_tunnel_release(const struct tc_action *a)

Why are these tunnel things in a mirred patch?


[...]


> static struct net_device *tcf_mirred_get_dev(const struct tc_action *a)
> {
> 	struct tcf_mirred *m = to_mirred(a);
>+	struct net_device *dev;
>+
>+	rcu_read_lock();
>+	dev = rcu_dereference(m->tcfm_dev);
>+	if (dev)
>+		dev_hold(dev);
>+	rcu_read_unlock();
> 
>-	return rtnl_dereference(m->tcfm_dev);
>+	return dev;
> }
> 
> static int tcf_mirred_delete(struct net *net, u32 index)
>diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
>index e8b0bbd0883f..0cce0eadc28b 100644
>--- a/net/sched/cls_api.c
>+++ b/net/sched/cls_api.c
>@@ -2167,6 +2167,7 @@ static int tc_exts_setup_cb_egdev_call(struct tcf_exts *exts,
> 		if (!dev)
> 			continue;
> 		ret = tc_setup_cb_egdev_call(dev, type, type_data, err_stop);
>+		dev_put(dev);

This looks really odd. a->ops->put_dev is needed.


> 		if (ret < 0)
> 			return ret;
> 		ok_count += ret;
>-- 
>2.7.5
>

^ permalink raw reply

* Re: [PATCH v1 2/3] zinc: Introduce minimal cryptography library
From: Jason A. Donenfeld @ 2018-08-07 18:54 UTC (permalink / raw)
  To: Andy Lutomirski, Eric Biggers
  Cc: Linux Crypto Mailing List, LKML, Netdev, David Miller,
	Andrew Lutomirski, Greg Kroah-Hartman, Samuel Neves,
	Daniel J . Bernstein, Tanja Lange, Jean-Philippe Aumasson,
	Karthikeyan Bhargavan
In-Reply-To: <CAHmME9pt3PxKQmc8E-arA-W0p2tp9z_oJ-uXQwis3qD=Zvpnsg@mail.gmail.com>

Hey Andy, Eric, & all,

I've started the work of separating this out into 16 individual
commits, have addressed numerous other things brought up like the
ifdef maze, and have begun rewriting (parts of) the original commit
message. It's still a work in progress, and I still have some work to
do, but if you want to follow along, things are happening here:

https://git.zx2c4.com/linux-dev/log/?h=jd/wireguard

I'll be rebasing and reworking this continuously, but that's how it's
shaping up.

As I'm still working on it, I won't be submitting v2 today, but if you
have suggestions or concerns or want to poke me while I'm working on
v2, don't hesitate to send me private email or ping me in IRC (I'm
"zx2c4" there) to chat.

Regards,
Jason

^ permalink raw reply

* [PATCH 4.4 07/12] netlink: Dont shift on 64 for ngroups
From: Greg Kroah-Hartman @ 2018-08-07 18:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, stable, David S. Miller, Herbert Xu,
	Steffen Klassert, netdev, Dmitry Safonov
In-Reply-To: <20180807172343.326201671@linuxfoundation.org>

4.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Dmitry Safonov <dima@arista.com>

commit 91874ecf32e41b5d86a4cb9d60e0bee50d828058 upstream.

It's legal to have 64 groups for netlink_sock.

As user-supplied nladdr->nl_groups is __u32, it's possible to subscribe
only to first 32 groups.

The check for correctness of .bind() userspace supplied parameter
is done by applying mask made from ngroups shift. Which broke Android
as they have 64 groups and the shift for mask resulted in an overflow.

Fixes: 61f4b23769f0 ("netlink: Don't shift with UB on nlk->ngroups")
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: netdev@vger.kernel.org
Cc: stable@vger.kernel.org
Reported-and-Tested-by: Nathan Chancellor <natechancellor@gmail.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 net/netlink/af_netlink.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -988,8 +988,8 @@ static int netlink_bind(struct socket *s
 
 	if (nlk->ngroups == 0)
 		groups = 0;
-	else
-		groups &= (1ULL << nlk->ngroups) - 1;
+	else if (nlk->ngroups < 8*sizeof(groups))
+		groups &= (1UL << nlk->ngroups) - 1;
 
 	bound = nlk->bound;
 	if (bound) {

^ permalink raw reply

* [PATCH 4.4 05/12] netlink: Do not subscribe to non-existent groups
From: Greg Kroah-Hartman @ 2018-08-07 18:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, stable, David S. Miller, Herbert Xu,
	Steffen Klassert, netdev, Dmitry Safonov
In-Reply-To: <20180807172343.326201671@linuxfoundation.org>

4.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Dmitry Safonov <dima@arista.com>

[ Upstream commit 7acf9d4237c46894e0fa0492dd96314a41742e84 ]

Make ABI more strict about subscribing to group > ngroups.
Code doesn't check for that and it looks bogus.
(one can subscribe to non-existing group)
Still, it's possible to bind() to all possible groups with (-1)

Cc: "David S. Miller" <davem@davemloft.net>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: netdev@vger.kernel.org
Signed-off-by: Dmitry Safonov <dima@arista.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 net/netlink/af_netlink.c |    1 +
 1 file changed, 1 insertion(+)

--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -985,6 +985,7 @@ static int netlink_bind(struct socket *s
 		if (err)
 			return err;
 	}
+	groups &= (1UL << nlk->ngroups) - 1;
 
 	bound = nlk->bound;
 	if (bound) {

^ permalink raw reply

* [PATCH 4.9 07/17] netlink: Dont shift on 64 for ngroups
From: Greg Kroah-Hartman @ 2018-08-07 18:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, stable, David S. Miller, Herbert Xu,
	Steffen Klassert, netdev, Dmitry Safonov
In-Reply-To: <20180807172342.071526922@linuxfoundation.org>

4.9-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Dmitry Safonov <dima@arista.com>

commit 91874ecf32e41b5d86a4cb9d60e0bee50d828058 upstream.

It's legal to have 64 groups for netlink_sock.

As user-supplied nladdr->nl_groups is __u32, it's possible to subscribe
only to first 32 groups.

The check for correctness of .bind() userspace supplied parameter
is done by applying mask made from ngroups shift. Which broke Android
as they have 64 groups and the shift for mask resulted in an overflow.

Fixes: 61f4b23769f0 ("netlink: Don't shift with UB on nlk->ngroups")
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: netdev@vger.kernel.org
Cc: stable@vger.kernel.org
Reported-and-Tested-by: Nathan Chancellor <natechancellor@gmail.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 net/netlink/af_netlink.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -988,8 +988,8 @@ static int netlink_bind(struct socket *s
 
 	if (nlk->ngroups == 0)
 		groups = 0;
-	else
-		groups &= (1ULL << nlk->ngroups) - 1;
+	else if (nlk->ngroups < 8*sizeof(groups))
+		groups &= (1UL << nlk->ngroups) - 1;
 
 	bound = nlk->bound;
 	if (bound) {

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox