@@ -200,6 +200,7 @@ endif
config STMMAC_PCI
tristate "STMMAC PCI bus support"
depends on STMMAC_ETH && PCI
+ select DWXPCS
---help---
This selects the platform specific bus support for the stmmac driver.
This driver was tested on XLINX XC2V3000 FF1152AMT0221
@@ -29,6 +29,7 @@ struct stmmac_resources {
int wol_irq;
int lpi_irq;
int irq;
+ int phy_conv_irq;
};
struct stmmac_tx_info {
@@ -203,6 +204,7 @@ struct stmmac_priv {
void __iomem *mmcaddr;
void __iomem *ptpaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ int phy_conv_irq;
#ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_dir;
@@ -2726,11 +2726,23 @@ static int stmmac_open(struct net_device *dev)
}
}
+ /* Start phy converter after MDIO bus IRQ handling is up */
+ if (priv->plat->setup_phy_conv) {
+ ret = priv->plat->setup_phy_conv(priv->mii, priv->phy_conv_irq);
+ if (ret < 0) {
+ netdev_err(priv->dev,
+ "%s: ERROR: setup phy conv (error: %d)\n",
+ __func__, ret);
+ goto phy_conv_error;
+ }
+ }
+
stmmac_enable_all_queues(priv);
stmmac_start_all_queues(priv);
return 0;
+phy_conv_error:
lpiirq_error:
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
@@ -2760,6 +2772,7 @@ static int stmmac_release(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
u32 chan;
+ int ret;
if (priv->eee_enabled)
del_timer_sync(&priv->eee_ctrl_timer);
@@ -2782,6 +2795,17 @@ static int stmmac_release(struct net_device *dev)
if (priv->lpi_irq > 0)
free_irq(priv->lpi_irq, dev);
+ /* Start phy converter after MDIO bus IRQ handling is up */
+ if (priv->plat->remove_phy_conv) {
+ ret = priv->plat->remove_phy_conv(priv->mii);
+ if (ret < 0) {
+ netdev_err(priv->dev,
+ "%s: ERROR: remove phy conv (error: %d)\n",
+ __func__, ret);
+ return 0;
+ }
+ }
+
/* Stop TX/RX DMA and clear the descriptors */
stmmac_stop_all_dma(priv);
@@ -4424,6 +4448,7 @@ int stmmac_dvr_probe(struct device *device,
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
priv->lpi_irq = res->lpi_irq;
+ priv->phy_conv_irq = res->phy_conv_irq;
if (!IS_ERR_OR_NULL(res->mac))
memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
@@ -10,9 +10,10 @@
*******************************************************************************/
#include <linux/clk-provider.h>
+#include <linux/phy.h>
#include <linux/pci.h>
#include <linux/dmi.h>
-
+#include <linux/dwxpcs.h>
#include "stmmac.h"
/*
@@ -109,6 +110,42 @@ static const struct stmmac_pci_info stmmac_pci_info = {
.setup = stmmac_default_data,
};
+static struct dwxpcs_platform_data intel_mgbe_pdata = {
+ .mode = DWXPCS_MODE_SGMII_AN,
+ .ext_phy_addr = 0x0,
+};
+
+static struct mdio_board_info intel_mgbe_bdinfo = {
+ .bus_id = "stmmac-1",
+ .modalias = "dwxpcs",
+ .mdio_addr = 0x16,
+ .platform_data = &intel_mgbe_pdata,
+};
+
+static int setup_intel_mgbe_phy_conv(struct mii_bus *bus, int irq)
+{
+ struct dwxpcs_platform_data *pdata = &intel_mgbe_pdata;
+
+ pdata->irq = irq;
+
+ return mdiobus_create_device(bus, &intel_mgbe_bdinfo);
+}
+
+static int remove_intel_mgbe_phy_conv(struct mii_bus *bus)
+{
+ struct mdio_board_info *bdinfo = &intel_mgbe_bdinfo;
+ struct mdio_device *mdiodev;
+
+ mdiodev = mdiobus_get_mdio_device(bus, bdinfo->mdio_addr);
+
+ if (!mdiodev)
+ return -1;
+
+ mdio_device_remove(mdiodev);
+
+ return 0;
+}
+
static int intel_mgbe_common_data(struct pci_dev *pdev,
struct plat_stmmacenet_data *plat)
{
@@ -197,6 +234,11 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
/* Set the maxmtu to a default of JUMBO_LEN */
plat->maxmtu = JUMBO_LEN;
+ if (plat->interface == PHY_INTERFACE_MODE_SGMII) {
+ plat->setup_phy_conv = setup_intel_mgbe_phy_conv;
+ plat->remove_phy_conv = remove_intel_mgbe_phy_conv;
+ }
+
return 0;
}
@@ -441,6 +483,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.phy_conv_irq = res.irq;
return stmmac_dvr_probe(&pdev->dev, plat, &res);
}
@@ -12,6 +12,7 @@
#ifndef __STMMAC_PLATFORM_DATA
#define __STMMAC_PLATFORM_DATA
+#include <linux/phy.h>
#include <linux/platform_device.h>
#define MTL_MAX_RX_QUEUES 8
@@ -162,6 +163,8 @@ struct plat_stmmacenet_data {
int (*init)(struct platform_device *pdev, void *priv);
void (*exit)(struct platform_device *pdev, void *priv);
struct mac_device_info *(*setup)(void *priv);
+ int (*setup_phy_conv)(struct mii_bus *bus, int irq);
+ int (*remove_phy_conv)(struct mii_bus *bus);
void *bsp_priv;
struct clk *stmmac_clk;
struct clk *pclk;
For EHL & TGL Ethernet PCS, the mdio bus address is the same across all TSN controller instances. External PHY is using default mdio bus address of 0x0. As Ethernet DW PCS is only applicable for SGMII interface, we only register setup_intel_mgbe_phy_conv() for all TSN controller with SGMII interface only. Also introduce callback for remove mdio_device for unloading driver. Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com> --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 25 +++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_pci.c | 45 ++++++++++++++++++- include/linux/stmmac.h | 3 ++ 5 files changed, 75 insertions(+), 1 deletion(-)