RE: [PATCH net-next v2 0/2] Enable 2.5Gbps speed for stmmac

2021-04-06 Thread Voon, Weifeng
> > The limitation is not on the MAC, PCS or the PHY. For Intel mgbe, the
> > overclocking of 2.5 times clock rate to support 2.5G is only able to
> > be configured in the BIOS during boot time. Kernel driver has no
> > access to modify the clock rate for 1Gbps/2.5G mode. The way to
> > determined the current 1G/2.5G mode is by reading a dedicated adhoc
> register through mdio bus.
> > In short, after the system boot up, it is either in 1G mode or 2.5G
> > mode which not able to be changed on the fly.
> 
> Right. It would of been a lot easier if this was in the commit message
> from the beginning. Please ensure the next version does say this.
> 
> > Since the stmmac MAC can pair with any PCS and PHY, I still prefer
> > that we tie this platform specific limitation with the of MAC. As
> > stmmac does handle platform specific config/limitation.
> 
> So yes, this needs to be somewhere in the intel specific stmmac code,
> with a nice comment explaining what is going on.
> 
> What PHY are you using? The Aquantia/Marvell multi-gige phy can do rate
> adaptation. So you could fix the MAC-PHY link to 2500BaseX, and let the
> PHY internally handle the different line speeds.
> 
Intel mgbe is flexible to pair with any PHY. Only Aquantia/Marvell
multi-gige PHY can do rate adaption right? Hence, we still need to take 
care of others PHYs.

Thanks for all the comments, will include them in v3. 

Weifeng


RE: [PATCH net-next v2 0/2] Enable 2.5Gbps speed for stmmac

2021-04-06 Thread Voon, Weifeng
> > > You have a MAC and an PCS in the stmmac IP block. That then has some
> > > sort of SERDES interface, running 1000BaseX, SGMII, SGMII
> > > overclocked at 2.5G or 25000BaseX. Connected to the SERDES you have
> > > a PHY which converts to copper, giving you 2500BaseT.
> > >
> > > You said earlier, that the PHY can only do 2500BaseT. So it should
> > > be the PHY driver which sets supported to 2500BaseT and no other
> > > speeds.
> > >
> > > You should think about when somebody uses this MAC with a different
> > > PHY, one that can do the full range of 10/half through to 2.5G full.
> > > What generally happens is that the PHY performs auto-neg to
> > > determine the link speed. For 10M-1G speeds the PHY will configure
> > > its SERDES interface to SGMII and phylink will ask the PCS to also
> > > be configured to SGMII. If the PHY negotiates 2500BaseT, it will
> > > configure its side of the SERDES to 2500BaseX or SGMII overclocked
> > > at 2.5G. Again, phylink will ask the PCS to match what the PHY is
> > > doing.
> > >
> > > So, where exactly is the limitation in your hardware? PCS or PHY?
> > The limitation in the hardware is at the PCS side where it is either
> > running in SGMII 2.5G or SGMII 1G speeds.
> > When running on SGMII 2.5G speeds, we disable the in-band AN and use
> > 2.5G speed only
> 
> So there is no actual limitation! The MAC should indicate it can do 10Half
> through to 2500BaseT. And you need to listen to PHYLINK and swap the PCS
> between SGMII to overclocked SGMII when it requests.
> 
> PHYLINK will call stmmac_mac_config() and use state->interface to decide
> how to configure the PCS to match what the PHY is doing.
> 
>  Andrew

The limitation is not on the MAC, PCS or the PHY. For Intel mgbe, the
overclocking of 2.5 times clock rate to support 2.5G is only able to be
configured in the BIOS during boot time. Kernel driver has no access to 
modify the clock rate for 1Gbps/2.5G mode. The way to determined the 
current 1G/2.5G mode is by reading a dedicated adhoc register through mdio bus.
In short, after the system boot up, it is either in 1G mode or 2.5G mode 
which not able to be changed on the fly. 

Since the stmmac MAC can pair with any PCS and PHY, I still prefer that we tie
this platform specific limitation with the of MAC. As stmmac does handle 
platform
specific config/limitation. 

What is your thoughts? 

Weifeng


[PATCH v2 net-next] stmmac: intel: Enable SERDES PHY rx clk for PSE

2021-04-05 Thread Voon Weifeng
EHL PSE SGMII mode requires to ungate the SERDES PHY rx clk for power up
sequence and vice versa.

Signed-off-by: Voon Weifeng 
---
Changes:
 v1 -> v2
 -change subject from "net: intel" to "stmmac: intel"
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c | 10 ++
 drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index add95e20548d..a4fec5fe0779 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -153,6 +153,11 @@ static int intel_serdes_powerup(struct net_device *ndev, 
void *priv_data)
return data;
}
 
+   /* PSE only - ungate SGMII PHY Rx Clock */
+   if (intel_priv->is_pse)
+   mdiobus_modify(priv->mii, serdes_phy_addr, SERDES_GCR0,
+  0, SERDES_PHY_RX_CLK);
+
return 0;
 }
 
@@ -168,6 +173,11 @@ static void intel_serdes_powerdown(struct net_device 
*ndev, void *intel_data)
 
serdes_phy_addr = intel_priv->mdio_adhoc_addr;
 
+   /* PSE only - gate SGMII PHY Rx Clock */
+   if (intel_priv->is_pse)
+   mdiobus_modify(priv->mii, serdes_phy_addr, SERDES_GCR0,
+  SERDES_PHY_RX_CLK, 0);
+
/*  move power state to P3 */
data = mdiobus_read(priv->mii, serdes_phy_addr, SERDES_GCR0);
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
index e723096c0b15..542acb8ce467 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
@@ -14,6 +14,7 @@
 
 /* SERDES defines */
 #define SERDES_PLL_CLK BIT(0)  /* PLL clk valid signal */
+#define SERDES_PHY_RX_CLK  BIT(1)  /* PSE SGMII PHY rx clk */
 #define SERDES_RST BIT(2)  /* Serdes Reset */
 #define SERDES_PWR_ST_MASK GENMASK(6, 4)   /* Serdes Power state*/
 #define SERDES_PWR_ST_SHIFT4
-- 
2.17.1



[PATCH net-next] net: intel: Enable SERDES PHY rx clk for PSE

2021-04-05 Thread Voon Weifeng
EHL PSE SGMII mode requires to ungate the SERDES PHY rx clk for power up
sequence and vice versa.

Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c | 10 ++
 drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index add95e20548d..a4fec5fe0779 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -153,6 +153,11 @@ static int intel_serdes_powerup(struct net_device *ndev, 
void *priv_data)
return data;
}
 
+   /* PSE only - ungate SGMII PHY Rx Clock */
+   if (intel_priv->is_pse)
+   mdiobus_modify(priv->mii, serdes_phy_addr, SERDES_GCR0,
+  0, SERDES_PHY_RX_CLK);
+
return 0;
 }
 
@@ -168,6 +173,11 @@ static void intel_serdes_powerdown(struct net_device 
*ndev, void *intel_data)
 
serdes_phy_addr = intel_priv->mdio_adhoc_addr;
 
+   /* PSE only - gate SGMII PHY Rx Clock */
+   if (intel_priv->is_pse)
+   mdiobus_modify(priv->mii, serdes_phy_addr, SERDES_GCR0,
+  SERDES_PHY_RX_CLK, 0);
+
/*  move power state to P3 */
data = mdiobus_read(priv->mii, serdes_phy_addr, SERDES_GCR0);
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
index e723096c0b15..542acb8ce467 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
@@ -14,6 +14,7 @@
 
 /* SERDES defines */
 #define SERDES_PLL_CLK BIT(0)  /* PLL clk valid signal */
+#define SERDES_PHY_RX_CLK  BIT(1)  /* PSE SGMII PHY rx clk */
 #define SERDES_RST BIT(2)  /* Serdes Reset */
 #define SERDES_PWR_ST_MASK GENMASK(6, 4)   /* Serdes Power state*/
 #define SERDES_PWR_ST_SHIFT4
-- 
2.17.1



RE: [PATCH net-next 1/2] net: stmmac: enable 2.5Gbps link speed

2021-04-05 Thread Voon, Weifeng
> On Fri, Apr 02, 2021 at 07:45:04AM +0000, Voon, Weifeng wrote:
> > > > +   /* 2.5G mode only support 2500baseT full duplex only */
> > > > +   if (priv->plat->has_gmac4 && priv->plat->speed_2500_en) {
> > > > +   phylink_set(mac_supported, 2500baseT_Full);
> > > > +   phylink_set(mask, 10baseT_Half);
> > > > +   phylink_set(mask, 10baseT_Full);
> > > > +   phylink_set(mask, 100baseT_Half);
> > > > +   phylink_set(mask, 100baseT_Full);
> > > > +   phylink_set(mask, 1000baseT_Half);
> > > > +   phylink_set(mask, 1000baseT_Full);
> > > > +   phylink_set(mask, 1000baseKX_Full);
> > >
> > > Why? This seems at odds to the comment above?
> >
> > > What about 2500baseX_Full ?
> >
> > The comments explain that the PCS<->PHY link is in 2500BASE-X and why
> > 10/100/1000 link speed is mutually exclusive with 2500.
> > But the connected external PHY are twisted pair cable which only
> > supports 2500baseT_full.
> 
> The PHY should indicate what modes its supports. The PHY drivers
> get_features() call should set supported to only 2500baseT_Full, if that is
> all it supports.
> 
> What modes are actually used should then be the intersect of what both the
> MAC and the PHY indicate they can do.

Noted Andrew. Instead of masking the 10/100/1000 mode support in the MAC, we 
will
set the supported modes in the PCS.


RE: [PATCH net-next 1/2] net: stmmac: enable 2.5Gbps link speed

2021-04-02 Thread Voon, Weifeng
> > +   /* 2.5G mode only support 2500baseT full duplex only */
> > +   if (priv->plat->has_gmac4 && priv->plat->speed_2500_en) {
> > +   phylink_set(mac_supported, 2500baseT_Full);
> > +   phylink_set(mask, 10baseT_Half);
> > +   phylink_set(mask, 10baseT_Full);
> > +   phylink_set(mask, 100baseT_Half);
> > +   phylink_set(mask, 100baseT_Full);
> > +   phylink_set(mask, 1000baseT_Half);
> > +   phylink_set(mask, 1000baseT_Full);
> > +   phylink_set(mask, 1000baseKX_Full);
> 
> Why? This seems at odds to the comment above?

> What about 2500baseX_Full ?

The comments explain that the PCS<->PHY link is in 2500BASE-X
and why 10/100/1000 link speed is mutually exclusive with 2500.
But the connected external PHY are twisted pair cable which only
supports 2500baseT_full.

Weifeng


[PATCH v2 net-next 3/5] net: stmmac: introduce MSI Interrupt routines for mac, safety, RX & TX

2021-03-25 Thread Voon Weifeng
From: Ong Boon Leong 

Now we introduce MSI interrupt service routines and hook these routines
up if stmmac_open() sees valid irq line being requested:-

stmmac_mac_interrupt():- MAC (dev->irq), WOL (wol_irq), LPI (lpi_irq)
stmmac_safety_interrupt() :- Safety Feat Correctible Error (sfty_ce_irq)
 & Uncorrectible Error (sfty_ue_irq)
stmmac_msi_intr_rx()  :- For all RX MSI irq (rx_irq)
stmmac_msi_intr_tx()  :- For all TX MSI irq (tx_irq)

Each of IRQs will have its unique name so that we can differentiate
them easily under /proc/interrupts.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
Changes:
v1 -> v2
 - Refactor out a huge if statement into separate subfunctions.
 - Removed the netdev_info for every successful request of IRQs.
 - Return 0 for each successful request of IRQs.
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  15 +
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  16 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 437 --
 include/linux/stmmac.h|   8 +
 4 files changed, 431 insertions(+), 45 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 5afb36a5c94c..c54a56b732b3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -259,6 +259,9 @@ struct stmmac_safety_stats {
 #define DMA_HW_FEAT_ACTPHYIF   0x7000  /* Active/selected PHY iface */
 #define DEFAULT_DMA_PBL8
 
+/* MSI defines */
+#define STMMAC_MSI_VEC_MAX 32
+
 /* PCS status and mask defines */
 #definePCS_ANE_IRQ BIT(2)  /* PCS Auto-Negotiation */
 #definePCS_LINK_IRQBIT(1)  /* PCS Link */
@@ -315,6 +318,18 @@ enum dma_irq_dir {
DMA_DIR_RXTX = 0x3,
 };
 
+enum request_irq_err {
+   REQ_IRQ_ERR_ALL,
+   REQ_IRQ_ERR_TX,
+   REQ_IRQ_ERR_RX,
+   REQ_IRQ_ERR_SFTY_UE,
+   REQ_IRQ_ERR_SFTY_CE,
+   REQ_IRQ_ERR_LPI,
+   REQ_IRQ_ERR_WOL,
+   REQ_IRQ_ERR_MAC,
+   REQ_IRQ_ERR_NO,
+};
+
 /* EEE and LPI defines */
 #defineCORE_IRQ_TX_PATH_IN_LPI_MODE(1 << 0)
 #defineCORE_IRQ_TX_PATH_EXIT_LPI_MODE  (1 << 1)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 4faad331a4ca..9966f6f10905 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -30,6 +30,10 @@ struct stmmac_resources {
int wol_irq;
int lpi_irq;
int irq;
+   int sfty_ce_irq;
+   int sfty_ue_irq;
+   int rx_irq[MTL_MAX_RX_QUEUES];
+   int tx_irq[MTL_MAX_TX_QUEUES];
 };
 
 struct stmmac_tx_info {
@@ -225,6 +229,18 @@ struct stmmac_priv {
void __iomem *mmcaddr;
void __iomem *ptpaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+   int sfty_ce_irq;
+   int sfty_ue_irq;
+   int rx_irq[MTL_MAX_RX_QUEUES];
+   int tx_irq[MTL_MAX_TX_QUEUES];
+   /*irq name */
+   char int_name_mac[IFNAMSIZ + 9];
+   char int_name_wol[IFNAMSIZ + 9];
+   char int_name_lpi[IFNAMSIZ + 9];
+   char int_name_sfty_ce[IFNAMSIZ + 10];
+   char int_name_sfty_ue[IFNAMSIZ + 10];
+   char int_name_rx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 14];
+   char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
 
 #ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_dir;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index abe990b9b07b..459477db455c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -105,6 +105,11 @@ module_param(chain_mode, int, 0444);
 MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode");
 
 static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+/* For MSI interrupts handling */
+static irqreturn_t stmmac_mac_interrupt(int irq, void *dev_id);
+static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id);
+static irqreturn_t stmmac_msi_intr_tx(int irq, void *data);
+static irqreturn_t stmmac_msi_intr_rx(int irq, void *data);
 
 #ifdef CONFIG_DEBUG_FS
 static const struct net_device_ops stmmac_netdev_ops;
@@ -2986,6 +2991,260 @@ static void stmmac_hw_teardown(struct net_device *dev)
clk_disable_unprepare(priv->plat->clk_ptp_ref);
 }
 
+static void stmmac_free_irq(struct net_device *dev,
+   enum request_irq_err irq_err, int irq_idx)
+{
+   struct stmmac_priv *priv = netdev_priv(dev);
+   int j;
+
+   switch (irq_err) {
+   case REQ_IRQ_ERR_ALL:
+   irq_idx = priv->plat->tx_queues_to_use;
+   fallthrough;
+   case REQ_IRQ_ERR_TX:
+   for (j = irq_idx - 1; j >= 0; j--) {
+   if (priv->tx_irq[j] > 0)
+ 

[PATCH v2 net-next 4/5] stmmac: intel: add support for multi-vector msi and msi-x

2021-03-25 Thread Voon Weifeng
From: Ong Boon Leong 

Intel mgbe controller supports multi-vector interrupts:
msi_rx_vec  0,2,4,6,8,10,12,14
msi_tx_vec  1,3,5,7,9,11,13,15
msi_sfty_ue_vec 26
msi_sfty_ce_vec 27
msi_lpi_vec 28
msi_mac_vec 29

During probe(), the driver will starts with request allocation for
multi-vector interrupts. If it fails, then it will automatically fallback
to request allocation for single interrupts.

Signed-off-by: Ong Boon Leong 
Co-developed-by: Voon Weifeng 
Signed-off-by: Voon Weifeng 
---
Changes:
v1 -> v2
 - Moved the msi tx/rx base vector check before alloc irq
 - Restuctured the clean up code after fail to alloc irq and fail to probe
 - Unprepared and unregistered the stmmac-clk if fail to alloc irq
---
 .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 120 --
 1 file changed, 111 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index 992294d25706..08b4852eed4c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -492,6 +492,14 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->has_crossts = true;
plat->crosststamp = intel_crosststamp;
 
+   /* Setup MSI vector offset specific to Intel mGbE controller */
+   plat->msi_mac_vec = 29;
+   plat->msi_lpi_vec = 28;
+   plat->msi_sfty_ce_vec = 27;
+   plat->msi_sfty_ue_vec = 26;
+   plat->msi_rx_base_vec = 0;
+   plat->msi_tx_base_vec = 1;
+
return 0;
 }
 
@@ -776,6 +784,79 @@ static const struct stmmac_pci_info quark_info = {
.setup = quark_default_data,
 };
 
+static int stmmac_config_single_msi(struct pci_dev *pdev,
+   struct plat_stmmacenet_data *plat,
+   struct stmmac_resources *res)
+{
+   int ret;
+
+   ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+   if (ret < 0) {
+   dev_info(>dev, "%s: Single IRQ enablement failed\n",
+__func__);
+   return ret;
+   }
+
+   res->irq = pci_irq_vector(pdev, 0);
+   res->wol_irq = res->irq;
+   plat->multi_msi_en = 0;
+   dev_info(>dev, "%s: Single IRQ enablement successful\n",
+__func__);
+
+   return 0;
+}
+
+static int stmmac_config_multi_msi(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat,
+  struct stmmac_resources *res)
+{
+   int ret;
+   int i;
+
+   if (plat->msi_rx_base_vec >= STMMAC_MSI_VEC_MAX ||
+   plat->msi_tx_base_vec >= STMMAC_MSI_VEC_MAX) {
+   dev_info(>dev, "%s: Invalid RX & TX vector defined\n",
+__func__);
+   return -1;
+   }
+
+   ret = pci_alloc_irq_vectors(pdev, 2, STMMAC_MSI_VEC_MAX,
+   PCI_IRQ_MSI | PCI_IRQ_MSIX);
+   if (ret < 0) {
+   dev_info(>dev, "%s: multi MSI enablement failed\n",
+__func__);
+   return ret;
+   }
+
+   /* For RX MSI */
+   for (i = 0; i < plat->rx_queues_to_use; i++) {
+   res->rx_irq[i] = pci_irq_vector(pdev,
+   plat->msi_rx_base_vec + i * 2);
+   }
+
+   /* For TX MSI */
+   for (i = 0; i < plat->tx_queues_to_use; i++) {
+   res->tx_irq[i] = pci_irq_vector(pdev,
+   plat->msi_tx_base_vec + i * 2);
+   }
+
+   if (plat->msi_mac_vec < STMMAC_MSI_VEC_MAX)
+   res->irq = pci_irq_vector(pdev, plat->msi_mac_vec);
+   if (plat->msi_wol_vec < STMMAC_MSI_VEC_MAX)
+   res->wol_irq = pci_irq_vector(pdev, plat->msi_wol_vec);
+   if (plat->msi_lpi_vec < STMMAC_MSI_VEC_MAX)
+   res->lpi_irq = pci_irq_vector(pdev, plat->msi_lpi_vec);
+   if (plat->msi_sfty_ce_vec < STMMAC_MSI_VEC_MAX)
+   res->sfty_ce_irq = pci_irq_vector(pdev, plat->msi_sfty_ce_vec);
+   if (plat->msi_sfty_ue_vec < STMMAC_MSI_VEC_MAX)
+   res->sfty_ue_irq = pci_irq_vector(pdev, plat->msi_sfty_ue_vec);
+
+   plat->multi_msi_en = 1;
+   dev_info(>dev, "%s: multi MSI enablement successful\n", __func__);
+
+   return 0;
+}
+
 /**
  * intel_eth_pci_probe
  *
@@ -833,18 +914,24 @@ static int intel_eth_pci_probe(struct pci_dev *pdev,
plat->bsp_priv = intel_priv;
intel_priv->mdio_adhoc_addr = INTEL_MGBE_ADHOC_ADDR;
 
+   /* Initialize all MSI vectors to invalid so that it can be set
+* according to platform data settings below.
+* Note: MSI vector takes value fr

[PATCH v2 net-next 5/5] net: stmmac: use interrupt mode INTM=1 for multi-MSI

2021-03-25 Thread Voon Weifeng
From: "Wong, Vee Khee" 

For interrupt mode INTM=0, TX/RX transfer complete will trigger signal
not only on sbd_perch_[tx|rx]_intr_o (Transmit/Receive Per Channel) but
also on the sbd_intr_o (Common).

As for multi-MSI implementation, setting interrupt mode INTM=1 is more
efficient as each TX intr and RX intr (TI/RI) will be handled by TX/RX ISR
without the need of calling the common MAC ISR.

Updated the TX/RX NORMAL interrupts status checking process as the
NIS status bit is not asserted for any RI/TI events for INTM=1.

Signed-off-by: Wong, Vee Khee 
Co-developed-by: Voon Weifeng 
Signed-off-by: Voon Weifeng 
---
Changes:
v1 -> v2
 -Moved the readl and writel into the if statement as it is only executed
  when multi msi is enabled
---
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |  7 ++
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |  3 +++
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  | 23 +--
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  1 +
 include/linux/stmmac.h|  1 +
 5 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 8954b85eb850..cb17f6c35e54 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -161,6 +161,13 @@ static void dwmac4_dma_init(void __iomem *ioaddr,
value |= DMA_SYS_BUS_EAME;
 
writel(value, ioaddr + DMA_SYS_BUS_MODE);
+
+   if (dma_cfg->multi_msi_en) {
+   value = readl(ioaddr + DMA_BUS_MODE);
+   value &= ~DMA_BUS_MODE_INTM_MASK;
+   value |= (DMA_BUS_MODE_INTM_MODE1 << DMA_BUS_MODE_INTM_SHIFT);
+   writel(value, ioaddr + DMA_BUS_MODE);
+   }
 }
 
 static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 5c0c53832adb..05481eb13ba6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -25,6 +25,9 @@
 #define DMA_TBS_CTRL   0x1050
 
 /* DMA Bus Mode bitmap */
+#define DMA_BUS_MODE_INTM_MASK GENMASK(17, 16)
+#define DMA_BUS_MODE_INTM_SHIFT16
+#define DMA_BUS_MODE_INTM_MODE10x1
 #define DMA_BUS_MODE_SFT_RESET BIT(0)
 
 /* DMA SYS Bus Mode bitmap */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index 3fa602dabf49..e63270267578 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -166,20 +166,19 @@ int dwmac4_dma_interrupt(void __iomem *ioaddr,
}
}
/* TX/RX NORMAL interrupts */
-   if (likely(intr_status & DMA_CHAN_STATUS_NIS)) {
+   if (likely(intr_status & DMA_CHAN_STATUS_NIS))
x->normal_irq_n++;
-   if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
-   x->rx_normal_irq_n++;
-   ret |= handle_rx;
-   }
-   if (likely(intr_status & (DMA_CHAN_STATUS_TI |
- DMA_CHAN_STATUS_TBU))) {
-   x->tx_normal_irq_n++;
-   ret |= handle_tx;
-   }
-   if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
-   x->rx_early_irq++;
+   if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
+   x->rx_normal_irq_n++;
+   ret |= handle_rx;
+   }
+   if (likely(intr_status & (DMA_CHAN_STATUS_TI |
+   DMA_CHAN_STATUS_TBU))) {
+   x->tx_normal_irq_n++;
+   ret |= handle_tx;
}
+   if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
+   x->rx_early_irq++;
 
writel(intr_status & intr_en, ioaddr + DMA_CHAN_STATUS(chan));
return ret;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 459477db455c..f4fa5402cd64 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -5620,6 +5620,7 @@ int stmmac_dvr_probe(struct device *device,
priv->plat = plat_dat;
priv->ioaddr = res->addr;
priv->dev->base_addr = (unsigned long)res->addr;
+   priv->plat->dma_cfg->multi_msi_en = priv->plat->multi_msi_en;
 
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index afc12b9385db..e338ef7abc00 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -96,6 +96,7 @@ struct stmmac_dma_cfg {
int mixed_burst;
bool aal;
bool eame;
+   bool multi_msi_en;
 };
 
 #define AXI_BLEN   7
-- 
2.17.1



[PATCH v2 net-next 2/5] net: stmmac: make stmmac_interrupt() function more friendly to MSI

2021-03-25 Thread Voon Weifeng
From: Ong Boon Leong 

Refactor stmmac_interrupt() by introducing stmmac_common_interrupt()
so that we prepare the ISR operation to be friendly to MSI later.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
Changes:
v1 -> v2
 -Remove defensive check for invalid dev pointer
---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 54 +++
 1 file changed, 31 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7c352d017eb2..abe990b9b07b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4382,21 +4382,8 @@ static void stmmac_fpe_event_status(struct stmmac_priv 
*priv, int status)
}
 }
 
-/**
- *  stmmac_interrupt - main ISR
- *  @irq: interrupt number.
- *  @dev_id: to pass the net device pointer (must be valid).
- *  Description: this is the main driver interrupt service routine.
- *  It can call:
- *  o DMA service routine (to manage incoming frame reception and transmission
- *status)
- *  o Core interrupts to manage: remote wake-up, management counter, LPI
- *interrupts.
- */
-static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+static void stmmac_common_interrupt(struct stmmac_priv *priv)
 {
-   struct net_device *dev = (struct net_device *)dev_id;
-   struct stmmac_priv *priv = netdev_priv(dev);
u32 rx_cnt = priv->plat->rx_queues_to_use;
u32 tx_cnt = priv->plat->tx_queues_to_use;
u32 queues_count;
@@ -4409,13 +4396,6 @@ static irqreturn_t stmmac_interrupt(int irq, void 
*dev_id)
if (priv->irq_wake)
pm_wakeup_event(priv->device, 0);
 
-   /* Check if adapter is up */
-   if (test_bit(STMMAC_DOWN, >state))
-   return IRQ_HANDLED;
-   /* Check if a fatal error happened */
-   if (stmmac_safety_feat_interrupt(priv))
-   return IRQ_HANDLED;
-
if (priv->dma_cap.estsel)
stmmac_est_irq_status(priv, priv->ioaddr, priv->dev,
  >xstats, tx_cnt);
@@ -4457,11 +4437,39 @@ static irqreturn_t stmmac_interrupt(int irq, void 
*dev_id)
/* PCS link status */
if (priv->hw->pcs) {
if (priv->xstats.pcs_link)
-   netif_carrier_on(dev);
+   netif_carrier_on(priv->dev);
else
-   netif_carrier_off(dev);
+   netif_carrier_off(priv->dev);
}
}
+}
+
+/**
+ *  stmmac_interrupt - main ISR
+ *  @irq: interrupt number.
+ *  @dev_id: to pass the net device pointer.
+ *  Description: this is the main driver interrupt service routine.
+ *  It can call:
+ *  o DMA service routine (to manage incoming frame reception and transmission
+ *status)
+ *  o Core interrupts to manage: remote wake-up, management counter, LPI
+ *interrupts.
+ */
+static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+{
+   struct net_device *dev = (struct net_device *)dev_id;
+   struct stmmac_priv *priv = netdev_priv(dev);
+
+   /* Check if adapter is up */
+   if (test_bit(STMMAC_DOWN, >state))
+   return IRQ_HANDLED;
+
+   /* Check if a fatal error happened */
+   if (stmmac_safety_feat_interrupt(priv))
+   return IRQ_HANDLED;
+
+   /* To handle Common interrupts */
+   stmmac_common_interrupt(priv);
 
/* To handle DMA interrupts */
stmmac_dma_interrupt(priv);
-- 
2.17.1



[PATCH v2 net-next 1/5] net: stmmac: introduce DMA interrupt status masking per traffic direction

2021-03-25 Thread Voon Weifeng
From: Ong Boon Leong 

In preparation to make stmmac support multi-vector MSI, we introduce the
interrupt status masking according to RX, TX or RXTX. Default to use RXTX
inside stmmac_dma_interrupt(), so there is no run-time logic difference
now.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  6 +
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 24 ++-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  | 21 +++-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |  7 +-
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   | 22 -
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |  8 ++-
 .../net/ethernet/stmicro/stmmac/dwxgmac2.h|  6 +
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c|  8 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  7 +++---
 10 files changed, 101 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index d065b11b7b10..5afb36a5c94c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -309,6 +309,12 @@ enum dma_irq_status {
handle_tx = 0x8,
 };
 
+enum dma_irq_dir {
+   DMA_DIR_RX = 0x1,
+   DMA_DIR_TX = 0x2,
+   DMA_DIR_RXTX = 0x3,
+};
+
 /* EEE and LPI defines */
 #defineCORE_IRQ_TX_PATH_IN_LPI_MODE(1 << 0)
 #defineCORE_IRQ_TX_PATH_EXIT_LPI_MODE  (1 << 1)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 6b75cf2603ff..e0bd08978fd6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -239,6 +239,22 @@ static const struct emac_variant emac_variant_h6 = {
 #define EMAC_RX_EARLY_INT   BIT(13)
 #define EMAC_RGMII_STA_INT  BIT(16)
 
+#define EMAC_INT_MSK_COMMONEMAC_RGMII_STA_INT
+#define EMAC_INT_MSK_TX(EMAC_TX_INT | \
+EMAC_TX_DMA_STOP_INT | \
+EMAC_TX_BUF_UA_INT | \
+EMAC_TX_TIMEOUT_INT | \
+EMAC_TX_UNDERFLOW_INT | \
+EMAC_TX_EARLY_INT |\
+EMAC_INT_MSK_COMMON)
+#define EMAC_INT_MSK_RX(EMAC_RX_INT | \
+EMAC_RX_BUF_UA_INT | \
+EMAC_RX_DMA_STOP_INT | \
+EMAC_RX_TIMEOUT_INT | \
+EMAC_RX_OVERFLOW_INT | \
+EMAC_RX_EARLY_INT | \
+EMAC_INT_MSK_COMMON)
+
 #define MAC_ADDR_TYPE_DST BIT(31)
 
 /* H3 specific bits for EPHY */
@@ -412,13 +428,19 @@ static void sun8i_dwmac_dma_stop_rx(void __iomem *ioaddr, 
u32 chan)
 }
 
 static int sun8i_dwmac_dma_interrupt(void __iomem *ioaddr,
-struct stmmac_extra_stats *x, u32 chan)
+struct stmmac_extra_stats *x, u32 chan,
+u32 dir)
 {
u32 v;
int ret = 0;
 
v = readl(ioaddr + EMAC_INT_STA);
 
+   if (dir == DMA_DIR_RX)
+   v &= EMAC_INT_MSK_RX;
+   else if (dir == DMA_DIR_TX)
+   v &= EMAC_INT_MSK_TX;
+
if (v & EMAC_TX_INT) {
ret |= handle_tx;
x->tx_normal_irq_n++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 8391ca63d943..5c0c53832adb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -149,6 +149,25 @@
 #define DMA_CHAN_STATUS_TPSBIT(1)
 #define DMA_CHAN_STATUS_TI BIT(0)
 
+#define DMA_CHAN_STATUS_MSK_COMMON (DMA_CHAN_STATUS_NIS | \
+DMA_CHAN_STATUS_AIS | \
+DMA_CHAN_STATUS_CDE | \
+DMA_CHAN_STATUS_FBE)
+
+#define DMA_CHAN_STATUS_MSK_RX (DMA_CHAN_STATUS_REB | \
+DMA_CHAN_STATUS_ERI | \
+DMA_CHAN_STATUS_RWT | \
+DMA_CHAN_STATUS_RPS | \
+DMA_CHAN_STATUS_RBU | \
+DMA_CHAN_STATUS_RI | \
+DMA_CHAN_STATUS_MSK_COMMON)
+
+#define DMA_CHAN_STATUS_MSK_TX (DMA_CHAN_STATUS_ETI | \
+DMA_CHAN_STATUS_TBU | \
+DMA_CHAN_STATUS_TPS | \
+   

[PATCH v2 net-next 0/5] net: stmmac: enable multi-vector MSI

2021-03-25 Thread Voon Weifeng
This patchset adds support for multi MSI interrupts in addition to
current single common interrupt implementation. Each MSI interrupt is tied
to a newly introduce interrupt service routine(ISR). Hence, each interrupt
will only go through the corresponding ISR.

In order to increase the efficiency, enabling multi MSI interrupt will
automatically select the interrupt mode configuration INTM=1. When INTM=1,
the TX/RX transfer complete signal will only asserted on corresponding
sbd_perch_tx_intr_o[] or sbd_perch_rx_intr_o[] without asserting signal
on the common sbd_intr_o. Hence, for each TX/RX interrupts, only the
corresponding ISR will be triggered.

Every vendor might have different MSI vector assignment. So, this patchset
only includes multi-vector MSI assignment for Intel platform.

Changes:
v1 -> v2
 patch 2/5
 -Remove defensive check for invalid dev pointer

 patch 3/5
 - Refactor out a huge if statement into separate subfunctions.
 - Removed the netdev_info for every successful request of IRQs.
 - Return 0 for each successful request of IRQs.

 patch 4/5
 - Moved the msi tx/rx base vector check before alloc irq
 - Restuctured the clean up code after fail to alloc irq and fail to probe
 - Unprepared and unregistered the stmmac-clk if fail to alloc irq

 patch 5/5
 -Moved the readl and writel into the if statement as it is only executed
  when multi msi is enabled

Ong Boon Leong (4):
  net: stmmac: introduce DMA interrupt status masking per traffic
direction
  net: stmmac: make stmmac_interrupt() function more friendly to MSI
  net: stmmac: introduce MSI Interrupt routines for mac, safety, RX & TX
  stmmac: intel: add support for multi-vector msi and msi-x

Wong, Vee Khee (1):
  net: stmmac: use interrupt mode INTM=1 for multi-MSI

 drivers/net/ethernet/stmicro/stmmac/common.h  |  21 +
 .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 120 -
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c |  24 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |   7 +
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |  24 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |  30 +-
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   |  22 +-
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |   8 +-
 .../net/ethernet/stmicro/stmmac/dwxgmac2.h|   6 +
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c|   8 +-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|   2 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  16 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 499 +++---
 include/linux/stmmac.h|   9 +
 14 files changed, 697 insertions(+), 99 deletions(-)

-- 
2.17.1



RE: [RESEND v1 net-next 3/5] net: stmmac: introduce MSI Interrupt routines for mac, safety, RX & TX

2021-03-24 Thread Voon, Weifeng
> On Tue, 16 Mar 2021 20:18:21 +0800 Voon Weifeng wrote:
> > From: Ong Boon Leong 
> >
> > Now we introduce MSI interrupt service routines and hook these
> > routines up if stmmac_open() sees valid irq line being requested:-
> >
> > stmmac_mac_interrupt():- MAC (dev->irq), WOL (wol_irq), LPI (lpi_irq)
> > stmmac_safety_interrupt() :- Safety Feat Correctible Error (sfty_ce_irq)
> >  & Uncorrectible Error (sfty_ue_irq)
> > stmmac_msi_intr_rx()  :- For all RX MSI irq (rx_irq)
> > stmmac_msi_intr_tx()  :- For all TX MSI irq (tx_irq)
> 
> Do you split RX and TX irqs out on purpose? Most commonly one queue pair
> maps to one CPU, so using single IRQ for Rx and Tx results in fewer IRQs
> being triggered and better system performance.

Yes, the RX and TX irqs are split out on purpose as the hardware is designed
to have independent MSI vector. You can refer the 4th patch in the this 
patchset.
https://patchwork.kernel.org/project/netdevbpf/patch/20210316121823.18659-5-weifeng.v...@intel.com/
  
This design also gives us the flexibility to group RX/TX MSI vectors to 
specific CPU freely.

Weifeng


> > Each of IRQs will have its unique name so that we can differentiate
> > them easily under /proc/interrupts.
> >
> > Signed-off-by: Ong Boon Leong 
> > Signed-off-by: Voon Weifeng 
> 
> > +static int stmmac_request_irq(struct net_device *dev)
> 
> This function is a one huge if statement, please factor out both sides into
> separate subfunctions.

Noted. Will do.

> 
> > +   netdev_info(priv->dev, "PASS: requesting IRQs\n");
> 
> Does the user really need to know interrupts were requested on every probe?

Will remove.

> 
> > +   return ret;
> 
> return 0; ?

Good catch, will fix.

> 
> > +irq_error:
> > +   stmmac_free_irq(dev, irq_err, irq_idx);
> > +   return ret;
> > +}


[RESEND v1 net-next 4/5] stmmac: intel: add support for multi-vector msi and msi-x

2021-03-16 Thread Voon Weifeng
From: Ong Boon Leong 

Intel mgbe controller supports multi-vector interrupts:
msi_rx_vec  0,2,4,6,8,10,12,14
msi_tx_vec  1,3,5,7,9,11,13,15
msi_sfty_ue_vec 26
msi_sfty_ce_vec 27
msi_lpi_vec 28
msi_mac_vec 29

During probe(), the driver will starts with request allocation for
multi-vector interrupts. If it fails, then it will automatically fallback
to request allocation for single interrupts.

Signed-off-by: Ong Boon Leong 
Co-developed-by: Voon Weifeng 
Signed-off-by: Voon Weifeng 
---
 .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 112 +-
 1 file changed, 106 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index c49646773871..3b01557e561b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -346,6 +346,14 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->mdio_bus_data->phy_mask = 1 << INTEL_MGBE_ADHOC_ADDR;
plat->mdio_bus_data->phy_mask |= 1 << INTEL_MGBE_XPCS_ADDR;
 
+   /* Setup MSI vector offset specific to Intel mGbE controller */
+   plat->msi_mac_vec = 29;
+   plat->msi_lpi_vec = 28;
+   plat->msi_sfty_ce_vec = 27;
+   plat->msi_sfty_ue_vec = 26;
+   plat->msi_rx_base_vec = 0;
+   plat->msi_tx_base_vec = 1;
+
return 0;
 }
 
@@ -622,6 +630,79 @@ static const struct stmmac_pci_info quark_info = {
.setup = quark_default_data,
 };
 
+static int stmmac_config_single_msi(struct pci_dev *pdev,
+   struct plat_stmmacenet_data *plat,
+   struct stmmac_resources *res)
+{
+   int ret;
+
+   ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+   if (ret < 0) {
+   dev_info(>dev, "%s: Single IRQ enablement failed\n",
+__func__);
+   return ret;
+   }
+
+   res->irq = pci_irq_vector(pdev, 0);
+   res->wol_irq = res->irq;
+   plat->multi_msi_en = 0;
+   dev_info(>dev, "%s: Single IRQ enablement successful\n",
+__func__);
+
+   return 0;
+}
+
+static int stmmac_config_multi_msi(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat,
+  struct stmmac_resources *res)
+{
+   int ret;
+   int i;
+
+   ret = pci_alloc_irq_vectors(pdev, 2, STMMAC_MSI_VEC_MAX,
+   PCI_IRQ_MSI | PCI_IRQ_MSIX);
+   if (ret < 0) {
+   dev_info(>dev, "%s: multi MSI enablement failed\n",
+__func__);
+   return ret;
+   }
+
+   if (plat->msi_rx_base_vec >= STMMAC_MSI_VEC_MAX ||
+   plat->msi_tx_base_vec >= STMMAC_MSI_VEC_MAX) {
+   dev_info(>dev, "%s: Invalid RX & TX vector defined\n",
+__func__);
+   return -1;
+   }
+
+   /* For RX MSI */
+   for (i = 0; i < plat->rx_queues_to_use; i++) {
+   res->rx_irq[i] = pci_irq_vector(pdev,
+   plat->msi_rx_base_vec + i * 2);
+   }
+
+   /* For TX MSI */
+   for (i = 0; i < plat->tx_queues_to_use; i++) {
+   res->tx_irq[i] = pci_irq_vector(pdev,
+   plat->msi_tx_base_vec + i * 2);
+   }
+
+   if (plat->msi_mac_vec < STMMAC_MSI_VEC_MAX)
+   res->irq = pci_irq_vector(pdev, plat->msi_mac_vec);
+   if (plat->msi_wol_vec < STMMAC_MSI_VEC_MAX)
+   res->wol_irq = pci_irq_vector(pdev, plat->msi_wol_vec);
+   if (plat->msi_lpi_vec < STMMAC_MSI_VEC_MAX)
+   res->lpi_irq = pci_irq_vector(pdev, plat->msi_lpi_vec);
+   if (plat->msi_sfty_ce_vec < STMMAC_MSI_VEC_MAX)
+   res->sfty_ce_irq = pci_irq_vector(pdev, plat->msi_sfty_ce_vec);
+   if (plat->msi_sfty_ue_vec < STMMAC_MSI_VEC_MAX)
+   res->sfty_ue_irq = pci_irq_vector(pdev, plat->msi_sfty_ue_vec);
+
+   plat->multi_msi_en = 1;
+   dev_info(>dev, "%s: multi MSI enablement successful\n", __func__);
+
+   return 0;
+}
+
 /**
  * intel_eth_pci_probe
  *
@@ -679,18 +760,24 @@ static int intel_eth_pci_probe(struct pci_dev *pdev,
plat->bsp_priv = intel_priv;
intel_priv->mdio_adhoc_addr = INTEL_MGBE_ADHOC_ADDR;
 
+   /* Initialize all MSI vectors to invalid so that it can be set
+* according to platform data settings below.
+* Note: MSI vector takes value from 0 upto 31 (STMMAC_MSI_VEC_MAX)
+*/
+   plat->msi_mac_vec = STMMAC_MSI_VEC_MAX;
+   plat->msi_wol_vec = STMMAC_MSI_VE

[RESEND v1 net-next 5/5] net: stmmac: use interrupt mode INTM=1 for multi-MSI

2021-03-16 Thread Voon Weifeng
From: "Wong, Vee Khee" 

For interrupt mode INTM=0, TX/RX transfer complete will trigger signal
not only on sbd_perch_[tx|rx]_intr_o (Transmit/Receive Per Channel) but
also on the sbd_intr_o (Common).

As for multi-MSI implementation, setting interrupt mode INTM=1 is more
efficient as each TX intr and RX intr (TI/RI) will be handled by TX/RX ISR
without the need of calling the common MAC ISR.

Updated the TX/RX NORMAL interrupts status checking process as the
NIS status bit is not asserted for any RI/TI events for INTM=1.

Signed-off-by: Wong, Vee Khee 
Co-developed-by: Voon Weifeng 
Signed-off-by: Voon Weifeng 
---
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |  8 +++
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |  3 +++
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  | 23 +--
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  1 +
 include/linux/stmmac.h|  1 +
 5 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 62aa0e95beb7..3c33b9a5b291 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -161,6 +161,14 @@ static void dwmac4_dma_init(void __iomem *ioaddr,
value |= DMA_SYS_BUS_EAME;
 
writel(value, ioaddr + DMA_SYS_BUS_MODE);
+
+   value = readl(ioaddr + DMA_BUS_MODE);
+
+   if (dma_cfg->multi_msi_en) {
+   value &= ~DMA_BUS_MODE_INTM_MASK;
+   value |= (DMA_BUS_MODE_INTM_MODE1 << DMA_BUS_MODE_INTM_SHIFT);
+   }
+   writel(value, ioaddr + DMA_BUS_MODE);
 }
 
 static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 5c0c53832adb..05481eb13ba6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -25,6 +25,9 @@
 #define DMA_TBS_CTRL   0x1050
 
 /* DMA Bus Mode bitmap */
+#define DMA_BUS_MODE_INTM_MASK GENMASK(17, 16)
+#define DMA_BUS_MODE_INTM_SHIFT16
+#define DMA_BUS_MODE_INTM_MODE10x1
 #define DMA_BUS_MODE_SFT_RESET BIT(0)
 
 /* DMA SYS Bus Mode bitmap */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index 3fa602dabf49..e63270267578 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -166,20 +166,19 @@ int dwmac4_dma_interrupt(void __iomem *ioaddr,
}
}
/* TX/RX NORMAL interrupts */
-   if (likely(intr_status & DMA_CHAN_STATUS_NIS)) {
+   if (likely(intr_status & DMA_CHAN_STATUS_NIS))
x->normal_irq_n++;
-   if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
-   x->rx_normal_irq_n++;
-   ret |= handle_rx;
-   }
-   if (likely(intr_status & (DMA_CHAN_STATUS_TI |
- DMA_CHAN_STATUS_TBU))) {
-   x->tx_normal_irq_n++;
-   ret |= handle_tx;
-   }
-   if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
-   x->rx_early_irq++;
+   if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
+   x->rx_normal_irq_n++;
+   ret |= handle_rx;
+   }
+   if (likely(intr_status & (DMA_CHAN_STATUS_TI |
+   DMA_CHAN_STATUS_TBU))) {
+   x->tx_normal_irq_n++;
+   ret |= handle_tx;
}
+   if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
+   x->rx_early_irq++;
 
writel(intr_status & intr_en, ioaddr + DMA_CHAN_STATUS(chan));
return ret;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index efc35434b9af..d23722e86721 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -5401,6 +5401,7 @@ int stmmac_dvr_probe(struct device *device,
priv->plat = plat_dat;
priv->ioaddr = res->addr;
priv->dev->base_addr = (unsigned long)res->addr;
+   priv->plat->dma_cfg->multi_msi_en = priv->plat->multi_msi_en;
 
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index cb260a04df80..e35224ce61cc 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -96,6 +96,7 @@ struct stmmac_dma_cfg {
int mixed_burst;
bool aal;
bool eame;
+   bool multi_msi_en;
 };
 
 #define AXI_BLEN   7
-- 
2.17.1



[RESEND v1 net-next 3/5] net: stmmac: introduce MSI Interrupt routines for mac, safety, RX & TX

2021-03-16 Thread Voon Weifeng
From: Ong Boon Leong 

Now we introduce MSI interrupt service routines and hook these routines
up if stmmac_open() sees valid irq line being requested:-

stmmac_mac_interrupt():- MAC (dev->irq), WOL (wol_irq), LPI (lpi_irq)
stmmac_safety_interrupt() :- Safety Feat Correctible Error (sfty_ce_irq)
 & Uncorrectible Error (sfty_ue_irq)
stmmac_msi_intr_rx()  :- For all RX MSI irq (rx_irq)
stmmac_msi_intr_tx()  :- For all TX MSI irq (tx_irq)

Each of IRQs will have its unique name so that we can differentiate
them easily under /proc/interrupts.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  15 +
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  16 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 415 --
 include/linux/stmmac.h|   8 +
 4 files changed, 409 insertions(+), 45 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index cf8ad27824d4..b6a012eb7519 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -253,6 +253,9 @@ struct stmmac_safety_stats {
 #define DMA_HW_FEAT_ACTPHYIF   0x7000  /* Active/selected PHY iface */
 #define DEFAULT_DMA_PBL8
 
+/* MSI defines */
+#define STMMAC_MSI_VEC_MAX 32
+
 /* PCS status and mask defines */
 #definePCS_ANE_IRQ BIT(2)  /* PCS Auto-Negotiation */
 #definePCS_LINK_IRQBIT(1)  /* PCS Link */
@@ -309,6 +312,18 @@ enum dma_irq_dir {
DMA_DIR_RXTX = 0x3,
 };
 
+enum request_irq_err {
+   REQ_IRQ_ERR_ALL,
+   REQ_IRQ_ERR_TX,
+   REQ_IRQ_ERR_RX,
+   REQ_IRQ_ERR_SFTY_UE,
+   REQ_IRQ_ERR_SFTY_CE,
+   REQ_IRQ_ERR_LPI,
+   REQ_IRQ_ERR_WOL,
+   REQ_IRQ_ERR_MAC,
+   REQ_IRQ_ERR_NO,
+};
+
 /* EEE and LPI defines */
 #defineCORE_IRQ_TX_PATH_IN_LPI_MODE(1 << 0)
 #defineCORE_IRQ_TX_PATH_EXIT_LPI_MODE  (1 << 1)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 10e8ae8e2d58..563f0fbb64d2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -30,6 +30,10 @@ struct stmmac_resources {
int wol_irq;
int lpi_irq;
int irq;
+   int sfty_ce_irq;
+   int sfty_ue_irq;
+   int rx_irq[MTL_MAX_RX_QUEUES];
+   int tx_irq[MTL_MAX_TX_QUEUES];
 };
 
 struct stmmac_tx_info {
@@ -225,6 +229,18 @@ struct stmmac_priv {
void __iomem *mmcaddr;
void __iomem *ptpaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+   int sfty_ce_irq;
+   int sfty_ue_irq;
+   int rx_irq[MTL_MAX_RX_QUEUES];
+   int tx_irq[MTL_MAX_TX_QUEUES];
+   /*irq name */
+   char int_name_mac[IFNAMSIZ + 9];
+   char int_name_wol[IFNAMSIZ + 9];
+   char int_name_lpi[IFNAMSIZ + 9];
+   char int_name_sfty_ce[IFNAMSIZ + 10];
+   char int_name_sfty_ue[IFNAMSIZ + 10];
+   char int_name_rx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 14];
+   char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
 
 #ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_dir;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 741b100c8971..efc35434b9af 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -105,6 +105,11 @@ module_param(chain_mode, int, 0444);
 MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode");
 
 static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+/* For MSI interrupts handling */
+static irqreturn_t stmmac_mac_interrupt(int irq, void *dev_id);
+static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id);
+static irqreturn_t stmmac_msi_intr_tx(int irq, void *data);
+static irqreturn_t stmmac_msi_intr_rx(int irq, void *data);
 
 #ifdef CONFIG_DEBUG_FS
 static const struct net_device_ops stmmac_netdev_ops;
@@ -2914,6 +2919,238 @@ static void stmmac_hw_teardown(struct net_device *dev)
clk_disable_unprepare(priv->plat->clk_ptp_ref);
 }
 
+static void stmmac_free_irq(struct net_device *dev,
+   enum request_irq_err irq_err, int irq_idx)
+{
+   struct stmmac_priv *priv = netdev_priv(dev);
+   int j;
+
+   switch (irq_err) {
+   case REQ_IRQ_ERR_ALL:
+   irq_idx = priv->plat->tx_queues_to_use;
+   fallthrough;
+   case REQ_IRQ_ERR_TX:
+   for (j = irq_idx - 1; j >= 0; j--) {
+   if (priv->tx_irq[j] > 0)
+   free_irq(priv->tx_irq[j], >tx_queue[j]);
+   }
+   irq_idx = priv->plat->rx_queues_to_use;
+   fallthrough;
+   case R

[RESEND v1 net-next 2/5] net: stmmac: make stmmac_interrupt() function more friendly to MSI

2021-03-16 Thread Voon Weifeng
From: Ong Boon Leong 

Refactor stmmac_interrupt() by introducing stmmac_common_interrupt()
so that we prepare the ISR operation to be friendly to MSI later.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 59 +++
 1 file changed, 36 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 53da3c855cba..741b100c8971 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4253,21 +4253,8 @@ static int stmmac_set_features(struct net_device *netdev,
return 0;
 }
 
-/**
- *  stmmac_interrupt - main ISR
- *  @irq: interrupt number.
- *  @dev_id: to pass the net device pointer (must be valid).
- *  Description: this is the main driver interrupt service routine.
- *  It can call:
- *  o DMA service routine (to manage incoming frame reception and transmission
- *status)
- *  o Core interrupts to manage: remote wake-up, management counter, LPI
- *interrupts.
- */
-static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+static void stmmac_common_interrupt(struct stmmac_priv *priv)
 {
-   struct net_device *dev = (struct net_device *)dev_id;
-   struct stmmac_priv *priv = netdev_priv(dev);
u32 rx_cnt = priv->plat->rx_queues_to_use;
u32 tx_cnt = priv->plat->tx_queues_to_use;
u32 queues_count;
@@ -4280,13 +4267,6 @@ static irqreturn_t stmmac_interrupt(int irq, void 
*dev_id)
if (priv->irq_wake)
pm_wakeup_event(priv->device, 0);
 
-   /* Check if adapter is up */
-   if (test_bit(STMMAC_DOWN, >state))
-   return IRQ_HANDLED;
-   /* Check if a fatal error happened */
-   if (stmmac_safety_feat_interrupt(priv))
-   return IRQ_HANDLED;
-
/* To handle GMAC own interrupts */
if ((priv->plat->has_gmac) || xmac) {
int status = stmmac_host_irq_status(priv, priv->hw, 
>xstats);
@@ -4317,11 +4297,44 @@ static irqreturn_t stmmac_interrupt(int irq, void 
*dev_id)
/* PCS link status */
if (priv->hw->pcs) {
if (priv->xstats.pcs_link)
-   netif_carrier_on(dev);
+   netif_carrier_on(priv->dev);
else
-   netif_carrier_off(dev);
+   netif_carrier_off(priv->dev);
}
}
+}
+
+/**
+ *  stmmac_interrupt - main ISR
+ *  @irq: interrupt number.
+ *  @dev_id: to pass the net device pointer.
+ *  Description: this is the main driver interrupt service routine.
+ *  It can call:
+ *  o DMA service routine (to manage incoming frame reception and transmission
+ *status)
+ *  o Core interrupts to manage: remote wake-up, management counter, LPI
+ *interrupts.
+ */
+static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+{
+   struct net_device *dev = (struct net_device *)dev_id;
+   struct stmmac_priv *priv = netdev_priv(dev);
+
+   if (unlikely(!dev)) {
+   netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
+   return IRQ_NONE;
+   }
+
+   /* Check if adapter is up */
+   if (test_bit(STMMAC_DOWN, >state))
+   return IRQ_HANDLED;
+
+   /* Check if a fatal error happened */
+   if (stmmac_safety_feat_interrupt(priv))
+   return IRQ_HANDLED;
+
+   /* To handle Common interrupts */
+   stmmac_common_interrupt(priv);
 
/* To handle DMA interrupts */
stmmac_dma_interrupt(priv);
-- 
2.17.1



[RESEND v1 net-next 1/5] net: stmmac: introduce DMA interrupt status masking per traffic direction

2021-03-16 Thread Voon Weifeng
From: Ong Boon Leong 

In preparation to make stmmac support multi-vector MSI, we introduce the
interrupt status masking according to RX, TX or RXTX. Default to use RXTX
inside stmmac_dma_interrupt(), so there is no run-time logic difference
now.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  6 +
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 24 ++-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  | 21 +++-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |  7 +-
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   | 22 -
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |  8 ++-
 .../net/ethernet/stmicro/stmmac/dwxgmac2.h|  6 +
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c|  8 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  7 +++---
 10 files changed, 101 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 6f271c46368d..cf8ad27824d4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -303,6 +303,12 @@ enum dma_irq_status {
handle_tx = 0x8,
 };
 
+enum dma_irq_dir {
+   DMA_DIR_RX = 0x1,
+   DMA_DIR_TX = 0x2,
+   DMA_DIR_RXTX = 0x3,
+};
+
 /* EEE and LPI defines */
 #defineCORE_IRQ_TX_PATH_IN_LPI_MODE(1 << 0)
 #defineCORE_IRQ_TX_PATH_EXIT_LPI_MODE  (1 << 1)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 6b75cf2603ff..e0bd08978fd6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -239,6 +239,22 @@ static const struct emac_variant emac_variant_h6 = {
 #define EMAC_RX_EARLY_INT   BIT(13)
 #define EMAC_RGMII_STA_INT  BIT(16)
 
+#define EMAC_INT_MSK_COMMONEMAC_RGMII_STA_INT
+#define EMAC_INT_MSK_TX(EMAC_TX_INT | \
+EMAC_TX_DMA_STOP_INT | \
+EMAC_TX_BUF_UA_INT | \
+EMAC_TX_TIMEOUT_INT | \
+EMAC_TX_UNDERFLOW_INT | \
+EMAC_TX_EARLY_INT |\
+EMAC_INT_MSK_COMMON)
+#define EMAC_INT_MSK_RX(EMAC_RX_INT | \
+EMAC_RX_BUF_UA_INT | \
+EMAC_RX_DMA_STOP_INT | \
+EMAC_RX_TIMEOUT_INT | \
+EMAC_RX_OVERFLOW_INT | \
+EMAC_RX_EARLY_INT | \
+EMAC_INT_MSK_COMMON)
+
 #define MAC_ADDR_TYPE_DST BIT(31)
 
 /* H3 specific bits for EPHY */
@@ -412,13 +428,19 @@ static void sun8i_dwmac_dma_stop_rx(void __iomem *ioaddr, 
u32 chan)
 }
 
 static int sun8i_dwmac_dma_interrupt(void __iomem *ioaddr,
-struct stmmac_extra_stats *x, u32 chan)
+struct stmmac_extra_stats *x, u32 chan,
+u32 dir)
 {
u32 v;
int ret = 0;
 
v = readl(ioaddr + EMAC_INT_STA);
 
+   if (dir == DMA_DIR_RX)
+   v &= EMAC_INT_MSK_RX;
+   else if (dir == DMA_DIR_TX)
+   v &= EMAC_INT_MSK_TX;
+
if (v & EMAC_TX_INT) {
ret |= handle_tx;
x->tx_normal_irq_n++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 8391ca63d943..5c0c53832adb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -149,6 +149,25 @@
 #define DMA_CHAN_STATUS_TPSBIT(1)
 #define DMA_CHAN_STATUS_TI BIT(0)
 
+#define DMA_CHAN_STATUS_MSK_COMMON (DMA_CHAN_STATUS_NIS | \
+DMA_CHAN_STATUS_AIS | \
+DMA_CHAN_STATUS_CDE | \
+DMA_CHAN_STATUS_FBE)
+
+#define DMA_CHAN_STATUS_MSK_RX (DMA_CHAN_STATUS_REB | \
+DMA_CHAN_STATUS_ERI | \
+DMA_CHAN_STATUS_RWT | \
+DMA_CHAN_STATUS_RPS | \
+DMA_CHAN_STATUS_RBU | \
+DMA_CHAN_STATUS_RI | \
+DMA_CHAN_STATUS_MSK_COMMON)
+
+#define DMA_CHAN_STATUS_MSK_TX (DMA_CHAN_STATUS_ETI | \
+DMA_CHAN_STATUS_TBU | \
+DMA_CHAN_STATUS_TPS | \
+   

[RESEND v1 net-next 0/5] net: stmmac: enable multi-vector MSI

2021-03-16 Thread Voon Weifeng
This patchset adds support for multi MSI interrupts in addition to
current single common interrupt implementation. Each MSI interrupt is tied
to a newly introduce interrupt service routine(ISR). Hence, each interrupt
will only go through the corresponding ISR.

In order to increase the efficiency, enabling multi MSI interrupt will
automatically select the interrupt mode configuration INTM=1. When INTM=1,
the TX/RX transfer complete signal will only asserted on corresponding
sbd_perch_tx_intr_o[] or sbd_perch_rx_intr_o[] without asserting signal
on the common sbd_intr_o. Hence, for each TX/RX interrupts, only the
corresponding ISR will be triggered.

Every vendor might have different MSI vector assignment. So, this patchset
only includes multi-vector MSI assignment for Intel platform.

Ong Boon Leong (4):
  net: stmmac: introduce DMA interrupt status masking per traffic
direction
  net: stmmac: make stmmac_interrupt() function more friendly to MSI
  net: stmmac: introduce MSI Interrupt routines for mac, safety, RX & TX
  stmmac: intel: add support for multi-vector msi and msi-x

Wong, Vee Khee (1):
  net: stmmac: use interrupt mode INTM=1 for multi-MSI

 drivers/net/ethernet/stmicro/stmmac/common.h  |  21 +
 .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 112 +++-
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c |  24 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |   8 +
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |  24 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |  30 +-
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   |  22 +-
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |   8 +-
 .../net/ethernet/stmicro/stmmac/dwxgmac2.h|   6 +
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c|   8 +-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|   2 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  16 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 482 +++---
 include/linux/stmmac.h|   9 +
 14 files changed, 676 insertions(+), 96 deletions(-)

-- 
2.17.1



[PATCH v1 net-next 1/5] net: stmmac: introduce DMA interrupt status masking per traffic direction

2021-03-03 Thread Voon Weifeng
From: Ong Boon Leong 

In preparation to make stmmac support multi-vector MSI, we introduce the
interrupt status masking according to RX, TX or RXTX. Default to use RXTX
inside stmmac_dma_interrupt(), so there is no run-time logic difference
now.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  6 +
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 24 ++-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  | 21 +++-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |  7 +-
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   | 22 -
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |  8 ++-
 .../net/ethernet/stmicro/stmmac/dwxgmac2.h|  6 +
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c|  8 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  7 +++---
 10 files changed, 101 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 6f271c46368d..cf8ad27824d4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -303,6 +303,12 @@ enum dma_irq_status {
handle_tx = 0x8,
 };
 
+enum dma_irq_dir {
+   DMA_DIR_RX = 0x1,
+   DMA_DIR_TX = 0x2,
+   DMA_DIR_RXTX = 0x3,
+};
+
 /* EEE and LPI defines */
 #defineCORE_IRQ_TX_PATH_IN_LPI_MODE(1 << 0)
 #defineCORE_IRQ_TX_PATH_EXIT_LPI_MODE  (1 << 1)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 6b75cf2603ff..e0bd08978fd6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -239,6 +239,22 @@ static const struct emac_variant emac_variant_h6 = {
 #define EMAC_RX_EARLY_INT   BIT(13)
 #define EMAC_RGMII_STA_INT  BIT(16)
 
+#define EMAC_INT_MSK_COMMONEMAC_RGMII_STA_INT
+#define EMAC_INT_MSK_TX(EMAC_TX_INT | \
+EMAC_TX_DMA_STOP_INT | \
+EMAC_TX_BUF_UA_INT | \
+EMAC_TX_TIMEOUT_INT | \
+EMAC_TX_UNDERFLOW_INT | \
+EMAC_TX_EARLY_INT |\
+EMAC_INT_MSK_COMMON)
+#define EMAC_INT_MSK_RX(EMAC_RX_INT | \
+EMAC_RX_BUF_UA_INT | \
+EMAC_RX_DMA_STOP_INT | \
+EMAC_RX_TIMEOUT_INT | \
+EMAC_RX_OVERFLOW_INT | \
+EMAC_RX_EARLY_INT | \
+EMAC_INT_MSK_COMMON)
+
 #define MAC_ADDR_TYPE_DST BIT(31)
 
 /* H3 specific bits for EPHY */
@@ -412,13 +428,19 @@ static void sun8i_dwmac_dma_stop_rx(void __iomem *ioaddr, 
u32 chan)
 }
 
 static int sun8i_dwmac_dma_interrupt(void __iomem *ioaddr,
-struct stmmac_extra_stats *x, u32 chan)
+struct stmmac_extra_stats *x, u32 chan,
+u32 dir)
 {
u32 v;
int ret = 0;
 
v = readl(ioaddr + EMAC_INT_STA);
 
+   if (dir == DMA_DIR_RX)
+   v &= EMAC_INT_MSK_RX;
+   else if (dir == DMA_DIR_TX)
+   v &= EMAC_INT_MSK_TX;
+
if (v & EMAC_TX_INT) {
ret |= handle_tx;
x->tx_normal_irq_n++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 8391ca63d943..5c0c53832adb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -149,6 +149,25 @@
 #define DMA_CHAN_STATUS_TPSBIT(1)
 #define DMA_CHAN_STATUS_TI BIT(0)
 
+#define DMA_CHAN_STATUS_MSK_COMMON (DMA_CHAN_STATUS_NIS | \
+DMA_CHAN_STATUS_AIS | \
+DMA_CHAN_STATUS_CDE | \
+DMA_CHAN_STATUS_FBE)
+
+#define DMA_CHAN_STATUS_MSK_RX (DMA_CHAN_STATUS_REB | \
+DMA_CHAN_STATUS_ERI | \
+DMA_CHAN_STATUS_RWT | \
+DMA_CHAN_STATUS_RPS | \
+DMA_CHAN_STATUS_RBU | \
+DMA_CHAN_STATUS_RI | \
+DMA_CHAN_STATUS_MSK_COMMON)
+
+#define DMA_CHAN_STATUS_MSK_TX (DMA_CHAN_STATUS_ETI | \
+DMA_CHAN_STATUS_TBU | \
+DMA_CHAN_STATUS_TPS | \
+   

[PATCH v1 net-next 2/5] net: stmmac: make stmmac_interrupt() function more friendly to MSI

2021-03-03 Thread Voon Weifeng
From: Ong Boon Leong 

Refactor stmmac_interrupt() by introducing stmmac_common_interrupt()
so that we prepare the ISR operation to be friendly to MSI later.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 59 +++
 1 file changed, 36 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 70c2eb7fc3eb..eb1fcf20aacd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4106,21 +4106,8 @@ static int stmmac_set_features(struct net_device *netdev,
return 0;
 }
 
-/**
- *  stmmac_interrupt - main ISR
- *  @irq: interrupt number.
- *  @dev_id: to pass the net device pointer (must be valid).
- *  Description: this is the main driver interrupt service routine.
- *  It can call:
- *  o DMA service routine (to manage incoming frame reception and transmission
- *status)
- *  o Core interrupts to manage: remote wake-up, management counter, LPI
- *interrupts.
- */
-static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+static void stmmac_common_interrupt(struct stmmac_priv *priv)
 {
-   struct net_device *dev = (struct net_device *)dev_id;
-   struct stmmac_priv *priv = netdev_priv(dev);
u32 rx_cnt = priv->plat->rx_queues_to_use;
u32 tx_cnt = priv->plat->tx_queues_to_use;
u32 queues_count;
@@ -4133,13 +4120,6 @@ static irqreturn_t stmmac_interrupt(int irq, void 
*dev_id)
if (priv->irq_wake)
pm_wakeup_event(priv->device, 0);
 
-   /* Check if adapter is up */
-   if (test_bit(STMMAC_DOWN, >state))
-   return IRQ_HANDLED;
-   /* Check if a fatal error happened */
-   if (stmmac_safety_feat_interrupt(priv))
-   return IRQ_HANDLED;
-
/* To handle GMAC own interrupts */
if ((priv->plat->has_gmac) || xmac) {
int status = stmmac_host_irq_status(priv, priv->hw, 
>xstats);
@@ -4170,11 +4150,44 @@ static irqreturn_t stmmac_interrupt(int irq, void 
*dev_id)
/* PCS link status */
if (priv->hw->pcs) {
if (priv->xstats.pcs_link)
-   netif_carrier_on(dev);
+   netif_carrier_on(priv->dev);
else
-   netif_carrier_off(dev);
+   netif_carrier_off(priv->dev);
}
}
+}
+
+/**
+ *  stmmac_interrupt - main ISR
+ *  @irq: interrupt number.
+ *  @dev_id: to pass the net device pointer.
+ *  Description: this is the main driver interrupt service routine.
+ *  It can call:
+ *  o DMA service routine (to manage incoming frame reception and transmission
+ *status)
+ *  o Core interrupts to manage: remote wake-up, management counter, LPI
+ *interrupts.
+ */
+static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+{
+   struct net_device *dev = (struct net_device *)dev_id;
+   struct stmmac_priv *priv = netdev_priv(dev);
+
+   if (unlikely(!dev)) {
+   netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
+   return IRQ_NONE;
+   }
+
+   /* Check if adapter is up */
+   if (test_bit(STMMAC_DOWN, >state))
+   return IRQ_HANDLED;
+
+   /* Check if a fatal error happened */
+   if (stmmac_safety_feat_interrupt(priv))
+   return IRQ_HANDLED;
+
+   /* To handle Common interrupts */
+   stmmac_common_interrupt(priv);
 
/* To handle DMA interrupts */
stmmac_dma_interrupt(priv);
-- 
2.17.1



[PATCH v1 net-next 0/5] net: stmmac: enable multi-vector MSI

2021-03-03 Thread Voon Weifeng
This patchset adds support for multi MSI interrupts in addition to
current single common interrupt implementation. Each MSI interrupt is tied
to a newly introduce interrupt service routine(ISR). Hence, each interrupt
will only go through the corresponding ISR.

In order to increase the efficiency, enabling multi MSI interrupt will
automatically select the interrupt mode configuration INTM=1. When INTM=1,
the TX/RX transfer complete signal will only asserted on corresponding
sbd_perch_tx_intr_o[] or sbd_perch_rx_intr_o[] without asserting signal
on the common sbd_intr_o. Hence, for each TX/RX interrupts, only the
corresponding ISR will be triggered.

Every vendor might have different MSI vector assignment. So, this patchset
only includes multi-vector MSI assignment for Intel platform.

Ong Boon Leong (4):
  net: stmmac: introduce DMA interrupt status masking per traffic
direction
  net: stmmac: make stmmac_interrupt() function more friendly to MSI
  net: stmmac: introduce MSI Interrupt routines for mac, safety, RX & TX
  stmmac: intel: add support for multi-vector msi and msi-x

Wong, Vee Khee (1):
  net: stmmac: use interrupt mode INTM=1 for multi-MSI

 drivers/net/ethernet/stmicro/stmmac/common.h  |  21 +
 .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 112 +++-
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c |  24 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |   8 +
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |  24 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |  30 +-
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   |  22 +-
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |   8 +-
 .../net/ethernet/stmicro/stmmac/dwxgmac2.h|   6 +
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c|   8 +-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|   2 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  16 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 482 +++---
 include/linux/stmmac.h|   9 +
 14 files changed, 676 insertions(+), 96 deletions(-)

-- 
2.17.1



[PATCH v1 net-next 4/5] stmmac: intel: add support for multi-vector msi and msi-x

2021-03-03 Thread Voon Weifeng
From: Ong Boon Leong 

Intel mgbe controller supports multi-vector interrupts:
msi_rx_vec  0,2,4,6,8,10,12,14
msi_tx_vec  1,3,5,7,9,11,13,15
msi_sfty_ue_vec 26
msi_sfty_ce_vec 27
msi_lpi_vec 28
msi_mac_vec 29

During probe(), the driver will starts with request allocation for
multi-vector interrupts. If it fails, then it will automatically fallback
to request allocation for single interrupts.

Signed-off-by: Ong Boon Leong 
Co-developed-by: Voon Weifeng 
Signed-off-by: Voon Weifeng 
---
 .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 112 +-
 1 file changed, 106 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index 751dfdeec41c..316428bb6a01 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -330,6 +330,14 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
/* Use the last Rx queue */
plat->vlan_fail_q = plat->rx_queues_to_use - 1;
 
+   /* Setup MSI vector offset specific to Intel mGbE controller */
+   plat->msi_mac_vec = 29;
+   plat->msi_lpi_vec = 28;
+   plat->msi_sfty_ce_vec = 27;
+   plat->msi_sfty_ue_vec = 26;
+   plat->msi_rx_base_vec = 0;
+   plat->msi_tx_base_vec = 1;
+
return 0;
 }
 
@@ -578,6 +586,79 @@ static const struct stmmac_pci_info quark_info = {
.setup = quark_default_data,
 };
 
+static int stmmac_config_single_msi(struct pci_dev *pdev,
+   struct plat_stmmacenet_data *plat,
+   struct stmmac_resources *res)
+{
+   int ret;
+
+   ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+   if (ret < 0) {
+   dev_info(>dev, "%s: Single IRQ enablement failed\n",
+__func__);
+   return ret;
+   }
+
+   res->irq = pci_irq_vector(pdev, 0);
+   res->wol_irq = res->irq;
+   plat->multi_msi_en = 0;
+   dev_info(>dev, "%s: Single IRQ enablement successful\n",
+__func__);
+
+   return 0;
+}
+
+static int stmmac_config_multi_msi(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat,
+  struct stmmac_resources *res)
+{
+   int ret;
+   int i;
+
+   ret = pci_alloc_irq_vectors(pdev, 2, STMMAC_MSI_VEC_MAX,
+   PCI_IRQ_MSI | PCI_IRQ_MSIX);
+   if (ret < 0) {
+   dev_info(>dev, "%s: multi MSI enablement failed\n",
+__func__);
+   return ret;
+   }
+
+   if (plat->msi_rx_base_vec >= STMMAC_MSI_VEC_MAX ||
+   plat->msi_tx_base_vec >= STMMAC_MSI_VEC_MAX) {
+   dev_info(>dev, "%s: Invalid RX & TX vector defined\n",
+__func__);
+   return -1;
+   }
+
+   /* For RX MSI */
+   for (i = 0; i < plat->rx_queues_to_use; i++) {
+   res->rx_irq[i] = pci_irq_vector(pdev,
+   plat->msi_rx_base_vec + i * 2);
+   }
+
+   /* For TX MSI */
+   for (i = 0; i < plat->tx_queues_to_use; i++) {
+   res->tx_irq[i] = pci_irq_vector(pdev,
+   plat->msi_tx_base_vec + i * 2);
+   }
+
+   if (plat->msi_mac_vec < STMMAC_MSI_VEC_MAX)
+   res->irq = pci_irq_vector(pdev, plat->msi_mac_vec);
+   if (plat->msi_wol_vec < STMMAC_MSI_VEC_MAX)
+   res->wol_irq = pci_irq_vector(pdev, plat->msi_wol_vec);
+   if (plat->msi_lpi_vec < STMMAC_MSI_VEC_MAX)
+   res->lpi_irq = pci_irq_vector(pdev, plat->msi_lpi_vec);
+   if (plat->msi_sfty_ce_vec < STMMAC_MSI_VEC_MAX)
+   res->sfty_ce_irq = pci_irq_vector(pdev, plat->msi_sfty_ce_vec);
+   if (plat->msi_sfty_ue_vec < STMMAC_MSI_VEC_MAX)
+   res->sfty_ue_irq = pci_irq_vector(pdev, plat->msi_sfty_ue_vec);
+
+   plat->multi_msi_en = 1;
+   dev_info(>dev, "%s: multi MSI enablement successful\n", __func__);
+
+   return 0;
+}
+
 /**
  * intel_eth_pci_probe
  *
@@ -635,18 +716,24 @@ static int intel_eth_pci_probe(struct pci_dev *pdev,
plat->bsp_priv = intel_priv;
intel_priv->mdio_adhoc_addr = 0x15;
 
+   /* Initialize all MSI vectors to invalid so that it can be set
+* according to platform data settings below.
+* Note: MSI vector takes value from 0 upto 31 (STMMAC_MSI_VEC_MAX)
+*/
+   plat->msi_mac_vec = STMMAC_MSI_VEC_MAX;
+   plat->msi_wol_vec = STMMAC_MSI_VEC_MAX;
+   plat->msi_lpi_vec = STMMAC_MSI_VEC_MAX;
+   plat->msi_

[PATCH v1 net-next 3/5] net: stmmac: introduce MSI Interrupt routines for mac, safety, RX & TX

2021-03-03 Thread Voon Weifeng
From: Ong Boon Leong 

Now we introduce MSI interrupt service routines and hook these routines
up if stmmac_open() sees valid irq line being requested:-

stmmac_mac_interrupt():- MAC (dev->irq), WOL (wol_irq), LPI (lpi_irq)
stmmac_safety_interrupt() :- Safety Feat Correctible Error (sfty_ce_irq)
 & Uncorrectible Error (sfty_ue_irq)
stmmac_msi_intr_rx()  :- For all RX MSI irq (rx_irq)
stmmac_msi_intr_tx()  :- For all TX MSI irq (tx_irq)

Each of IRQs will have its unique name so that we can differentiate
them easily under /proc/interrupts.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  15 +
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  16 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 415 --
 include/linux/stmmac.h|   8 +
 4 files changed, 409 insertions(+), 45 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index cf8ad27824d4..b6a012eb7519 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -253,6 +253,9 @@ struct stmmac_safety_stats {
 #define DMA_HW_FEAT_ACTPHYIF   0x7000  /* Active/selected PHY iface */
 #define DEFAULT_DMA_PBL8
 
+/* MSI defines */
+#define STMMAC_MSI_VEC_MAX 32
+
 /* PCS status and mask defines */
 #definePCS_ANE_IRQ BIT(2)  /* PCS Auto-Negotiation */
 #definePCS_LINK_IRQBIT(1)  /* PCS Link */
@@ -309,6 +312,18 @@ enum dma_irq_dir {
DMA_DIR_RXTX = 0x3,
 };
 
+enum request_irq_err {
+   REQ_IRQ_ERR_ALL,
+   REQ_IRQ_ERR_TX,
+   REQ_IRQ_ERR_RX,
+   REQ_IRQ_ERR_SFTY_UE,
+   REQ_IRQ_ERR_SFTY_CE,
+   REQ_IRQ_ERR_LPI,
+   REQ_IRQ_ERR_WOL,
+   REQ_IRQ_ERR_MAC,
+   REQ_IRQ_ERR_NO,
+};
+
 /* EEE and LPI defines */
 #defineCORE_IRQ_TX_PATH_IN_LPI_MODE(1 << 0)
 #defineCORE_IRQ_TX_PATH_EXIT_LPI_MODE  (1 << 1)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index e553b9a1f785..9a37a7b4dec1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -30,6 +30,10 @@ struct stmmac_resources {
int wol_irq;
int lpi_irq;
int irq;
+   int sfty_ce_irq;
+   int sfty_ue_irq;
+   int rx_irq[MTL_MAX_RX_QUEUES];
+   int tx_irq[MTL_MAX_TX_QUEUES];
 };
 
 struct stmmac_tx_info {
@@ -225,6 +229,18 @@ struct stmmac_priv {
void __iomem *mmcaddr;
void __iomem *ptpaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+   int sfty_ce_irq;
+   int sfty_ue_irq;
+   int rx_irq[MTL_MAX_RX_QUEUES];
+   int tx_irq[MTL_MAX_TX_QUEUES];
+   /*irq name */
+   char int_name_mac[IFNAMSIZ + 9];
+   char int_name_wol[IFNAMSIZ + 9];
+   char int_name_lpi[IFNAMSIZ + 9];
+   char int_name_sfty_ce[IFNAMSIZ + 10];
+   char int_name_sfty_ue[IFNAMSIZ + 10];
+   char int_name_rx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 14];
+   char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
 
 #ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_dir;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index eb1fcf20aacd..e9cf8f672126 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -104,6 +104,11 @@ module_param(chain_mode, int, 0444);
 MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode");
 
 static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+/* For MSI interrupts handling */
+static irqreturn_t stmmac_mac_interrupt(int irq, void *dev_id);
+static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id);
+static irqreturn_t stmmac_msi_intr_tx(int irq, void *data);
+static irqreturn_t stmmac_msi_intr_rx(int irq, void *data);
 
 #ifdef CONFIG_DEBUG_FS
 static const struct net_device_ops stmmac_netdev_ops;
@@ -2785,6 +2790,238 @@ static void stmmac_hw_teardown(struct net_device *dev)
clk_disable_unprepare(priv->plat->clk_ptp_ref);
 }
 
+static void stmmac_free_irq(struct net_device *dev,
+   enum request_irq_err irq_err, int irq_idx)
+{
+   struct stmmac_priv *priv = netdev_priv(dev);
+   int j;
+
+   switch (irq_err) {
+   case REQ_IRQ_ERR_ALL:
+   irq_idx = priv->plat->tx_queues_to_use;
+   fallthrough;
+   case REQ_IRQ_ERR_TX:
+   for (j = irq_idx - 1; j >= 0; j--) {
+   if (priv->tx_irq[j] > 0)
+   free_irq(priv->tx_irq[j], >tx_queue[j]);
+   }
+   irq_idx = priv->plat->rx_queues_to_use;
+   fallthrough;
+   case R

[PATCH v1 net-next 5/5] net: stmmac: use interrupt mode INTM=1 for multi-MSI

2021-03-03 Thread Voon Weifeng
From: "Wong, Vee Khee" 

For interrupt mode INTM=0, TX/RX transfer complete will trigger signal
not only on sbd_perch_[tx|rx]_intr_o (Transmit/Receive Per Channel) but
also on the sbd_intr_o (Common).

As for multi-MSI implementation, setting interrupt mode INTM=1 is more
efficient as each TX intr and RX intr (TI/RI) will be handled by TX/RX ISR
without the need of calling the common MAC ISR.

Updated the TX/RX NORMAL interrupts status checking process as the
NIS status bit is not asserted for any RI/TI events for INTM=1.

Signed-off-by: Wong, Vee Khee 
Co-developed-by: Voon Weifeng 
Signed-off-by: Voon Weifeng 
---
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |  8 +++
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |  3 +++
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  | 23 +--
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  1 +
 include/linux/stmmac.h|  1 +
 5 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index bb29bfcd62c3..57d54a924169 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -144,6 +144,14 @@ static void dwmac4_dma_init(void __iomem *ioaddr,
value |= DMA_SYS_BUS_EAME;
 
writel(value, ioaddr + DMA_SYS_BUS_MODE);
+
+   value = readl(ioaddr + DMA_BUS_MODE);
+
+   if (dma_cfg->multi_msi_en) {
+   value &= ~DMA_BUS_MODE_INTM_MASK;
+   value |= (DMA_BUS_MODE_INTM_MODE1 << DMA_BUS_MODE_INTM_SHIFT);
+   }
+   writel(value, ioaddr + DMA_BUS_MODE);
 }
 
 static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 5c0c53832adb..05481eb13ba6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -25,6 +25,9 @@
 #define DMA_TBS_CTRL   0x1050
 
 /* DMA Bus Mode bitmap */
+#define DMA_BUS_MODE_INTM_MASK GENMASK(17, 16)
+#define DMA_BUS_MODE_INTM_SHIFT16
+#define DMA_BUS_MODE_INTM_MODE10x1
 #define DMA_BUS_MODE_SFT_RESET BIT(0)
 
 /* DMA SYS Bus Mode bitmap */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index 7154312d6f86..95a20e958c72 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -170,20 +170,19 @@ int dwmac4_dma_interrupt(void __iomem *ioaddr,
}
}
/* TX/RX NORMAL interrupts */
-   if (likely(intr_status & DMA_CHAN_STATUS_NIS)) {
+   if (likely(intr_status & DMA_CHAN_STATUS_NIS))
x->normal_irq_n++;
-   if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
-   x->rx_normal_irq_n++;
-   ret |= handle_rx;
-   }
-   if (likely(intr_status & (DMA_CHAN_STATUS_TI |
- DMA_CHAN_STATUS_TBU))) {
-   x->tx_normal_irq_n++;
-   ret |= handle_tx;
-   }
-   if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
-   x->rx_early_irq++;
+   if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
+   x->rx_normal_irq_n++;
+   ret |= handle_rx;
+   }
+   if (likely(intr_status & (DMA_CHAN_STATUS_TI |
+   DMA_CHAN_STATUS_TBU))) {
+   x->tx_normal_irq_n++;
+   ret |= handle_tx;
}
+   if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
+   x->rx_early_irq++;
 
writel(intr_status & intr_en, ioaddr + DMA_CHAN_STATUS(chan));
return ret;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index e9cf8f672126..e55e83c65756 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -5240,6 +5240,7 @@ int stmmac_dvr_probe(struct device *device,
priv->plat = plat_dat;
priv->ioaddr = res->addr;
priv->dev->base_addr = (unsigned long)res->addr;
+   priv->plat->dma_cfg->multi_msi_en = priv->plat->multi_msi_en;
 
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 3bdf27a28fb5..9dc535c1ce11 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -95,6 +95,7 @@ struct stmmac_dma_cfg {
int mixed_burst;
bool aal;
bool eame;
+   bool multi_msi_en;
 };
 
 #define AXI_BLEN   7
-- 
2.17.1



[RESEND v3 net-next] net: stmmac: Enable EEE HW LPI timer with auto SW/HW switching

2020-10-27 Thread Voon Weifeng
From: "Vineetha G. Jaya Kumaran" 

This patch enables the HW LPI Timer which controls the automatic entry
and exit of the LPI state.
The EEE LPI timer value is configured through ethtool. The driver will
auto select the LPI HW timer if the value in the HW timer supported range.
Else, the driver will fallback to SW timer.

Signed-off-by: Vineetha G. Jaya Kumaran 
Signed-off-by: Voon Weifeng 
---
v3 changelog:
-Changed stmmac_lpi_entry_timer_config() to static function

v2 changelog:
-removed #define for LPI_ET_ENABLE and LPI_ET_DISABLE and directly use
 literals
-removed not required function header in stmmac.h
-renamed stmmac_lpi_entry_timer_enable() to stmmac_lpi_entry_timer_config()
-Moved stmmac_lpi_entry_timer_enable() up in the file before
 stmmac_disable_eee_mode()

 drivers/net/ethernet/stmicro/stmmac/common.h  |  1 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h  |  2 ++
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 24 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  3 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  1 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +--
 6 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index df7de50497a0..6f271c46368d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -402,6 +402,7 @@ struct dma_features {
 /* Default LPI timers */
 #define STMMAC_DEFAULT_LIT_LS  0x3E8
 #define STMMAC_DEFAULT_TWT_LS  0x1E
+#define STMMAC_ET_MAX  0xF
 
 #define STMMAC_CHAIN_MODE  0x1
 #define STMMAC_RING_MODE   0x2
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 592b043f9676..82df91c130f7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -176,9 +176,11 @@ enum power_event {
  */
 #define GMAC4_LPI_CTRL_STATUS  0xd0
 #define GMAC4_LPI_TIMER_CTRL   0xd4
+#define GMAC4_LPI_ENTRY_TIMER  0xd8
 
 /* LPI control and status defines */
 #define GMAC4_LPI_CTRL_STATUS_LPITCSE  BIT(21) /* LPI Tx Clock Stop Enable */
+#define GMAC4_LPI_CTRL_STATUS_LPIATE   BIT(20) /* LPI Timer Enable */
 #define GMAC4_LPI_CTRL_STATUS_LPITXA   BIT(19) /* Enable LPI TX Automate */
 #define GMAC4_LPI_CTRL_STATUS_PLS  BIT(17) /* PHY Link Status */
 #define GMAC4_LPI_CTRL_STATUS_LPIENBIT(16) /* LPI Enable */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 002791b77356..3ed4f4cda7f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -379,6 +379,27 @@ static void dwmac4_set_eee_pls(struct mac_device_info *hw, 
int link)
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
 }
 
+static void dwmac4_set_eee_lpi_entry_timer(struct mac_device_info *hw, int et)
+{
+   void __iomem *ioaddr = hw->pcsr;
+   int value = et & STMMAC_ET_MAX;
+   int regval;
+
+   /* Program LPI entry timer value into register */
+   writel(value, ioaddr + GMAC4_LPI_ENTRY_TIMER);
+
+   /* Enable/disable LPI entry timer */
+   regval = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA;
+
+   if (et)
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIATE;
+   else
+   regval &= ~GMAC4_LPI_CTRL_STATUS_LPIATE;
+
+   writel(regval, ioaddr + GMAC4_LPI_CTRL_STATUS);
+}
+
 static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
 {
void __iomem *ioaddr = hw->pcsr;
@@ -1164,6 +1185,7 @@ const struct stmmac_ops dwmac4_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1206,6 +1228,7 @@ const struct stmmac_ops dwmac410_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1249,6 +1272,7 @@ const struct stmmac_ops dwmac510_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
diff --git a/drivers/net/ethernet/

[PATCH v3 net-next] net: stmmac: Enable EEE HW LPI timer with auto SW/HW switching

2020-10-15 Thread Voon Weifeng
From: "Vineetha G. Jaya Kumaran" 

This patch enables the HW LPI Timer which controls the automatic entry
and exit of the LPI state.
The EEE LPI timer value is configured through ethtool. The driver will
auto select the LPI HW timer if the value in the HW timer supported range.
Else, the driver will fallback to SW timer.

Signed-off-by: Vineetha G. Jaya Kumaran 
Signed-off-by: Voon Weifeng 
---
v3 changelog:
-Changed stmmac_lpi_entry_timer_config() to static function

v2 changelog:
-removed #define for LPI_ET_ENABLE and LPI_ET_DISABLE and directly use
 literals
-removed not required function header in stmmac.h
-renamed stmmac_lpi_entry_timer_enable() to stmmac_lpi_entry_timer_config()
-Moved stmmac_lpi_entry_timer_enable() up in the file before
 stmmac_disable_eee_mode()

 drivers/net/ethernet/stmicro/stmmac/common.h  |  1 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h  |  2 ++
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 24 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  3 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  1 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +--
 6 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index df7de50497a0..6f271c46368d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -402,6 +402,7 @@ struct dma_features {
 /* Default LPI timers */
 #define STMMAC_DEFAULT_LIT_LS  0x3E8
 #define STMMAC_DEFAULT_TWT_LS  0x1E
+#define STMMAC_ET_MAX  0xF
 
 #define STMMAC_CHAIN_MODE  0x1
 #define STMMAC_RING_MODE   0x2
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 592b043f9676..82df91c130f7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -176,9 +176,11 @@ enum power_event {
  */
 #define GMAC4_LPI_CTRL_STATUS  0xd0
 #define GMAC4_LPI_TIMER_CTRL   0xd4
+#define GMAC4_LPI_ENTRY_TIMER  0xd8
 
 /* LPI control and status defines */
 #define GMAC4_LPI_CTRL_STATUS_LPITCSE  BIT(21) /* LPI Tx Clock Stop Enable */
+#define GMAC4_LPI_CTRL_STATUS_LPIATE   BIT(20) /* LPI Timer Enable */
 #define GMAC4_LPI_CTRL_STATUS_LPITXA   BIT(19) /* Enable LPI TX Automate */
 #define GMAC4_LPI_CTRL_STATUS_PLS  BIT(17) /* PHY Link Status */
 #define GMAC4_LPI_CTRL_STATUS_LPIENBIT(16) /* LPI Enable */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 002791b77356..3ed4f4cda7f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -379,6 +379,27 @@ static void dwmac4_set_eee_pls(struct mac_device_info *hw, 
int link)
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
 }
 
+static void dwmac4_set_eee_lpi_entry_timer(struct mac_device_info *hw, int et)
+{
+   void __iomem *ioaddr = hw->pcsr;
+   int value = et & STMMAC_ET_MAX;
+   int regval;
+
+   /* Program LPI entry timer value into register */
+   writel(value, ioaddr + GMAC4_LPI_ENTRY_TIMER);
+
+   /* Enable/disable LPI entry timer */
+   regval = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA;
+
+   if (et)
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIATE;
+   else
+   regval &= ~GMAC4_LPI_CTRL_STATUS_LPIATE;
+
+   writel(regval, ioaddr + GMAC4_LPI_CTRL_STATUS);
+}
+
 static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
 {
void __iomem *ioaddr = hw->pcsr;
@@ -1164,6 +1185,7 @@ const struct stmmac_ops dwmac4_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1206,6 +1228,7 @@ const struct stmmac_ops dwmac410_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1249,6 +1272,7 @@ const struct stmmac_ops dwmac510_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
diff --git a/drivers/net/ethernet/

[PATCH v2 net-next] net: stmmac: Enable EEE HW LPI timer with auto SW/HW switching

2020-10-15 Thread Voon Weifeng
From: "Vineetha G. Jaya Kumaran" 

This patch enables the HW LPI Timer which controls the automatic entry
and exit of the LPI state.
The EEE LPI timer value is configured through ethtool. The driver will
auto select the LPI HW timer if the value in the HW timer supported range.
Else, the driver will fallback to SW timer.

Signed-off-by: Vineetha G. Jaya Kumaran 
Signed-off-by: Voon Weifeng 
---
v2 changelog:
-removed #define for LPI_ET_ENABLE and LPI_ET_DISABLE and directly use
 literals
-removed not required function header in stmmac.h
-renamed stmmac_lpi_entry_timer_enable() to stmmac_lpi_entry_timer_config()
-Moved stmmac_lpi_entry_timer_enable() up in the file before
 stmmac_disable_eee_mode()

 drivers/net/ethernet/stmicro/stmmac/common.h  |  1 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h  |  2 ++
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 24 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  3 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  1 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +--
 6 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index df7de50497a0..6f271c46368d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -402,6 +402,7 @@ struct dma_features {
 /* Default LPI timers */
 #define STMMAC_DEFAULT_LIT_LS  0x3E8
 #define STMMAC_DEFAULT_TWT_LS  0x1E
+#define STMMAC_ET_MAX  0xF
 
 #define STMMAC_CHAIN_MODE  0x1
 #define STMMAC_RING_MODE   0x2
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 592b043f9676..82df91c130f7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -176,9 +176,11 @@ enum power_event {
  */
 #define GMAC4_LPI_CTRL_STATUS  0xd0
 #define GMAC4_LPI_TIMER_CTRL   0xd4
+#define GMAC4_LPI_ENTRY_TIMER  0xd8
 
 /* LPI control and status defines */
 #define GMAC4_LPI_CTRL_STATUS_LPITCSE  BIT(21) /* LPI Tx Clock Stop Enable */
+#define GMAC4_LPI_CTRL_STATUS_LPIATE   BIT(20) /* LPI Timer Enable */
 #define GMAC4_LPI_CTRL_STATUS_LPITXA   BIT(19) /* Enable LPI TX Automate */
 #define GMAC4_LPI_CTRL_STATUS_PLS  BIT(17) /* PHY Link Status */
 #define GMAC4_LPI_CTRL_STATUS_LPIENBIT(16) /* LPI Enable */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 002791b77356..3ed4f4cda7f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -379,6 +379,27 @@ static void dwmac4_set_eee_pls(struct mac_device_info *hw, 
int link)
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
 }
 
+static void dwmac4_set_eee_lpi_entry_timer(struct mac_device_info *hw, int et)
+{
+   void __iomem *ioaddr = hw->pcsr;
+   int value = et & STMMAC_ET_MAX;
+   int regval;
+
+   /* Program LPI entry timer value into register */
+   writel(value, ioaddr + GMAC4_LPI_ENTRY_TIMER);
+
+   /* Enable/disable LPI entry timer */
+   regval = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA;
+
+   if (et)
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIATE;
+   else
+   regval &= ~GMAC4_LPI_CTRL_STATUS_LPIATE;
+
+   writel(regval, ioaddr + GMAC4_LPI_CTRL_STATUS);
+}
+
 static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
 {
void __iomem *ioaddr = hw->pcsr;
@@ -1164,6 +1185,7 @@ const struct stmmac_ops dwmac4_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1206,6 +1228,7 @@ const struct stmmac_ops dwmac410_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1249,6 +1272,7 @@ const struct stmmac_ops dwmac510_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h 
b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index e2

RE: [PATCH v1 net-next] net: stmmac: Enable EEE HW LPI timer with auto SW/HW switching

2020-10-08 Thread Voon, Weifeng
> Subject: [PATCH v1 net-next] net: stmmac: Enable EEE HW LPI timer with auto
> SW/HW switching
> 
> From: "Vineetha G. Jaya Kumaran" 
> 
> This patch enables the HW LPI Timer which controls the automatic entry and
> exit of the LPI state.
> The EEE LPI timer value is configured through ethtool. The driver will auto
> select the LPI HW timer if the value in the HW timer supported range.
> Else, the driver will fallback to SW timer.
> 
> Signed-off-by: Vineetha G. Jaya Kumaran 
> Signed-off-by: Voon Weifeng 

Please help to review and comment. Thanks. 
Weifeng



[PATCH v1 net-next] net: stmmac: Enable EEE HW LPI timer with auto SW/HW switching

2020-10-08 Thread Voon Weifeng
From: "Vineetha G. Jaya Kumaran" 

This patch enables the HW LPI Timer which controls the automatic entry
and exit of the LPI state.
The EEE LPI timer value is configured through ethtool. The driver will
auto select the LPI HW timer if the value in the HW timer supported range.
Else, the driver will fallback to SW timer.

Signed-off-by: Vineetha G. Jaya Kumaran 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  3 ++
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h  |  2 ++
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 24 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  3 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  2 ++
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +--
 6 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index df7de50497a0..f59c4a1c1674 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -402,6 +402,9 @@ struct dma_features {
 /* Default LPI timers */
 #define STMMAC_DEFAULT_LIT_LS  0x3E8
 #define STMMAC_DEFAULT_TWT_LS  0x1E
+#define STMMAC_ET_MAX  0xF
+#define LPI_ET_ENABLE  1
+#define LPI_ET_DISABLE 0
 
 #define STMMAC_CHAIN_MODE  0x1
 #define STMMAC_RING_MODE   0x2
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 592b043f9676..82df91c130f7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -176,9 +176,11 @@ enum power_event {
  */
 #define GMAC4_LPI_CTRL_STATUS  0xd0
 #define GMAC4_LPI_TIMER_CTRL   0xd4
+#define GMAC4_LPI_ENTRY_TIMER  0xd8
 
 /* LPI control and status defines */
 #define GMAC4_LPI_CTRL_STATUS_LPITCSE  BIT(21) /* LPI Tx Clock Stop Enable */
+#define GMAC4_LPI_CTRL_STATUS_LPIATE   BIT(20) /* LPI Timer Enable */
 #define GMAC4_LPI_CTRL_STATUS_LPITXA   BIT(19) /* Enable LPI TX Automate */
 #define GMAC4_LPI_CTRL_STATUS_PLS  BIT(17) /* PHY Link Status */
 #define GMAC4_LPI_CTRL_STATUS_LPIENBIT(16) /* LPI Enable */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 002791b77356..3ed4f4cda7f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -379,6 +379,27 @@ static void dwmac4_set_eee_pls(struct mac_device_info *hw, 
int link)
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
 }
 
+static void dwmac4_set_eee_lpi_entry_timer(struct mac_device_info *hw, int et)
+{
+   void __iomem *ioaddr = hw->pcsr;
+   int value = et & STMMAC_ET_MAX;
+   int regval;
+
+   /* Program LPI entry timer value into register */
+   writel(value, ioaddr + GMAC4_LPI_ENTRY_TIMER);
+
+   /* Enable/disable LPI entry timer */
+   regval = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA;
+
+   if (et)
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIATE;
+   else
+   regval &= ~GMAC4_LPI_CTRL_STATUS_LPIATE;
+
+   writel(regval, ioaddr + GMAC4_LPI_CTRL_STATUS);
+}
+
 static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
 {
void __iomem *ioaddr = hw->pcsr;
@@ -1164,6 +1185,7 @@ const struct stmmac_ops dwmac4_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1206,6 +1228,7 @@ const struct stmmac_ops dwmac410_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1249,6 +1272,7 @@ const struct stmmac_ops dwmac510_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h 
b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index e2dca9b6e992..b40b2e0667bb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -337,6 +337,7 @@ struct stmmac_ops {
void (*set_eee_mode)(struct mac_device_info *hw,
 

RE: [PATCH v1 net-next] net: stmmac: Enable EEE HW LPI timer with auto SW/HW auto switch

2020-10-06 Thread Voon, Weifeng
> From: "Vineetha G. Jaya Kumaran" 
> 
> This patch enables the HW LPI Timer which controls the automatic entry and
> exit of the LPI state.
> The EEE LPI timer value is configured through ethtool. The driver will auto
> select the LPI HW timer if the value in the HW timer supported range.
> Else, the driver will fallback to SW timer.
> 
> Signed-off-by: Vineetha G. Jaya Kumaran 
> Signed-off-by: Voon Weifeng 
> ---

Please drop this patch. Sorry for accidentally sending out this patch.


[PATCH v1 net-next] net: stmmac: Enable EEE HW LPI timer with auto SW/HW auto switch

2020-10-06 Thread Voon Weifeng
From: "Vineetha G. Jaya Kumaran" 

This patch enables the HW LPI Timer which controls the automatic entry
and exit of the LPI state.
The EEE LPI timer value is configured through ethtool. The driver will
auto select the LPI HW timer if the value in the HW timer supported range.
Else, the driver will fallback to SW timer.

Signed-off-by: Vineetha G. Jaya Kumaran 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  3 ++
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h  |  2 ++
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 24 +++
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  3 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  1 +
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 30 +--
 include/linux/stmmac.h|  1 +
 7 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index df7de50497a0..f59c4a1c1674 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -402,6 +402,9 @@ struct dma_features {
 /* Default LPI timers */
 #define STMMAC_DEFAULT_LIT_LS  0x3E8
 #define STMMAC_DEFAULT_TWT_LS  0x1E
+#define STMMAC_ET_MAX  0xF
+#define LPI_ET_ENABLE  1
+#define LPI_ET_DISABLE 0
 
 #define STMMAC_CHAIN_MODE  0x1
 #define STMMAC_RING_MODE   0x2
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 592b043f9676..82df91c130f7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -176,9 +176,11 @@ enum power_event {
  */
 #define GMAC4_LPI_CTRL_STATUS  0xd0
 #define GMAC4_LPI_TIMER_CTRL   0xd4
+#define GMAC4_LPI_ENTRY_TIMER  0xd8
 
 /* LPI control and status defines */
 #define GMAC4_LPI_CTRL_STATUS_LPITCSE  BIT(21) /* LPI Tx Clock Stop Enable */
+#define GMAC4_LPI_CTRL_STATUS_LPIATE   BIT(20) /* LPI Timer Enable */
 #define GMAC4_LPI_CTRL_STATUS_LPITXA   BIT(19) /* Enable LPI TX Automate */
 #define GMAC4_LPI_CTRL_STATUS_PLS  BIT(17) /* PHY Link Status */
 #define GMAC4_LPI_CTRL_STATUS_LPIENBIT(16) /* LPI Enable */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 002791b77356..3ed4f4cda7f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -379,6 +379,27 @@ static void dwmac4_set_eee_pls(struct mac_device_info *hw, 
int link)
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
 }
 
+static void dwmac4_set_eee_lpi_entry_timer(struct mac_device_info *hw, int et)
+{
+   void __iomem *ioaddr = hw->pcsr;
+   int value = et & STMMAC_ET_MAX;
+   int regval;
+
+   /* Program LPI entry timer value into register */
+   writel(value, ioaddr + GMAC4_LPI_ENTRY_TIMER);
+
+   /* Enable/disable LPI entry timer */
+   regval = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA;
+
+   if (et)
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIATE;
+   else
+   regval &= ~GMAC4_LPI_CTRL_STATUS_LPIATE;
+
+   writel(regval, ioaddr + GMAC4_LPI_CTRL_STATUS);
+}
+
 static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
 {
void __iomem *ioaddr = hw->pcsr;
@@ -1164,6 +1185,7 @@ const struct stmmac_ops dwmac4_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1206,6 +1228,7 @@ const struct stmmac_ops dwmac410_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1249,6 +1272,7 @@ const struct stmmac_ops dwmac510_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h 
b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index e2dca9b6e992..b40b2e0667bb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -337,6 +337,7 @@ struct stmmac_ops {
voi

[PATCH v1 net-next] net: stmmac: Enable EEE HW LPI timer with auto SW/HW switching

2020-10-06 Thread Voon Weifeng
From: "Vineetha G. Jaya Kumaran" 

This patch enables the HW LPI Timer which controls the automatic entry
and exit of the LPI state.
The EEE LPI timer value is configured through ethtool. The driver will
auto select the LPI HW timer if the value in the HW timer supported range.
Else, the driver will fallback to SW timer.

Signed-off-by: Vineetha G. Jaya Kumaran 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  3 ++
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h  |  2 ++
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 24 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  3 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  2 ++
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +--
 6 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index df7de50497a0..f59c4a1c1674 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -402,6 +402,9 @@ struct dma_features {
 /* Default LPI timers */
 #define STMMAC_DEFAULT_LIT_LS  0x3E8
 #define STMMAC_DEFAULT_TWT_LS  0x1E
+#define STMMAC_ET_MAX  0xF
+#define LPI_ET_ENABLE  1
+#define LPI_ET_DISABLE 0
 
 #define STMMAC_CHAIN_MODE  0x1
 #define STMMAC_RING_MODE   0x2
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 592b043f9676..82df91c130f7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -176,9 +176,11 @@ enum power_event {
  */
 #define GMAC4_LPI_CTRL_STATUS  0xd0
 #define GMAC4_LPI_TIMER_CTRL   0xd4
+#define GMAC4_LPI_ENTRY_TIMER  0xd8
 
 /* LPI control and status defines */
 #define GMAC4_LPI_CTRL_STATUS_LPITCSE  BIT(21) /* LPI Tx Clock Stop Enable */
+#define GMAC4_LPI_CTRL_STATUS_LPIATE   BIT(20) /* LPI Timer Enable */
 #define GMAC4_LPI_CTRL_STATUS_LPITXA   BIT(19) /* Enable LPI TX Automate */
 #define GMAC4_LPI_CTRL_STATUS_PLS  BIT(17) /* PHY Link Status */
 #define GMAC4_LPI_CTRL_STATUS_LPIENBIT(16) /* LPI Enable */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 002791b77356..3ed4f4cda7f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -379,6 +379,27 @@ static void dwmac4_set_eee_pls(struct mac_device_info *hw, 
int link)
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
 }
 
+static void dwmac4_set_eee_lpi_entry_timer(struct mac_device_info *hw, int et)
+{
+   void __iomem *ioaddr = hw->pcsr;
+   int value = et & STMMAC_ET_MAX;
+   int regval;
+
+   /* Program LPI entry timer value into register */
+   writel(value, ioaddr + GMAC4_LPI_ENTRY_TIMER);
+
+   /* Enable/disable LPI entry timer */
+   regval = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA;
+
+   if (et)
+   regval |= GMAC4_LPI_CTRL_STATUS_LPIATE;
+   else
+   regval &= ~GMAC4_LPI_CTRL_STATUS_LPIATE;
+
+   writel(regval, ioaddr + GMAC4_LPI_CTRL_STATUS);
+}
+
 static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
 {
void __iomem *ioaddr = hw->pcsr;
@@ -1164,6 +1185,7 @@ const struct stmmac_ops dwmac4_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1206,6 +1228,7 @@ const struct stmmac_ops dwmac410_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
@@ -1249,6 +1272,7 @@ const struct stmmac_ops dwmac510_ops = {
.get_umac_addr = dwmac4_get_umac_addr,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
.set_eee_timer = dwmac4_set_eee_timer,
.set_eee_pls = dwmac4_set_eee_pls,
.pcs_ctrl_ane = dwmac4_ctrl_ane,
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h 
b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index e2dca9b6e992..b40b2e0667bb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -337,6 +337,7 @@ struct stmmac_ops {
void (*set_eee_mode)(struct mac_device_info *hw,
 

[PATCH v2 net] net: stmmac: Modify configuration method of EEE timers

2020-10-01 Thread Voon Weifeng
From: "Vineetha G. Jaya Kumaran" 

Ethtool manual stated that the tx-timer is the "the amount of time the
device should stay in idle mode prior to asserting its Tx LPI". The
previous implementation for "ethtool --set-eee tx-timer" sets the LPI TW
timer duration which is not correct. Hence, this patch fixes the
"ethtool --set-eee tx-timer" to configure the EEE LPI timer.

The LPI TW Timer will be using the defined default value instead of
"ethtool --set-eee tx-timer" which follows the EEE LS timer implementation.

Fixes: d765955d2ae0 ("stmmac: add the Energy Efficient Ethernet support")
Signed-off-by: Vineetha G. Jaya Kumaran 
Signed-off-by: Voon Weifeng 

Changelog V2
*Not removing/modifying the eee_timer.
*EEE LPI timer can be configured through ethtool and also the eee_timer
module param.
*EEE TW Timer will be configured with default value only, not able to be
configured through ethtool or module param. This follows the implementation
of the EEE LS Timer.
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  2 ++
 .../ethernet/stmicro/stmmac/stmmac_ethtool.c  | 12 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 23 ---
 3 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 9c02fc754bf1..545696971f65 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -203,6 +203,8 @@ struct stmmac_priv {
int eee_enabled;
int eee_active;
int tx_lpi_timer;
+   int tx_lpi_enabled;
+   int eee_tw_timer;
unsigned int mode;
unsigned int chain_mode;
int extend_desc;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 430a4b32ec1e..814879f91f76 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -665,6 +665,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev,
edata->eee_enabled = priv->eee_enabled;
edata->eee_active = priv->eee_active;
edata->tx_lpi_timer = priv->tx_lpi_timer;
+   edata->tx_lpi_enabled = priv->tx_lpi_enabled;
 
return phylink_ethtool_get_eee(priv->phylink, edata);
 }
@@ -678,6 +679,10 @@ static int stmmac_ethtool_op_set_eee(struct net_device 
*dev,
if (!priv->dma_cap.eee)
return -EOPNOTSUPP;
 
+   if (priv->tx_lpi_enabled != edata->tx_lpi_enabled)
+   netdev_warn(priv->dev,
+   "Setting EEE tx-lpi is not supported\n");
+
if (!edata->eee_enabled)
stmmac_disable_eee_mode(priv);
 
@@ -685,7 +690,12 @@ static int stmmac_ethtool_op_set_eee(struct net_device 
*dev,
if (ret)
return ret;
 
-   priv->tx_lpi_timer = edata->tx_lpi_timer;
+   if (edata->eee_enabled &&
+   priv->tx_lpi_timer != edata->tx_lpi_timer) {
+   priv->tx_lpi_timer = edata->tx_lpi_timer;
+   stmmac_eee_init(priv);
+   }
+
return 0;
 }
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 89b2b3472852..b56b13d64ab4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -94,7 +94,7 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | 
NETIF_MSG_PROBE |
 static int eee_timer = STMMAC_DEFAULT_LPI_TIMER;
 module_param(eee_timer, int, 0644);
 MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
-#define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x))
+#define STMMAC_LPI_T(x) (jiffies + usecs_to_jiffies(x))
 
 /* By default the driver will use the ring mode to manage tx and rx 
descriptors,
  * but allow user to force to use the chain instead of the ring
@@ -370,7 +370,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
struct stmmac_priv *priv = from_timer(priv, t, eee_ctrl_timer);
 
stmmac_enable_eee_mode(priv);
-   mod_timer(>eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
+   mod_timer(>eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
 }
 
 /**
@@ -383,7 +383,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
  */
 bool stmmac_eee_init(struct stmmac_priv *priv)
 {
-   int tx_lpi_timer = priv->tx_lpi_timer;
+   int eee_tw_timer = priv->eee_tw_timer;
 
/* Using PCS we cannot dial with the phy registers at this stage
 * so we do not support extra feature like EEE.
@@ -403,7 +403,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
if (priv->eee_enabled) {
netdev_dbg(priv->dev, "disable EEE\n");

[PATCH v1 net] net: stmmac: Modify configuration method of EEE timers

2020-09-28 Thread Voon Weifeng
From: "Vineetha G. Jaya Kumaran" 

Ethtool manual stated that the tx-timer is the "the amount of time the
device should stay in idle mode prior to asserting its Tx LPI". The
previous implementation for "ethtool --set-eee tx-timer" sets the LPI TW
timer duration which is not correct.

Hence, this patch fixes the the configuration of LPI TW timer via
module parameters instead of ethtool. And, "ethtool --set-eee tx-timer"
should configure EEE LPI timer.

Fixes: d765955d2ae0 ("stmmac: add the Energy Efficient Ethernet support")
Signed-off-by: Vineetha G. Jaya Kumaran 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  1 +
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  1 +
 .../ethernet/stmicro/stmmac/stmmac_ethtool.c  | 12 ++-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 35 +++
 4 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 127f75862962..7338babfebad 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -395,6 +395,7 @@ struct dma_features {
 /* Default LPI timers */
 #define STMMAC_DEFAULT_LIT_LS  0x3E8
 #define STMMAC_DEFAULT_TWT_LS  0x1E
+#define STMMAC_TWT_MAX 0x
 
 #define STMMAC_CHAIN_MODE  0x1
 #define STMMAC_RING_MODE   0x2
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 9c02fc754bf1..d5a83c45510e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -203,6 +203,7 @@ struct stmmac_priv {
int eee_enabled;
int eee_active;
int tx_lpi_timer;
+   int tx_lpi_enabled;
unsigned int mode;
unsigned int chain_mode;
int extend_desc;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 430a4b32ec1e..348bb8a9cf7f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -665,6 +665,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev,
edata->eee_enabled = priv->eee_enabled;
edata->eee_active = priv->eee_active;
edata->tx_lpi_timer = priv->tx_lpi_timer;
+   edata->tx_lpi_enabled = priv->tx_lpi_enabled;
 
return phylink_ethtool_get_eee(priv->phylink, edata);
 }
@@ -678,6 +679,10 @@ static int stmmac_ethtool_op_set_eee(struct net_device 
*dev,
if (!priv->dma_cap.eee)
return -EOPNOTSUPP;
 
+   if (priv->tx_lpi_enabled != edata->tx_lpi_enabled)
+   netdev_warn(priv->dev,
+   "Setting EEE tx-lpi is not supported\n");
+
if (!edata->eee_enabled)
stmmac_disable_eee_mode(priv);
 
@@ -685,7 +690,12 @@ static int stmmac_ethtool_op_set_eee(struct net_device 
*dev,
if (ret)
return ret;
 
-   priv->tx_lpi_timer = edata->tx_lpi_timer;
+   if (edata->eee_enabled && priv->tx_lpi_enabled &&
+   priv->tx_lpi_timer != edata->tx_lpi_timer) {
+   priv->tx_lpi_timer = edata->tx_lpi_timer;
+   stmmac_eee_init(priv);
+   }
+
return 0;
 }
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 89b2b3472852..2d1b9b76d678 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -90,11 +90,12 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | 
NETIF_MSG_PROBE |
  NETIF_MSG_LINK | NETIF_MSG_IFUP |
  NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
 
-#define STMMAC_DEFAULT_LPI_TIMER   1000
-static int eee_timer = STMMAC_DEFAULT_LPI_TIMER;
-module_param(eee_timer, int, 0644);
-MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
-#define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x))
+#define STMMAC_DEFAULT_LPI_TIMER   100
+#define STMMAC_LPI_T(x)(jiffies + usecs_to_jiffies(x))
+
+static int tw_timer = STMMAC_DEFAULT_TWT_LS;
+module_param(tw_timer, int, 0644);
+MODULE_PARM_DESC(tw_timer, "LPI TW timer value in msec");
 
 /* By default the driver will use the ring mode to manage tx and rx 
descriptors,
  * but allow user to force to use the chain instead of the ring
@@ -130,8 +131,8 @@ static void stmmac_verify_args(void)
flow_ctrl = FLOW_OFF;
if (unlikely((pause < 0) || (pause > 0x)))
pause = PAUSE_TIME;
-   if (eee_timer < 0)
-   eee_timer = STMMAC_DEFAULT_LPI_TIMER;
+   if (tw_timer < 0 || tw_timer > STMMAC_

[PATCH v1 net-next] stmmac: intel: Adding ref clock 1us tic for LPI cntr

2020-09-28 Thread Voon Weifeng
From: Rusaimi Amira Ruslan 

Adding reference clock (1us tic) for all LPI timer on Intel platforms.
The reference clock is derived from ptp clk. This also enables all LPI
counter.

Signed-off-by: Rusaimi Amira Ruslan 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c | 9 +
 drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c  | 9 +
 include/linux/stmmac.h | 1 +
 3 files changed, 19 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
index b1323d5c95b5..f61cb997a8f6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
@@ -11,6 +11,7 @@
 #include 
 #include 
 
+#include "dwmac4.h"
 #include "stmmac.h"
 #include "stmmac_platform.h"
 
@@ -146,6 +147,14 @@ static int intel_eth_plat_probe(struct platform_device 
*pdev)
}
 
plat_dat->bsp_priv = dwmac;
+   plat_dat->eee_usecs_rate = plat_dat->clk_ptp_rate;
+
+   if (plat_dat->eee_usecs_rate > 0) {
+   u32 tx_lpi_usec;
+
+   tx_lpi_usec = (plat_dat->eee_usecs_rate / 100) - 1;
+   writel(tx_lpi_usec, stmmac_res.addr + GMAC_1US_TIC_COUNTER);
+   }
 
ret = stmmac_dvr_probe(>dev, plat_dat, _res);
if (ret) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index ab0a81e0fea1..2af9458be95f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -6,6 +6,7 @@
 #include 
 #include 
 #include "dwmac-intel.h"
+#include "dwmac4.h"
 #include "stmmac.h"
 
 struct intel_priv_data {
@@ -295,6 +296,7 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->axi->axi_blen[2] = 16;
 
plat->ptp_max_adj = plat->clk_ptp_rate;
+   plat->eee_usecs_rate = plat->clk_ptp_rate;
 
/* Set system clock */
plat->stmmac_clk = clk_register_fixed_rate(>dev,
@@ -623,6 +625,13 @@ static int intel_eth_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;
 
+   if (plat->eee_usecs_rate > 0) {
+   u32 tx_lpi_usec;
+
+   tx_lpi_usec = (plat->eee_usecs_rate / 100) - 1;
+   writel(tx_lpi_usec, res.addr + GMAC_1US_TIC_COUNTER);
+   }
+
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
if (ret < 0)
return ret;
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 00e83c877496..628e28903b8b 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -200,5 +200,6 @@ struct plat_stmmacenet_data {
int has_xgmac;
bool vlan_fail_q_en;
u8 vlan_fail_q;
+   unsigned int eee_usecs_rate;
 };
 #endif
-- 
2.17.1



[PATCH v1 net] net: stmmac: removed enabling eee in EEE set callback

2020-09-23 Thread Voon Weifeng
EEE should be only be enabled during stmmac_mac_link_up() when the
link are up and being set up properly. set_eee should only do settings
configuration and disabling the eee.

Without this fix, turning on EEE using ethtool will return
"Operation not supported". This is due to the driver is in a dead loop
waiting for eee to be advertised in the for eee to be activated but the
driver will only configure the EEE advertisement after the eee is
activated.

Ethtool should only return "Operation not supported" if there is no EEE
capbility in the MAC controller.

Fixes: 8a7493e58ad6 ("net: stmmac: Fix a race in EEE enable callback")

Signed-off-by: Voon Weifeng 
---
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c  | 15 ---
 1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index ac5e8cc5fb9f..430a4b32ec1e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -675,23 +675,16 @@ static int stmmac_ethtool_op_set_eee(struct net_device 
*dev,
struct stmmac_priv *priv = netdev_priv(dev);
int ret;
 
-   if (!edata->eee_enabled) {
+   if (!priv->dma_cap.eee)
+   return -EOPNOTSUPP;
+
+   if (!edata->eee_enabled)
stmmac_disable_eee_mode(priv);
-   } else {
-   /* We are asking for enabling the EEE but it is safe
-* to verify all by invoking the eee_init function.
-* In case of failure it will return an error.
-*/
-   edata->eee_enabled = stmmac_eee_init(priv);
-   if (!edata->eee_enabled)
-   return -EOPNOTSUPP;
-   }
 
ret = phylink_ethtool_set_eee(priv->phylink, edata);
if (ret)
return ret;
 
-   priv->eee_enabled = edata->eee_enabled;
priv->tx_lpi_timer = edata->tx_lpi_timer;
return 0;
 }
-- 
2.17.1



[PATCH v3 net-next] net: stmmac: Add support for MDIO interrupts

2019-09-05 Thread Voon Weifeng
From: "Chuah, Kim Tatt" 

DW EQoS v5.xx controllers added capability for interrupt generation
when MDIO interface is done (GMII Busy bit is cleared).
This patch adds support for this interrupt on supported HW to avoid
polling on GMII Busy bit.

stmmac_mdio_read() & stmmac_mdio_write() will sleep until wake_up() is
called by the interrupt handler.

Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh, Hock Leong 
Reviewed-by: Ong Boon Leong 
Signed-off-by: Chuah, Kim Tatt 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 

Changelog v3
*Move the changelog to before the --- marker line
Changelog v2
*mdio interrupt mode or polling mode will depends on mdio interrupt
 enable bit
*Disable the mdio interrupt enable bit in stmmac_release
*Remove the condition for initialize wait queues
*Applied reverse Christmas tree
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |  2 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h  |  1 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c |  7 +++
 drivers/net/ethernet/stmicro/stmmac/dwmac5.c  |  8 
 drivers/net/ethernet/stmicro/stmmac/dwmac5.h  |  4 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.c|  9 
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  4 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  5 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 57 +++
 9 files changed, 89 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 49aa56ca09cc..775a1c114b1a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -448,6 +448,8 @@ struct mac_device_info {
unsigned int pcs;
unsigned int pmt;
unsigned int ps;
+   bool mdio_intr_en;
+   wait_queue_head_t mdio_busy_wait;
 };
 
 struct stmmac_rx_routing {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 2ed11a581d80..1be6a8a88b8f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -106,6 +106,7 @@ enum dwmac4_irq_status {
mmc_irq = 0x0100,
lpi_irq = 0x0020,
pmt_irq = 0x0010,
+   mdio_irq = 0x0004,
 };
 
 /* MAC PMT bitmap */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index fc9954e4a772..97fca6d65141 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -59,6 +59,9 @@ static void dwmac4_core_init(struct mac_device_info *hw,
if (hw->pcs)
value |= GMAC_PCS_IRQ_DEFAULT;
 
+   if (hw->mdio_intr_en)
+   value |= GMAC_INT_MDIO_EN;
+
writel(value, ioaddr + GMAC_INT_EN);
 }
 
@@ -629,6 +632,9 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
x->irq_rx_path_exit_lpi_mode_n++;
}
 
+   if (intr_status & mdio_irq)
+   wake_up(>mdio_busy_wait);
+
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
if (intr_status & PCS_RGSMIIIS_IRQ)
dwmac4_phystatus(ioaddr, x);
@@ -836,6 +842,7 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, 
bool enable)
.rxp_config = dwmac5_rxp_config,
.flex_pps_config = dwmac5_flex_pps_config,
.set_mac_loopback = dwmac4_set_mac_loopback,
+   .mdio_intr_dis = dwmac5_mdio_intr_dis,
 };
 
 int dwmac4_setup(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index 3f4f3132e16b..c58751e1dcb6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -549,3 +549,11 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
writel(val, ioaddr + MAC_PPS_CONTROL);
return 0;
 }
+
+void dwmac5_mdio_intr_dis(void __iomem *ioaddr)
+{
+   u32 val = readl(ioaddr + GMAC_INT_EN);
+
+   val &= ~GMAC_INT_MDIO_EN;
+   writel(val, ioaddr + GMAC_INT_EN);
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index 775db776b3cc..a56511a4c97d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -72,6 +72,9 @@
 #define TCEIE  BIT(0)
 #define DMA_ECC_INT_STATUS 0x1088
 
+/* MDIO interrupt enable in MAC_Interrupt_Enable register */
+#define GMAC_INT_MDIO_EN   BIT(18)
+
 int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp);
 int dwmac5_safety_feat_irq_status(struct net_device *ndev,
void __iomem *ioaddr, unsigned int asp,
@@ -83,5 +86,6 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct 
stmmac_tc_entry *entries,
 int dwmac5_fle

RE: [PATCH v2 net-next] net: stmmac: Add support for MDIO interrupts

2019-09-05 Thread Voon, Weifeng
> > The change log is near the end of the patch:
> > /**
> > --
> > Changelog v2
> > *mdio interrupt mode or polling mode will depends on mdio interrupt
> > enable bit *Disable the mdio interrupt enable bit in stmmac_release
> > *Remove the condition for initialize wait queues *Applied reverse
> > Christmas tree
> > 1.9.1
> 
> At the end, nobody sees it, because everybody else does it at the
> beginning.
> 
> https://www.kernel.org/doc/html/latest/process/submitting-
> patches.html?highlight=submitting#the-canonical-patch-format
> 
> This talks about the ---. David prefers to see the change log before the
> ---. Other maintainers want it after the ---.
> 
> >
> > >
> > > The formatting of this patch also looks a bit odd. Did you use git
> > > format-patch ; git send-email?
> >
> > Yes, I do git format-patch, then ./scripts/checkpatch.pl.
> > Lastly git send-email
> 
> What looked odd is the missing --- marker. git format-patch should of
> create that as part of the patch.
> 
>Andrew

I found out why as I did a git format-patch with -p which is without the
Stat. I will resent v3 to using correct format.

Weifeng


RE: [PATCH v2 net-next] net: stmmac: Add support for MDIO interrupts

2019-09-04 Thread Voon, Weifeng
> On Wed, Sep 04, 2019 at 10:02:54PM +0800, Voon Weifeng wrote:
> > From: "Chuah, Kim Tatt" 
> >
> > DW EQoS v5.xx controllers added capability for interrupt generation
> > when MDIO interface is done (GMII Busy bit is cleared).
> > This patch adds support for this interrupt on supported HW to avoid
> > polling on GMII Busy bit.
> >
> > stmmac_mdio_read() & stmmac_mdio_write() will sleep until wake_up() is
> > called by the interrupt handler.
> >
> > Reviewed-by: Voon Weifeng 
> > Reviewed-by: Kweh, Hock Leong 
> > Reviewed-by: Ong Boon Leong 
> > Signed-off-by: Chuah, Kim Tatt 
> > Signed-off-by: Ong Boon Leong 
> > Signed-off-by: Voon Weifeng 
> 
> Hi Voon
> 
> It is normal to include a short description of what you changed between
> the previous version and this version.

The change log is near the end of the patch:
/**
--
Changelog v2
*mdio interrupt mode or polling mode will depends on mdio interrupt enable bit
*Disable the mdio interrupt enable bit in stmmac_release
*Remove the condition for initialize wait queues
*Applied reverse Christmas tree
1.9.1

> 
> The formatting of this patch also looks a bit odd. Did you use git
> format-patch ; git send-email?

Yes, I do git format-patch, then ./scripts/checkpatch.pl. 
Lastly git send-email

> 
> Thanks
>   Andrew


[PATCH v2 net-next] net: stmmac: Add support for MDIO interrupts

2019-09-04 Thread Voon Weifeng
From: "Chuah, Kim Tatt" 

DW EQoS v5.xx controllers added capability for interrupt generation
when MDIO interface is done (GMII Busy bit is cleared).
This patch adds support for this interrupt on supported HW to avoid
polling on GMII Busy bit.

stmmac_mdio_read() & stmmac_mdio_write() will sleep until wake_up() is
called by the interrupt handler.

Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh, Hock Leong 
Reviewed-by: Ong Boon Leong 
Signed-off-by: Chuah, Kim Tatt 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 49aa56ca09cc..775a1c114b1a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -448,6 +448,8 @@ struct mac_device_info {
unsigned int pcs;
unsigned int pmt;
unsigned int ps;
+   bool mdio_intr_en;
+   wait_queue_head_t mdio_busy_wait;
 };
 
 struct stmmac_rx_routing {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 2ed11a581d80..1be6a8a88b8f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -106,6 +106,7 @@ enum dwmac4_irq_status {
mmc_irq = 0x0100,
lpi_irq = 0x0020,
pmt_irq = 0x0010,
+   mdio_irq = 0x0004,
 };
 
 /* MAC PMT bitmap */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index fc9954e4a772..97fca6d65141 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -59,6 +59,9 @@ static void dwmac4_core_init(struct mac_device_info *hw,
if (hw->pcs)
value |= GMAC_PCS_IRQ_DEFAULT;
 
+   if (hw->mdio_intr_en)
+   value |= GMAC_INT_MDIO_EN;
+
writel(value, ioaddr + GMAC_INT_EN);
 }
 
@@ -629,6 +632,9 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
x->irq_rx_path_exit_lpi_mode_n++;
}
 
+   if (intr_status & mdio_irq)
+   wake_up(>mdio_busy_wait);
+
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
if (intr_status & PCS_RGSMIIIS_IRQ)
dwmac4_phystatus(ioaddr, x);
@@ -836,6 +842,7 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, 
bool enable)
.rxp_config = dwmac5_rxp_config,
.flex_pps_config = dwmac5_flex_pps_config,
.set_mac_loopback = dwmac4_set_mac_loopback,
+   .mdio_intr_dis = dwmac5_mdio_intr_dis,
 };
 
 int dwmac4_setup(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index 3f4f3132e16b..c58751e1dcb6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -549,3 +549,11 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
writel(val, ioaddr + MAC_PPS_CONTROL);
return 0;
 }
+
+void dwmac5_mdio_intr_dis(void __iomem *ioaddr)
+{
+   u32 val = readl(ioaddr + GMAC_INT_EN);
+
+   val &= ~GMAC_INT_MDIO_EN;
+   writel(val, ioaddr + GMAC_INT_EN);
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index 775db776b3cc..a56511a4c97d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -72,6 +72,9 @@
 #define TCEIE  BIT(0)
 #define DMA_ECC_INT_STATUS 0x1088
 
+/* MDIO interrupt enable in MAC_Interrupt_Enable register */
+#define GMAC_INT_MDIO_EN   BIT(18)
+
 int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp);
 int dwmac5_safety_feat_irq_status(struct net_device *ndev,
void __iomem *ioaddr, unsigned int asp,
@@ -83,5 +86,6 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct 
stmmac_tc_entry *entries,
 int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
   struct stmmac_pps_cfg *cfg, bool enable,
   u32 sub_second_inc, u32 systime_flags);
+void dwmac5_mdio_intr_dis(void __iomem *ioaddr);
 
 #endif /* __DWMAC5_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c 
b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 3af2e5015245..7127efe652db 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -73,6 +73,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
bool gmac;
bool gmac4;
bool xgmac;
+   bool mdio_intr_en;
u32 min_id;
const struct stmmac_regs_off regs;
const void *desc;
@@ -90,6 +91,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 =

RE: [PATCH v1 net-next] net: phy: mdio_bus: make mdiobus_scan also cover PHY that only talks C45

2019-08-28 Thread Voon, Weifeng
> On 8/28/19 8:41 AM, Ong, Boon Leong wrote:
> >> On Tue, Aug 27, 2019 at 03:23:34PM +, Voon, Weifeng wrote:
> >>>>>> Make mdiobus_scan() to try harder to look for any PHY that only
> >>>> talks C45.
> >>>>> If you are not using Device Tree or ACPI, and you are letting the
> >>>>> MDIO bus be scanned, it sounds like there should be a way for you
> >>>>> to provide a hint as to which addresses should be scanned (that's
> >>>>> mii_bus::phy_mask) and possibly enhance that with a mask of
> >>>>> possible
> >>>>> C45 devices?
> >>>>
> >>>> Yes, i don't like this unconditional c45 scanning. A lot of MDIO
> >>>> bus drivers don't look for the MII_ADDR_C45. They are going to do a
> >>>> C22 transfer, and maybe not mask out the MII_ADDR_C45 from reg,
> >>>> causing an invalid register write. Bad things can then happen.
> >>>>
> >>>> With DT and ACPI, we have an explicit indication that C45 should be
> >>>> used, so we know on this platform C45 is safe to use. We need
> >>>> something similar when not using DT or ACPI.
> >>>>
> >>>>Andrew
> >>>
> >>> Florian and Andrew,
> >>> The mdio c22 is using the start-of-frame ST=01 while mdio c45 is
> >>> using ST=00 as identifier. So mdio c22 device will not response to
> mdio c45 protocol.
> >>> As in IEEE 802.1ae-2002 Annex 45A.3 mention that:
> >>> " Even though the Clause 45 MDIO frames using the ST=00 frame code
> >>> will also be driven on to the Clause 22 MII Management interface,
> >>> the Clause 22 PHYs will ignore the frames. "
> >>>
> >>> Hence, I am not seeing any concern that the c45 scanning will mess
> >>> up with
> >>> c22 devices.
> >>
> >> Hi Voon
> >>
> >> Take for example mdio-hisi-femac.c
> >>
> >> static int hisi_femac_mdio_read(struct mii_bus *bus, int mii_id, int
> >> regnum) {
> >>struct hisi_femac_mdio_data *data = bus->priv;
> >>int ret;
> >>
> >>ret = hisi_femac_mdio_wait_ready(data);
> >>if (ret)
> >>return ret;
> >>
> >>writel((mii_id << BIT_PHY_ADDR_OFFSET) | regnum,
> >>   data->membase + MDIO_RWCTRL);
> >>
> >>
> >> There is no check here for MII_ADDR_C45. So it will perform a C22
> >> transfer. And regnum will still have MII_ADDR_C45 in it, so the
> >> writel() is going to set bit 30, since #define MII_ADDR_C45 (1<<30).
> >> What happens on this hardware under these conditions?
> >>
> >> You cannot unconditionally ask an MDIO driver to do a C45 transfer.
> >> Some drivers are going to do bad things.
> >
> > Andrew & Florian, thanks for your review on this patch and insights on
> it.
> > We will look into the implementation as suggested as follow.
> >
> > - for each bit clear in mii_bus::phy_mask, scan it as C22
> > - for each bit clear in mii_bus::phy_c45_mask, scan it as C45
> >
> > We will work on this and resubmit soonest.
> 
> Sounds good. If you do not need to scan the MDIO bus, another approach
> is to call get_phy_device() by passing the is_c45 boolean to true in
> order to connect directly to a C45 device for which you already know the
> address.
> 
> Assuming this is done for the stmmac PCI changes that you have submitted,
> and that those cards have a fixed set of addresses for their PHYs, maybe
> scanning the bus is overkill?
> --
> Florian

Good suggestion. And yes, we have a fix phy address too. But the MAC is free 
to pair with any PHY which might supports only mdio c22 or only mdio c45. 
We will consider it and resubmit soonest.





RE: [PATCH v1 net-next] net: stmmac: Add support for MDIO interrupts

2019-08-28 Thread Voon, Weifeng
> >> DW EQoS v5.xx controllers added capability for interrupt generation
> >> when MDIO interface is done (GMII Busy bit is cleared).
> >> This patch adds support for this interrupt on supported HW to avoid
> >> polling on GMII Busy bit.
> >>
> >> stmmac_mdio_read() & stmmac_mdio_write() will sleep until wake_up()
> >> is called by the interrupt handler.
> >
> > Hi Voon
> >
> > I _think_ there are some order of operation issues here. The mdiobus
> > is registered in the probe function. As soon as of_mdiobus_register()
> > is called, the MDIO bus must work. At that point MDIO read/writes can
> > start to happen.
> >
> > As far as i can see, the interrupt handler is only requested in
> > stmmac_open(). So it seems like any MDIO operations after probe, but
> > before open are going to fail?
> 
> AFAIR, wait_event_timeout() will continue to busy loop and wait until
> the timeout, but not return an error because the polled condition was
> true, at least that is my recollection from having the same issue with
> the bcmgenet driver before it was moved to connecting to the PHY in the
> ndo_open() function.
> --
> Florian

Florian is right as the poll condition is still true after the timeout. 
Hence, any mdio operation after probe and before ndo_open will still work.
The only cons here is that attaching the PHY will takes a full length of 
timeout time for each mdio_read and mdio_write. 
So we should attach the phy only after the interrupt handler is requested?
 


RE: [PATCH v1 net-next] net: phy: mdio_bus: make mdiobus_scan also cover PHY that only talks C45

2019-08-27 Thread Voon, Weifeng
> > > Make mdiobus_scan() to try harder to look for any PHY that only
> talks C45.
> > If you are not using Device Tree or ACPI, and you are letting the MDIO
> > bus be scanned, it sounds like there should be a way for you to
> > provide a hint as to which addresses should be scanned (that's
> > mii_bus::phy_mask) and possibly enhance that with a mask of possible
> > C45 devices?
> 
> Yes, i don't like this unconditional c45 scanning. A lot of MDIO bus
> drivers don't look for the MII_ADDR_C45. They are going to do a C22
> transfer, and maybe not mask out the MII_ADDR_C45 from reg, causing an
> invalid register write. Bad things can then happen.
> 
> With DT and ACPI, we have an explicit indication that C45 should be used,
> so we know on this platform C45 is safe to use. We need something
> similar when not using DT or ACPI.
> 
> Andrew

Florian and Andrew,
The mdio c22 is using the start-of-frame ST=01 while mdio c45 is using ST=00
as identifier. So mdio c22 device will not response to mdio c45 protocol.
As in IEEE 802.1ae-2002 Annex 45A.3 mention that:
" Even though the Clause 45 MDIO frames using the ST=00 frame code
will also be driven on to the Clause 22 MII Management interface,
the Clause 22 PHYs will ignore the frames. "

Hence, I am not seeing any concern that the c45 scanning will mess up with 
c22 devices.

Weifeng 




RE: [PATCH v1 net-next 4/4] net: stmmac: setup higher frequency clk support for EHL & TGL

2019-08-27 Thread Voon, Weifeng
> > > +#include 
> > >  #include 
> > >  #include 
> > >
> > > @@ -174,6 +175,19 @@ static int intel_mgbe_common_data(struct
> pci_dev *pdev,
> > >   plat->axi->axi_blen[1] = 8;
> > >   plat->axi->axi_blen[2] = 16;
> > >
> > > + plat->ptp_max_adj = plat->clk_ptp_rate;
> > > +
> > > + /* Set system clock */
> > > + plat->stmmac_clk = clk_register_fixed_rate(>dev,
> > > +"stmmac-clk", NULL, 0,
> > > +plat->clk_ptp_rate);
> > > +
> > > + if (IS_ERR(plat->stmmac_clk)) {
> > > + dev_warn(>dev, "Fail to register stmmac-clk\n");
> > > + plat->stmmac_clk = NULL;
> >
> > Don't you need to propagate at least EPROBE_DEFER here?
> 
> Hi Florian
> 
> Isn't a fixed rate clock a complete fake. There is no hardware behind it.
> So can it return EPROBE_DEFER?
> 
> Andrew

Yes, there is no hardware behind it. So, I don't think we need to deferred probe
and a warning message should be sufficient. Anyhow, please point it out if I 
miss
out anything.

Thanks. 



RE: [PATCH v1 net-next] net: phy: mdio_bus: make mdiobus_scan also cover PHY that only talks C45

2019-08-27 Thread Voon, Weifeng
> There is something wrong with the clock on the computer you are posting
> these patches from, the date in these postings are in the future by
> several hours.
> 
> This messes up the ordering of changes in patchwork and makes my life
> miserable to a certain degree, so please fix this.
> 
> Thank you.

Sorry about that as my machine's date somehow went out of
sync with the server time. I have already fixed that.

Thanks,
Weifeng


[PATCH v1 net-next] net: phy: mdio_bus: make mdiobus_scan also cover PHY that only talks C45

2019-08-26 Thread Voon Weifeng
From: Ong Boon Leong 

Make mdiobus_scan() to try harder to look for any PHY that only talks C45.

Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index bd04fe762056..30dbc48b4c7e 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -525,8 +525,12 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int 
addr)
int err;
 
phydev = get_phy_device(bus, addr, false);
-   if (IS_ERR(phydev))
-   return phydev;
+   if (IS_ERR(phydev)) {
+   /* Try C45 to ensure we don't miss PHY that only talks C45 */
+   phydev = get_phy_device(bus, addr, true);
+   if (IS_ERR(phydev))
+   return phydev;
+   }
 
/*
 * For DT, see if the auto-probed phy has a correspoding child
-- 
1.9.1



[PATCH v1 net-next] net: stmmac: Add support for MDIO interrupts

2019-08-26 Thread Voon Weifeng
From: "Chuah, Kim Tatt" 

DW EQoS v5.xx controllers added capability for interrupt generation
when MDIO interface is done (GMII Busy bit is cleared).
This patch adds support for this interrupt on supported HW to avoid
polling on GMII Busy bit.

stmmac_mdio_read() & stmmac_mdio_write() will sleep until wake_up() is
called by the interrupt handler.

Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh, Hock Leong 
Reviewed-by: Ong Boon Leong 
Signed-off-by: Chuah, Kim Tatt 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 49aa56ca09cc..775a1c114b1a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -448,6 +448,8 @@ struct mac_device_info {
unsigned int pcs;
unsigned int pmt;
unsigned int ps;
+   bool mdio_intr_en;
+   wait_queue_head_t mdio_busy_wait;
 };
 
 struct stmmac_rx_routing {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 2ed11a581d80..1be6a8a88b8f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -106,6 +106,7 @@ enum dwmac4_irq_status {
mmc_irq = 0x0100,
lpi_irq = 0x0020,
pmt_irq = 0x0010,
+   mdio_irq = 0x0004,
 };
 
 /* MAC PMT bitmap */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index fc9954e4a772..54adad616b90 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -59,6 +59,9 @@ static void dwmac4_core_init(struct mac_device_info *hw,
if (hw->pcs)
value |= GMAC_PCS_IRQ_DEFAULT;
 
+   if (hw->mdio_intr_en)
+   value |= GMAC_INT_MDIO_EN;
+
writel(value, ioaddr + GMAC_INT_EN);
 }
 
@@ -629,6 +632,9 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
x->irq_rx_path_exit_lpi_mode_n++;
}
 
+   if (intr_status & mdio_irq)
+   wake_up(>mdio_busy_wait);
+
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
if (intr_status & PCS_RGSMIIIS_IRQ)
dwmac4_phystatus(ioaddr, x);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h 
b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index 775db776b3cc..48550d617b01 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -72,6 +72,9 @@
 #define TCEIE  BIT(0)
 #define DMA_ECC_INT_STATUS 0x1088
 
+/* MDIO interrupt enable in MAC_Interrupt_Enable register */
+#define GMAC_INT_MDIO_EN   BIT(18)
+
 int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp);
 int dwmac5_safety_feat_irq_status(struct net_device *ndev,
void __iomem *ioaddr, unsigned int asp,
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c 
b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 3af2e5015245..11c7f92e99b4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -73,6 +73,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
bool gmac;
bool gmac4;
bool xgmac;
+   bool mdio_intr_en;
u32 min_id;
const struct stmmac_regs_off regs;
const void *desc;
@@ -90,6 +91,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = false,
.xgmac = false,
+   .mdio_intr_en = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -108,6 +110,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = true,
.gmac4 = false,
.xgmac = false,
+   .mdio_intr_en = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -126,6 +129,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = true,
.xgmac = false,
+   .mdio_intr_en = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
@@ -144,6 +148,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = true,
.xgmac = false,
+   .mdio_intr_en = false,
.min_id = DWMAC_CORE_4_00,
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
@@ -162,6 +167,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = tr

[PATCH v1 net-next 2/4] net: stmmac: add TGL SGMII 1Gbps PCI info and PCI ID

2019-08-26 Thread Voon Weifeng
Added TGL SGMII 1Gbps PCI ID. Different MII and speed will have
different PCI ID.

Signed-off-by: Voon Weifeng 
Signed-off-by: Ong Boon Leong 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 29 
 1 file changed, 29 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index f6930e02f578..edb76408308b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -213,6 +213,33 @@ static int ehl_sgmii_data(struct pci_dev *pdev,
.setup = ehl_sgmii_data,
 };
 
+static int tgl_common_data(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat)
+{
+   int ret;
+
+   plat->rx_queues_to_use = 6;
+   plat->tx_queues_to_use = 4;
+   ret = intel_mgbe_common_data(pdev, plat);
+   if (ret)
+   return ret;
+
+   return 0;
+}
+
+static int tgl_sgmii_data(struct pci_dev *pdev,
+ struct plat_stmmacenet_data *plat)
+{
+   plat->bus_id = 1;
+   plat->phy_addr = 0;
+   plat->interface = PHY_INTERFACE_MODE_SGMII;
+   return tgl_common_data(pdev, plat);
+}
+
+static struct stmmac_pci_info tgl_sgmii1g_pci_info = {
+   .setup = tgl_sgmii_data,
+};
+
 static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = {
{
.func = 6,
@@ -455,6 +482,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
 #define STMMAC_QUARK_ID  0x0937
 #define STMMAC_DEVICE_ID 0x1108
 #define STMMAC_EHL_SGMII1G_ID  0x4b31
+#define STMMAC_TGL_SGMII1G_ID  0xa0ac
 
 #define STMMAC_DEVICE(vendor_id, dev_id, info) {   \
PCI_VDEVICE(vendor_id, dev_id), \
@@ -466,6 +494,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
STMMAC_DEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_MAC, stmmac_pci_info),
STMMAC_DEVICE(INTEL, STMMAC_QUARK_ID, quark_pci_info),
STMMAC_DEVICE(INTEL, STMMAC_EHL_SGMII1G_ID, ehl_sgmii1g_pci_info),
+   STMMAC_DEVICE(INTEL, STMMAC_TGL_SGMII1G_ID, tgl_sgmii1g_pci_info),
{}
 };
 
-- 
1.9.1



[PATCH v1 net-next 3/4] net: stmmac: add EHL RGMII 1Gbps PCI info and PCI ID

2019-08-26 Thread Voon Weifeng
Added EHL RGMII 1Gbps PCI ID. Different MII and speed will have
different PCI ID.

Signed-off-by: Voon Weifeng 
Signed-off-by: Ong Boon Leong 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index edb76408308b..e969dc9bb9f0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -213,6 +213,19 @@ static int ehl_sgmii_data(struct pci_dev *pdev,
.setup = ehl_sgmii_data,
 };
 
+static int ehl_rgmii_data(struct pci_dev *pdev,
+ struct plat_stmmacenet_data *plat)
+{
+   plat->bus_id = 1;
+   plat->phy_addr = 0;
+   plat->interface = PHY_INTERFACE_MODE_RGMII;
+   return ehl_common_data(pdev, plat);
+}
+
+static struct stmmac_pci_info ehl_rgmii1g_pci_info = {
+   .setup = ehl_rgmii_data,
+};
+
 static int tgl_common_data(struct pci_dev *pdev,
   struct plat_stmmacenet_data *plat)
 {
@@ -481,6 +494,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
 
 #define STMMAC_QUARK_ID  0x0937
 #define STMMAC_DEVICE_ID 0x1108
+#define STMMAC_EHL_RGMII1G_ID  0x4b30
 #define STMMAC_EHL_SGMII1G_ID  0x4b31
 #define STMMAC_TGL_SGMII1G_ID  0xa0ac
 
@@ -493,6 +507,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
STMMAC_DEVICE(STMMAC, STMMAC_DEVICE_ID, stmmac_pci_info),
STMMAC_DEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_MAC, stmmac_pci_info),
STMMAC_DEVICE(INTEL, STMMAC_QUARK_ID, quark_pci_info),
+   STMMAC_DEVICE(INTEL, STMMAC_EHL_RGMII1G_ID, ehl_rgmii1g_pci_info),
STMMAC_DEVICE(INTEL, STMMAC_EHL_SGMII1G_ID, ehl_sgmii1g_pci_info),
STMMAC_DEVICE(INTEL, STMMAC_TGL_SGMII1G_ID, tgl_sgmii1g_pci_info),
{}
-- 
1.9.1



[PATCH v1 net-next 4/4] net: stmmac: setup higher frequency clk support for EHL & TGL

2019-08-26 Thread Voon Weifeng
EHL DW EQOS is running on a 200MHz clock. Setting up stmmac-clk,
ptp clock and ptp_max_adj to 200MHz.

Signed-off-by: Voon Weifeng 
Signed-off-by: Ong Boon Leong 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 21 +
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c |  3 +++
 include/linux/stmmac.h   |  1 +
 3 files changed, 25 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index e969dc9bb9f0..20906287b6d4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -9,6 +9,7 @@
   Author: Giuseppe Cavallaro 
 
***/
 
+#include 
 #include 
 #include 
 
@@ -174,6 +175,19 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->axi->axi_blen[1] = 8;
plat->axi->axi_blen[2] = 16;
 
+   plat->ptp_max_adj = plat->clk_ptp_rate;
+
+   /* Set system clock */
+   plat->stmmac_clk = clk_register_fixed_rate(>dev,
+  "stmmac-clk", NULL, 0,
+  plat->clk_ptp_rate);
+
+   if (IS_ERR(plat->stmmac_clk)) {
+   dev_warn(>dev, "Fail to register stmmac-clk\n");
+   plat->stmmac_clk = NULL;
+   }
+   clk_prepare_enable(plat->stmmac_clk);
+
/* Set default value for multicast hash bins */
plat->multicast_filter_bins = HASH_TABLE_SIZE;
 
@@ -193,6 +207,7 @@ static int ehl_common_data(struct pci_dev *pdev,
 
plat->rx_queues_to_use = 8;
plat->tx_queues_to_use = 8;
+   plat->clk_ptp_rate = 2;
ret = intel_mgbe_common_data(pdev, plat);
if (ret)
return ret;
@@ -233,6 +248,7 @@ static int tgl_common_data(struct pci_dev *pdev,
 
plat->rx_queues_to_use = 6;
plat->tx_queues_to_use = 4;
+   plat->clk_ptp_rate = 2;
ret = intel_mgbe_common_data(pdev, plat);
if (ret)
return ret;
@@ -438,10 +454,15 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
  */
 static void stmmac_pci_remove(struct pci_dev *pdev)
 {
+   struct net_device *ndev = dev_get_drvdata(>dev);
+   struct stmmac_priv *priv = netdev_priv(ndev);
int i;
 
stmmac_dvr_remove(>dev);
 
+   if (priv->plat->stmmac_clk)
+   clk_unregister_fixed_rate(priv->plat->stmmac_clk);
+
for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
if (pci_resource_len(pdev, i) == 0)
continue;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index c48224973a37..173493db038c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -194,6 +194,9 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
priv->pps[i].available = true;
}
 
+   if (priv->plat->ptp_max_adj)
+   stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
+
stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
 
spin_lock_init(>ptp_lock);
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 5cc6b6faf359..7ad7ae35cf88 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -168,6 +168,7 @@ struct plat_stmmacenet_data {
struct clk *clk_ptp_ref;
unsigned int clk_ptp_rate;
unsigned int clk_ref_rate;
+   s32 ptp_max_adj;
struct reset_control *stmmac_rst;
struct stmmac_axi *axi;
int has_gmac4;
-- 
1.9.1



[PATCH v1 net-next 0/4] Add EHL and TGL PCI info and PCI ID

2019-08-26 Thread Voon Weifeng
In order to keep PCI info simple and neat, this patch series have
introduced a 3 hierarchy of struct. First layer will be the
intel_mgbe_common_data struct which keeps all Intel common configuration.
Second layer will be xxx_common_data which keeps all the different Intel
microarchitecture, e.g tgl, ehl. The third layer will be configuration
that tied to the PCI ID only based on speed and RGMII/SGMII interface.

EHL and TGL will also having a higher system clock which is 200Mhz.

Voon Weifeng (4):
  net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID
  net: stmmac: add TGL SGMII 1Gbps PCI info and PCI ID
  net: stmmac: add EHL RGMII 1Gbps PCI info and PCI ID
  net: stmmac: setup higher frequency clk support for EHL & TGL

 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 172 +++
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c |   3 +
 include/linux/stmmac.h   |   1 +
 3 files changed, 176 insertions(+)

-- 
1.9.1



[PATCH v1 net-next 1/4] net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

2019-08-26 Thread Voon Weifeng
Added EHL SGMII 1Gbps PCI ID. Different MII and speed will have
different PCI ID.

Signed-off-by: Voon Weifeng 
Signed-off-by: Ong Boon Leong 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 107 +++
 1 file changed, 107 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index d5d08e11c353..f6930e02f578 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -108,6 +108,111 @@ static int stmmac_default_data(struct pci_dev *pdev,
.setup = stmmac_default_data,
 };
 
+static int intel_mgbe_common_data(struct pci_dev *pdev,
+ struct plat_stmmacenet_data *plat)
+{
+   int i;
+
+   plat->clk_csr = 5;
+   plat->has_gmac = 0;
+   plat->has_gmac4 = 1;
+   plat->force_sf_dma_mode = 0;
+   plat->tso_en = 1;
+
+   plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
+
+   for (i = 0; i < plat->rx_queues_to_use; i++) {
+   plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+   plat->rx_queues_cfg[i].chan = i;
+
+   /* Disable Priority config by default */
+   plat->rx_queues_cfg[i].use_prio = false;
+
+   /* Disable RX queues routing by default */
+   plat->rx_queues_cfg[i].pkt_route = 0x0;
+   }
+
+   for (i = 0; i < plat->tx_queues_to_use; i++) {
+   plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+
+   /* Disable Priority config by default */
+   plat->tx_queues_cfg[i].use_prio = false;
+   }
+
+   /* FIFO size is 4096 bytes for 1 tx/rx queue */
+   plat->tx_fifo_size = plat->tx_queues_to_use * 4096;
+   plat->rx_fifo_size = plat->rx_queues_to_use * 4096;
+
+   plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
+   plat->tx_queues_cfg[0].weight = 0x09;
+   plat->tx_queues_cfg[1].weight = 0x0A;
+   plat->tx_queues_cfg[2].weight = 0x0B;
+   plat->tx_queues_cfg[3].weight = 0x0C;
+   plat->tx_queues_cfg[4].weight = 0x0D;
+   plat->tx_queues_cfg[5].weight = 0x0E;
+   plat->tx_queues_cfg[6].weight = 0x0F;
+   plat->tx_queues_cfg[7].weight = 0x10;
+
+   plat->mdio_bus_data->phy_mask = 0;
+
+   plat->dma_cfg->pbl = 32;
+   plat->dma_cfg->pblx8 = true;
+   plat->dma_cfg->fixed_burst = 0;
+   plat->dma_cfg->mixed_burst = 0;
+   plat->dma_cfg->aal = 0;
+
+   plat->axi = devm_kzalloc(>dev, sizeof(*plat->axi),
+GFP_KERNEL);
+   if (!plat->axi)
+   return -ENOMEM;
+
+   plat->axi->axi_lpi_en = 0;
+   plat->axi->axi_xit_frm = 0;
+   plat->axi->axi_wr_osr_lmt = 1;
+   plat->axi->axi_rd_osr_lmt = 1;
+   plat->axi->axi_blen[0] = 4;
+   plat->axi->axi_blen[1] = 8;
+   plat->axi->axi_blen[2] = 16;
+
+   /* Set default value for multicast hash bins */
+   plat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+   /* Set default value for unicast filter entries */
+   plat->unicast_filter_entries = 1;
+
+   /* Set the maxmtu to a default of JUMBO_LEN */
+   plat->maxmtu = JUMBO_LEN;
+
+   return 0;
+}
+
+static int ehl_common_data(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat)
+{
+   int ret;
+
+   plat->rx_queues_to_use = 8;
+   plat->tx_queues_to_use = 8;
+   ret = intel_mgbe_common_data(pdev, plat);
+   if (ret)
+   return ret;
+
+   return 0;
+}
+
+static int ehl_sgmii_data(struct pci_dev *pdev,
+ struct plat_stmmacenet_data *plat)
+{
+   plat->bus_id = 1;
+   plat->phy_addr = 0;
+   plat->interface = PHY_INTERFACE_MODE_SGMII;
+   return ehl_common_data(pdev, plat);
+}
+
+static struct stmmac_pci_info ehl_sgmii1g_pci_info = {
+   .setup = ehl_sgmii_data,
+};
+
 static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = {
{
.func = 6,
@@ -349,6 +454,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
 
 #define STMMAC_QUARK_ID  0x0937
 #define STMMAC_DEVICE_ID 0x1108
+#define STMMAC_EHL_SGMII1G_ID  0x4b31
 
 #define STMMAC_DEVICE(vendor_id, dev_id, info) {   \
PCI_VDEVICE(vendor_id, dev_id), \
@@ -359,6 +465,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
STMMAC_DEVICE(STMMAC, STMMAC_DEVICE_ID, stmmac_pci_info),
STMMAC_DEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_MAC, stmmac_pci_info),
STMMAC_DEVICE(INTEL, STMMAC_QUARK_ID, quark_pci_info),
+   STMMAC_DEVICE(INTEL, STMMAC_EHL_SGMII1G_ID, ehl_sgmii1g_pci_info),
{}
 };
 
-- 
1.9.1



[PATCH v2 net-next] net: stmmac: enable clause 45 mdio support

2019-07-05 Thread Voon Weifeng
From: Kweh Hock Leong 

DWMAC4 is capable to support clause 45 mdio communication.
This patch enable the feature on stmmac_mdio_write() and
stmmac_mdio_read() by following phy_write_mmd() and
phy_read_mmd() mdiobus read write implementation format.

Reviewed-by: Li, Yifan 
Signed-off-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 18cadf0b0d66..4304c1abc5d1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -24,11 +24,14 @@
 
 #define MII_BUSY 0x0001
 #define MII_WRITE 0x0002
+#define MII_DATA_MASK GENMASK(15, 0)
 
 /* GMAC4 defines */
 #define MII_GMAC4_GOC_SHIFT2
+#define MII_GMAC4_REG_ADDR_SHIFT   16
 #define MII_GMAC4_WRITE(1 << MII_GMAC4_GOC_SHIFT)
 #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
+#define MII_GMAC4_C45E BIT(1)
 
 /* XGMAC defines */
 #define MII_XGMAC_SADDRBIT(18)
@@ -155,22 +158,34 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
-   int data;
u32 value = MII_BUSY;
+   int data = 0;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_READ;
+   if (phyreg & MII_ADDR_C45) {
+   value |= MII_GMAC4_C45E;
+   value &= ~priv->hw->mii.reg_mask;
+   value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
+  priv->hw->mii.reg_shift) &
+  priv->hw->mii.reg_mask;
+
+   data |= (phyreg & MII_REGADDR_C45_MASK) <<
+   MII_GMAC4_REG_ADDR_SHIFT;
+   }
+   }
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
   100, 1))
return -EBUSY;
 
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -178,7 +193,7 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
return -EBUSY;
 
/* Read the data from the MII data register */
-   data = (int)readl(priv->ioaddr + mii_data);
+   data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
 
return data;
 }
@@ -198,8 +213,9 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
u32 value = MII_BUSY;
+   int data = phydata;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
@@ -207,10 +223,21 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
 
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_WRITE;
-   else
+   if (phyreg & MII_ADDR_C45) {
+   value |= MII_GMAC4_C45E;
+   value &= ~priv->hw->mii.reg_mask;
+   value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
+  priv->hw->mii.reg_shift) &
+  priv->hw->mii.reg_mask;
+
+   data |= (phyreg & MII_REGADDR_C45_MASK) <<
+   MII_GMAC4_REG_ADDR_SHIFT;
+   }
+   } else {
value |= MII_WRITE;
+   }
 
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -218,7 +245,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
return -EBUSY;
 
/* Set the MII

RE: [PATCH v1 net-next] net: stmmac: enable clause 45 mdio support

2019-07-05 Thread Voon, Weifeng
> > If the community prefers readability
> 
> Readability nearly always comes first. There is nothing performance
> critical here, MDIO is a slow bus. So the code should be readable,
> simple to understand.
> 
Noted and thanks for the comments.

> 
> , I will suggest to do the c45 setup in
> > both stmmac_mdio_read() and stmmac_mdio_write() 's if(C45) condition
> rather
> > than splitting into 2 new c45_read() and c45_write() functions.
> 
> Fine.
> 
>   Andrew

I will start preparing v2. Thanks.  

Weifeng


RE: [PATCH v1 net-next] net: stmmac: enable clause 45 mdio support

2019-07-04 Thread Voon, Weifeng
> I think there is too much passing variables around by reference than by
> value, to make this code easy to understand.
> 
> Maybe a better structure would be
> 
> static int stmmac_mdion_c45_read(struct stmmac_priv *priv, int phyaddr,
> int phyreg) {
> 
>   unsigned int reg_shift = priv->hw->mii.reg_shift;
>   unsigned int reg_mask = priv->hw->mii.reg_mask;
>   u32 mii_addr_val, mii_data_val;
> 
>   mii_addr_val = MII_GMAC4_C45E |
>((phyreg >> MII_DEVADDR_C45_SHIFT) << reg_shift)
> & reg_mask;
> mii_data_val = (phyreg & MII_REGADDR_C45_MASK) <<
> MII_GMAC4_REG_ADDR_SHIFT;
> 
>   writel(mii_data_val, priv->ioaddr + priv->hw->mii_data);
>   writel(mii_addr_val, priv->ioaddr + priv->hw->mii_addrress);
> 
>   return (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
> }
> 
> static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
> {
> 
> ...
>   if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v &
> MII_BUSY),
> 100, 1))
>   return -EBUSY;
> 
>   if (priv->plat->has_gmac4 && phyreg & MII_ADDR_C45)
>   return stmmac_mdio_c45_read(priv, phyaddr, phyreg);
> 
>   Andrew

Both c45 read/write needs to set c45 enable bit(MII_ADDR_C45) in mii_adrress
and set the register address in mii_data. Besides this, the whole programming
flow will be the same as c22. With the current design, user can easily know
that the different between c22 and c45 is just in stmmac_mdio_c45_setup(). 

If the community prefers readability, I will suggest to do the c45 setup in
both stmmac_mdio_read() and stmmac_mdio_write() 's if(C45) condition rather
than splitting into 2 new c45_read() and c45_write() functions. 

static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
{

...
if (phyreg & MII_ADDR_C45)
   *val |= MII_GMAC4_C45E;
   *val &= ~reg_mask;
   *val |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << reg_shift) & reg_mask;

   *data |= (phyreg & MII_REGADDR_C45_MASK) << MII_GMAC4_REG_ADDR_SHIFT;

Weifeng




RE: [PATCH v1 net-next] net: stmmac: enable clause 45 mdio support

2019-07-04 Thread Voon, Weifeng
> > > > > > @@ -155,22 +171,26 @@ static int stmmac_mdio_read(struct
> > > > > > mii_bus *bus,
> > > > > int phyaddr, int phyreg)
> > > > > > struct stmmac_priv *priv = netdev_priv(ndev);
> > > > > > unsigned int mii_address = priv->hw->mii.addr;
> > > > > > unsigned int mii_data = priv->hw->mii.data;
> > > > > > -   u32 v;
> > > > > > -   int data;
> > > > > > u32 value = MII_BUSY;
> > > > > > +   int data = 0;
> > > > > > +   u32 v;
> > > > > >
> > > > > > value |= (phyaddr << priv->hw->mii.addr_shift)
> > > > > > & priv->hw->mii.addr_mask;
> > > > > > value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw-
> > > > > >mii.reg_mask;
> > > > > > value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
> > > > > > & priv->hw->mii.clk_csr_mask;
> > > > > > -   if (priv->plat->has_gmac4)
> > > > > > +   if (priv->plat->has_gmac4) {
> > > > > > value |= MII_GMAC4_READ;
> > > > > > +   if (phyreg & MII_ADDR_C45)
> > > > > > +   stmmac_mdio_c45_setup(priv, phyreg, ,
> );
> > > > > > +   }
> > > > > >
> > > > > > if (readl_poll_timeout(priv->ioaddr + mii_address,
> v, !(v &
> > > > > MII_BUSY),
> > > > > >100, 1))
> > > > > > return -EBUSY;
> > > > > >
> > > > > > +   writel(data, priv->ioaddr + mii_data);
> > > > >
> > > > > That looks odd. Could you explain why it is needed.
> > > > >
> > > > > Thanks
> > > > >   Andrew
> > > >
> > > > Hi Andrew,
> > > > This mdio c45 support needed to access DWC xPCS which is a
> > > > Clause-45
> > >
> > > I mean it looks odd doing a write to the data register in the middle
> > > of stmmac_mdio_read().
> >
> > MAC is using an indirect access to access mdio devices. In order to
> > read, the driver needs to write into both mii_data and mii_address to
> > select c45, read/write command, phy address, address to read, and etc.
> 
> Yes, that is all clear. The stmmac_mdio_c45_setup() does part of this
> setup. There is also a write to mii_address which i snipped out when
> replying. But why do you need to write to the data registers during a
> read? C22 does not need this write. Are there some bits in the top of
> the data register which are relevant to C45?
> 

Yes, the top 16 bit of the data register only valid when C45 is enable.
It contains the Register address which MDIO c45 frame intended for.


RE: [PATCH v1 net-next] net: stmmac: enable clause 45 mdio support

2019-07-04 Thread Voon, Weifeng
> > > > @@ -155,22 +171,26 @@ static int stmmac_mdio_read(struct mii_bus
> > > > *bus,
> > > int phyaddr, int phyreg)
> > > > struct stmmac_priv *priv = netdev_priv(ndev);
> > > > unsigned int mii_address = priv->hw->mii.addr;
> > > > unsigned int mii_data = priv->hw->mii.data;
> > > > -   u32 v;
> > > > -   int data;
> > > > u32 value = MII_BUSY;
> > > > +   int data = 0;
> > > > +   u32 v;
> > > >
> > > > value |= (phyaddr << priv->hw->mii.addr_shift)
> > > > & priv->hw->mii.addr_mask;
> > > > value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw-
> > > >mii.reg_mask;
> > > > value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
> > > > & priv->hw->mii.clk_csr_mask;
> > > > -   if (priv->plat->has_gmac4)
> > > > +   if (priv->plat->has_gmac4) {
> > > > value |= MII_GMAC4_READ;
> > > > +   if (phyreg & MII_ADDR_C45)
> > > > +   stmmac_mdio_c45_setup(priv, phyreg, , 
> > > > );
> > > > +   }
> > > >
> > > > if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v &
> > > MII_BUSY),
> > > >100, 1))
> > > > return -EBUSY;
> > > >
> > > > +   writel(data, priv->ioaddr + mii_data);
> > >
> > > That looks odd. Could you explain why it is needed.
> > >
> > > Thanks
> > >   Andrew
> >
> > Hi Andrew,
> > This mdio c45 support needed to access DWC xPCS which is a Clause-45
> 
> I mean it looks odd doing a write to the data register in the middle of
> stmmac_mdio_read().

MAC is using an indirect access to access mdio devices. In order to read,
the driver needs to write into both mii_data and mii_address to select 
c45, read/write command, phy address, address to read, and etc. 

Weifeng



RE: [PATCH v1 net-next] net: stmmac: enable clause 45 mdio support

2019-07-03 Thread Voon, Weifeng
> > @@ -155,22 +171,26 @@ static int stmmac_mdio_read(struct mii_bus *bus,
> int phyaddr, int phyreg)
> > struct stmmac_priv *priv = netdev_priv(ndev);
> > unsigned int mii_address = priv->hw->mii.addr;
> > unsigned int mii_data = priv->hw->mii.data;
> > -   u32 v;
> > -   int data;
> > u32 value = MII_BUSY;
> > +   int data = 0;
> > +   u32 v;
> >
> > value |= (phyaddr << priv->hw->mii.addr_shift)
> > & priv->hw->mii.addr_mask;
> > value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw-
> >mii.reg_mask;
> > value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
> > & priv->hw->mii.clk_csr_mask;
> > -   if (priv->plat->has_gmac4)
> > +   if (priv->plat->has_gmac4) {
> > value |= MII_GMAC4_READ;
> > +   if (phyreg & MII_ADDR_C45)
> > +   stmmac_mdio_c45_setup(priv, phyreg, , );
> > +   }
> >
> > if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v &
> MII_BUSY),
> >100, 1))
> > return -EBUSY;
> >
> > +   writel(data, priv->ioaddr + mii_data);
> 
> That looks odd. Could you explain why it is needed.
> 
> Thanks
>   Andrew

Hi Andrew,
This mdio c45 support needed to access DWC xPCS which is a Clause-45
MDIO Manageable Device (MMD). This is discuss in:
https://patchwork.ozlabs.org/patch/1109776/
https://patchwork.ozlabs.org/patch/1109777/
Since the patch is still WIP to make the xPCS as PHY driver for SGMII
to RGMII converter. So i decided to upstream this patch first.

Biao Huang also needed this patch and tested pass with this patch on 
their platform.
https://patchwork.ozlabs.org/patch/1103861/

Biao Huang's patch on MDIO-c45 access 
https://patchwork.ozlabs.org/patch/1092436/ 

Regards,
Weifeng




[PATCH v1 net-next] net: stmmac: Enable dwmac4 jumbo frame more than 8KiB

2019-07-03 Thread Voon Weifeng
From: Weifeng Voon 

Enable GMAC v4.xx and beyond to support 16KiB buffer.

Signed-off-by: Weifeng Voon 
Signed-off-by: Ong Boon Leong 

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index cf6436d3d6c7..dbde23e7e169 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -443,6 +443,15 @@ static void dwmac4_clear(struct dma_desc *p)
p->des3 = 0;
 }
 
+static int set_16kib_bfsize(int mtu)
+{
+   int ret = 0;
+
+   if (unlikely(mtu >= BUF_SIZE_8KiB))
+   ret = BUF_SIZE_16KiB;
+   return ret;
+}
+
 const struct stmmac_desc_ops dwmac4_desc_ops = {
.tx_status = dwmac4_wrback_get_tx_status,
.rx_status = dwmac4_wrback_get_rx_status,
@@ -469,4 +478,6 @@ static void dwmac4_clear(struct dma_desc *p)
.clear = dwmac4_clear,
 };
 
-const struct stmmac_mode_ops dwmac4_ring_mode_ops = { };
+const struct stmmac_mode_ops dwmac4_ring_mode_ops = {
+   .set_16kib_bfsize = set_16kib_bfsize,
+};
-- 
1.9.1



[PATCH v1 net-next] net: stmmac: enable clause 45 mdio support

2019-07-02 Thread Voon Weifeng
From: Kweh Hock Leong 

DWMAC4 is capable to support clause 45 mdio communication.
This patch enable the feature on stmmac_mdio_write() and
stmmac_mdio_read() by following phy_write_mmd() and
phy_read_mmd() mdiobus read write implementation format.

Reviewed-by: Li, Yifan 
Signed-off-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Weifeng Voon 

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 18cadf0b0d66..b9edb18769f2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -24,11 +24,27 @@
 
 #define MII_BUSY 0x0001
 #define MII_WRITE 0x0002
+#define MII_DATA_MASK GENMASK(15, 0)
 
 /* GMAC4 defines */
 #define MII_GMAC4_GOC_SHIFT2
+#define MII_GMAC4_REG_ADDR_SHIFT   16
 #define MII_GMAC4_WRITE(1 << MII_GMAC4_GOC_SHIFT)
 #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
+#define MII_GMAC4_C45E BIT(1)
+
+static void stmmac_mdio_c45_setup(struct stmmac_priv *priv, int phyreg,
+ u32 *val, u32 *data)
+{
+   unsigned int reg_shift = priv->hw->mii.reg_shift;
+   unsigned int reg_mask = priv->hw->mii.reg_mask;
+
+   *val |= MII_GMAC4_C45E;
+   *val &= ~reg_mask;
+   *val |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << reg_shift) & reg_mask;
+
+   *data |= (phyreg & MII_REGADDR_C45_MASK) << MII_GMAC4_REG_ADDR_SHIFT;
+}
 
 /* XGMAC defines */
 #define MII_XGMAC_SADDRBIT(18)
@@ -155,22 +171,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
-   int data;
u32 value = MII_BUSY;
+   int data = 0;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_READ;
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   }
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
   100, 1))
return -EBUSY;
 
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -178,7 +198,7 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
return -EBUSY;
 
/* Read the data from the MII data register */
-   data = (int)readl(priv->ioaddr + mii_data);
+   data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
 
return data;
 }
@@ -198,8 +218,9 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
u32 value = MII_BUSY;
+   int data = phydata;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
@@ -207,10 +228,13 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
 
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_WRITE;
-   else
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   } else {
value |= MII_WRITE;
+   }
 
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -218,7 +242,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
return -EBUSY;
 
/* Set the MII address register to write */
-   writel(phydata, priv->ioaddr + mii_data);
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
/* Wait until any existing MII operation is complete */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index d0af7d37fdf9..1739c6dc470e 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -195,6 +195,8 @@ static inline const char *phy_modes(phy_interface_t 
interface)
 /* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
IEEE 802.3ae clause 45 addressing mode used by 

RE: linux-next: Fixes tag needs some work in the net tree

2019-06-23 Thread Voon, Weifeng
> Hi all,
> 
> In commit
> 
>   d0bb82fd6018 ("net: stmmac: set IC bit when transmitting frames with
> HW timestamp")
> 
> Fixes tag
> 
>   Fixes: f748be531d70 ("net: stmmac: Rework coalesce timer and fix
> multi-queue races")
> 
> has these problem(s):
> 
>   - Subject does not match target commit subject
> Just use
>   git log -1 --format='Fixes: %h ("%s")'
> 
> Fixes: f748be531d70 ("stmmac: support new GMAC4")
> 
> or did you mean
> 
> Fixes: 8fce33317023 ("net: stmmac: Rework coalesce timer and fix multi-
> queue races")
> 

Sorry for the confusion, what I meant is:
Fixes: 8fce33317023 ("net: stmmac: Rework coalesce timer and fix multi-
queue races")

Regards,
Weifeng

> --
> Cheers,
> Stephen Rothwell


RE: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-19 Thread Voon, Weifeng
> > +static int est_poll_srwo(void *ioaddr) {
> > +   /* Poll until the EST GCL Control[SRWO] bit clears.
> > +* Total wait = 12 x 50ms ~= 0.6s.
> > +*/
> > +   unsigned int retries = 12;
> > +   unsigned int value;
> > +
> > +   do {
> > +   value = TSN_RD32(ioaddr + MTL_EST_GCL_CTRL);
> > +   if (!(value & MTL_EST_GCL_CTRL_SRWO))
> > +   return 0;
> > +   msleep(50);
> > +   } while (--retries);
> > +
> > +   return -ETIMEDOUT;
> 
> Maybe use one of the readx_poll_timeout() macros?
> 
> > +static int est_read_gce(void *ioaddr, unsigned int row,
> > +   unsigned int *gates, unsigned int *ti_nsec,
> > +   unsigned int dbgb, unsigned int dbgm) {
> > +   struct tsn_hw_cap *cap = _tsn_hwcap;
> > +   unsigned int ti_wid = cap->ti_wid;
> > +   unsigned int gates_mask;
> > +   unsigned int ti_mask;
> > +   unsigned int value;
> > +   int ret;
> > +
> > +   gates_mask = (1 << cap->txqcnt) - 1;
> > +   ti_mask = (1 << ti_wid) - 1;
> > +
> > +   ret = est_read_gcl_config(ioaddr, , row, 0, dbgb, dbgm);
> > +   if (ret) {
> > +   TSN_ERR("Read GCE failed! row=%u\n", row);
> 
> It is generally not a good idea to put wrappers around the kernel print
> functions. It would be better if all these functions took struct
> stmmac_priv *priv rather than ioaddr, so you could then do
> 
>   netdev_err(priv->dev, "Read GCE failed! row=%u\n", row);
> 
> > +   /* Ensure that HW is not in the midst of GCL transition */
> > +   value = TSN_RD32(ioaddr + MTL_EST_CTRL);
> 
> Also, don't put wrapper around readl()/writel().
> 
> > +   value &= ~MTL_EST_CTRL_SSWL;
> > +
> > +   /* MTL_EST_CTRL value has been read earlier, if TILS value
> > +* differs, we update here.
> > +*/
> > +   if (tils != dw_tsn_hwtunable[TSN_HWTUNA_TX_EST_TILS]) {
> > +   value &= ~MTL_EST_CTRL_TILS;
> > +   value |= (tils << MTL_EST_CTRL_TILS_SHIFT);
> > +
> > +   TSN_WR32(value, ioaddr + MTL_EST_CTRL);
> > +   dw_tsn_hwtunable[TSN_HWTUNA_TX_EST_TILS] = tils;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int est_set_ov(void *ioaddr,
> > + const unsigned int *ptov,
> > + const unsigned int *ctov)
> > +{
> > +   unsigned int value;
> > +
> > +   if (!dw_tsn_feat_en[TSN_FEAT_ID_EST])
> > +   return -ENOTSUPP;
> > +
> > +   value = TSN_RD32(ioaddr + MTL_EST_CTRL);
> > +   value &= ~MTL_EST_CTRL_SSWL;
> > +
> > +   if (ptov) {
> > +   if (*ptov > EST_PTOV_MAX) {
> > +   TSN_WARN("EST: invalid PTOV(%u), max=%u\n",
> > +*ptov, EST_PTOV_MAX);
> 
> It looks like most o the TSN_WARN should actually be netdev_dbg().
> 
>Andrew

Hi Andrew,
This file is targeted for dual licensing which is GPL-2.0 OR BSD-3-Clause.
This is the reason why we are using wrappers around the functions so that
all the function call is generic.

Regards,
Weifeng



[net v1] net: stmmac: set IC bit when transmitting frames with HW timestamp

2019-06-19 Thread Voon Weifeng
From: Roland Hii 

When transmitting certain PTP frames, e.g. SYNC and DELAY_REQ, the
PTP daemon, e.g. ptp4l, is polling the driver for the frame transmit
hardware timestamp. The polling will most likely timeout if the tx
coalesce is enabled due to the Interrupt-on-Completion (IC) bit is
not set in tx descriptor for those frames.

This patch will ignore the tx coalesce parameter and set the IC bit
when transmitting PTP frames which need to report out the frame
transmit hardware timestamp to user space.

Fixes: f748be531d70 ("net: stmmac: Rework coalesce timer and fix multi-queue 
races")
Signed-off-by: Roland Hii 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 06dd51f47cfd..06358fe5b245 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2947,12 +2947,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, 
struct net_device *dev)
 
/* Manage tx mitigation */
tx_q->tx_count_frames += nfrags + 1;
-   if (priv->tx_coal_frames <= tx_q->tx_count_frames) {
+   if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
+   !(priv->synopsys_id >= DWMAC_CORE_4_00 &&
+   (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+   priv->hwts_tx_en)) {
+   stmmac_tx_timer_arm(priv, queue);
+   } else {
+   tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
priv->xstats.tx_set_ic_bit++;
-   tx_q->tx_count_frames = 0;
-   } else {
-   stmmac_tx_timer_arm(priv, queue);
}
 
skb_tx_timestamp(skb);
@@ -3166,12 +3169,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, 
struct net_device *dev)
 * element in case of no SG.
 */
tx_q->tx_count_frames += nfrags + 1;
-   if (priv->tx_coal_frames <= tx_q->tx_count_frames) {
+   if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
+   !(priv->synopsys_id >= DWMAC_CORE_4_00 &&
+   (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+   priv->hwts_tx_en)) {
+   stmmac_tx_timer_arm(priv, queue);
+   } else {
+   tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
priv->xstats.tx_set_ic_bit++;
-   tx_q->tx_count_frames = 0;
-   } else {
-   stmmac_tx_timer_arm(priv, queue);
}
 
skb_tx_timestamp(skb);
-- 
1.9.1



[net v1] net: stmmac: fixed new system time seconds value calculation

2019-06-19 Thread Voon Weifeng
From: Roland Hii 

When ADDSUB bit is set, the system time seconds field is calculated as
the complement of the seconds part of the update value.

For example, if 3.1 seconds need to be subtracted from the
system time, this field is calculated as
2^32 - 3 = 4294967296 - 3 = 0x1 - 3 = 0xFFFD

Previously, the 0x1 is mistakenly written as 1.

This is further simplified from
  sec = (0x1ULL - sec);
to
  sec = -sec;

Fixes: ba1ffd74df74 ("stmmac: fix PTP support for GMAC4")
Signed-off-by: Roland Hii 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
index 2dcdf761d525..020159622559 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -112,7 +112,7 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, 
u32 nsec,
 * programmed with (2^32 – )
 */
if (gmac4)
-   sec = (1ULL - sec);
+   sec = -sec;
 
value = readl(ioaddr + PTP_TCR);
if (value & PTP_TCR_TSCTRLSSR)
-- 
1.9.1



[RFC net-next 5/5] net: stmmac: Set TSN HW tunable after tsn setup

2019-06-18 Thread Voon Weifeng
TSN HW tunable data for PTP Time Offset Value(PTOV),
Current Time Offset Value(CTOV) and Time Interval Shift
Amount(TILS) are added as platform data. These platform
data are set after tsn setup.

Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 16 
 include/linux/stmmac.h|  3 +++
 2 files changed, 19 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index a443c42fa58b..d3ce86abdc69 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2533,6 +2533,22 @@ static int stmmac_hw_setup(struct net_device *dev, bool 
init_ptp)
/* Setup for TSN capability */
dwmac_tsn_setup(priv->ioaddr);
 
+   /* Set TSN HW tunable */
+   if (priv->plat->ptov)
+   stmmac_set_tsn_hwtunable(priv, priv->ioaddr,
+TSN_HWTUNA_TX_EST_PTOV,
+>plat->ptov);
+
+   if (priv->plat->ctov)
+   stmmac_set_tsn_hwtunable(priv, priv->ioaddr,
+TSN_HWTUNA_TX_EST_CTOV,
+>plat->ctov);
+
+   if (priv->plat->tils)
+   stmmac_set_tsn_hwtunable(priv, priv->ioaddr,
+TSN_HWTUNA_TX_EST_TILS,
+>plat->tils);
+
return 0;
 }
 
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index d4a90f48e49b..792aa8b3e138 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -176,5 +176,8 @@ struct plat_stmmacenet_data {
int mac_port_sel_speed;
bool en_tx_lpi_clockgating;
int has_xgmac;
+   unsigned int ptov;
+   unsigned int ctov;
+   unsigned int tils;
 };
 #endif
-- 
1.9.1



[RFC net-next 4/5] net: stmmac: enable HW offloading for tc taprio

2019-06-18 Thread Voon Weifeng
This patch enable iproute2's tc taprio to run IEEE802.1Qbv using HW.
tc taprio manual can refer to:
http://man7.org/linux/man-pages/man8/tc-taprio.8.html

To enable HW offloading, an extra argument need to be added:
offload 1

Example to run:
$ tc qdisc add dev IFACE parent root handle 100 taprio \
  num_tc 3 \
  map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \
  queues 1@0 1@1 2@2 \
  base-time 1000 \
  sched-entry S 03 30 \
  sched-entry S 02 30 \
  sched-entry S 06 40 \
  clockid CLOCK_TAI
  offload 1

Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  5 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  2 +
 drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c   | 96 +++
 3 files changed, 103 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h 
b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index dec9b1f5c557..c9fa60934710 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -514,6 +514,7 @@ struct stmmac_mode_ops {
 struct stmmac_priv;
 struct tc_cls_u32_offload;
 struct tc_cbs_qopt_offload;
+struct tc_taprio_qopt_offload;
 
 struct stmmac_tc_ops {
int (*init)(struct stmmac_priv *priv);
@@ -521,6 +522,8 @@ struct stmmac_tc_ops {
 struct tc_cls_u32_offload *cls);
int (*setup_cbs)(struct stmmac_priv *priv,
 struct tc_cbs_qopt_offload *qopt);
+   int (*setup_taprio)(struct stmmac_priv *priv,
+   struct tc_taprio_qopt_offload *qopt);
 };
 
 #define stmmac_tc_init(__priv, __args...) \
@@ -529,6 +532,8 @@ struct stmmac_tc_ops {
stmmac_do_callback(__priv, tc, setup_cls_u32, __args)
 #define stmmac_tc_setup_cbs(__priv, __args...) \
stmmac_do_callback(__priv, tc, setup_cbs, __args)
+#define stmmac_tc_setup_taprio(__priv, __args...) \
+   stmmac_do_callback(__priv, tc, setup_taprio, __args)
 
 struct stmmac_counters;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index c28b5e69f2cd..a443c42fa58b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3811,6 +3811,8 @@ static int stmmac_setup_tc(struct net_device *ndev, enum 
tc_setup_type type,
return stmmac_setup_tc_block(priv, type_data);
case TC_SETUP_QDISC_CBS:
return stmmac_tc_setup_cbs(priv, priv, type_data);
+   case TC_SETUP_QDISC_TAPRIO:
+   return stmmac_tc_setup_taprio(priv, priv, type_data);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 58ea18af9813..d118e3636d50 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -7,10 +7,13 @@
 #include 
 #include 
 #include "common.h"
+#include "dw_tsn_lib.h"
 #include "dwmac4.h"
 #include "dwmac5.h"
 #include "stmmac.h"
 
+#define ONE_SEC_IN_NANOSEC 10ULL
+
 static void tc_fill_all_pass_entry(struct stmmac_tc_entry *entry)
 {
memset(entry, 0, sizeof(*entry));
@@ -349,8 +352,101 @@ static int tc_setup_cbs(struct stmmac_priv *priv,
return 0;
 }
 
+static int tc_setup_taprio(struct stmmac_priv *priv,
+  struct tc_taprio_qopt_offload *qopt)
+{
+   u64 time_extension = qopt->cycle_time_extension;
+   u64 base_time = ktime_to_ns(qopt->base_time);
+   u64 cycle_time = qopt->cycle_time;
+   struct est_gcrr egcrr;
+   u32 extension_ns;
+   u32 extension_s;
+   u32 cycle_ns;
+   u32 cycle_s;
+   u32 base_ns;
+   u32 base_s;
+   int ret;
+   int i;
+
+   if (qopt->enable) {
+   stmmac_set_est_enable(priv, priv->ioaddr, 1);
+   dev_info(priv->device, "taprio: EST enabled\n");
+   } else {
+   stmmac_set_est_enable(priv, priv->ioaddr, 0);
+   dev_info(priv->device, "taprio: EST disabled\n");
+   return 0;
+   }
+
+   dev_dbg(priv->device, "taprio: time_extension %lld, base_time %lld, 
cycle_time %lld\n",
+   qopt->cycle_time_extension, qopt->base_time, qopt->cycle_time);
+
+   for (i = 0; i < qopt->num_entries; i++) {
+   struct est_gc_entry sgce;
+
+   sgce.gates = qopt->entries[i].gate_mask;
+   sgce.ti_nsec = qopt->entries[i].interval;
+
+   /* cycle_time will be sum of all time interval
+* of the entries in the schedule if the
+* cycle_time is not provided
+*/
+   if (!qopt->cycle_time)
+  

[RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-18 Thread Voon Weifeng
From: Ong Boon Leong 

IEEE 802.1Qbv Enhancements for Scheduled Traffics (EST) is available in
EQoS ver5.xx. The change adds basic EST functionalities:

a) EST initialization with hardware capabilities detection.
b) Setting Gate Control List (GCL), i.e. gate open/close & time intervals,
   and all GC Related Registers (GCRR), e.g., base time (BTR), cycle time
   (CTR), time extension (TER) and GC List Length (LLR).
c) Setting time interval left shift (TILS), PTP time offset (PTOV) and
   current time offset (CTOV).
d) Enable/disable EST.
e) Getting TSN hardware capabilities.
f) Getting Gate Control configuration either from driver data store or
   hardware.

We extend the main driver logic to include basic TSN capability discovery,
and setup. We also add EST feature enable/disable control.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c  | 790 ++
 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h  | 173 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c |  13 +
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  52 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  46 ++
 include/linux/stmmac.h|   1 +
 7 files changed, 1076 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile 
b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c59926d96bcc..76fb36cb4da7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o 
ring_mode.o  \
  mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
  dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
  stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
- $(stmmac-y)
+ dw_tsn_lib.o $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c 
b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
new file mode 100644
index ..cba27c604cb1
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
@@ -0,0 +1,790 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright (c) 2019, Intel Corporation.
+ * dw_tsn_lib.c: DW EQoS v5.00 TSN capabilities
+ */
+
+#include "dwmac4.h"
+#include "dwmac5.h"
+#include "dw_tsn_lib.h"
+
+static struct tsn_hw_cap dw_tsn_hwcap;
+static bool dw_tsn_feat_en[TSN_FEAT_ID_MAX];
+static unsigned int dw_tsn_hwtunable[TSN_HWTUNA_MAX];
+static struct est_gc_config dw_est_gc_config;
+
+static unsigned int est_get_gcl_depth(unsigned int hw_cap)
+{
+   unsigned int estdep = (hw_cap & GMAC_HW_FEAT_ESTDEP)
+   >> GMAC_HW_FEAT_ESTDEP_SHIFT;
+   unsigned int depth;
+
+   switch (estdep) {
+   case 1:
+   depth = 64;
+   break;
+   case 2:
+   depth = 128;
+   break;
+   case 3:
+   depth = 256;
+   break;
+   case 4:
+   depth = 512;
+   break;
+   case 5:
+   depth = 1024;
+   break;
+   default:
+   depth = 0;
+   }
+
+   return depth;
+}
+
+static unsigned int est_get_ti_width(unsigned int hw_cap)
+{
+   unsigned int estwid = (hw_cap & GMAC_HW_FEAT_ESTWID)
+   >> GMAC_HW_FEAT_ESTWID_SHIFT;
+   unsigned int width;
+
+   switch (estwid) {
+   case 1:
+   width = 16;
+   break;
+   case 2:
+   width = 20;
+   break;
+   case 3:
+   width = 24;
+   break;
+   default:
+   width = 0;
+   }
+
+   return width;
+}
+
+static int est_poll_srwo(void *ioaddr)
+{
+   /* Poll until the EST GCL Control[SRWO] bit clears.
+* Total wait = 12 x 50ms ~= 0.6s.
+*/
+   unsigned int retries = 12;
+   unsigned int value;
+
+   do {
+   value = TSN_RD32(ioaddr + MTL_EST_GCL_CTRL);
+   if (!(value & MTL_EST_GCL_CTRL_SRWO))
+   return 0;
+   msleep(50);
+   } while (--retries);
+
+   return -ETIMEDOUT;
+}
+
+static int est_set_gcl_addr(void *ioaddr, unsigned int addr,
+   unsigned int gcrr, unsigned int rwops,
+   unsigned int dbgb, unsigned int dbgm)
+{
+   unsigned int value;
+
+   value = MTL_EST_GCL_CTRL_ADDR_VAL(addr) & MTL_EST_GCL_CTRL_ADDR;
+
+   if (dbgm) {
+   if 

[RFC net-next 0/5] net: stmmac: Introducing IEEE802.1Qbv feature

2019-06-18 Thread Voon Weifeng
Enabling IEEE 802.1Qbv Enhancements for Scheduled Traffics (EST) which
is available in EQoS ver5.xx. The EST features can be configured using
tc taprio hw offload which proposed by Vinicius. A few hw tunable data
are configured through platform data.

Ong Boon Leong (1):
  net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

Vinicius Costa Gomes (1):
  taprio: Add support for hardware offloading

Voon Weifeng (3):
  net: stmmac: gcl errors reporting and its interrupt handling
  net: stmmac: enable HW offloading for tc taprio
  net: stmmac: Set TSN HW tunable after tsn setup

 drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h  |   4 +
 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c  | 913 ++
 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h  | 218 ++
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c |  16 +
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  66 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  71 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c   |  96 +++
 include/linux/netdevice.h |   1 +
 include/linux/stmmac.h|   4 +
 include/net/pkt_sched.h   |  18 +
 include/uapi/linux/pkt_sched.h|   4 +
 net/sched/sch_taprio.c| 263 ++-
 13 files changed, 1673 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h

-- 
1.9.1



[RFC net-next 2/5] net: stmmac: gcl errors reporting and its interrupt handling

2019-06-18 Thread Voon Weifeng
Enabled interrupt for Constant Gate Control Error (CGCE), Head-of-Line
Blocking due to scheduling error (HLBS) and Head-of-Line Blocking due to
frame size error (HLBF).

CGCE should not happen as the driver has already implemented a check
before applying the settings. CGCE handling is added as a safety
check so that we can catch it if there is such error being fired. For
HLBS, the user will get the info of all the queues that shows this
error. For HLBF, the user will get the info of all the queue with the
latest frame size which causes the error. Frame size 0 indicates no
error.

This patch also added functionality to get and clear the gcl errors.

The ISR handling takes place when EST feature is enabled by user.

Signed-off-by: Voon Weifeng 
Signed-off-by: Ong Boon Leong 
---
 drivers/net/ethernet/stmicro/stmmac/common.h  |   4 +
 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c  | 123 ++
 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h  |  45 
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c |   3 +
 drivers/net/ethernet/stmicro/stmmac/hwif.h|   9 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   7 ++
 6 files changed, 191 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index ad9e9368535d..9723b0a12110 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -407,6 +407,9 @@ struct mii_regs {
unsigned int clk_csr_mask;
 };
 
+/* tsn capability,  meant for mac_device_info->tsn_cap */
+#define TSN_CAP_ESTBIT(0)
+
 struct mac_device_info {
const struct stmmac_ops *mac;
const struct stmmac_desc_ops *desc;
@@ -425,6 +428,7 @@ struct mac_device_info {
unsigned int pcs;
unsigned int pmt;
unsigned int ps;
+   u32 tsn_cap;
 };
 
 struct stmmac_rx_routing {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c 
b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
index cba27c604cb1..f14e86fcc93c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
@@ -11,6 +11,7 @@
 static bool dw_tsn_feat_en[TSN_FEAT_ID_MAX];
 static unsigned int dw_tsn_hwtunable[TSN_HWTUNA_MAX];
 static struct est_gc_config dw_est_gc_config;
+static struct tsn_err_stat dw_err_stat;
 
 static unsigned int est_get_gcl_depth(unsigned int hw_cap)
 {
@@ -295,6 +296,24 @@ void dwmac_tsn_init(void *ioaddr)
 gcl_depth, ti_wid, tils_max, cap->txqcnt);
 }
 
+/* dwmac_tsn_setup is called within stmmac_hw_setup() after
+ * stmmac_init_dma_engine() which resets MAC controller.
+ * This is so-that MAC registers are not cleared.
+ */
+void dwmac_tsn_setup(void *ioaddr)
+{
+   struct tsn_hw_cap *cap = _tsn_hwcap;
+   unsigned int value;
+
+   if (cap->est_support) {
+   /* Enable EST interrupts */
+   value = (MTL_EST_INT_EN_CGCE | MTL_EST_INT_EN_IEHS |
+MTL_EST_INT_EN_IEHF | MTL_EST_INT_EN_IEBE |
+MTL_EST_INT_EN_IECC);
+   TSN_WR32(value, ioaddr + MTL_EST_INT_EN);
+   }
+}
+
 void dwmac_get_tsn_hwcap(struct tsn_hw_cap **tsn_hwcap)
 {
*tsn_hwcap = _tsn_hwcap;
@@ -788,3 +807,107 @@ int dwmac_get_est_gcc(void *ioaddr,
 
return 0;
 }
+
+int dwmac_est_irq_status(void *ioaddr)
+{
+   struct tsn_err_stat *err_stat = _err_stat;
+   struct tsn_hw_cap *cap = _tsn_hwcap;
+   unsigned int txqcnt_mask = 0;
+   unsigned int status = 0;
+   unsigned int value = 0;
+   unsigned int feqn = 0;
+   unsigned int hbfq = 0;
+   unsigned int hbfs = 0;
+
+   txqcnt_mask = (1 << cap->txqcnt) - 1;
+   status = TSN_RD32(ioaddr + MTL_EST_STATUS);
+
+   value = (MTL_EST_STATUS_CGCE | MTL_EST_STATUS_HLBS |
+MTL_EST_STATUS_HLBF | MTL_EST_STATUS_BTRE |
+MTL_EST_STATUS_SWLC);
+
+   /* Return if there is no error */
+   if (!(status & value))
+   return 0;
+
+   /* spin_lock() is not needed here because of BTRE and SWLC
+* bit will not be altered. Both of the bit will be
+* polled in dwmac_set_est_gcrr_times()
+*/
+   if (status & MTL_EST_STATUS_CGCE) {
+   /* Clear Interrupt */
+   TSN_WR32(MTL_EST_STATUS_CGCE, ioaddr + MTL_EST_STATUS);
+
+   err_stat->cgce_n++;
+   }
+
+   if (status & MTL_EST_STATUS_HLBS) {
+   value = TSN_RD32(ioaddr + MTL_EST_SCH_ERR);
+   value &= txqcnt_mask;
+
+   /* Clear Interrupt */
+   TSN_WR32(value, ioaddr + MTL_EST_SCH_ERR);
+
+   /* Collecting info to shows all the queues that has HLBS */
+   /* issue. The only way to clear this is to clear the */
+   /* statistic  */
+   err_stat->hlbs_q 

[RFC net-next 3/5] taprio: Add support for hardware offloading

2019-06-18 Thread Voon Weifeng
From: Vinicius Costa Gomes 

This allows taprio to offload the schedule enforcement to capable
network cards, resulting in more precise windows and less CPU usage.

The important detail here is the difference between the gate_mask in
taprio and gate_mask for the network driver. For the driver, each bit
in gate_mask references a transmission queue: bit 0 for queue 0, bit 1
for queue 1, and so on. This is done so the driver doesn't need to
know about traffic classes.

Signed-off-by: Vinicius Costa Gomes 
Signed-off-by: Voon Weifeng 
---
 include/linux/netdevice.h  |   1 +
 include/net/pkt_sched.h|  18 +++
 include/uapi/linux/pkt_sched.h |   4 +
 net/sched/sch_taprio.c | 263 -
 4 files changed, 284 insertions(+), 2 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index eeacebd7debb..e6bf0ede8cfa 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -845,6 +845,7 @@ enum tc_setup_type {
TC_SETUP_QDISC_ETF,
TC_SETUP_ROOT_QDISC,
TC_SETUP_QDISC_GRED,
+   TC_SETUP_QDISC_TAPRIO,
 };
 
 /* These structures hold the attributes of bpf state that are being passed
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index a16fbe9a2a67..c107f920 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -161,4 +161,22 @@ struct tc_etf_qopt_offload {
s32 queue;
 };
 
+struct tc_taprio_sched_entry {
+   u8 command; /* TC_TAPRIO_CMD_* */
+
+   /* The gate_mask in the offloading side refers to HW queues */
+   u32 gate_mask;
+   u32 interval;
+};
+
+struct tc_taprio_qopt_offload {
+   u8 enable;
+   ktime_t base_time;
+   u64 cycle_time;
+   u64 cycle_time_extension;
+
+   size_t num_entries;
+   struct tc_taprio_sched_entry entries[0];
+};
+
 #endif
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 8b2f993cbb77..08a260fd7843 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -1158,6 +1158,9 @@ enum {
  *   [TCA_TAPRIO_ATTR_SCHED_ENTRY_INTERVAL]
  */
 
+#define TCA_TAPRIO_ATTR_OFFLOAD_FLAG_FULL_OFFLOAD 0x1
+#define TCA_TAPRIO_ATTR_OFFLOAD_FLAG_TXTIME_OFFLOAD 0x2
+
 enum {
TCA_TAPRIO_ATTR_UNSPEC,
TCA_TAPRIO_ATTR_PRIOMAP, /* struct tc_mqprio_qopt */
@@ -1169,6 +1172,7 @@ enum {
TCA_TAPRIO_ATTR_ADMIN_SCHED, /* The admin sched, only used in dump */
TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME, /* s64 */
TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME_EXTENSION, /* s64 */
+   TCA_TAPRIO_ATTR_OFFLOAD_FLAGS, /* u32 */
__TCA_TAPRIO_ATTR_MAX,
 };
 
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index 9ecfb8f5902a..9e8f066a2474 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -26,6 +26,9 @@
 static DEFINE_SPINLOCK(taprio_list_lock);
 
 #define TAPRIO_ALL_GATES_OPEN -1
+#define FULL_OFFLOAD_IS_ON(flags) ((flags) & 
TCA_TAPRIO_ATTR_OFFLOAD_FLAG_FULL_OFFLOAD)
+#define TXTIME_OFFLOAD_IS_ON(flags) ((flags) & 
TCA_TAPRIO_ATTR_OFFLOAD_FLAG_TXTIME_OFFLOAD)
+#define VALID_OFFLOAD(flags) ((flags) != U32_MAX)
 
 struct sched_entry {
struct list_head list;
@@ -55,6 +58,8 @@ struct sched_gate_list {
 struct taprio_sched {
struct Qdisc **qdiscs;
struct Qdisc *root;
+   struct tc_mqprio_qopt mqprio;
+   u32 offload_flags;
int clockid;
atomic64_t picos_per_byte; /* Using picoseconds because for 10Gbps+
* speeds it's sub-nanoseconds per byte
@@ -66,6 +71,8 @@ struct taprio_sched {
struct sched_gate_list __rcu *oper_sched;
struct sched_gate_list __rcu *admin_sched;
ktime_t (*get_time)(void);
+   struct sk_buff *(*dequeue)(struct Qdisc *sch);
+   struct sk_buff *(*peek)(struct Qdisc *sch);
struct hrtimer advance_timer;
struct list_head taprio_list;
 };
@@ -143,7 +150,30 @@ static int taprio_enqueue(struct sk_buff *skb, struct 
Qdisc *sch,
return qdisc_enqueue(skb, child, to_free);
 }
 
-static struct sk_buff *taprio_peek(struct Qdisc *sch)
+static struct sk_buff *taprio_peek_offload(struct Qdisc *sch)
+{
+   struct taprio_sched *q = qdisc_priv(sch);
+   struct net_device *dev = qdisc_dev(sch);
+   struct sk_buff *skb;
+   int i;
+
+   for (i = 0; i < dev->num_tx_queues; i++) {
+   struct Qdisc *child = q->qdiscs[i];
+
+   if (unlikely(!child))
+   continue;
+
+   skb = child->ops->peek(child);
+   if (!skb)
+   continue;
+
+   return skb;
+   }
+
+   return NULL;
+}
+
+static struct sk_buff *taprio_peek_soft(struct Qdisc *sch)
 {
struct taprio_sched *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
@@ -184,6 +214,13 @@ static struct sk_buff *taprio_peek(struct Qdisc *sch)
return NULL;
 }
 

[PATCH net-next v6 4/5] net: stmmac: add xPCS functions for device with DWMACv5.1

2019-06-04 Thread Voon Weifeng
From: Ong Boon Leong 

We introduce support for driver that has v5.10 IP and is also using
xPCS as MMD. This can be easily enabled for other product that integrates
xPCS that is not using v5.00 IP.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Reviewed-by: Baoli Zhang 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
Acked-by: Jose Abreu 
---
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 34 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.c| 42 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  2 ++
 3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 5e98da4e14f9..ccc5f8355dda 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -824,6 +824,40 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, 
bool enable)
.set_mac_loopback = dwmac4_set_mac_loopback,
 };
 
+const struct stmmac_ops dwmac510_xpcs_ops = {
+   .core_init = dwmac4_core_init,
+   .set_mac = stmmac_dwmac4_set_mac,
+   .rx_ipc = dwmac4_rx_ipc_enable,
+   .rx_queue_enable = dwmac4_rx_queue_enable,
+   .rx_queue_prio = dwmac4_rx_queue_priority,
+   .tx_queue_prio = dwmac4_tx_queue_priority,
+   .rx_queue_routing = dwmac4_rx_queue_routing,
+   .prog_mtl_rx_algorithms = dwmac4_prog_mtl_rx_algorithms,
+   .prog_mtl_tx_algorithms = dwmac4_prog_mtl_tx_algorithms,
+   .set_mtl_tx_queue_weight = dwmac4_set_mtl_tx_queue_weight,
+   .map_mtl_to_dma = dwmac4_map_mtl_dma,
+   .config_cbs = dwmac4_config_cbs,
+   .dump_regs = dwmac4_dump_regs,
+   .host_irq_status = dwmac4_irq_status,
+   .host_mtl_irq_status = dwmac4_irq_mtl_status,
+   .flow_ctrl = dwmac4_flow_ctrl,
+   .pmt = dwmac4_pmt,
+   .set_umac_addr = dwmac4_set_umac_addr,
+   .get_umac_addr = dwmac4_get_umac_addr,
+   .set_eee_mode = dwmac4_set_eee_mode,
+   .reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_timer = dwmac4_set_eee_timer,
+   .set_eee_pls = dwmac4_set_eee_pls,
+   .debug = dwmac4_debug,
+   .set_filter = dwmac4_set_filter,
+   .safety_feat_config = dwmac5_safety_feat_config,
+   .safety_feat_irq_status = dwmac5_safety_feat_irq_status,
+   .safety_feat_dump = dwmac5_safety_feat_dump,
+   .rxp_config = dwmac5_rxp_config,
+   .flex_pps_config = dwmac5_flex_pps_config,
+   .set_mac_loopback = dwmac4_set_mac_loopback,
+};
+
 int dwmac4_setup(struct stmmac_priv *priv)
 {
struct mac_device_info *mac = priv->hw;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c 
b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 6c61b753b55e..052a000feeb5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -73,11 +73,13 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
bool gmac;
bool gmac4;
bool xgmac;
+   bool has_xpcs;
u32 min_id;
const struct stmmac_regs_off regs;
const void *desc;
const void *dma;
const void *mac;
+   const void *xpcs;
const void *hwtimestamp;
const void *mode;
const void *tc;
@@ -90,6 +92,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = false,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -98,6 +101,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.desc = NULL,
.dma = _dma_ops,
.mac = _ops,
+   .xpcs = NULL,
.hwtimestamp = _ptp,
.mode = NULL,
.tc = NULL,
@@ -108,6 +112,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = true,
.gmac4 = false,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -116,6 +121,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.desc = NULL,
.dma = _dma_ops,
.mac = _ops,
+   .xpcs = NULL,
.hwtimestamp = _ptp,
.mode = NULL,
.tc = NULL,
@@ -126,6 +132,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = true,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
@@ -133,6 +140,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *p

[PATCH net-next v6 5/5] net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

2019-06-04 Thread Voon Weifeng
Added EHL SGMII 1Gbps PCI ID. Different MII and speed will have
different PCI ID.

Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 111 +++
 1 file changed, 111 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 7cbc01f316fa..1bdf716bfcbb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -23,6 +23,7 @@
 #include 
 
 #include "stmmac.h"
+#include "dwxpcs.h"
 
 /*
  * This struct is used to associate PCI Function of MAC controller on a board,
@@ -118,6 +119,113 @@ static int stmmac_default_data(struct pci_dev *pdev,
.setup = stmmac_default_data,
 };
 
+static int ehl_common_data(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat)
+{
+   int i;
+
+   plat->bus_id = 1;
+   plat->phy_addr = 0;
+   plat->clk_csr = 5;
+   plat->has_gmac = 0;
+   plat->has_gmac4 = 1;
+   plat->xpcs_phy_addr = 0x16;
+   plat->pcs_mode = AN_CTRL_PCS_MD_C37_SGMII;
+   plat->force_sf_dma_mode = 0;
+   plat->tso_en = 1;
+
+   plat->rx_queues_to_use = 8;
+   plat->tx_queues_to_use = 8;
+   plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
+
+   for (i = 0; i < plat->rx_queues_to_use; i++) {
+   plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+   plat->rx_queues_cfg[i].chan = i;
+
+   /* Disable Priority config by default */
+   plat->rx_queues_cfg[i].use_prio = false;
+
+   /* Disable RX queues routing by default */
+   plat->rx_queues_cfg[i].pkt_route = 0x0;
+   }
+
+   for (i = 0; i < plat->tx_queues_to_use; i++) {
+   plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+
+   /* Disable Priority config by default */
+   plat->tx_queues_cfg[i].use_prio = false;
+   }
+
+   plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
+   plat->tx_queues_cfg[0].weight = 0x09;
+   plat->tx_queues_cfg[1].weight = 0x0A;
+   plat->tx_queues_cfg[2].weight = 0x0B;
+   plat->tx_queues_cfg[3].weight = 0x0C;
+   plat->tx_queues_cfg[4].weight = 0x0D;
+   plat->tx_queues_cfg[5].weight = 0x0E;
+   plat->tx_queues_cfg[6].weight = 0x0F;
+   plat->tx_queues_cfg[7].weight = 0x10;
+
+   plat->mdio_bus_data->phy_reset = NULL;
+   plat->mdio_bus_data->phy_mask = 0;
+
+   plat->dma_cfg->pbl = 32;
+   plat->dma_cfg->pblx8 = true;
+   plat->dma_cfg->fixed_burst = 0;
+   plat->dma_cfg->mixed_burst = 0;
+   plat->dma_cfg->aal = 0;
+
+   plat->axi = devm_kzalloc(>dev, sizeof(*plat->axi),
+GFP_KERNEL);
+   if (!plat->axi)
+   return -ENOMEM;
+
+   plat->axi->axi_lpi_en = 0;
+   plat->axi->axi_xit_frm = 0;
+   plat->axi->axi_wr_osr_lmt = 1;
+   plat->axi->axi_rd_osr_lmt = 1;
+   plat->axi->axi_blen[0] = 4;
+   plat->axi->axi_blen[1] = 8;
+   plat->axi->axi_blen[2] = 16;
+
+   /* Set default value for multicast hash bins */
+   plat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+   /* Set default value for unicast filter entries */
+   plat->unicast_filter_entries = 1;
+
+   /* Set the maxmtu to a default of JUMBO_LEN */
+   plat->maxmtu = JUMBO_LEN;
+
+   /* Set 32KB fifo size as the advertised fifo size in
+* the HW features is not the same as the HW implementation
+*/
+   plat->tx_fifo_size = 32768;
+   plat->rx_fifo_size = 32768;
+
+   return 0;
+}
+
+static int ehl_sgmii1g_data(struct pci_dev *pdev,
+   struct plat_stmmacenet_data *plat)
+{
+   int ret;
+
+   /* Set common default data first */
+   ret = ehl_common_data(pdev, plat);
+   if (ret)
+   return ret;
+
+   plat->interface = PHY_INTERFACE_MODE_SGMII;
+   plat->has_xpcs = 1;
+
+   return 0;
+}
+
+static struct stmmac_pci_info ehl_sgmii1g_pci_info = {
+   .setup = ehl_sgmii1g_data,
+};
+
 static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = {
{
.func = 6,
@@ -290,6 +398,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
res.addr = pcim_iomap_table(pdev)[i];
res.wol_irq = pdev->irq;
res.irq = pdev->irq;
+   res.xpcs_irq = 0;
 
return stmmac_dvr_probe(>dev, plat, );
 }
@@ -359,6 +468,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
 
 #define STMMAC_QUARK_ID  0x0937
 #define STMMAC_DEVICE_ID 0x1108
+#define STMMAC_EHL_SGMII1G_ID   0x4b31
 
 #define STMMAC_DEVICE(vendor_id, dev_id, info) {   \

[PATCH net-next v6 3/5] net: stmmac: add xpcs function hooks into main driver and ethtool

2019-06-04 Thread Voon Weifeng
From: Ong Boon Leong 

With xPCS functions now ready, we add them into the main driver and
ethtool logics. To differentiate from EQoS MAC PCS and DWC Ethernet
xPCS, we introduce 'has_xpcs' in platform data as a mean to indicate
whether GBE controller includes xPCS or not.

To support platform-specific C37 AN PCS mode selection for MII MMD,
we introduce 'pcs_mode' in platform data.

The basic framework for xPCS interrupt handling is implemented too.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Reviewed-by: Baoli Zhang 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h   |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 ++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 139 +++--
 include/linux/stmmac.h |   2 +
 4 files changed, 145 insertions(+), 48 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index a16ada8b8507..999311236521 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -36,6 +36,7 @@ struct stmmac_resources {
const char *mac;
int wol_irq;
int lpi_irq;
+   int xpcs_irq;
int irq;
 };
 
@@ -168,6 +169,7 @@ struct stmmac_priv {
int clk_csr;
struct timer_list eee_ctrl_timer;
int lpi_irq;
+   int xpcs_irq;
int eee_enabled;
int eee_active;
int tx_lpi_timer;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index cec51ba34296..be6edbe3d658 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -28,6 +28,7 @@
 
 #include "stmmac.h"
 #include "dwmac_dma.h"
+#include "dwxpcs.h"
 
 #define REG_SPACE_SIZE 0x1060
 #define MAC100_ETHTOOL_NAME"st_mac100"
@@ -277,7 +278,8 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
struct phy_device *phy = dev->phydev;
 
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-   priv->hw->pcs & STMMAC_PCS_SGMII) {
+   priv->hw->pcs & STMMAC_PCS_SGMII ||
+   priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
struct rgmii_adv adv;
u32 supported, advertising, lp_advertising;
 
@@ -294,6 +296,11 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
if (stmmac_pcs_get_adv_lp(priv, priv->ioaddr, ))
return -EOPNOTSUPP; /* should never happen indeed */
 
+   /* Get ADV & LPA is only application for 1000BASE-X C37.
+* For MAC side SGMII AN, get ADV & LPA from PHY.
+*/
+   stmmac_xpcs_get_adv_lp(priv, dev, , priv->plat->pcs_mode);
+
/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
 
ethtool_convert_link_mode_to_legacy_u32(
@@ -376,22 +383,23 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
int rc;
 
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-   priv->hw->pcs & STMMAC_PCS_SGMII) {
-   u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
-
+   priv->hw->pcs & STMMAC_PCS_SGMII ||
+   priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
/* Only support ANE */
if (cmd->base.autoneg != AUTONEG_ENABLE)
return -EINVAL;
 
-   mask &= (ADVERTISED_1000baseT_Half |
-   ADVERTISED_1000baseT_Full |
-   ADVERTISED_100baseT_Half |
-   ADVERTISED_100baseT_Full |
-   ADVERTISED_10baseT_Half |
-   ADVERTISED_10baseT_Full);
-
mutex_lock(>lock);
stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0);
+
+   /* For 1000BASE-X C37 AN, it is always 1000Mbps. And, we only
+* support FD which is set by default in SR_MII_AN_ADV
+* during XPCS init. So, we don't need to set FD again.
+* For SGMII C37 AN, we let user to change link settings
+* through PHY since it is MAC side SGMII.
+*/
+   stmmac_xpcs_ctrl_ane(priv, dev, 1, 0);
+
mutex_unlock(>lock);
 
return 0;
@@ -457,6 +465,16 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
pause->autoneg = 1;
if (!adv_lp.pause)
return;
+   } else if (priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX &&
+  !stmmac_xpcs_ge

[PATCH net-next v6 0/5] net: stmmac: enable EHL SGMII

2019-06-04 Thread Voon Weifeng
This patch-set is to enable Ethernet controller
(DW Ethernet QoS and DW Ethernet PCS) with SGMII interface in Elkhart Lake.
The DW Ethernet PCS is the Physical Coding Sublayer that is between Ethernet
MAC and PHY and uses MDIO Clause-45 as Communication.

Selttests results:
root@intel-corei7-64:~# ethtool -t eth0
The test result is PASS
The test extra info:
 1. MAC Loopback 0
 2. PHY Loopback -95
 3. MMC Counters 0
 4. EEE  -95
 5. Hash Filter MC   0
 6. Perfect Filter UC0
 7. MC Filter0
 8. UC Filter0
 9. Flow Control 0

Kweh Hock Leong (1):
  net: stmmac: enable clause 45 mdio support

Ong Boon Leong (3):
  net: stmmac: introducing support for DWC xPCS logics
  net: stmmac: add xpcs function hooks into main driver and ethtool
  net: stmmac: add xPCS functions for device with DWMACv5.1

Voon Weifeng (1):
  net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

 drivers/net/ethernet/stmicro/stmmac/Makefile   |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h   |   1 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c  |  34 
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c   | 208 +
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h   |  51 +
 drivers/net/ethernet/stmicro/stmmac/hwif.c |  42 -
 drivers/net/ethernet/stmicro/stmmac/hwif.h |  21 +++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h   |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 +++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 139 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c  |  40 +++-
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c   | 111 +++
 include/linux/phy.h|   2 +
 include/linux/stmmac.h |   3 +
 14 files changed, 648 insertions(+), 58 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h

-- 
Changelog v6:
*Added missing selftests entry in dwmac510_xpcs_ops
*Applied more reversed christmas tree
Changelog v5:
*Cosmetic touch up
*Change axi_wr_osr_lmt and axi_rd_osr_lmt value to 1 since the register
 has a default value of 1
Changelog v4:
*Rebased to latest net-next
Changelog v3:
*Applied reversed christmas tree
Changelog v2:
*Added support for the C37 AN for 1000BASE-X and SGMII (MAC side SGMII only)
*removed and submitted the fix patch to net
 "net: stmmac: dma channel control register need to be init first"
*Squash the following 2 patches and move it to the end of the patch set:
 "net: stmmac: add EHL SGMII 1Gbps platform data and PCI ID"
 "net: stmmac: add xPCS platform data for EHL"
1.9.1



[PATCH net-next v6 1/5] net: stmmac: enable clause 45 mdio support

2019-06-04 Thread Voon Weifeng
From: Kweh Hock Leong 

DWMAC4 is capable to support clause 45 mdio communication.
This patch enable the feature on stmmac_mdio_write() and
stmmac_mdio_read() by following phy_write_mmd() and
phy_read_mmd() mdiobus read write implementation format.

Reviewed-by: Li, Yifan 
Signed-off-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Weifeng Voon 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 40 ++-
 include/linux/phy.h   |  2 ++
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 093a223fe408..073078c7a7d0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -34,11 +34,27 @@
 
 #define MII_BUSY 0x0001
 #define MII_WRITE 0x0002
+#define MII_DATA_MASK GENMASK(15, 0)
 
 /* GMAC4 defines */
 #define MII_GMAC4_GOC_SHIFT2
+#define MII_GMAC4_REG_ADDR_SHIFT   16
 #define MII_GMAC4_WRITE(1 << MII_GMAC4_GOC_SHIFT)
 #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
+#define MII_GMAC4_C45E BIT(1)
+
+static void stmmac_mdio_c45_setup(struct stmmac_priv *priv, int phyreg,
+ u32 *val, u32 *data)
+{
+   unsigned int reg_shift = priv->hw->mii.reg_shift;
+   unsigned int reg_mask = priv->hw->mii.reg_mask;
+
+   *val |= MII_GMAC4_C45E;
+   *val &= ~reg_mask;
+   *val |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << reg_shift) & reg_mask;
+
+   *data |= (phyreg & MII_REGADDR_C45_MASK) << MII_GMAC4_REG_ADDR_SHIFT;
+}
 
 /* XGMAC defines */
 #define MII_XGMAC_SADDRBIT(18)
@@ -165,22 +181,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
-   int data;
u32 value = MII_BUSY;
+   int data = 0;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_READ;
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   }
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
   100, 1))
return -EBUSY;
 
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -188,7 +208,7 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
return -EBUSY;
 
/* Read the data from the MII data register */
-   data = (int)readl(priv->ioaddr + mii_data);
+   data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
 
return data;
 }
@@ -208,8 +228,9 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
u32 value = MII_BUSY;
+   int data = phydata;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
@@ -217,10 +238,13 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
 
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_WRITE;
-   else
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   } else {
value |= MII_WRITE;
+   }
 
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -228,7 +252,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
return -EBUSY;
 
/* Set the MII address register to write */
-   writel(phydata, priv->ioaddr + mii_data);
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
/* Wait until any existing MII operation is complete */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index dc4b51060ebc..a2c25a975661 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -200,6 +200,8 @@ 

[PATCH net-next v6 2/5] net: stmmac: introducing support for DWC xPCS logics

2019-06-04 Thread Voon Weifeng
From: Ong Boon Leong 

xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated
into a GbE controller that uses DWC EQoS MAC controller. An example of
HW configuration is shown below:-

  <-GBE Controller-->|<--External PHY chip-->

  +--+ +++---+   +--+
  |   EQoS   | <-GMII->| DW |<-->|PHY| <-- SGMII --> | External GbE |
  |   MAC| |xPCS||IF |   | PHY Chip |
  +--+ +++---+   +--+
 ^   ^  ^
 |   |  |
 +-MDIO-+

xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
differentiate it from external PHY chip that is discovered over MDIO.
Therefore, xpcs_phy_addr is introduced in stmmac platform data
(plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
belongs to external PHY.

Basic functionalities for initializing xPCS and configuring auto
negotiation (AN), loopback, link status, AN advertisement and Link
Partner ability are implemented. The implementation supports the C37
AN for 1000BASE-X and SGMII (MAC side SGMII only).

Tested-by: Tan, Tee Min 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/Makefile |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h |   1 +
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c | 208 +++
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h |  51 +++
 drivers/net/ethernet/stmicro/stmmac/hwif.h   |  19 +++
 include/linux/stmmac.h   |   1 +
 6 files changed, 281 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile 
b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c59926d96bcc..f007fb873455 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o 
ring_mode.o  \
  mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
  dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
  stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
- $(stmmac-y)
+ dwxpcs.o $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 1961fe9144ca..83df093c4636 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -419,6 +419,7 @@ struct mii_regs {
 
 struct mac_device_info {
const struct stmmac_ops *mac;
+   const struct stmmac_xpcs_ops *xpcs;
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
const struct stmmac_mode_ops *mode;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c 
b/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
new file mode 100644
index ..7e850b9dd7b7
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Intel Corporation.
+ * DWC Ethernet Physical Coding Sublayer
+ */
+#include 
+#include 
+#include "dwxpcs.h"
+#include "stmmac.h"
+
+/* DW xPCS mdiobus_read and mdiobus_write helper functions */
+#define xpcs_read(dev, reg) \
+   mdiobus_read(priv->mii, xpcs_phy_addr, \
+MII_ADDR_C45 | (reg) | \
+((dev) << MII_DEVADDR_C45_SHIFT))
+#define xpcs_write(dev, reg, val) \
+   mdiobus_write(priv->mii, xpcs_phy_addr, \
+ MII_ADDR_C45 | (reg) | \
+ ((dev) << MII_DEVADDR_C45_SHIFT), val)
+
+static void dw_xpcs_init(struct net_device *ndev, int pcs_mode)
+{
+   struct stmmac_priv *priv = netdev_priv(ndev);
+   int xpcs_phy_addr;
+   int phydata;
+
+   xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+
+   if (pcs_mode == AN_CTRL_PCS_MD_C37_SGMII) {
+   /* For AN for SGMII mode, the settings are :-
+* 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
+* 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
+*DW xPCS used with DW EQoS MAC is always MAC
+*side SGMII.
+* 3) VR_MII_AN_CTRL Bit(0) [AN_INTR_EN] = 1b (AN Interrupt
+*enabled)
+* 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
+*speed mode change after SGMII AN complete)
+ 

RE: [PATCH net-next v5 0/5] net: stmmac: enable EHL SGMI

2019-06-04 Thread Voon, Weifeng
> > This patch-set is to enable Ethernet controller (DW Ethernet QoS and
> > DW Ethernet PCS) with SGMII interface in Elkhart Lake.
> > The DW Ethernet PCS is the Physical Coding Sublayer that is between
> > Ethernet MAC and PHY and uses MDIO Clause-45 as Communication.
> 
> This series look fine to me but unfortunately I don't have my GMAC5.10
> setup available to test for regressions ... The changes look isolated
> though.
> 
> Could you please run the stmmac selftests at least and add the output
> here ?

Sure, the selftests feature is good as I am able to detect that the 
dwmac510_xpcs_ops misses the selftest entry. I will fix and add the
selftests results in the v6 cover letter. 


> 
> Thanks,
> Jose Miguel Abreu


[PATCH net-next v5 5/5] net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

2019-05-31 Thread Voon Weifeng
Added EHL SGMII 1Gbps PCI ID. Different MII and speed will have
different PCI ID.

Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 111 +++
 1 file changed, 111 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 7cbc01f316fa..1bdf716bfcbb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -23,6 +23,7 @@
 #include 
 
 #include "stmmac.h"
+#include "dwxpcs.h"
 
 /*
  * This struct is used to associate PCI Function of MAC controller on a board,
@@ -118,6 +119,113 @@ static int stmmac_default_data(struct pci_dev *pdev,
.setup = stmmac_default_data,
 };
 
+static int ehl_common_data(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat)
+{
+   int i;
+
+   plat->bus_id = 1;
+   plat->phy_addr = 0;
+   plat->clk_csr = 5;
+   plat->has_gmac = 0;
+   plat->has_gmac4 = 1;
+   plat->xpcs_phy_addr = 0x16;
+   plat->pcs_mode = AN_CTRL_PCS_MD_C37_SGMII;
+   plat->force_sf_dma_mode = 0;
+   plat->tso_en = 1;
+
+   plat->rx_queues_to_use = 8;
+   plat->tx_queues_to_use = 8;
+   plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
+
+   for (i = 0; i < plat->rx_queues_to_use; i++) {
+   plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+   plat->rx_queues_cfg[i].chan = i;
+
+   /* Disable Priority config by default */
+   plat->rx_queues_cfg[i].use_prio = false;
+
+   /* Disable RX queues routing by default */
+   plat->rx_queues_cfg[i].pkt_route = 0x0;
+   }
+
+   for (i = 0; i < plat->tx_queues_to_use; i++) {
+   plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+
+   /* Disable Priority config by default */
+   plat->tx_queues_cfg[i].use_prio = false;
+   }
+
+   plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
+   plat->tx_queues_cfg[0].weight = 0x09;
+   plat->tx_queues_cfg[1].weight = 0x0A;
+   plat->tx_queues_cfg[2].weight = 0x0B;
+   plat->tx_queues_cfg[3].weight = 0x0C;
+   plat->tx_queues_cfg[4].weight = 0x0D;
+   plat->tx_queues_cfg[5].weight = 0x0E;
+   plat->tx_queues_cfg[6].weight = 0x0F;
+   plat->tx_queues_cfg[7].weight = 0x10;
+
+   plat->mdio_bus_data->phy_reset = NULL;
+   plat->mdio_bus_data->phy_mask = 0;
+
+   plat->dma_cfg->pbl = 32;
+   plat->dma_cfg->pblx8 = true;
+   plat->dma_cfg->fixed_burst = 0;
+   plat->dma_cfg->mixed_burst = 0;
+   plat->dma_cfg->aal = 0;
+
+   plat->axi = devm_kzalloc(>dev, sizeof(*plat->axi),
+GFP_KERNEL);
+   if (!plat->axi)
+   return -ENOMEM;
+
+   plat->axi->axi_lpi_en = 0;
+   plat->axi->axi_xit_frm = 0;
+   plat->axi->axi_wr_osr_lmt = 1;
+   plat->axi->axi_rd_osr_lmt = 1;
+   plat->axi->axi_blen[0] = 4;
+   plat->axi->axi_blen[1] = 8;
+   plat->axi->axi_blen[2] = 16;
+
+   /* Set default value for multicast hash bins */
+   plat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+   /* Set default value for unicast filter entries */
+   plat->unicast_filter_entries = 1;
+
+   /* Set the maxmtu to a default of JUMBO_LEN */
+   plat->maxmtu = JUMBO_LEN;
+
+   /* Set 32KB fifo size as the advertised fifo size in
+* the HW features is not the same as the HW implementation
+*/
+   plat->tx_fifo_size = 32768;
+   plat->rx_fifo_size = 32768;
+
+   return 0;
+}
+
+static int ehl_sgmii1g_data(struct pci_dev *pdev,
+   struct plat_stmmacenet_data *plat)
+{
+   int ret;
+
+   /* Set common default data first */
+   ret = ehl_common_data(pdev, plat);
+   if (ret)
+   return ret;
+
+   plat->interface = PHY_INTERFACE_MODE_SGMII;
+   plat->has_xpcs = 1;
+
+   return 0;
+}
+
+static struct stmmac_pci_info ehl_sgmii1g_pci_info = {
+   .setup = ehl_sgmii1g_data,
+};
+
 static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = {
{
.func = 6,
@@ -290,6 +398,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
res.addr = pcim_iomap_table(pdev)[i];
res.wol_irq = pdev->irq;
res.irq = pdev->irq;
+   res.xpcs_irq = 0;
 
return stmmac_dvr_probe(>dev, plat, );
 }
@@ -359,6 +468,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
 
 #define STMMAC_QUARK_ID  0x0937
 #define STMMAC_DEVICE_ID 0x1108
+#define STMMAC_EHL_SGMII1G_ID   0x4b31
 
 #define STMMAC_DEVICE(vendor_id, dev_id, info) {   \

[PATCH net-next v5 3/5] net: stmmac: add xpcs function hooks into main driver and ethtool

2019-05-31 Thread Voon Weifeng
From: Ong Boon Leong 

With xPCS functions now ready, we add them into the main driver and
ethtool logics. To differentiate from EQoS MAC PCS and DWC Ethernet
xPCS, we introduce 'has_xpcs' in platform data as a mean to indicate
whether GBE controller includes xPCS or not.

To support platform-specific C37 AN PCS mode selection for MII MMD,
we introduce 'pcs_mode' in platform data.

The basic framework for xPCS interrupt handling is implemented too.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Reviewed-by: Baoli Zhang 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h   |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 ++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 140 +++--
 include/linux/stmmac.h |   2 +
 4 files changed, 146 insertions(+), 48 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index a16ada8b8507..999311236521 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -36,6 +36,7 @@ struct stmmac_resources {
const char *mac;
int wol_irq;
int lpi_irq;
+   int xpcs_irq;
int irq;
 };
 
@@ -168,6 +169,7 @@ struct stmmac_priv {
int clk_csr;
struct timer_list eee_ctrl_timer;
int lpi_irq;
+   int xpcs_irq;
int eee_enabled;
int eee_active;
int tx_lpi_timer;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index cec51ba34296..be6edbe3d658 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -28,6 +28,7 @@
 
 #include "stmmac.h"
 #include "dwmac_dma.h"
+#include "dwxpcs.h"
 
 #define REG_SPACE_SIZE 0x1060
 #define MAC100_ETHTOOL_NAME"st_mac100"
@@ -277,7 +278,8 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
struct phy_device *phy = dev->phydev;
 
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-   priv->hw->pcs & STMMAC_PCS_SGMII) {
+   priv->hw->pcs & STMMAC_PCS_SGMII ||
+   priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
struct rgmii_adv adv;
u32 supported, advertising, lp_advertising;
 
@@ -294,6 +296,11 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
if (stmmac_pcs_get_adv_lp(priv, priv->ioaddr, ))
return -EOPNOTSUPP; /* should never happen indeed */
 
+   /* Get ADV & LPA is only application for 1000BASE-X C37.
+* For MAC side SGMII AN, get ADV & LPA from PHY.
+*/
+   stmmac_xpcs_get_adv_lp(priv, dev, , priv->plat->pcs_mode);
+
/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
 
ethtool_convert_link_mode_to_legacy_u32(
@@ -376,22 +383,23 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
int rc;
 
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-   priv->hw->pcs & STMMAC_PCS_SGMII) {
-   u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
-
+   priv->hw->pcs & STMMAC_PCS_SGMII ||
+   priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
/* Only support ANE */
if (cmd->base.autoneg != AUTONEG_ENABLE)
return -EINVAL;
 
-   mask &= (ADVERTISED_1000baseT_Half |
-   ADVERTISED_1000baseT_Full |
-   ADVERTISED_100baseT_Half |
-   ADVERTISED_100baseT_Full |
-   ADVERTISED_10baseT_Half |
-   ADVERTISED_10baseT_Full);
-
mutex_lock(>lock);
stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0);
+
+   /* For 1000BASE-X C37 AN, it is always 1000Mbps. And, we only
+* support FD which is set by default in SR_MII_AN_ADV
+* during XPCS init. So, we don't need to set FD again.
+* For SGMII C37 AN, we let user to change link settings
+* through PHY since it is MAC side SGMII.
+*/
+   stmmac_xpcs_ctrl_ane(priv, dev, 1, 0);
+
mutex_unlock(>lock);
 
return 0;
@@ -457,6 +465,16 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
pause->autoneg = 1;
if (!adv_lp.pause)
return;
+   } else if (priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX &&
+  !stmmac_xpcs_ge

[PATCH net-next v5 4/5] net: stmmac: add xPCS functions for device with DWMACv5.1

2019-05-31 Thread Voon Weifeng
From: Ong Boon Leong 

We introduce support for driver that has v5.10 IP and is also using
xPCS as MMD. This can be easily enabled for other product that integrates
xPCS that is not using v5.00 IP.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Reviewed-by: Baoli Zhang 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
Acked-by: Jose Abreu 
---
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 33 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.c| 42 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  2 ++
 3 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 5e98da4e14f9..3afb60f2775c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -824,6 +824,39 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, 
bool enable)
.set_mac_loopback = dwmac4_set_mac_loopback,
 };
 
+const struct stmmac_ops dwmac510_xpcs_ops = {
+   .core_init = dwmac4_core_init,
+   .set_mac = stmmac_dwmac4_set_mac,
+   .rx_ipc = dwmac4_rx_ipc_enable,
+   .rx_queue_enable = dwmac4_rx_queue_enable,
+   .rx_queue_prio = dwmac4_rx_queue_priority,
+   .tx_queue_prio = dwmac4_tx_queue_priority,
+   .rx_queue_routing = dwmac4_rx_queue_routing,
+   .prog_mtl_rx_algorithms = dwmac4_prog_mtl_rx_algorithms,
+   .prog_mtl_tx_algorithms = dwmac4_prog_mtl_tx_algorithms,
+   .set_mtl_tx_queue_weight = dwmac4_set_mtl_tx_queue_weight,
+   .map_mtl_to_dma = dwmac4_map_mtl_dma,
+   .config_cbs = dwmac4_config_cbs,
+   .dump_regs = dwmac4_dump_regs,
+   .host_irq_status = dwmac4_irq_status,
+   .host_mtl_irq_status = dwmac4_irq_mtl_status,
+   .flow_ctrl = dwmac4_flow_ctrl,
+   .pmt = dwmac4_pmt,
+   .set_umac_addr = dwmac4_set_umac_addr,
+   .get_umac_addr = dwmac4_get_umac_addr,
+   .set_eee_mode = dwmac4_set_eee_mode,
+   .reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_timer = dwmac4_set_eee_timer,
+   .set_eee_pls = dwmac4_set_eee_pls,
+   .debug = dwmac4_debug,
+   .set_filter = dwmac4_set_filter,
+   .safety_feat_config = dwmac5_safety_feat_config,
+   .safety_feat_irq_status = dwmac5_safety_feat_irq_status,
+   .safety_feat_dump = dwmac5_safety_feat_dump,
+   .rxp_config = dwmac5_rxp_config,
+   .flex_pps_config = dwmac5_flex_pps_config,
+};
+
 int dwmac4_setup(struct stmmac_priv *priv)
 {
struct mac_device_info *mac = priv->hw;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c 
b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 6c61b753b55e..052a000feeb5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -73,11 +73,13 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
bool gmac;
bool gmac4;
bool xgmac;
+   bool has_xpcs;
u32 min_id;
const struct stmmac_regs_off regs;
const void *desc;
const void *dma;
const void *mac;
+   const void *xpcs;
const void *hwtimestamp;
const void *mode;
const void *tc;
@@ -90,6 +92,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = false,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -98,6 +101,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.desc = NULL,
.dma = _dma_ops,
.mac = _ops,
+   .xpcs = NULL,
.hwtimestamp = _ptp,
.mode = NULL,
.tc = NULL,
@@ -108,6 +112,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = true,
.gmac4 = false,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -116,6 +121,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.desc = NULL,
.dma = _dma_ops,
.mac = _ops,
+   .xpcs = NULL,
.hwtimestamp = _ptp,
.mode = NULL,
.tc = NULL,
@@ -126,6 +132,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = true,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
@@ -133,6 +140,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
},
.desc = _desc_

[PATCH net-next v5 0/5] net: stmmac: enable EHL SGMI

2019-05-31 Thread Voon Weifeng
This patch-set is to enable Ethernet controller
(DW Ethernet QoS and DW Ethernet PCS) with SGMII interface in Elkhart Lake.
The DW Ethernet PCS is the Physical Coding Sublayer that is between Ethernet
MAC and PHY and uses MDIO Clause-45 as Communication.

Kweh Hock Leong (1):
  net: stmmac: enable clause 45 mdio support

Ong Boon Leong (3):
  net: stmmac: introducing support for DWC xPCS logics
  net: stmmac: add xpcs function hooks into main driver and ethtool
  net: stmmac: add xPCS functions for device with DWMACv5.1

Voon Weifeng (1):
  net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

 drivers/net/ethernet/stmicro/stmmac/Makefile   |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h   |   1 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c  |  33 
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c   | 198 +
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h   |  51 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.c |  42 -
 drivers/net/ethernet/stmicro/stmmac/hwif.h |  21 +++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h   |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 --
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 140 +++
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c  |  40 -
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c   | 111 
 include/linux/phy.h|   2 +
 include/linux/stmmac.h |   3 +
 14 files changed, 638 insertions(+), 58 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h

-- 
Changelog v5:
*Cosmetic touch up
*Change axi_wr_osr_lmt and axi_rd_osr_lmt value to 1 since the register
 has a default value of 1
Changelog v4:
*Rebased to latest net-next
Changelog v3:
*Applied reversed christmas tree
Changelog v2:
*Added support for the C37 AN for 1000BASE-X and SGMII (MAC side SGMII only)
*removed and submitted the fix patch to net
 "net: stmmac: dma channel control register need to be init first"
*Squash the following 2 patches and move it to the end of the patch set:
 "net: stmmac: add EHL SGMII 1Gbps platform data and PCI ID"
 "net: stmmac: add xPCS platform data for EHL"
1.9.1



[PATCH net-next v5 1/5] net: stmmac: enable clause 45 mdio support

2019-05-31 Thread Voon Weifeng
From: Kweh Hock Leong 

DWMAC4 is capable to support clause 45 mdio communication.
This patch enable the feature on stmmac_mdio_write() and
stmmac_mdio_read() by following phy_write_mmd() and
phy_read_mmd() mdiobus read write implementation format.

Reviewed-by: Li, Yifan 
Signed-off-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Weifeng Voon 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 40 ++-
 include/linux/phy.h   |  2 ++
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index bdd351597b55..c3d8f1d145ec 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -34,11 +34,27 @@
 
 #define MII_BUSY 0x0001
 #define MII_WRITE 0x0002
+#define MII_DATA_MASK GENMASK(15, 0)
 
 /* GMAC4 defines */
 #define MII_GMAC4_GOC_SHIFT2
+#define MII_GMAC4_REG_ADDR_SHIFT   16
 #define MII_GMAC4_WRITE(1 << MII_GMAC4_GOC_SHIFT)
 #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
+#define MII_GMAC4_C45E BIT(1)
+
+static void stmmac_mdio_c45_setup(struct stmmac_priv *priv, int phyreg,
+ u32 *val, u32 *data)
+{
+   unsigned int reg_shift = priv->hw->mii.reg_shift;
+   unsigned int reg_mask = priv->hw->mii.reg_mask;
+
+   *val |= MII_GMAC4_C45E;
+   *val &= ~reg_mask;
+   *val |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << reg_shift) & reg_mask;
+
+   *data |= (phyreg & MII_REGADDR_C45_MASK) << MII_GMAC4_REG_ADDR_SHIFT;
+}
 
 /* XGMAC defines */
 #define MII_XGMAC_SADDRBIT(18)
@@ -165,22 +181,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
-   int data;
u32 value = MII_BUSY;
+   int data = 0;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_READ;
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   }
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
   100, 1))
return -EBUSY;
 
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -188,7 +208,7 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
return -EBUSY;
 
/* Read the data from the MII data register */
-   data = (int)readl(priv->ioaddr + mii_data);
+   data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
 
return data;
 }
@@ -208,8 +228,9 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
u32 value = MII_BUSY;
+   int data = phydata;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
@@ -217,10 +238,13 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
 
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_WRITE;
-   else
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   } else {
value |= MII_WRITE;
+   }
 
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -228,7 +252,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
return -EBUSY;
 
/* Set the MII address register to write */
-   writel(phydata, priv->ioaddr + mii_data);
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
/* Wait until any existing MII operation is complete */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index dc4b51060ebc..a2c25a975661 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -200,6 +200,8 @@ 

[PATCH net-next v5 2/5] net: stmmac: introducing support for DWC xPCS logics

2019-05-31 Thread Voon Weifeng
From: Ong Boon Leong 

xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated
into a GbE controller that uses DWC EQoS MAC controller. An example of
HW configuration is shown below:-

  <-GBE Controller-->|<--External PHY chip-->

  +--+ +++---+   +--+
  |   EQoS   | <-GMII->| DW |<-->|PHY| <-- SGMII --> | External GbE |
  |   MAC| |xPCS||IF |   | PHY Chip |
  +--+ +++---+   +--+
 ^   ^  ^
 |   |  |
 +-MDIO-+

xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
differentiate it from external PHY chip that is discovered over MDIO.
Therefore, xpcs_phy_addr is introduced in stmmac platform data
(plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
belongs to external PHY.

Basic functionalities for initializing xPCS and configuring auto
negotiation (AN), loopback, link status, AN advertisement and Link
Partner ability are implemented. The implementation supports the C37
AN for 1000BASE-X and SGMII (MAC side SGMII only).

Tested-by: Tan, Tee Min 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/Makefile |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h |   1 +
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c | 198 +++
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h |  51 +++
 drivers/net/ethernet/stmicro/stmmac/hwif.h   |  19 +++
 include/linux/stmmac.h   |   1 +
 6 files changed, 271 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile 
b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c59926d96bcc..f007fb873455 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o 
ring_mode.o  \
  mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
  dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
  stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
- $(stmmac-y)
+ dwxpcs.o $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 1961fe9144ca..83df093c4636 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -419,6 +419,7 @@ struct mii_regs {
 
 struct mac_device_info {
const struct stmmac_ops *mac;
+   const struct stmmac_xpcs_ops *xpcs;
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
const struct stmmac_mode_ops *mode;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c 
b/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
new file mode 100644
index ..0a328d7a0db5
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Intel Corporation.
+ * DWC Ethernet Physical Coding Sublayer
+ */
+#include 
+#include 
+#include "dwxpcs.h"
+#include "stmmac.h"
+
+/* DW xPCS mdiobus_read and mdiobus_write helper functions */
+#define xpcs_read(dev, reg) \
+   mdiobus_read(priv->mii, xpcs_phy_addr, \
+MII_ADDR_C45 | (reg) | \
+((dev) << MII_DEVADDR_C45_SHIFT))
+#define xpcs_write(dev, reg, val) \
+   mdiobus_write(priv->mii, xpcs_phy_addr, \
+ MII_ADDR_C45 | (reg) | \
+ ((dev) << MII_DEVADDR_C45_SHIFT), val)
+
+static void dw_xpcs_init(struct net_device *ndev, int pcs_mode)
+{
+   struct stmmac_priv *priv = netdev_priv(ndev);
+   int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+   int phydata;
+
+   if (pcs_mode == AN_CTRL_PCS_MD_C37_SGMII) {
+   /* For AN for SGMII mode, the settings are :-
+* 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
+* 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
+*DW xPCS used with DW EQoS MAC is always MAC
+*side SGMII.
+* 3) VR_MII_AN_CTRL Bit(0) [AN_INTR_EN] = 1b (AN Interrupt
+*enabled)
+* 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
+*speed mode change after SGMII AN complete)
+* Note: Since it is MAC side SGMII

RE: [PATCH net-next v3 0/5] net: stmmac: enable EHL SGMII

2019-05-29 Thread Voon, Weifeng
> > > Did you rebase this series against latest net-next tree ?
> > >
> > > Because you are missing MMC module in your HWIF table entry. This
> > > module was recently added with the addition of selftests.
> >
> > No, the base is on last Thursday. Let me rebased on the latest net-next and
> submit for v4.
> 
> Hi Weifeng
> 
> Anything you submit needs to be on todays net-next. If the patches don't
> apply cleanly using git am, David will automatically reject them.
> 
> If you just want review, but not merge, please prefix the subject with "RFC".
> 
>   Andrew

Thanks Andrew for the detail explanation. I will keep this in mind. 

Regards,
Weifeng


RE: [PATCH net-next v4 5/5] net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

2019-05-29 Thread Voon, Weifeng
> 
> > +   plat->axi->axi_lpi_en = 0;
> > +   plat->axi->axi_xit_frm = 0;
> > +   plat->axi->axi_wr_osr_lmt = 0;
> 
> This is not a valid value.

Can you please explained why is not a valid value? And what should
be the recommended value? 
Databook mentioned that "Maximum outstanding requests =
WR_OSR_LMT + 1"

> 
> > +   plat->axi->axi_rd_osr_lmt = 2;
> > +   plat->axi->axi_blen[0] = 4;
> > +   plat->axi->axi_blen[1] = 8;
> > +   plat->axi->axi_blen[2] = 16;
> > +
> > +   /* Set default value for multicast hash bins */
> > +   plat->multicast_filter_bins = HASH_TABLE_SIZE;
> > +
> > +   /* Set default value for unicast filter entries */
> > +   plat->unicast_filter_entries = 1;
> > +
> > +   /* Set the maxmtu to a default of JUMBO_LEN */
> > +   plat->maxmtu = JUMBO_LEN;
> > +
> > +   /* Set 32KB fifo size as the advertised fifo size in
> > +* the HW features is not the same as the HW implementation
> > +*/
> 
> Hmm ? I'm curious, can you explain ?

The RTL comes with a 64KB selection in HW features. But the HW implementation
only uses a 32KB RAM. This will be documented as errata.  

> 
> > +   plat->tx_fifo_size = 32768;
> > +   plat->rx_fifo_size = 32768;
> > +
> > +   return 0;
> > +}
> > +
> > +static int ehl_sgmii1g_data(struct pci_dev *pdev,
> > +   struct plat_stmmacenet_data *plat) {
> > +   int ret;
> > +
> > +   /* Set common default data first */
> > +   ret = ehl_common_data(pdev, plat);
> > +
> 

Regards
Weifeng


RE: [PATCH net-next v4 1/5] net: stmmac: enable clause 45 mdio support

2019-05-29 Thread Voon, Weifeng
> > +static void stmmac_mdio_c45_setup(struct stmmac_priv *priv, int phyreg,
> > + u32 *val, u32 *data)
> > +{
> > +   unsigned int reg_shift = priv->hw->mii.reg_shift;
> > +   unsigned int reg_mask = priv->hw->mii.reg_mask;
> 
> Reverse christmas tree here. You also should align the function variables with
> the opening parenthesis of the function here and in the remaining series.
> 
> Otherwise this patch looks good to me.

It is already reversed Christmas tree. Somehow each of the character's width in 
the
email is not equal. As you can see that the first line of assignment is having 
more
character than the second line of assignment.
The alignment is also correct when I check it after doing a git am.

Regards,
Weifeng

> 
> Thanks,
> Jose Miguel Abreu


[PATCH net-next v4 5/5] net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

2019-05-29 Thread Voon Weifeng
Added EHL SGMII 1Gbps PCI ID. Different MII and speed will have
different PCI ID.

Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 111 +++
 1 file changed, 111 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 7cbc01f316fa..f2225c1eafc2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -23,6 +23,7 @@
 #include 
 
 #include "stmmac.h"
+#include "dwxpcs.h"
 
 /*
  * This struct is used to associate PCI Function of MAC controller on a board,
@@ -118,6 +119,113 @@ static int stmmac_default_data(struct pci_dev *pdev,
.setup = stmmac_default_data,
 };
 
+static int ehl_common_data(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat)
+{
+   int i;
+
+   plat->bus_id = 1;
+   plat->phy_addr = 0;
+   plat->clk_csr = 5;
+   plat->has_gmac = 0;
+   plat->has_gmac4 = 1;
+   plat->xpcs_phy_addr = 0x16;
+   plat->pcs_mode = AN_CTRL_PCS_MD_C37_SGMII;
+   plat->force_sf_dma_mode = 0;
+   plat->tso_en = 1;
+
+   plat->rx_queues_to_use = 8;
+   plat->tx_queues_to_use = 8;
+   plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
+
+   for (i = 0; i < plat->rx_queues_to_use; i++) {
+   plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+   plat->rx_queues_cfg[i].chan = i;
+
+   /* Disable Priority config by default */
+   plat->rx_queues_cfg[i].use_prio = false;
+
+   /* Disable RX queues routing by default */
+   plat->rx_queues_cfg[i].pkt_route = 0x0;
+   }
+
+   for (i = 0; i < plat->tx_queues_to_use; i++) {
+   plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+
+   /* Disable Priority config by default */
+   plat->tx_queues_cfg[i].use_prio = false;
+   }
+
+   plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
+   plat->tx_queues_cfg[0].weight = 0x09;
+   plat->tx_queues_cfg[1].weight = 0x0A;
+   plat->tx_queues_cfg[2].weight = 0x0B;
+   plat->tx_queues_cfg[3].weight = 0x0C;
+   plat->tx_queues_cfg[4].weight = 0x0D;
+   plat->tx_queues_cfg[5].weight = 0x0E;
+   plat->tx_queues_cfg[6].weight = 0x0F;
+   plat->tx_queues_cfg[7].weight = 0x10;
+
+   plat->mdio_bus_data->phy_reset = NULL;
+   plat->mdio_bus_data->phy_mask = 0;
+
+   plat->dma_cfg->pbl = 32;
+   plat->dma_cfg->pblx8 = true;
+   plat->dma_cfg->fixed_burst = 0;
+   plat->dma_cfg->mixed_burst = 0;
+   plat->dma_cfg->aal = 0;
+
+   plat->axi = devm_kzalloc(>dev, sizeof(*plat->axi),
+GFP_KERNEL);
+   if (!plat->axi)
+   return -ENOMEM;
+   plat->axi->axi_lpi_en = 0;
+   plat->axi->axi_xit_frm = 0;
+   plat->axi->axi_wr_osr_lmt = 0;
+   plat->axi->axi_rd_osr_lmt = 2;
+   plat->axi->axi_blen[0] = 4;
+   plat->axi->axi_blen[1] = 8;
+   plat->axi->axi_blen[2] = 16;
+
+   /* Set default value for multicast hash bins */
+   plat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+   /* Set default value for unicast filter entries */
+   plat->unicast_filter_entries = 1;
+
+   /* Set the maxmtu to a default of JUMBO_LEN */
+   plat->maxmtu = JUMBO_LEN;
+
+   /* Set 32KB fifo size as the advertised fifo size in
+* the HW features is not the same as the HW implementation
+*/
+   plat->tx_fifo_size = 32768;
+   plat->rx_fifo_size = 32768;
+
+   return 0;
+}
+
+static int ehl_sgmii1g_data(struct pci_dev *pdev,
+   struct plat_stmmacenet_data *plat)
+{
+   int ret;
+
+   /* Set common default data first */
+   ret = ehl_common_data(pdev, plat);
+
+   if (ret)
+   return ret;
+
+   plat->interface = PHY_INTERFACE_MODE_SGMII;
+   plat->has_xpcs = 1;
+
+   return 0;
+}
+
+static struct stmmac_pci_info ehl_sgmii1g_pci_info = {
+   .setup = ehl_sgmii1g_data,
+};
+
 static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = {
{
.func = 6,
@@ -290,6 +398,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
res.addr = pcim_iomap_table(pdev)[i];
res.wol_irq = pdev->irq;
res.irq = pdev->irq;
+   res.xpcs_irq = 0;
 
return stmmac_dvr_probe(>dev, plat, );
 }
@@ -359,6 +468,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
 
 #define STMMAC_QUARK_ID  0x0937
 #define STMMAC_DEVICE_ID 0x1108
+#define STMMAC_EHL_SGMII1G_ID   0x4b31
 
 #define STMMAC_DEVICE(vendor_id, dev_id, info) {   \

[PATCH net-next v4 0/5] net: stmmac: enable EHL SGMI

2019-05-29 Thread Voon Weifeng
This patch-set is to enable Ethernet controller
(DW Ethernet QoS and DW Ethernet PCS) with SGMII interface in Elkhart Lake.
The DW Ethernet PCS is the Physical Coding Sublayer that is between Ethernet
MAC and PHY and uses MDIO Clause-45 as Communication.

Kweh Hock Leong (1):
  net: stmmac: enable clause 45 mdio support

Ong Boon Leong (3):
  net: stmmac: introducing support for DWC xPCS logics
  net: stmmac: add xpcs function hooks into main driver and ethtool
  net: stmmac: add xPCS functions for device with DWMACv5.1

Voon Weifeng (1):
  net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

 drivers/net/ethernet/stmicro/stmmac/Makefile   |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h   |   1 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c  |  33 
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c   | 198 +
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h   |  51 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.c |  42 -
 drivers/net/ethernet/stmicro/stmmac/hwif.h |  21 +++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h   |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 --
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 152 
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c  |  40 -
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c   | 111 
 include/linux/phy.h|   2 +
 include/linux/stmmac.h |   3 +
 14 files changed, 650 insertions(+), 58 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h

-- 
Changelog v2:
*Added support for the C37 AN for 1000BASE-X and SGMII (MAC side SGMII only)
*removed and submitted the fix patch to net
 "net: stmmac: dma channel control register need to be init first"
*Squash the following 2 patches and move it to the end of the patch set:
 "net: stmmac: add EHL SGMII 1Gbps platform data and PCI ID"
 "net: stmmac: add xPCS platform data for EHL"
Changelog v3:
*Applied reversed christmas tree
Changelog v4:
*Rebased to latest net-next
1.9.1



[PATCH net-next v4 4/5] net: stmmac: add xPCS functions for device with DWMACv5.1

2019-05-29 Thread Voon Weifeng
From: Ong Boon Leong 

We introduce support for driver that has v5.10 IP and is also using
xPCS as MMD. This can be easily enabled for other product that integrates
xPCS that is not using v5.00 IP.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Reviewed-by: Baoli Zhang 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 33 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.c| 42 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  2 ++
 3 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 5e98da4e14f9..3afb60f2775c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -824,6 +824,39 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, 
bool enable)
.set_mac_loopback = dwmac4_set_mac_loopback,
 };
 
+const struct stmmac_ops dwmac510_xpcs_ops = {
+   .core_init = dwmac4_core_init,
+   .set_mac = stmmac_dwmac4_set_mac,
+   .rx_ipc = dwmac4_rx_ipc_enable,
+   .rx_queue_enable = dwmac4_rx_queue_enable,
+   .rx_queue_prio = dwmac4_rx_queue_priority,
+   .tx_queue_prio = dwmac4_tx_queue_priority,
+   .rx_queue_routing = dwmac4_rx_queue_routing,
+   .prog_mtl_rx_algorithms = dwmac4_prog_mtl_rx_algorithms,
+   .prog_mtl_tx_algorithms = dwmac4_prog_mtl_tx_algorithms,
+   .set_mtl_tx_queue_weight = dwmac4_set_mtl_tx_queue_weight,
+   .map_mtl_to_dma = dwmac4_map_mtl_dma,
+   .config_cbs = dwmac4_config_cbs,
+   .dump_regs = dwmac4_dump_regs,
+   .host_irq_status = dwmac4_irq_status,
+   .host_mtl_irq_status = dwmac4_irq_mtl_status,
+   .flow_ctrl = dwmac4_flow_ctrl,
+   .pmt = dwmac4_pmt,
+   .set_umac_addr = dwmac4_set_umac_addr,
+   .get_umac_addr = dwmac4_get_umac_addr,
+   .set_eee_mode = dwmac4_set_eee_mode,
+   .reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_timer = dwmac4_set_eee_timer,
+   .set_eee_pls = dwmac4_set_eee_pls,
+   .debug = dwmac4_debug,
+   .set_filter = dwmac4_set_filter,
+   .safety_feat_config = dwmac5_safety_feat_config,
+   .safety_feat_irq_status = dwmac5_safety_feat_irq_status,
+   .safety_feat_dump = dwmac5_safety_feat_dump,
+   .rxp_config = dwmac5_rxp_config,
+   .flex_pps_config = dwmac5_flex_pps_config,
+};
+
 int dwmac4_setup(struct stmmac_priv *priv)
 {
struct mac_device_info *mac = priv->hw;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c 
b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 6c61b753b55e..6364fc89f0e4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -73,11 +73,13 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
bool gmac;
bool gmac4;
bool xgmac;
+   bool has_xpcs;
u32 min_id;
const struct stmmac_regs_off regs;
const void *desc;
const void *dma;
const void *mac;
+   const void *xpcs;
const void *hwtimestamp;
const void *mode;
const void *tc;
@@ -90,6 +92,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = false,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -98,6 +101,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.desc = NULL,
.dma = _dma_ops,
.mac = _ops,
+   .xpcs = NULL,
.hwtimestamp = _ptp,
.mode = NULL,
.tc = NULL,
@@ -108,6 +112,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = true,
.gmac4 = false,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -116,6 +121,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.desc = NULL,
.dma = _dma_ops,
.mac = _ops,
+   .xpcs = NULL,
.hwtimestamp = _ptp,
.mode = NULL,
.tc = NULL,
@@ -126,6 +132,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = true,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
@@ -133,6 +140,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
},
.desc = _desc_ops,
.dma = _dma_

[PATCH net-next v4 3/5] net: stmmac: add xpcs function hooks into main driver and ethtool

2019-05-29 Thread Voon Weifeng
From: Ong Boon Leong 

With xPCS functions now ready, we add them into the main driver and
ethtool logics. To differentiate from EQoS MAC PCS and DWC Ethernet
xPCS, we introduce 'has_xpcs' in platform data as a mean to indicate
whether GBE controller includes xPCS or not.

To support platform-specific C37 AN PCS mode selection for MII MMD,
we introduce 'pcs_mode' in platform data.

The basic framework for xPCS interrupt handling is implemented too.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Reviewed-by: Baoli Zhang 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h   |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 +--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 152 -
 include/linux/stmmac.h |   2 +
 4 files changed, 158 insertions(+), 48 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index a16ada8b8507..999311236521 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -36,6 +36,7 @@ struct stmmac_resources {
const char *mac;
int wol_irq;
int lpi_irq;
+   int xpcs_irq;
int irq;
 };
 
@@ -168,6 +169,7 @@ struct stmmac_priv {
int clk_csr;
struct timer_list eee_ctrl_timer;
int lpi_irq;
+   int xpcs_irq;
int eee_enabled;
int eee_active;
int tx_lpi_timer;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index cec51ba34296..be6edbe3d658 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -28,6 +28,7 @@
 
 #include "stmmac.h"
 #include "dwmac_dma.h"
+#include "dwxpcs.h"
 
 #define REG_SPACE_SIZE 0x1060
 #define MAC100_ETHTOOL_NAME"st_mac100"
@@ -277,7 +278,8 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
struct phy_device *phy = dev->phydev;
 
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-   priv->hw->pcs & STMMAC_PCS_SGMII) {
+   priv->hw->pcs & STMMAC_PCS_SGMII ||
+   priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
struct rgmii_adv adv;
u32 supported, advertising, lp_advertising;
 
@@ -294,6 +296,11 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
if (stmmac_pcs_get_adv_lp(priv, priv->ioaddr, ))
return -EOPNOTSUPP; /* should never happen indeed */
 
+   /* Get ADV & LPA is only application for 1000BASE-X C37.
+* For MAC side SGMII AN, get ADV & LPA from PHY.
+*/
+   stmmac_xpcs_get_adv_lp(priv, dev, , priv->plat->pcs_mode);
+
/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
 
ethtool_convert_link_mode_to_legacy_u32(
@@ -376,22 +383,23 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
int rc;
 
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-   priv->hw->pcs & STMMAC_PCS_SGMII) {
-   u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
-
+   priv->hw->pcs & STMMAC_PCS_SGMII ||
+   priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
/* Only support ANE */
if (cmd->base.autoneg != AUTONEG_ENABLE)
return -EINVAL;
 
-   mask &= (ADVERTISED_1000baseT_Half |
-   ADVERTISED_1000baseT_Full |
-   ADVERTISED_100baseT_Half |
-   ADVERTISED_100baseT_Full |
-   ADVERTISED_10baseT_Half |
-   ADVERTISED_10baseT_Full);
-
mutex_lock(>lock);
stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0);
+
+   /* For 1000BASE-X C37 AN, it is always 1000Mbps. And, we only
+* support FD which is set by default in SR_MII_AN_ADV
+* during XPCS init. So, we don't need to set FD again.
+* For SGMII C37 AN, we let user to change link settings
+* through PHY since it is MAC side SGMII.
+*/
+   stmmac_xpcs_ctrl_ane(priv, dev, 1, 0);
+
mutex_unlock(>lock);
 
return 0;
@@ -457,6 +465,16 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
pause->autoneg = 1;
if (!adv_lp.pause)
return;
+   } else if (priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX &&
+  !stmmac_xpcs_ge

[PATCH net-next v4 2/5] net: stmmac: introducing support for DWC xPCS logics

2019-05-29 Thread Voon Weifeng
From: Ong Boon Leong 

xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated
into a GbE controller that uses DWC EQoS MAC controller. An example of
HW configuration is shown below:-

  <-GBE Controller-->|<--External PHY chip-->

  +--+ +++---+   +--+
  |   EQoS   | <-GMII->| DW |<-->|PHY| <-- SGMII --> | External GbE |
  |   MAC| |xPCS||IF |   | PHY Chip |
  +--+ +++---+   +--+
 ^   ^  ^
 |   |  |
 +-MDIO-+

xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
differentiate it from external PHY chip that is discovered over MDIO.
Therefore, xpcs_phy_addr is introduced in stmmac platform data
(plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
belongs to external PHY.

Basic functionalities for initializing xPCS and configuring auto
negotiation (AN), loopback, link status, AN advertisement and Link
Partner ability are implemented. The implementation supports the C37
AN for 1000BASE-X and SGMII (MAC side SGMII only).

Tested-by: Tan, Tee Min 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/Makefile |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h |   1 +
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c | 198 +++
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h |  51 +++
 drivers/net/ethernet/stmicro/stmmac/hwif.h   |  19 +++
 include/linux/stmmac.h   |   1 +
 6 files changed, 271 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile 
b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c59926d96bcc..f007fb873455 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o 
ring_mode.o  \
  mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
  dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
  stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
- $(stmmac-y)
+ dwxpcs.o $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 1961fe9144ca..822786872796 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -419,6 +419,7 @@ struct mii_regs {
 
 struct mac_device_info {
const struct stmmac_ops *mac;
+   const struct stmmac_xpcs *xpcs;
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
const struct stmmac_mode_ops *mode;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c 
b/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
new file mode 100644
index ..081d3631afd2
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Intel Corporation.
+ * DWC Ethernet Physical Coding Sublayer
+ */
+#include 
+#include 
+#include "dwxpcs.h"
+#include "stmmac.h"
+
+/* DW xPCS mdiobus_read and mdiobus_write helper functions */
+#define xpcs_read(dev, reg) \
+   mdiobus_read(priv->mii, xpcs_phy_addr, \
+MII_ADDR_C45 | (reg) | \
+((dev) << MII_DEVADDR_C45_SHIFT))
+#define xpcs_write(dev, reg, val) \
+   mdiobus_write(priv->mii, xpcs_phy_addr, \
+ MII_ADDR_C45 | (reg) | \
+ ((dev) << MII_DEVADDR_C45_SHIFT), val)
+
+static void dw_xpcs_init(struct net_device *ndev, int pcs_mode)
+{
+   struct stmmac_priv *priv = netdev_priv(ndev);
+   int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+   int phydata;
+
+   if (pcs_mode == AN_CTRL_PCS_MD_C37_SGMII) {
+   /* For AN for SGMII mode, the settings are :-
+* 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
+* 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
+*DW xPCS used with DW EQoS MAC is always MAC
+*side SGMII.
+* 3) VR_MII_AN_CTRL Bit(0) [AN_INTR_EN] = 1b (AN Interrupt
+*enabled)
+* 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
+*speed mode change after SGMII AN complete)
+* Note: Since it is MAC side SGMII

[PATCH net-next v4 1/5] net: stmmac: enable clause 45 mdio support

2019-05-29 Thread Voon Weifeng
From: Kweh Hock Leong 

DWMAC4 is capable to support clause 45 mdio communication.
This patch enable the feature on stmmac_mdio_write() and
stmmac_mdio_read() by following phy_write_mmd() and
phy_read_mmd() mdiobus read write implementation format.

Reviewed-by: Li, Yifan 
Signed-off-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Weifeng Voon 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 40 ++-
 include/linux/phy.h   |  2 ++
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index bdd351597b55..c3d8f1d145ec 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -34,11 +34,27 @@
 
 #define MII_BUSY 0x0001
 #define MII_WRITE 0x0002
+#define MII_DATA_MASK GENMASK(15, 0)
 
 /* GMAC4 defines */
 #define MII_GMAC4_GOC_SHIFT2
+#define MII_GMAC4_REG_ADDR_SHIFT   16
 #define MII_GMAC4_WRITE(1 << MII_GMAC4_GOC_SHIFT)
 #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
+#define MII_GMAC4_C45E BIT(1)
+
+static void stmmac_mdio_c45_setup(struct stmmac_priv *priv, int phyreg,
+ u32 *val, u32 *data)
+{
+   unsigned int reg_shift = priv->hw->mii.reg_shift;
+   unsigned int reg_mask = priv->hw->mii.reg_mask;
+
+   *val |= MII_GMAC4_C45E;
+   *val &= ~reg_mask;
+   *val |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << reg_shift) & reg_mask;
+
+   *data |= (phyreg & MII_REGADDR_C45_MASK) << MII_GMAC4_REG_ADDR_SHIFT;
+}
 
 /* XGMAC defines */
 #define MII_XGMAC_SADDRBIT(18)
@@ -165,22 +181,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
-   int data;
u32 value = MII_BUSY;
+   int data = 0;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_READ;
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   }
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
   100, 1))
return -EBUSY;
 
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -188,7 +208,7 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
return -EBUSY;
 
/* Read the data from the MII data register */
-   data = (int)readl(priv->ioaddr + mii_data);
+   data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
 
return data;
 }
@@ -208,8 +228,9 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
u32 value = MII_BUSY;
+   int data = phydata;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
@@ -217,10 +238,13 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
 
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_WRITE;
-   else
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   } else {
value |= MII_WRITE;
+   }
 
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -228,7 +252,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
return -EBUSY;
 
/* Set the MII address register to write */
-   writel(phydata, priv->ioaddr + mii_data);
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
/* Wait until any existing MII operation is complete */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 7180b1d1e5e3..27d267bde363 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -201,6 +201,8 @@ 

RE: [PATCH net-next v3 0/5] net: stmmac: enable EHL SGMII

2019-05-29 Thread Voon, Weifeng
> 
> Did you rebase this series against latest net-next tree ?
> 
> Because you are missing MMC module in your HWIF table entry. This module
> was recently added with the addition of selftests.

No, the base is on last Thursday. Let me rebased on the latest net-next and 
submit for v4.

Thanks,
Weifeng

> 
> Thanks,
> Jose Miguel Abreu


[PATCH net-next v3 0/5] net: stmmac: enable EHL SGMII

2019-05-28 Thread Voon Weifeng
This patch-set is to enable Ethernet controller
(DW Ethernet QoS and DW Ethernet PCS) with SGMII interface in Elkhart Lake.
The DW Ethernet PCS is the Physical Coding Sublayer that is between Ethernet
MAC and PHY and uses MDIO Clause-45 as Communication.

Kweh Hock Leong (1):
  net: stmmac: enable clause 45 mdio support

Ong Boon Leong (3):
  net: stmmac: introducing support for DWC xPCS logics
  net: stmmac: add xpcs function hooks into main driver and ethtool
  net: stmmac: add xPCS functions for device with DWMACv5.1

Voon Weifeng (1):
  net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

 drivers/net/ethernet/stmicro/stmmac/Makefile   |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h   |   1 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c  |  33 
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c   | 198 +
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h   |  51 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.c |  41 -
 drivers/net/ethernet/stmicro/stmmac/hwif.h |  21 +++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h   |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 --
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 152 
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c  |  40 -
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c   | 111 
 include/linux/phy.h|   2 +
 include/linux/stmmac.h |   3 +
 14 files changed, 649 insertions(+), 58 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h

-- 
Changelog v2:
*Added support for the C37 AN for 1000BASE-X and SGMII (MAC side SGMII only)
*removed and submitted the fix patch to net
 "net: stmmac: dma channel control register need to be init first"
*Squash the following 2 patches and move it to the end of the patch set:
 "net: stmmac: add EHL SGMII 1Gbps platform data and PCI ID"
 "net: stmmac: add xPCS platform data for EHL"
Changelog v3:
*Applied reversed christmas tree
1.9.1



[PATCH net-next v3 5/5] net: stmmac: add EHL SGMII 1Gbps PCI info and PCI ID

2019-05-28 Thread Voon Weifeng
Added EHL SGMII 1Gbps PCI ID. Different MII and speed will have
different PCI ID.

Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 111 +++
 1 file changed, 111 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 7cbc01f316fa..f2225c1eafc2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -23,6 +23,7 @@
 #include 
 
 #include "stmmac.h"
+#include "dwxpcs.h"
 
 /*
  * This struct is used to associate PCI Function of MAC controller on a board,
@@ -118,6 +119,113 @@ static int stmmac_default_data(struct pci_dev *pdev,
.setup = stmmac_default_data,
 };
 
+static int ehl_common_data(struct pci_dev *pdev,
+  struct plat_stmmacenet_data *plat)
+{
+   int i;
+
+   plat->bus_id = 1;
+   plat->phy_addr = 0;
+   plat->clk_csr = 5;
+   plat->has_gmac = 0;
+   plat->has_gmac4 = 1;
+   plat->xpcs_phy_addr = 0x16;
+   plat->pcs_mode = AN_CTRL_PCS_MD_C37_SGMII;
+   plat->force_sf_dma_mode = 0;
+   plat->tso_en = 1;
+
+   plat->rx_queues_to_use = 8;
+   plat->tx_queues_to_use = 8;
+   plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
+
+   for (i = 0; i < plat->rx_queues_to_use; i++) {
+   plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+   plat->rx_queues_cfg[i].chan = i;
+
+   /* Disable Priority config by default */
+   plat->rx_queues_cfg[i].use_prio = false;
+
+   /* Disable RX queues routing by default */
+   plat->rx_queues_cfg[i].pkt_route = 0x0;
+   }
+
+   for (i = 0; i < plat->tx_queues_to_use; i++) {
+   plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
+
+   /* Disable Priority config by default */
+   plat->tx_queues_cfg[i].use_prio = false;
+   }
+
+   plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
+   plat->tx_queues_cfg[0].weight = 0x09;
+   plat->tx_queues_cfg[1].weight = 0x0A;
+   plat->tx_queues_cfg[2].weight = 0x0B;
+   plat->tx_queues_cfg[3].weight = 0x0C;
+   plat->tx_queues_cfg[4].weight = 0x0D;
+   plat->tx_queues_cfg[5].weight = 0x0E;
+   plat->tx_queues_cfg[6].weight = 0x0F;
+   plat->tx_queues_cfg[7].weight = 0x10;
+
+   plat->mdio_bus_data->phy_reset = NULL;
+   plat->mdio_bus_data->phy_mask = 0;
+
+   plat->dma_cfg->pbl = 32;
+   plat->dma_cfg->pblx8 = true;
+   plat->dma_cfg->fixed_burst = 0;
+   plat->dma_cfg->mixed_burst = 0;
+   plat->dma_cfg->aal = 0;
+
+   plat->axi = devm_kzalloc(>dev, sizeof(*plat->axi),
+GFP_KERNEL);
+   if (!plat->axi)
+   return -ENOMEM;
+   plat->axi->axi_lpi_en = 0;
+   plat->axi->axi_xit_frm = 0;
+   plat->axi->axi_wr_osr_lmt = 0;
+   plat->axi->axi_rd_osr_lmt = 2;
+   plat->axi->axi_blen[0] = 4;
+   plat->axi->axi_blen[1] = 8;
+   plat->axi->axi_blen[2] = 16;
+
+   /* Set default value for multicast hash bins */
+   plat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+   /* Set default value for unicast filter entries */
+   plat->unicast_filter_entries = 1;
+
+   /* Set the maxmtu to a default of JUMBO_LEN */
+   plat->maxmtu = JUMBO_LEN;
+
+   /* Set 32KB fifo size as the advertised fifo size in
+* the HW features is not the same as the HW implementation
+*/
+   plat->tx_fifo_size = 32768;
+   plat->rx_fifo_size = 32768;
+
+   return 0;
+}
+
+static int ehl_sgmii1g_data(struct pci_dev *pdev,
+   struct plat_stmmacenet_data *plat)
+{
+   int ret;
+
+   /* Set common default data first */
+   ret = ehl_common_data(pdev, plat);
+
+   if (ret)
+   return ret;
+
+   plat->interface = PHY_INTERFACE_MODE_SGMII;
+   plat->has_xpcs = 1;
+
+   return 0;
+}
+
+static struct stmmac_pci_info ehl_sgmii1g_pci_info = {
+   .setup = ehl_sgmii1g_data,
+};
+
 static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = {
{
.func = 6,
@@ -290,6 +398,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
res.addr = pcim_iomap_table(pdev)[i];
res.wol_irq = pdev->irq;
res.irq = pdev->irq;
+   res.xpcs_irq = 0;
 
return stmmac_dvr_probe(>dev, plat, );
 }
@@ -359,6 +468,7 @@ static int __maybe_unused stmmac_pci_resume(struct device 
*dev)
 
 #define STMMAC_QUARK_ID  0x0937
 #define STMMAC_DEVICE_ID 0x1108
+#define STMMAC_EHL_SGMII1G_ID   0x4b31
 
 #define STMMAC_DEVICE(vendor_id, dev_id, info) {   \

[PATCH net-next v3 2/5] net: stmmac: introducing support for DWC xPCS logics

2019-05-28 Thread Voon Weifeng
From: Ong Boon Leong 

xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated
into a GbE controller that uses DWC EQoS MAC controller. An example of
HW configuration is shown below:-

  <-GBE Controller-->|<--External PHY chip-->

  +--+ +++---+   +--+
  |   EQoS   | <-GMII->| DW |<-->|PHY| <-- SGMII --> | External GbE |
  |   MAC| |xPCS||IF |   | PHY Chip |
  +--+ +++---+   +--+
 ^   ^  ^
 |   |  |
 +-MDIO-+

xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
differentiate it from external PHY chip that is discovered over MDIO.
Therefore, xpcs_phy_addr is introduced in stmmac platform data
(plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
belongs to external PHY.

Basic functionalities for initializing xPCS and configuring auto
negotiation (AN), loopback, link status, AN advertisement and Link
Partner ability are implemented. The implementation supports the C37
AN for 1000BASE-X and SGMII (MAC side SGMII only).

Tested-by: Tan, Tee Min 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/Makefile |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h |   1 +
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c | 198 +++
 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h |  51 +++
 drivers/net/ethernet/stmicro/stmmac/hwif.h   |  19 +++
 include/linux/stmmac.h   |   1 +
 6 files changed, 271 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwxpcs.h

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile 
b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c529c21e9bdd..57ca648fae4e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o 
ring_mode.o  \
  mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
  dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
  stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
- $(stmmac-y)
+ dwxpcs.o $(stmmac-y)
 
 # Ordering matters. Generic driver must be last.
 obj-$(CONFIG_STMMAC_PLATFORM)  += stmmac-platform.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h 
b/drivers/net/ethernet/stmicro/stmmac/common.h
index 272b9ca66314..67d03a5a21af 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -419,6 +419,7 @@ struct mii_regs {
 
 struct mac_device_info {
const struct stmmac_ops *mac;
+   const struct stmmac_xpcs *xpcs;
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
const struct stmmac_mode_ops *mode;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c 
b/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
new file mode 100644
index ..081d3631afd2
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxpcs.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Intel Corporation.
+ * DWC Ethernet Physical Coding Sublayer
+ */
+#include 
+#include 
+#include "dwxpcs.h"
+#include "stmmac.h"
+
+/* DW xPCS mdiobus_read and mdiobus_write helper functions */
+#define xpcs_read(dev, reg) \
+   mdiobus_read(priv->mii, xpcs_phy_addr, \
+MII_ADDR_C45 | (reg) | \
+((dev) << MII_DEVADDR_C45_SHIFT))
+#define xpcs_write(dev, reg, val) \
+   mdiobus_write(priv->mii, xpcs_phy_addr, \
+ MII_ADDR_C45 | (reg) | \
+ ((dev) << MII_DEVADDR_C45_SHIFT), val)
+
+static void dw_xpcs_init(struct net_device *ndev, int pcs_mode)
+{
+   struct stmmac_priv *priv = netdev_priv(ndev);
+   int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+   int phydata;
+
+   if (pcs_mode == AN_CTRL_PCS_MD_C37_SGMII) {
+   /* For AN for SGMII mode, the settings are :-
+* 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
+* 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
+*DW xPCS used with DW EQoS MAC is always MAC
+*side SGMII.
+* 3) VR_MII_AN_CTRL Bit(0) [AN_INTR_EN] = 1b (AN Interrupt
+*enabled)
+* 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
+*speed mode change after SGMII AN complete)
+ 

[PATCH net-next v3 4/5] net: stmmac: add xPCS functions for device with DWMACv5.1

2019-05-28 Thread Voon Weifeng
From: Ong Boon Leong 

We introduce support for driver that has v5.10 IP and is also using
xPCS as MMD. This can be easily enabled for other product that integrates
xPCS that is not using v5.00 IP.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Reviewed-by: Baoli Zhang 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 33 ++
 drivers/net/ethernet/stmicro/stmmac/hwif.c| 41 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  2 ++
 3 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index b4bb5629de38..34f05068142e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -801,6 +801,39 @@ static void dwmac4_debug(void __iomem *ioaddr, struct 
stmmac_extra_stats *x,
.flex_pps_config = dwmac5_flex_pps_config,
 };
 
+const struct stmmac_ops dwmac510_xpcs_ops = {
+   .core_init = dwmac4_core_init,
+   .set_mac = stmmac_dwmac4_set_mac,
+   .rx_ipc = dwmac4_rx_ipc_enable,
+   .rx_queue_enable = dwmac4_rx_queue_enable,
+   .rx_queue_prio = dwmac4_rx_queue_priority,
+   .tx_queue_prio = dwmac4_tx_queue_priority,
+   .rx_queue_routing = dwmac4_rx_queue_routing,
+   .prog_mtl_rx_algorithms = dwmac4_prog_mtl_rx_algorithms,
+   .prog_mtl_tx_algorithms = dwmac4_prog_mtl_tx_algorithms,
+   .set_mtl_tx_queue_weight = dwmac4_set_mtl_tx_queue_weight,
+   .map_mtl_to_dma = dwmac4_map_mtl_dma,
+   .config_cbs = dwmac4_config_cbs,
+   .dump_regs = dwmac4_dump_regs,
+   .host_irq_status = dwmac4_irq_status,
+   .host_mtl_irq_status = dwmac4_irq_mtl_status,
+   .flow_ctrl = dwmac4_flow_ctrl,
+   .pmt = dwmac4_pmt,
+   .set_umac_addr = dwmac4_set_umac_addr,
+   .get_umac_addr = dwmac4_get_umac_addr,
+   .set_eee_mode = dwmac4_set_eee_mode,
+   .reset_eee_mode = dwmac4_reset_eee_mode,
+   .set_eee_timer = dwmac4_set_eee_timer,
+   .set_eee_pls = dwmac4_set_eee_pls,
+   .debug = dwmac4_debug,
+   .set_filter = dwmac4_set_filter,
+   .safety_feat_config = dwmac5_safety_feat_config,
+   .safety_feat_irq_status = dwmac5_safety_feat_irq_status,
+   .safety_feat_dump = dwmac5_safety_feat_dump,
+   .rxp_config = dwmac5_rxp_config,
+   .flex_pps_config = dwmac5_flex_pps_config,
+};
+
 int dwmac4_setup(struct stmmac_priv *priv)
 {
struct mac_device_info *mac = priv->hw;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c 
b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 81b966a8261b..f1cb3ce165e5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -73,11 +73,13 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
bool gmac;
bool gmac4;
bool xgmac;
+   bool has_xpcs;
u32 min_id;
const struct stmmac_regs_off regs;
const void *desc;
const void *dma;
const void *mac;
+   const void *xpcs;
const void *hwtimestamp;
const void *mode;
const void *tc;
@@ -89,6 +91,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = false,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -97,6 +100,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.desc = NULL,
.dma = _dma_ops,
.mac = _ops,
+   .xpcs = NULL,
.hwtimestamp = _ptp,
.mode = NULL,
.tc = NULL,
@@ -106,6 +110,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = true,
.gmac4 = false,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -114,6 +119,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.desc = NULL,
.dma = _dma_ops,
.mac = _ops,
+   .xpcs = NULL,
.hwtimestamp = _ptp,
.mode = NULL,
.tc = NULL,
@@ -123,6 +129,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
.gmac = false,
.gmac4 = true,
.xgmac = false,
+   .has_xpcs = false,
.min_id = 0,
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
@@ -130,6 +137,7 @@ static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
},
.desc = _desc_ops,
.dma = _dma_

[PATCH net-next v3 3/5] net: stmmac: add xpcs function hooks into main driver and ethtool

2019-05-28 Thread Voon Weifeng
From: Ong Boon Leong 

With xPCS functions now ready, we add them into the main driver and
ethtool logics. To differentiate from EQoS MAC PCS and DWC Ethernet
xPCS, we introduce 'has_xpcs' in platform data as a mean to indicate
whether GBE controller includes xPCS or not.

To support platform-specific C37 AN PCS mode selection for MII MMD,
we introduce 'pcs_mode' in platform data.

The basic framework for xPCS interrupt handling is implemented too.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Reviewed-by: Baoli Zhang 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h   |   2 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  50 +--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 152 -
 include/linux/stmmac.h |   2 +
 4 files changed, 158 insertions(+), 48 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index dd95d959c1ce..0b8460a4a220 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -36,6 +36,7 @@ struct stmmac_resources {
const char *mac;
int wol_irq;
int lpi_irq;
+   int xpcs_irq;
int irq;
 };
 
@@ -168,6 +169,7 @@ struct stmmac_priv {
int clk_csr;
struct timer_list eee_ctrl_timer;
int lpi_irq;
+   int xpcs_irq;
int eee_enabled;
int eee_active;
int tx_lpi_timer;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index e09522c5509a..f0815d196147 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -28,6 +28,7 @@
 
 #include "stmmac.h"
 #include "dwmac_dma.h"
+#include "dwxpcs.h"
 
 #define REG_SPACE_SIZE 0x1060
 #define MAC100_ETHTOOL_NAME"st_mac100"
@@ -277,7 +278,8 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
struct phy_device *phy = dev->phydev;
 
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-   priv->hw->pcs & STMMAC_PCS_SGMII) {
+   priv->hw->pcs & STMMAC_PCS_SGMII ||
+   priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
struct rgmii_adv adv;
u32 supported, advertising, lp_advertising;
 
@@ -294,6 +296,11 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
if (stmmac_pcs_get_adv_lp(priv, priv->ioaddr, ))
return -EOPNOTSUPP; /* should never happen indeed */
 
+   /* Get ADV & LPA is only application for 1000BASE-X C37.
+* For MAC side SGMII AN, get ADV & LPA from PHY.
+*/
+   stmmac_xpcs_get_adv_lp(priv, dev, , priv->plat->pcs_mode);
+
/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
 
ethtool_convert_link_mode_to_legacy_u32(
@@ -376,22 +383,23 @@ static int stmmac_ethtool_get_link_ksettings(struct 
net_device *dev,
int rc;
 
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-   priv->hw->pcs & STMMAC_PCS_SGMII) {
-   u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
-
+   priv->hw->pcs & STMMAC_PCS_SGMII ||
+   priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX) {
/* Only support ANE */
if (cmd->base.autoneg != AUTONEG_ENABLE)
return -EINVAL;
 
-   mask &= (ADVERTISED_1000baseT_Half |
-   ADVERTISED_1000baseT_Full |
-   ADVERTISED_100baseT_Half |
-   ADVERTISED_100baseT_Full |
-   ADVERTISED_10baseT_Half |
-   ADVERTISED_10baseT_Full);
-
mutex_lock(>lock);
stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0);
+
+   /* For 1000BASE-X C37 AN, it is always 1000Mbps. And, we only
+* support FD which is set by default in SR_MII_AN_ADV
+* during XPCS init. So, we don't need to set FD again.
+* For SGMII C37 AN, we let user to change link settings
+* through PHY since it is MAC side SGMII.
+*/
+   stmmac_xpcs_ctrl_ane(priv, dev, 1, 0);
+
mutex_unlock(>lock);
 
return 0;
@@ -457,6 +465,16 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
pause->autoneg = 1;
if (!adv_lp.pause)
return;
+   } else if (priv->plat->pcs_mode == AN_CTRL_PCS_MD_C37_1000BASEX &&
+  !stmmac_xpcs_ge

[PATCH net-next v3 1/5] net: stmmac: enable clause 45 mdio support

2019-05-28 Thread Voon Weifeng
From: Kweh Hock Leong 

DWMAC4 is capable to support clause 45 mdio communication.
This patch enable the feature on stmmac_mdio_write() and
stmmac_mdio_read() by following phy_write_mmd() and
phy_read_mmd() mdiobus read write implementation format.

Reviewed-by: Li, Yifan 
Signed-off-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Weifeng Voon 
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 40 ++-
 include/linux/phy.h   |  2 ++
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index bdd351597b55..c3d8f1d145ec 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -34,11 +34,27 @@
 
 #define MII_BUSY 0x0001
 #define MII_WRITE 0x0002
+#define MII_DATA_MASK GENMASK(15, 0)
 
 /* GMAC4 defines */
 #define MII_GMAC4_GOC_SHIFT2
+#define MII_GMAC4_REG_ADDR_SHIFT   16
 #define MII_GMAC4_WRITE(1 << MII_GMAC4_GOC_SHIFT)
 #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
+#define MII_GMAC4_C45E BIT(1)
+
+static void stmmac_mdio_c45_setup(struct stmmac_priv *priv, int phyreg,
+ u32 *val, u32 *data)
+{
+   unsigned int reg_shift = priv->hw->mii.reg_shift;
+   unsigned int reg_mask = priv->hw->mii.reg_mask;
+
+   *val |= MII_GMAC4_C45E;
+   *val &= ~reg_mask;
+   *val |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << reg_shift) & reg_mask;
+
+   *data |= (phyreg & MII_REGADDR_C45_MASK) << MII_GMAC4_REG_ADDR_SHIFT;
+}
 
 /* XGMAC defines */
 #define MII_XGMAC_SADDRBIT(18)
@@ -165,22 +181,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
-   int data;
u32 value = MII_BUSY;
+   int data = 0;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_READ;
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   }
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
   100, 1))
return -EBUSY;
 
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -188,7 +208,7 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
return -EBUSY;
 
/* Read the data from the MII data register */
-   data = (int)readl(priv->ioaddr + mii_data);
+   data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
 
return data;
 }
@@ -208,8 +228,9 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
-   u32 v;
u32 value = MII_BUSY;
+   int data = phydata;
+   u32 v;
 
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
@@ -217,10 +238,13 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
 
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
-   if (priv->plat->has_gmac4)
+   if (priv->plat->has_gmac4) {
value |= MII_GMAC4_WRITE;
-   else
+   if (phyreg & MII_ADDR_C45)
+   stmmac_mdio_c45_setup(priv, phyreg, , );
+   } else {
value |= MII_WRITE;
+   }
 
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -228,7 +252,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
return -EBUSY;
 
/* Set the MII address register to write */
-   writel(phydata, priv->ioaddr + mii_data);
+   writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
 
/* Wait until any existing MII operation is complete */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 073fb151b5a9..d3daac8ec686 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -198,6 +198,8 @@ 

  1   2   >