Merge branch 'stmmac-tegra186'
authorDavid S. Miller <davem@davemloft.net>
Mon, 13 Mar 2017 06:35:21 +0000 (23:35 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 13 Mar 2017 06:35:21 +0000 (23:35 -0700)
Thierry Reding says:

====================
net: stmmac: Fixes and Tegra186 support

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-20170310.

Changes in v2:
- address review comments by Mikko and Joao
- add two additional cleanup patches
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/devicetree/bindings/net/stmmac.txt
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c

index d3bfc2b30fb5ecc07493b4c5510d5cdc32b3ff3a..11b27dfd1627f8361f497f4c80871c2b7c525ae3 100644 (file)
@@ -28,9 +28,9 @@ Optional properties:
   clocks may be specified in derived bindings.
 - clock-names: One name for each entry in the clocks property, the
   first one should be "stmmaceth" and the second one should be "pclk".
-- clk_ptp_ref: this is the PTP reference clock; in case of the PTP is
-  available this clock is used for programming the Timestamp Addend Register.
-  If not passed then the system clock will be used and this is fine on some
+- ptp_ref: this is the PTP reference clock; in case of the PTP is available
+  this clock is used for programming the Timestamp Addend Register. If not
+  passed then the system clock will be used and this is fine on some
   platforms.
 - tx-fifo-depth: See ethernet.txt file in the same directory
 - rx-fifo-depth: See ethernet.txt file in the same directory
index 04d9245b7149ce663b0827a158901a10b58ea701..3ca36744007beb059152915d939d52d7c3c338e4 100644 (file)
@@ -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 */
index 1a3fa3d9f85549c9b5cc10064c6aaac799184adc..dd6a2f9791cc11a390d71bcb5a1b071cd1bca068 100644 (file)
 #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/iopoll.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #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"
+#include "dwmac4.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)
@@ -106,13 +124,309 @@ static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
        return 0;
 }
 
+static void *dwc_qos_probe(struct platform_device *pdev,
+                          struct plat_stmmacenet_data *plat_dat,
+                          struct stmmac_resources *stmmac_res)
+{
+       int err;
+
+       plat_dat->stmmac_clk = devm_clk_get(&pdev->dev, "apb_pclk");
+       if (IS_ERR(plat_dat->stmmac_clk)) {
+               dev_err(&pdev->dev, "apb_pclk clock not found.\n");
+               return ERR_CAST(plat_dat->stmmac_clk);
+       }
+
+       err = clk_prepare_enable(plat_dat->stmmac_clk);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to enable apb_pclk clock: %d\n",
+                       err);
+               return ERR_PTR(err);
+       }
+
+       plat_dat->pclk = devm_clk_get(&pdev->dev, "phy_ref_clk");
+       if (IS_ERR(plat_dat->pclk)) {
+               dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
+               err = PTR_ERR(plat_dat->pclk);
+               goto disable;
+       }
+
+       err = clk_prepare_enable(plat_dat->pclk);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n",
+                       err);
+               goto disable;
+       }
+
+       return NULL;
+
+disable:
+       clk_disable_unprepare(plat_dat->stmmac_clk);
+       return ERR_PTR(err);
+}
+
+static int dwc_qos_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct stmmac_priv *priv = netdev_priv(ndev);
+
+       clk_disable_unprepare(priv->plat->pclk);
+       clk_disable_unprepare(priv->plat->stmmac_clk);
+
+       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;
+       u32 value;
+       int err;
+
+       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);
+
+               err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
+                                               value,
+                                               value & AUTO_CAL_STATUS_ACTIVE,
+                                               1, 10);
+               if (err < 0) {
+                       dev_err(eqos->dev, "calibration did not start\n");
+                       goto failed;
+               }
+
+               err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
+                                               value,
+                                               (value & AUTO_CAL_STATUS_ACTIVE) == 0,
+                                               20, 200);
+               if (err < 0) {
+                       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);
+       }
+
+       err = clk_set_rate(eqos->clk_tx, rate);
+       if (err < 0)
+               dev_err(eqos->dev, "failed to set TX rate: %d\n", err);
+}
+
+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 = (rate / 1000000) - 1;
+       writel(value, eqos->regs + GMAC_1US_TIC_COUNTER);
+
+       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,
+                      struct stmmac_resources *res);
+       int (*remove)(struct platform_device *pdev);
+};
+
+static const struct dwc_eth_dwmac_data dwc_qos_data = {
+       .probe = dwc_qos_probe,
+       .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;
        struct plat_stmmacenet_data *plat_dat;
        struct stmmac_resources stmmac_res;
        struct resource *res;
+       void *priv;
        int ret;
 
+       data = of_device_get_match_data(&pdev->dev);
+
        memset(&stmmac_res, 0, sizeof(struct stmmac_resources));
 
        /**
@@ -138,39 +452,26 @@ static int dwc_eth_dwmac_probe(struct platform_device *pdev)
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
-       plat_dat->stmmac_clk = devm_clk_get(&pdev->dev, "apb_pclk");
-       if (IS_ERR(plat_dat->stmmac_clk)) {
-               dev_err(&pdev->dev, "apb_pclk clock not found.\n");
-               ret = PTR_ERR(plat_dat->stmmac_clk);
-               plat_dat->stmmac_clk = NULL;
-               goto err_remove_config_dt;
-       }
-       clk_prepare_enable(plat_dat->stmmac_clk);
-
-       plat_dat->pclk = devm_clk_get(&pdev->dev, "phy_ref_clk");
-       if (IS_ERR(plat_dat->pclk)) {
-               dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
-               ret = PTR_ERR(plat_dat->pclk);
-               plat_dat->pclk = NULL;
-               goto err_out_clk_dis_phy;
+       priv = data->probe(pdev, plat_dat, &stmmac_res);
+       if (IS_ERR(priv)) {
+               ret = PTR_ERR(priv);
+               dev_err(&pdev->dev, "failed to probe subdriver: %d\n", ret);
+               goto remove_config;
        }
-       clk_prepare_enable(plat_dat->pclk);
 
        ret = dwc_eth_dwmac_config_dt(pdev, plat_dat);
        if (ret)
-               goto err_out_clk_dis_aper;
+               goto remove;
 
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
        if (ret)
-               goto err_out_clk_dis_aper;
+               goto remove;
 
-       return 0;
+       return ret;
 
-err_out_clk_dis_aper:
-       clk_disable_unprepare(plat_dat->pclk);
-err_out_clk_dis_phy:
-       clk_disable_unprepare(plat_dat->stmmac_clk);
-err_remove_config_dt:
+remove:
+       data->remove(pdev);
+remove_config:
        stmmac_remove_config_dt(pdev, plat_dat);
 
        return ret;
@@ -178,11 +479,29 @@ err_remove_config_dt:
 
 static int dwc_eth_dwmac_remove(struct platform_device *pdev)
 {
-       return stmmac_pltfr_remove(pdev);
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       const struct dwc_eth_dwmac_data *data;
+       int err;
+
+       data = of_device_get_match_data(&pdev->dev);
+
+       err = stmmac_dvr_remove(&pdev->dev);
+       if (err < 0)
+               dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
+
+       err = data->remove(pdev);
+       if (err < 0)
+               dev_err(&pdev->dev, "failed to remove subdriver: %d\n", err);
+
+       stmmac_remove_config_dt(pdev, priv->plat);
+
+       return err;
 }
 
 static const struct of_device_id dwc_eth_dwmac_match[] = {
-       { .compatible = "snps,dwc-qos-ethernet-4.10", },
+       { .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);
index db45134fddf04e50c703254b8570b744004123f8..018fc2d447c4d704c7f949498f9a81e0fece0737 100644 (file)
@@ -25,6 +25,7 @@
 #define GMAC_RXQ_CTRL0                 0x000000a0
 #define GMAC_INT_STATUS                        0x000000b0
 #define GMAC_INT_EN                    0x000000b4
+#define GMAC_1US_TIC_COUNTER           0x000000dc
 #define GMAC_PCS_BASE                  0x000000e0
 #define GMAC_PHYIF_CONTROL_STATUS      0x000000f8
 #define GMAC_PMT                       0x000000c0
@@ -148,6 +149,8 @@ enum power_event {
 /* MAC HW features1 bitmap */
 #define GMAC_HW_FEAT_AVSEL             BIT(20)
 #define GMAC_HW_TSOEN                  BIT(18)
+#define GMAC_HW_TXFIFOSIZE             GENMASK(10, 6)
+#define GMAC_HW_RXFIFOSIZE             GENMASK(4, 0)
 
 /* MAC HW features2 bitmap */
 #define GMAC_HW_FEAT_TXCHCNT           GENMASK(21, 18)
@@ -180,6 +183,7 @@ enum power_event {
 #define MTL_OP_MODE_TSF                        BIT(1)
 
 #define MTL_OP_MODE_TQS_MASK           GENMASK(24, 16)
+#define MTL_OP_MODE_TQS_SHIFT          16
 
 #define MTL_OP_MODE_TTC_MASK           0x70
 #define MTL_OP_MODE_TTC_SHIFT          4
@@ -193,6 +197,17 @@ enum power_event {
 #define MTL_OP_MODE_TTC_384            (6 << MTL_OP_MODE_TTC_SHIFT)
 #define MTL_OP_MODE_TTC_512            (7 << MTL_OP_MODE_TTC_SHIFT)
 
+#define MTL_OP_MODE_RQS_MASK           GENMASK(29, 20)
+#define MTL_OP_MODE_RQS_SHIFT          20
+
+#define MTL_OP_MODE_RFD_MASK           GENMASK(19, 14)
+#define MTL_OP_MODE_RFD_SHIFT          14
+
+#define MTL_OP_MODE_RFA_MASK           GENMASK(13, 8)
+#define MTL_OP_MODE_RFA_SHIFT          8
+
+#define MTL_OP_MODE_EHFC               BIT(7)
+
 #define MTL_OP_MODE_RTC_MASK           0x18
 #define MTL_OP_MODE_RTC_SHIFT          3
 
index f97b0d5d998742efcad71972bd74ce40cc02afad..6ac6b2600a7cee93229e7ba128b8c6b04c3e955f 100644 (file)
@@ -183,8 +183,9 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
 }
 
 static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
-                                   int rxmode, u32 channel)
+                                   int rxmode, u32 channel, int rxfifosz)
 {
+       unsigned int rqs = rxfifosz / 256 - 1;
        u32 mtl_tx_op, mtl_rx_op, mtl_rx_int;
 
        /* Following code only done for channel 0, other channels not yet
@@ -250,6 +251,53 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
                        mtl_rx_op |= MTL_OP_MODE_RTC_128;
        }
 
+       mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
+       mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
+
+       /* enable flow control only if each channel gets 4 KiB or more FIFO */
+       if (rxfifosz >= 4096) {
+               unsigned int rfd, rfa;
+
+               mtl_rx_op |= MTL_OP_MODE_EHFC;
+
+               /* Set Threshold for Activating Flow Control to min 2 frames,
+                * i.e. 1500 * 2 = 3000 bytes.
+                *
+                * Set Threshold for Deactivating Flow Control to min 1 frame,
+                * i.e. 1500 bytes.
+                */
+               switch (rxfifosz) {
+               case 4096:
+                       /* This violates the above formula because of FIFO size
+                        * limit therefore overflow may occur in spite of this.
+                        */
+                       rfd = 0x03; /* Full-2.5K */
+                       rfa = 0x01; /* Full-1.5K */
+                       break;
+
+               case 8192:
+                       rfd = 0x06; /* Full-4K */
+                       rfa = 0x0a; /* Full-6K */
+                       break;
+
+               case 16384:
+                       rfd = 0x06; /* Full-4K */
+                       rfa = 0x12; /* Full-10K */
+                       break;
+
+               default:
+                       rfd = 0x06; /* Full-4K */
+                       rfa = 0x1e; /* Full-16K */
+                       break;
+               }
+
+               mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK;
+               mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT;
+
+               mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK;
+               mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT;
+       }
+
        writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel));
 
        /* Enable MTL RX overflow */
@@ -262,7 +310,7 @@ static void dwmac4_dma_operation_mode(void __iomem *ioaddr, int txmode,
                                      int rxmode, int rxfifosz)
 {
        /* Only Channel 0 is actually configured and used */
-       dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0);
+       dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0, rxfifosz);
 }
 
 static void dwmac4_get_hw_feature(void __iomem *ioaddr,
@@ -294,6 +342,11 @@ 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;
+       /* RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by
+        * shifting and store the sizes in bytes.
+        */
+       dma_cap->tx_fifo_size = 128 << ((hw_cap & GMAC_HW_TXFIFOSIZE) >> 6);
+       dma_cap->rx_fifo_size = 128 << ((hw_cap & GMAC_HW_RXFIFOSIZE) >> 0);
        /* MAC HW feature2 */
        hw_cap = readl(ioaddr + GMAC_HW_FEATURE2);
        /* TX and RX number of channels */
index 4498a3861aa3ad09460e922bd7f38e3506889dcb..78f6ec2d165b7b225422e36cf45c981ddcac551e 100644 (file)
@@ -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) {
@@ -1711,6 +1714,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
        stmmac_mmc_setup(priv);
 
        if (init_ptp) {
+               ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
+               if (ret < 0)
+                       netdev_warn(priv->dev, "failed to enable PTP reference clock: %d\n", ret);
+
                ret = stmmac_init_ptp(priv);
                if (ret == -EOPNOTSUPP)
                        netdev_warn(priv->dev, "PTP not supported by HW\n");
@@ -1754,6 +1761,13 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
        return 0;
 }
 
+static void stmmac_hw_teardown(struct net_device *dev)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+
+       clk_disable_unprepare(priv->plat->clk_ptp_ref);
+}
+
 /**
  *  stmmac_open - open entry point of the driver
  *  @dev : pointer to the device structure.
@@ -1821,7 +1835,7 @@ static int stmmac_open(struct net_device *dev)
                netdev_err(priv->dev,
                           "%s: ERROR: allocating the IRQ %d (error: %d)\n",
                           __func__, dev->irq, ret);
-               goto init_error;
+               goto irq_error;
        }
 
        /* Request the Wake IRQ in case of another line is used for WoL */
@@ -1858,7 +1872,12 @@ lpiirq_error:
                free_irq(priv->wol_irq, dev);
 wolirq_error:
        free_irq(dev->irq, dev);
+irq_error:
+       if (dev->phydev)
+               phy_stop(dev->phydev);
 
+       del_timer_sync(&priv->txtimer);
+       stmmac_hw_teardown(dev);
 init_error:
        free_dma_desc_resources(priv);
 dma_desc_error:
@@ -2063,6 +2082,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
                des = skb_frag_dma_map(priv->device, frag, 0,
                                       skb_frag_size(frag),
                                       DMA_TO_DEVICE);
+               if (dma_mapping_error(priv->device, des))
+                       goto dma_map_err;
 
                stmmac_tso_allocator(priv, des, skb_frag_size(frag),
                                     (i == nfrags - 1));
index 0ba1caf186190fe9618d453798a82bc78c2eae33..fe49c3105755b1b90b7e18b853eeec1bdedbf1f9 100644 (file)
@@ -359,13 +359,12 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
        clk_prepare_enable(plat->pclk);
 
        /* Fall-back to main clock in case of no PTP ref is passed */
-       plat->clk_ptp_ref = devm_clk_get(&pdev->dev, "clk_ptp_ref");
+       plat->clk_ptp_ref = devm_clk_get(&pdev->dev, "ptp_ref");
        if (IS_ERR(plat->clk_ptp_ref)) {
                plat->clk_ptp_rate = clk_get_rate(plat->stmmac_clk);
                plat->clk_ptp_ref = NULL;
                dev_warn(&pdev->dev, "PTP uses main clock\n");
        } else {
-               clk_prepare_enable(plat->clk_ptp_ref);
                plat->clk_ptp_rate = clk_get_rate(plat->clk_ptp_ref);
                dev_dbg(&pdev->dev, "PTP rate %d\n", plat->clk_ptp_rate);
        }