[net-next.git 2/2] stmmac: start managing pcs RGMII modes andrestart ANE

From: Giuseppe Cavallaro
Date: Fri Feb 22 2013 - 06:24:00 EST


This patch adds the minimal support to manage the PCS
modes (RGMII) and restart the ANE when the interface is
opened.

Currently the following main things are missing:

o SGMII/TBI support
o manage the advertisement register (e.g. reg 50)
o manage pause via ADV.
o manage the Auto-Nogotiation Ability Register (51)
o improve the ethtool.

Thanks to Byungho that wrote some part of this code.

Signed-off-by: Byungho An <bh74.an@xxxxxxxxxxx>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@xxxxxx>
---
drivers/net/ethernet/stmicro/stmmac/common.h | 7 +++
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 20 +++++++
.../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 15 +++++
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 13 +++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 55 +++++++++++++++----
6 files changed, 99 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 1db761c..04134ad 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -142,6 +142,12 @@ struct stmmac_extra_stats {
#define FLOW_TX 2
#define FLOW_AUTO (FLOW_TX | FLOW_RX)

+/* PCS defines */
+#define STMMAC_PCS_RGMII (1<<0)
+#define STMMAC_PCS_SGMII (1<<1)
+#define STMMAC_PCS_TBI (1<<2)
+#define STMMAC_PCS_RTBI (1<<1)
+
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */

/* DAM HW feature register fields */
@@ -347,6 +353,7 @@ struct stmmac_ops {
void (*reset_eee_mode) (void __iomem *ioaddr);
void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
void (*set_eee_pls) (void __iomem *ioaddr, int link);
+ void (*ctrl_ane) (void __iomem *ioaddr, bool restart);
};

struct mac_link {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 8a8c39f..5cfd4d2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -98,6 +98,24 @@ enum power_event {
#define GMAC_TBI 0x000000d4 /* TBI extend status */
#define GMAC_S_R_GMII 0x000000d8 /* SGMII RGMII status */

+/* AN Configuration defines */
+#define GMAC_AN_CTRL_RAN 0x00000200 /* Restart Auto-Negotiation */
+#define GMAC_AN_CTRL_ANE 0x00001000 /* Auto-Negotiation Enable */
+#define GMAC_AN_CTRL_ELE 0x00004000 /* External Loopback Enable */
+#define GMAC_AN_CTRL_ECD 0x00010000 /* Enable Comma Detect */
+#define GMAC_AN_CTRL_LR 0x00020000 /* Lock to Reference */
+#define GMAC_AN_CTRL_SGMRAL 0x00040000 /* SGMII RAL Control */
+
+/* AN Status defines */
+#define GMAC_AN_STATUS_LS 0x00000004 /* Link Status 0:down 1:up */
+#define GMAC_AN_STATUS_ANA 0x00000008 /* Auto-Negotiation Ability */
+#define GMAC_AN_STATUS_ANC 0x00000020 /* Auto-Negotiation Complete */
+#define GMAC_AN_STATUS_ES 0x00000100 /* Extended Status */
+
+ /* GMAC Configuration defines */
+#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
+#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
+
/* GMAC Configuration defines */
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
@@ -231,5 +249,7 @@ enum rtc_control {
#define GMAC_MMC_TX_INTR 0x108
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208

+
+
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
#endif /* __DWMAC1000_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index ff4c79e..f59366d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -309,6 +309,20 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
writel(value, ioaddr + LPI_TIMER_CTRL);
}

+static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart)
+{
+ u32 value;
+
+ value = readl(ioaddr + GMAC_AN_CTRL);
+ /* auto negotiation enable and External Loopback enable */
+ value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;
+
+ if (restart)
+ value |= GMAC_AN_CTRL_RAN;
+
+ writel(value, ioaddr + GMAC_AN_CTRL);
+}
+
static const struct stmmac_ops dwmac1000_ops = {
.core_init = dwmac1000_core_init,
.rx_ipc = dwmac1000_rx_ipc_enable,
@@ -323,6 +337,7 @@ static const struct stmmac_ops dwmac1000_ops = {
.reset_eee_mode = dwmac1000_reset_eee_mode,
.set_eee_timer = dwmac1000_set_eee_timer,
.set_eee_pls = dwmac1000_set_eee_pls,
+ .ctrl_ane = dwmac1000_ctrl_ane,
};

struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index b05df89..197497c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -93,6 +93,7 @@ struct stmmac_priv {
u32 tx_coal_timer;
int use_riwt;
u32 rx_riwt;
+ int pcs;
};

extern int phyaddr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index e15004f..71b58ea 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -222,6 +222,10 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phy = priv->phydev;
int rc;
+
+ if (priv->pcs) /* FIXME */
+ return -EOPNOTSUPP;
+
if (phy == NULL) {
pr_err("%s: %s: PHY is not registered\n",
__func__, dev->name);
@@ -246,6 +250,9 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
struct phy_device *phy = priv->phydev;
int rc;

+ if (priv->pcs) /* FIXME */
+ return -EOPNOTSUPP;
+
spin_lock(&priv->lock);
rc = phy_ethtool_sset(phy, cmd);
spin_unlock(&priv->lock);
@@ -317,6 +324,9 @@ stmmac_get_pauseparam(struct net_device *netdev,

spin_lock(&priv->lock);

+ if (priv->pcs)
+ return -EOPNOTSUPP;
+
pause->rx_pause = 0;
pause->tx_pause = 0;
pause->autoneg = priv->phydev->autoneg;
@@ -338,6 +348,9 @@ stmmac_set_pauseparam(struct net_device *netdev,
int new_pause = FLOW_OFF;
int ret = 0;

+ if (priv->pcs)
+ return -EOPNOTSUPP;
+
spin_lock(&priv->lock);

if (pause->rx_pause)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 1f2f349..6366266 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -398,6 +398,21 @@ static void stmmac_adjust_link(struct net_device *dev)
DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n");
}

+static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
+{
+ int interface = priv->plat->interface;
+
+ if (priv->dma_cap.pcs) {
+ if ((interface & PHY_INTERFACE_MODE_RGMII) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_ID) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_RXID) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_TXID)) {
+ pr_debug("STMMAC: PCS RGMII support enable\n");
+ priv->pcs = STMMAC_PCS_RGMII;
+ }
+ }
+}
+
/**
* stmmac_init_phy - PHY initialization
* @dev: net device structure
@@ -1012,10 +1027,13 @@ static int stmmac_open(struct net_device *dev)

stmmac_check_ether_addr(priv);

- ret = stmmac_init_phy(dev);
- if (unlikely(ret)) {
- pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret);
- goto open_error;
+ if (!priv->pcs) {
+ ret = stmmac_init_phy(dev);
+ if (unlikely(ret)) {
+ pr_err("%s: Cannot attach to PHY (error: %d)\n",
+ __func__, ret);
+ goto open_error;
+ }
}

/* Create and initialize the TX/RX descriptors chains. */
@@ -1104,7 +1122,12 @@ static int stmmac_open(struct net_device *dev)
phy_start(priv->phydev);

priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER;
- priv->eee_enabled = stmmac_eee_init(priv);
+
+ /* Using PCS we cannot dial with the phy registers at this stage
+ * so we do not support extra feature like EEE.
+ */
+ if (!priv->pcs)
+ priv->eee_enabled = stmmac_eee_init(priv);

stmmac_init_tx_coalesce(priv);

@@ -1113,6 +1136,9 @@ static int stmmac_open(struct net_device *dev)
priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);
}

+ if (priv->pcs && priv->hw->mac->ctrl_ane)
+ priv->hw->mac->ctrl_ane(priv->ioaddr, 1);
+
napi_enable(&priv->napi);
netif_start_queue(dev);

@@ -2028,12 +2054,16 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
else
priv->clk_csr = priv->plat->clk_csr;

- /* MDIO bus Registration */
- ret = stmmac_mdio_register(ndev);
- if (ret < 0) {
- pr_debug("%s: MDIO bus (id: %d) registration failed",
- __func__, priv->plat->bus_id);
- goto error_mdio_register;
+ stmmac_check_pcs_mode(priv);
+
+ if (!priv->pcs) {
+ /* MDIO bus Registration */
+ ret = stmmac_mdio_register(ndev);
+ if (ret < 0) {
+ pr_debug("%s: MDIO bus (id: %d) registration failed",
+ __func__, priv->plat->bus_id);
+ goto error_mdio_register;
+ }
}

return priv;
@@ -2065,7 +2095,8 @@ int stmmac_dvr_remove(struct net_device *ndev)
priv->hw->dma->stop_tx(priv->ioaddr);

stmmac_set_mac(priv->ioaddr, false);
- stmmac_mdio_unregister(ndev);
+ if (!priv->pcs)
+ stmmac_mdio_unregister(ndev);
netif_carrier_off(ndev);
unregister_netdev(ndev);
free_netdev(ndev);
--
1.7.4.4


--------------090907080700060704020909--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/