Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1587038 > unrolled thread

[PATCH 0/7] net: stmmac: Fixes and Tegra186 support

Started byThierry Reding <thierry.reding@gmail.com>
First post2017-02-23 18:30 +0100
Last post2017-02-27 08:40 +0100
Articles 7 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/7] net: stmmac: Fixes and Tegra186 support Thierry Reding <thierry.reding@gmail.com> - 2017-02-23 18:30 +0100
    [PATCH 7/7] net: stmmac: dwc-qos: Add Tegra186 support Thierry Reding <thierry.reding@gmail.com> - 2017-02-23 18:30 +0100
      Re: [PATCH 7/7] net: stmmac: dwc-qos: Add Tegra186 support Mikko Perttunen <cyndis@kapsi.fi> - 2017-02-27 16:10 +0100
    [PATCH 4/7] net: stmmac: Parse FIFO sizes from feature registers Thierry Reding <thierry.reding@gmail.com> - 2017-02-23 18:30 +0100
      Re: [PATCH 4/7] net: stmmac: Parse FIFO sizes from feature registers Mikko Perttunen <cyndis@kapsi.fi> - 2017-02-27 11:00 +0100
    Re: [PATCH 0/7] net: stmmac: Fixes and Tegra186 support David Miller <davem@davemloft.net> - 2017-02-23 19:30 +0100
      Re: [PATCH 0/7] net: stmmac: Fixes and Tegra186 support Thierry Reding <thierry.reding@gmail.com> - 2017-02-27 08:40 +0100

#1587038 — [PATCH 0/7] net: stmmac: Fixes and Tegra186 support

FromThierry Reding <thierry.reding@gmail.com>
Date2017-02-23 18:30 +0100
Subject[PATCH 0/7] net: stmmac: Fixes and Tegra186 support
Message-ID<te5nj-4nQ-5@gated-at.bofh.it>
From: Thierry Reding <treding@nvidia.com>

Hi everyone,

This series of patches start with a few cleanups that I ran across while
adding Tegra186 support to the stmmac driver. It then adds code for FIFO
size parsing from feature registers and finally enables support for the
incarnation of the Synopsys DWC QOS IP found on NVIDIA Tegra186 SoCs.

This is based on next-20170223.

Thanks,
Thierry

Thierry Reding (7):
  net: stmmac: Rename clk_ptp_ref clock to ptp_ref
  net: stmmac: Balance PTP reference clock enable/disable
  net: stmmac: Check for DMA mapping errors
  net: stmmac: Parse FIFO sizes from feature registers
  net: stmmac: Program RX queue size and flow control
  net: stmmac: dwc-qos: Split out ->probe() and ->remove()
  net: stmmac: dwc-qos: Add Tegra186 support

 Documentation/devicetree/bindings/net/stmmac.txt   |   6 +-
 drivers/net/ethernet/stmicro/stmmac/common.h       |   3 +
 .../ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c    | 366 +++++++++++++++++++--
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h       |  12 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c   |  45 ++-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   9 +
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |   3 +-
 7 files changed, 411 insertions(+), 33 deletions(-)

-- 
2.11.1

[toc] | [next] | [standalone]


#1587039 — [PATCH 7/7] net: stmmac: dwc-qos: Add Tegra186 support

FromThierry Reding <thierry.reding@gmail.com>
Date2017-02-23 18:30 +0100
Subject[PATCH 7/7] net: stmmac: dwc-qos: Add Tegra186 support
Message-ID<te5nk-4nQ-35@gated-at.bofh.it>
In reply to#1587038
From: Thierry Reding <treding@nvidia.com>

The NVIDIA Tegra186 SoC contains an instance of the Synopsys DWC
ethernet QOS IP core. The binding that it uses is slightly different
from existing ones because of the integration (clocks, resets, ...).

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 .../ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c    | 252 +++++++++++++++++++++
 1 file changed, 252 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
index 5071d3c15adc..54dfbdc48f6d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/ethtool.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
@@ -22,10 +23,24 @@
 #include <linux/of_net.h>
 #include <linux/mfd/syscon.h>
 #include <linux/platform_device.h>
+#include <linux/reset.h>
 #include <linux/stmmac.h>
 
 #include "stmmac_platform.h"
 
+struct tegra_eqos {
+	struct device *dev;
+	void __iomem *regs;
+
+	struct reset_control *rst;
+	struct clk *clk_master;
+	struct clk *clk_slave;
+	struct clk *clk_tx;
+	struct clk *clk_rx;
+
+	struct gpio_desc *reset;
+};
+
 static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
 				   struct plat_stmmacenet_data *plat_dat)
 {
@@ -148,6 +163,237 @@ static int dwc_qos_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#define SDMEMCOMPPADCTRL 0x8800
+#define  SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31)
+
+#define AUTO_CAL_CONFIG 0x8804
+#define  AUTO_CAL_CONFIG_START BIT(31)
+#define  AUTO_CAL_CONFIG_ENABLE BIT(29)
+
+#define AUTO_CAL_STATUS 0x880c
+#define  AUTO_CAL_STATUS_ACTIVE BIT(31)
+
+static void tegra_eqos_fix_speed(void *priv, unsigned int speed)
+{
+	struct tegra_eqos *eqos = priv;
+	unsigned long rate = 125000000;
+	bool needs_calibration = false;
+	unsigned int i;
+	u32 value;
+
+	switch (speed) {
+	case SPEED_1000:
+		needs_calibration = true;
+		rate = 125000000;
+		break;
+
+	case SPEED_100:
+		needs_calibration = true;
+		rate = 25000000;
+		break;
+
+	case SPEED_10:
+		rate = 2500000;
+		break;
+
+	default:
+		dev_err(eqos->dev, "invalid speed %u\n", speed);
+		break;
+	}
+
+	if (needs_calibration) {
+		/* calibrate */
+		value = readl(eqos->regs + SDMEMCOMPPADCTRL);
+		value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
+		writel(value, eqos->regs + SDMEMCOMPPADCTRL);
+
+		udelay(1);
+
+		value = readl(eqos->regs + AUTO_CAL_CONFIG);
+		value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE;
+		writel(value, eqos->regs + AUTO_CAL_CONFIG);
+
+		for (i = 0; i <= 10; i++) {
+			value = readl(eqos->regs + AUTO_CAL_STATUS);
+			if (value & AUTO_CAL_STATUS_ACTIVE)
+				break;
+
+			udelay(1);
+		}
+
+		if ((value & AUTO_CAL_STATUS_ACTIVE) == 0) {
+			dev_err(eqos->dev, "calibration did not start\n");
+			goto failed;
+		}
+
+		for (i = 0; i <= 10; i++) {
+			value = readl(eqos->regs + AUTO_CAL_STATUS);
+			if ((value & AUTO_CAL_STATUS_ACTIVE) == 0)
+				break;
+
+			udelay(20);
+		}
+
+		if (value & AUTO_CAL_STATUS_ACTIVE) {
+			dev_err(eqos->dev, "calibration didn't finish\n");
+			goto failed;
+		}
+
+	failed:
+		value = readl(eqos->regs + SDMEMCOMPPADCTRL);
+		value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
+		writel(value, eqos->regs + SDMEMCOMPPADCTRL);
+	} else {
+		value = readl(eqos->regs + AUTO_CAL_CONFIG);
+		value &= ~AUTO_CAL_CONFIG_ENABLE;
+		writel(value, eqos->regs + AUTO_CAL_CONFIG);
+	}
+
+	clk_set_rate(eqos->clk_tx, rate);
+}
+
+static int tegra_eqos_init(struct platform_device *pdev, void *priv)
+{
+	struct tegra_eqos *eqos = priv;
+	unsigned long rate;
+	u32 value;
+
+	rate = clk_get_rate(eqos->clk_slave);
+
+	value = readl(eqos->regs + 0xdc);
+	value = (rate / 1000000) - 1;
+	writel(value, eqos->regs + 0xdc);
+
+	return 0;
+}
+
+static void *tegra_eqos_probe(struct platform_device *pdev,
+			      struct plat_stmmacenet_data *data,
+			      struct stmmac_resources *res)
+{
+	struct tegra_eqos *eqos;
+	int err;
+
+	eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL);
+	if (!eqos) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	eqos->dev = &pdev->dev;
+	eqos->regs = res->addr;
+
+	eqos->clk_master = devm_clk_get(&pdev->dev, "master_bus");
+	if (IS_ERR(eqos->clk_master)) {
+		err = PTR_ERR(eqos->clk_master);
+		goto error;
+	}
+
+	err = clk_prepare_enable(eqos->clk_master);
+	if (err < 0)
+		goto error;
+
+	eqos->clk_slave = devm_clk_get(&pdev->dev, "slave_bus");
+	if (IS_ERR(eqos->clk_slave)) {
+		err = PTR_ERR(eqos->clk_slave);
+		goto disable_master;
+	}
+
+	data->stmmac_clk = eqos->clk_slave;
+
+	err = clk_prepare_enable(eqos->clk_slave);
+	if (err < 0)
+		goto disable_master;
+
+	eqos->clk_rx = devm_clk_get(&pdev->dev, "rx");
+	if (IS_ERR(eqos->clk_rx)) {
+		err = PTR_ERR(eqos->clk_rx);
+		goto disable_slave;
+	}
+
+	err = clk_prepare_enable(eqos->clk_rx);
+	if (err < 0)
+		goto disable_slave;
+
+	eqos->clk_tx = devm_clk_get(&pdev->dev, "tx");
+	if (IS_ERR(eqos->clk_tx)) {
+		err = PTR_ERR(eqos->clk_tx);
+		goto disable_rx;
+	}
+
+	err = clk_prepare_enable(eqos->clk_tx);
+	if (err < 0)
+		goto disable_rx;
+
+	eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(eqos->reset)) {
+		err = PTR_ERR(eqos->reset);
+		goto disable_tx;
+	}
+
+	usleep_range(2000, 4000);
+	gpiod_set_value(eqos->reset, 0);
+
+	eqos->rst = devm_reset_control_get(&pdev->dev, "eqos");
+	if (IS_ERR(eqos->rst)) {
+		err = PTR_ERR(eqos->rst);
+		goto reset_phy;
+	}
+
+	err = reset_control_assert(eqos->rst);
+	if (err < 0)
+		goto reset_phy;
+
+	usleep_range(2000, 4000);
+
+	err = reset_control_deassert(eqos->rst);
+	if (err < 0)
+		goto reset_phy;
+
+	usleep_range(2000, 4000);
+
+	data->fix_mac_speed = tegra_eqos_fix_speed;
+	data->init = tegra_eqos_init;
+	data->bsp_priv = eqos;
+
+	err = tegra_eqos_init(pdev, eqos);
+	if (err < 0)
+		goto reset;
+
+out:
+	return eqos;
+
+reset:
+	reset_control_assert(eqos->rst);
+reset_phy:
+	gpiod_set_value(eqos->reset, 1);
+disable_tx:
+	clk_disable_unprepare(eqos->clk_tx);
+disable_rx:
+	clk_disable_unprepare(eqos->clk_rx);
+disable_slave:
+	clk_disable_unprepare(eqos->clk_slave);
+disable_master:
+	clk_disable_unprepare(eqos->clk_master);
+error:
+	eqos = ERR_PTR(err);
+	goto out;
+}
+
+static int tegra_eqos_remove(struct platform_device *pdev)
+{
+	struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev);
+
+	reset_control_assert(eqos->rst);
+	gpiod_set_value(eqos->reset, 1);
+	clk_disable_unprepare(eqos->clk_tx);
+	clk_disable_unprepare(eqos->clk_rx);
+	clk_disable_unprepare(eqos->clk_slave);
+	clk_disable_unprepare(eqos->clk_master);
+
+	return 0;
+}
+
 struct dwc_eth_dwmac_data {
 	void *(*probe)(struct platform_device *pdev,
 		       struct plat_stmmacenet_data *data,
@@ -160,6 +406,11 @@ static const struct dwc_eth_dwmac_data dwc_qos_data = {
 	.remove = dwc_qos_remove,
 };
 
+static const struct dwc_eth_dwmac_data tegra_eqos_data = {
+	.probe = tegra_eqos_probe,
+	.remove = tegra_eqos_remove,
+};
+
 static int dwc_eth_dwmac_probe(struct platform_device *pdev)
 {
 	const struct dwc_eth_dwmac_data *data;
@@ -245,6 +496,7 @@ static int dwc_eth_dwmac_remove(struct platform_device *pdev)
 
 static const struct of_device_id dwc_eth_dwmac_match[] = {
 	{ .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },
+	{ .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);
-- 
2.11.1

[toc] | [prev] | [next] | [standalone]


#1588709 — Re: [PATCH 7/7] net: stmmac: dwc-qos: Add Tegra186 support

FromMikko Perttunen <cyndis@kapsi.fi>
Date2017-02-27 16:10 +0100
SubjectRe: [PATCH 7/7] net: stmmac: dwc-qos: Add Tegra186 support
Message-ID<tfv61-7iD-1@gated-at.bofh.it>
In reply to#1587039
On 23.02.2017 19:24, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> The NVIDIA Tegra186 SoC contains an instance of the Synopsys DWC
> ethernet QOS IP core. The binding that it uses is slightly different
> from existing ones because of the integration (clocks, resets, ...).
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>  .../ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c    | 252 +++++++++++++++++++++
>  1 file changed, 252 insertions(+)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
> index 5071d3c15adc..54dfbdc48f6d 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
> @@ -14,6 +14,7 @@
>  #include <linux/clk.h>
>  #include <linux/clk-provider.h>
>  #include <linux/device.h>
> +#include <linux/gpio/consumer.h>
>  #include <linux/ethtool.h>
>  #include <linux/io.h>
>  #include <linux/ioport.h>
> @@ -22,10 +23,24 @@
>  #include <linux/of_net.h>
>  #include <linux/mfd/syscon.h>
>  #include <linux/platform_device.h>
> +#include <linux/reset.h>
>  #include <linux/stmmac.h>
>
>  #include "stmmac_platform.h"
>
> +struct tegra_eqos {
> +	struct device *dev;
> +	void __iomem *regs;
> +
> +	struct reset_control *rst;
> +	struct clk *clk_master;
> +	struct clk *clk_slave;
> +	struct clk *clk_tx;
> +	struct clk *clk_rx;
> +
> +	struct gpio_desc *reset;
> +};
> +
>  static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
>  				   struct plat_stmmacenet_data *plat_dat)
>  {
> @@ -148,6 +163,237 @@ static int dwc_qos_remove(struct platform_device *pdev)
>  	return 0;
>  }
>
> +#define SDMEMCOMPPADCTRL 0x8800
> +#define  SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31)
> +
> +#define AUTO_CAL_CONFIG 0x8804
> +#define  AUTO_CAL_CONFIG_START BIT(31)
> +#define  AUTO_CAL_CONFIG_ENABLE BIT(29)
> +
> +#define AUTO_CAL_STATUS 0x880c
> +#define  AUTO_CAL_STATUS_ACTIVE BIT(31)
> +
> +static void tegra_eqos_fix_speed(void *priv, unsigned int speed)
> +{
> +	struct tegra_eqos *eqos = priv;
> +	unsigned long rate = 125000000;
> +	bool needs_calibration = false;
> +	unsigned int i;
> +	u32 value;
> +
> +	switch (speed) {
> +	case SPEED_1000:
> +		needs_calibration = true;
> +		rate = 125000000;
> +		break;
> +
> +	case SPEED_100:
> +		needs_calibration = true;
> +		rate = 25000000;
> +		break;
> +
> +	case SPEED_10:
> +		rate = 2500000;
> +		break;
> +
> +	default:
> +		dev_err(eqos->dev, "invalid speed %u\n", speed);
> +		break;
> +	}
> +
> +	if (needs_calibration) {
> +		/* calibrate */
> +		value = readl(eqos->regs + SDMEMCOMPPADCTRL);
> +		value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
> +		writel(value, eqos->regs + SDMEMCOMPPADCTRL);
> +
> +		udelay(1);
> +
> +		value = readl(eqos->regs + AUTO_CAL_CONFIG);
> +		value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE;
> +		writel(value, eqos->regs + AUTO_CAL_CONFIG);
> +
> +		for (i = 0; i <= 10; i++) {
> +			value = readl(eqos->regs + AUTO_CAL_STATUS);
> +			if (value & AUTO_CAL_STATUS_ACTIVE)
> +				break;
> +
> +			udelay(1);
> +		}
> +
> +		if ((value & AUTO_CAL_STATUS_ACTIVE) == 0) {
> +			dev_err(eqos->dev, "calibration did not start\n");
> +			goto failed;
> +		}
> +
> +		for (i = 0; i <= 10; i++) {
> +			value = readl(eqos->regs + AUTO_CAL_STATUS);
> +			if ((value & AUTO_CAL_STATUS_ACTIVE) == 0)
> +				break;
> +
> +			udelay(20);
> +		}
> +
> +		if (value & AUTO_CAL_STATUS_ACTIVE) {
> +			dev_err(eqos->dev, "calibration didn't finish\n");
> +			goto failed;
> +		}

Could use readl_poll_timeout/readl_poll_timeout_atomic for these loops 
instead.

> +
> +	failed:
> +		value = readl(eqos->regs + SDMEMCOMPPADCTRL);
> +		value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
> +		writel(value, eqos->regs + SDMEMCOMPPADCTRL);
> +	} else {
> +		value = readl(eqos->regs + AUTO_CAL_CONFIG);
> +		value &= ~AUTO_CAL_CONFIG_ENABLE;
> +		writel(value, eqos->regs + AUTO_CAL_CONFIG);
> +	}
> +
> +	clk_set_rate(eqos->clk_tx, rate);

Could check error code here, and for other clock ops too.

> +}
> +
> +static int tegra_eqos_init(struct platform_device *pdev, void *priv)
> +{
> +	struct tegra_eqos *eqos = priv;
> +	unsigned long rate;
> +	u32 value;
> +
> +	rate = clk_get_rate(eqos->clk_slave);
> +
> +	value = readl(eqos->regs + 0xdc);

No point in reading the value when it is fully overwritten.

> +	value = (rate / 1000000) - 1;
> +	writel(value, eqos->regs + 0xdc);

Please add a define for 0xdc.

> +
> +	return 0;
> +}
> +
> +static void *tegra_eqos_probe(struct platform_device *pdev,
> +			      struct plat_stmmacenet_data *data,
> +			      struct stmmac_resources *res)
> +{
> +	struct tegra_eqos *eqos;
> +	int err;
> +
> +	eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL);
> +	if (!eqos) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	eqos->dev = &pdev->dev;
> +	eqos->regs = res->addr;
> +
> +	eqos->clk_master = devm_clk_get(&pdev->dev, "master_bus");
> +	if (IS_ERR(eqos->clk_master)) {
> +		err = PTR_ERR(eqos->clk_master);
> +		goto error;
> +	}
> +
> +	err = clk_prepare_enable(eqos->clk_master);
> +	if (err < 0)
> +		goto error;
> +
> +	eqos->clk_slave = devm_clk_get(&pdev->dev, "slave_bus");
> +	if (IS_ERR(eqos->clk_slave)) {
> +		err = PTR_ERR(eqos->clk_slave);
> +		goto disable_master;
> +	}
> +
> +	data->stmmac_clk = eqos->clk_slave;
> +
> +	err = clk_prepare_enable(eqos->clk_slave);
> +	if (err < 0)
> +		goto disable_master;
> +
> +	eqos->clk_rx = devm_clk_get(&pdev->dev, "rx");
> +	if (IS_ERR(eqos->clk_rx)) {
> +		err = PTR_ERR(eqos->clk_rx);
> +		goto disable_slave;
> +	}
> +
> +	err = clk_prepare_enable(eqos->clk_rx);
> +	if (err < 0)
> +		goto disable_slave;
> +
> +	eqos->clk_tx = devm_clk_get(&pdev->dev, "tx");
> +	if (IS_ERR(eqos->clk_tx)) {
> +		err = PTR_ERR(eqos->clk_tx);
> +		goto disable_rx;
> +	}
> +
> +	err = clk_prepare_enable(eqos->clk_tx);
> +	if (err < 0)
> +		goto disable_rx;
> +
> +	eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH);
> +	if (IS_ERR(eqos->reset)) {
> +		err = PTR_ERR(eqos->reset);
> +		goto disable_tx;
> +	}
> +
> +	usleep_range(2000, 4000);
> +	gpiod_set_value(eqos->reset, 0);
> +
> +	eqos->rst = devm_reset_control_get(&pdev->dev, "eqos");
> +	if (IS_ERR(eqos->rst)) {
> +		err = PTR_ERR(eqos->rst);
> +		goto reset_phy;
> +	}
> +
> +	err = reset_control_assert(eqos->rst);
> +	if (err < 0)
> +		goto reset_phy;
> +
> +	usleep_range(2000, 4000);
> +
> +	err = reset_control_deassert(eqos->rst);
> +	if (err < 0)
> +		goto reset_phy;
> +
> +	usleep_range(2000, 4000);
> +
> +	data->fix_mac_speed = tegra_eqos_fix_speed;
> +	data->init = tegra_eqos_init;
> +	data->bsp_priv = eqos;
> +
> +	err = tegra_eqos_init(pdev, eqos);
> +	if (err < 0)
> +		goto reset;
> +
> +out:
> +	return eqos;
> +
> +reset:
> +	reset_control_assert(eqos->rst);
> +reset_phy:
> +	gpiod_set_value(eqos->reset, 1);
> +disable_tx:
> +	clk_disable_unprepare(eqos->clk_tx);
> +disable_rx:
> +	clk_disable_unprepare(eqos->clk_rx);
> +disable_slave:
> +	clk_disable_unprepare(eqos->clk_slave);
> +disable_master:
> +	clk_disable_unprepare(eqos->clk_master);
> +error:
> +	eqos = ERR_PTR(err);
> +	goto out;
> +}
> +
> +static int tegra_eqos_remove(struct platform_device *pdev)
> +{
> +	struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev);
> +
> +	reset_control_assert(eqos->rst);
> +	gpiod_set_value(eqos->reset, 1);
> +	clk_disable_unprepare(eqos->clk_tx);
> +	clk_disable_unprepare(eqos->clk_rx);
> +	clk_disable_unprepare(eqos->clk_slave);
> +	clk_disable_unprepare(eqos->clk_master);
> +
> +	return 0;
> +}
> +
>  struct dwc_eth_dwmac_data {
>  	void *(*probe)(struct platform_device *pdev,
>  		       struct plat_stmmacenet_data *data,
> @@ -160,6 +406,11 @@ static const struct dwc_eth_dwmac_data dwc_qos_data = {
>  	.remove = dwc_qos_remove,
>  };
>
> +static const struct dwc_eth_dwmac_data tegra_eqos_data = {
> +	.probe = tegra_eqos_probe,
> +	.remove = tegra_eqos_remove,
> +};
> +
>  static int dwc_eth_dwmac_probe(struct platform_device *pdev)
>  {
>  	const struct dwc_eth_dwmac_data *data;
> @@ -245,6 +496,7 @@ static int dwc_eth_dwmac_remove(struct platform_device *pdev)
>
>  static const struct of_device_id dwc_eth_dwmac_match[] = {
>  	{ .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },
> +	{ .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data},

Missing space before '}'.

>  	{ }
>  };
>  MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);
>

[toc] | [prev] | [next] | [standalone]


#1587042 — [PATCH 4/7] net: stmmac: Parse FIFO sizes from feature registers

FromThierry Reding <thierry.reding@gmail.com>
Date2017-02-23 18:30 +0100
Subject[PATCH 4/7] net: stmmac: Parse FIFO sizes from feature registers
Message-ID<te5nk-4nQ-33@gated-at.bofh.it>
In reply to#1587038
From: Thierry Reding <treding@nvidia.com>

New version of this core encode the FIFO sizes in one of the feature
registers. Use these sizes as default, but still allow device tree to
override them for backwards compatibility.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h      | 3 +++
 drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c  | 2 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +++
 3 files changed, 8 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 144fe84e8a53..6ac653845d82 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -324,6 +324,9 @@ struct dma_features {
 	unsigned int number_tx_queues;
 	/* Alternate (enhanced) DESC mode */
 	unsigned int enh_desc;
+	/* TX and RX FIFO sizes */
+	unsigned int tx_fifo_size;
+	unsigned int rx_fifo_size;
 };
 
 /* GMAC TX FIFO is 8K, Rx FIFO is 16K */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 377d1b44d4f2..8d249f3b34c8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -296,6 +296,8 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
 	hw_cap = readl(ioaddr + GMAC_HW_FEATURE1);
 	dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20;
 	dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18;
+	dma_cap->tx_fifo_size = 128 << ((hw_cap >> 6) & 0x1f);
+	dma_cap->rx_fifo_size = 128 << ((hw_cap >> 0) & 0x1f);
 	/* MAC HW feature2 */
 	hw_cap = readl(ioaddr + GMAC_HW_FEATURE2);
 	/* TX and RX number of channels */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d7387919bdb6..291e34f0ca94 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1281,6 +1281,9 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 {
 	int rxfifosz = priv->plat->rx_fifo_size;
 
+	if (rxfifosz == 0)
+		rxfifosz = priv->dma_cap.rx_fifo_size;
+
 	if (priv->plat->force_thresh_dma_mode)
 		priv->hw->dma->dma_mode(priv->ioaddr, tc, tc, rxfifosz);
 	else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
-- 
2.11.1

[toc] | [prev] | [next] | [standalone]


#1588567 — Re: [PATCH 4/7] net: stmmac: Parse FIFO sizes from feature registers

FromMikko Perttunen <cyndis@kapsi.fi>
Date2017-02-27 11:00 +0100
SubjectRe: [PATCH 4/7] net: stmmac: Parse FIFO sizes from feature registers
Message-ID<tfqg1-3L5-9@gated-at.bofh.it>
In reply to#1587042
On 23.02.2017 19:24, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> New version of this core encode the FIFO sizes in one of the feature
> registers. Use these sizes as default, but still allow device tree to
> override them for backwards compatibility.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/common.h      | 3 +++
>  drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c  | 2 ++
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +++
>  3 files changed, 8 insertions(+)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
> index 144fe84e8a53..6ac653845d82 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/common.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/common.h
> @@ -324,6 +324,9 @@ struct dma_features {
>  	unsigned int number_tx_queues;
>  	/* Alternate (enhanced) DESC mode */
>  	unsigned int enh_desc;
> +	/* TX and RX FIFO sizes */
> +	unsigned int tx_fifo_size;
> +	unsigned int rx_fifo_size;
>  };
>
>  /* GMAC TX FIFO is 8K, Rx FIFO is 16K */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> index 377d1b44d4f2..8d249f3b34c8 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> @@ -296,6 +296,8 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
>  	hw_cap = readl(ioaddr + GMAC_HW_FEATURE1);
>  	dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20;
>  	dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18;
> +	dma_cap->tx_fifo_size = 128 << ((hw_cap >> 6) & 0x1f);
> +	dma_cap->rx_fifo_size = 128 << ((hw_cap >> 0) & 0x1f);
>  	/* MAC HW feature2 */
>  	hw_cap = readl(ioaddr + GMAC_HW_FEATURE2);
>  	/* TX and RX number of channels */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index d7387919bdb6..291e34f0ca94 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -1281,6 +1281,9 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
>  {
>  	int rxfifosz = priv->plat->rx_fifo_size;
>
> +	if (rxfifosz == 0)
> +		rxfifosz = priv->dma_cap.rx_fifo_size;
> +
>  	if (priv->plat->force_thresh_dma_mode)
>  		priv->hw->dma->dma_mode(priv->ioaddr, tc, tc, rxfifosz);
>  	else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
>

Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>

[toc] | [prev] | [next] | [standalone]


#1587067

FromDavid Miller <davem@davemloft.net>
Date2017-02-23 19:30 +0100
Message-ID<te6jn-4Yu-1@gated-at.bofh.it>
In reply to#1587038
The net-next tree is closed, therefore it is not appropriate to submit
feature patches or cleanups at this time.

Please wait for the merge window to be finished and the net-next tree
to open back up before resubmitting this patch series.

Thanks.

[toc] | [prev] | [next] | [standalone]


#1588531

FromThierry Reding <thierry.reding@gmail.com>
Date2017-02-27 08:40 +0100
Message-ID<tfo4x-2jd-7@gated-at.bofh.it>
In reply to#1587067

[Multipart message — attachments visible in raw view] — view raw

On Thu, Feb 23, 2017 at 12:57:05PM -0500, David Miller wrote:
> 
> The net-next tree is closed, therefore it is not appropriate to submit
> feature patches or cleanups at this time.
> 
> Please wait for the merge window to be finished and the net-next tree
> to open back up before resubmitting this patch series.

Okay, I'll resend this after the merge window. In the meantime, surely
it's okay for others to review patches?

Thierry

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web