drivers: net: xgene: Add flow control configuration
authorIyappan Subramanian <isubramanian@apm.com>
Fri, 2 Dec 2016 00:41:42 +0000 (16:41 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 3 Dec 2016 20:46:50 +0000 (15:46 -0500)
This patch adds functions to configure mac, when flow control
and pause frame settings change.

Signed-off-by: Iyappan Subramanian <isubramanian@apm.com>
Signed-off-by: Quan Nguyen <qnguyen@apm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
drivers/net/ethernet/apm/xgene/xgene_enet_main.h
drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h

index 92cc7e53fce9e0198b9d71bf1285dd2abdfbcf8d..23a0175085895c28fed568c635e055470a458897 100644 (file)
@@ -509,6 +509,51 @@ static void xgene_enet_set_frame_size(struct xgene_enet_pdata *pdata, int size)
        xgene_enet_wr_mcx_mac(pdata, MAX_FRAME_LEN_ADDR, size);
 }
 
+static void xgene_gmac_enable_tx_pause(struct xgene_enet_pdata *pdata,
+                                      bool enable)
+{
+       u32 data;
+
+       xgene_enet_rd_mcx_csr(pdata, CSR_ECM_CFG_0_ADDR, &data);
+
+       if (enable)
+               data |= MULTI_DPF_AUTOCTRL | PAUSE_XON_EN;
+       else
+               data &= ~(MULTI_DPF_AUTOCTRL | PAUSE_XON_EN);
+
+       xgene_enet_wr_mcx_csr(pdata, CSR_ECM_CFG_0_ADDR, data);
+}
+
+static void xgene_gmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable)
+{
+       u32 data;
+
+       xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
+
+       if (enable)
+               data |= TX_FLOW_EN;
+       else
+               data &= ~TX_FLOW_EN;
+
+       xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data);
+
+       pdata->mac_ops->enable_tx_pause(pdata, enable);
+}
+
+static void xgene_gmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable)
+{
+       u32 data;
+
+       xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
+
+       if (enable)
+               data |= RX_FLOW_EN;
+       else
+               data &= ~RX_FLOW_EN;
+
+       xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data);
+}
+
 static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
 {
        u32 value;
@@ -909,6 +954,9 @@ const struct xgene_mac_ops xgene_gmac_ops = {
        .set_speed = xgene_gmac_set_speed,
        .set_mac_addr = xgene_gmac_set_mac_addr,
        .set_framesize = xgene_enet_set_frame_size,
+       .enable_tx_pause = xgene_gmac_enable_tx_pause,
+       .flowctl_tx     = xgene_gmac_flowctl_tx,
+       .flowctl_rx     = xgene_gmac_flowctl_rx,
 };
 
 const struct xgene_port_ops xgene_gport_ops = {
index bd6cb6c4339087a012b9d5a15f3e86283a73e6ce..7ba649d2573d07bf2eb30110e1205c2c7ec98de0 100644 (file)
@@ -170,6 +170,10 @@ enum xgene_enet_rm {
 #define CFG_WAITASYNCRD_SET(dst, val)          xgene_set_bits(dst, val, 0, 16)
 #define CFG_CLE_DSTQID0(val)           ((val) & GENMASK(11, 0))
 #define CFG_CLE_FPSEL0(val)            (((val) << 16) & GENMASK(19, 16))
+#define CSR_ECM_CFG_0_ADDR             0x0220
+#define CSR_ECM_CFG_1_ADDR             0x0224
+#define PAUSE_XON_EN                   BIT(30)
+#define MULTI_DPF_AUTOCTRL             BIT(28)
 #define CFG_CLE_NXTFPSEL0(val)         (((val) << 20) & GENMASK(23, 20))
 #define ICM_CONFIG0_REG_0_ADDR         0x0400
 #define ICM_CONFIG2_REG_0_ADDR         0x0410
@@ -198,6 +202,8 @@ enum xgene_enet_rm {
 #define SOFT_RESET1                    BIT(31)
 #define TX_EN                          BIT(0)
 #define RX_EN                          BIT(2)
+#define TX_FLOW_EN                     BIT(4)
+#define RX_FLOW_EN                     BIT(5)
 #define ENET_LHD_MODE                  BIT(25)
 #define ENET_GHD_MODE                  BIT(26)
 #define FULL_DUPLEX2                   BIT(0)
index 61aa9878a901c717786efd2f005137ff233388ae..52571741da9f5559145e5ce172a7ee910818bbc4 100644 (file)
@@ -159,6 +159,9 @@ struct xgene_mac_ops {
        void (*set_framesize)(struct xgene_enet_pdata *pdata, int framesize);
        void (*set_mss)(struct xgene_enet_pdata *pdata, u16 mss, u8 index);
        void (*link_state)(struct work_struct *work);
+       void (*enable_tx_pause)(struct xgene_enet_pdata *pdata, bool enable);
+       void (*flowctl_rx)(struct xgene_enet_pdata *pdata, bool enable);
+       void (*flowctl_tx)(struct xgene_enet_pdata *pdata, bool enable);
 };
 
 struct xgene_port_ops {
@@ -234,6 +237,9 @@ struct xgene_enet_pdata {
        bool mdio_driver;
        struct gpio_desc *sfp_rdy;
        bool sfp_gpio_en;
+       u32 pause_autoneg;
+       bool tx_pause;
+       bool rx_pause;
 };
 
 struct xgene_indirect_ctl {
index 6283f2b00dc96ccd9c1dd50e7aa921ef883292d1..1c9b8ba5dcae4bacf5b6240af7850f48012262f0 100644 (file)
@@ -365,6 +365,32 @@ static void xgene_sgmii_enable_autoneg(struct xgene_enet_pdata *p)
                netdev_err(p->ndev, "Auto-negotiation failed\n");
 }
 
+static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set)
+{
+       u32 data;
+
+       data = xgene_enet_rd_mac(p, MAC_CONFIG_1_ADDR);
+
+       if (set)
+               data |= bits;
+       else
+               data &= ~bits;
+
+       xgene_enet_wr_mac(p, MAC_CONFIG_1_ADDR, data);
+}
+
+static void xgene_sgmac_flowctl_tx(struct xgene_enet_pdata *p, bool enable)
+{
+       xgene_sgmac_rxtx(p, TX_FLOW_EN, enable);
+
+       p->mac_ops->enable_tx_pause(p, enable);
+}
+
+static void xgene_sgmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable)
+{
+       xgene_sgmac_rxtx(pdata, RX_FLOW_EN, enable);
+}
+
 static void xgene_sgmac_init(struct xgene_enet_pdata *p)
 {
        u32 enet_spare_cfg_reg, rsif_config_reg;
@@ -411,20 +437,6 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p)
        xgene_enet_wr_mcx_csr(p, rx_dv_gate_reg, RESUME_RX0);
 }
 
-static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set)
-{
-       u32 data;
-
-       data = xgene_enet_rd_mac(p, MAC_CONFIG_1_ADDR);
-
-       if (set)
-               data |= bits;
-       else
-               data &= ~bits;
-
-       xgene_enet_wr_mac(p, MAC_CONFIG_1_ADDR, data);
-}
-
 static void xgene_sgmac_rx_enable(struct xgene_enet_pdata *p)
 {
        xgene_sgmac_rxtx(p, RX_EN, true);
@@ -591,6 +603,25 @@ static void xgene_enet_link_state(struct work_struct *work)
        schedule_delayed_work(&p->link_work, poll_interval);
 }
 
+static void xgene_sgmac_enable_tx_pause(struct xgene_enet_pdata *p, bool enable)
+{
+       u32 data, ecm_cfg_addr;
+
+       if (p->enet_id == XGENE_ENET1) {
+               ecm_cfg_addr = (!(p->port_id % 2)) ? CSR_ECM_CFG_0_ADDR :
+                               CSR_ECM_CFG_1_ADDR;
+       } else {
+               ecm_cfg_addr = XG_MCX_ECM_CFG_0_ADDR;
+       }
+
+       data = xgene_enet_rd_mcx_csr(p, ecm_cfg_addr);
+       if (enable)
+               data |= MULTI_DPF_AUTOCTRL | PAUSE_XON_EN;
+       else
+               data &= ~(MULTI_DPF_AUTOCTRL | PAUSE_XON_EN);
+       xgene_enet_wr_mcx_csr(p, ecm_cfg_addr, data);
+}
+
 const struct xgene_mac_ops xgene_sgmac_ops = {
        .init           = xgene_sgmac_init,
        .reset          = xgene_sgmac_reset,
@@ -601,7 +632,10 @@ const struct xgene_mac_ops xgene_sgmac_ops = {
        .set_speed      = xgene_sgmac_set_speed,
        .set_mac_addr   = xgene_sgmac_set_mac_addr,
        .set_framesize  = xgene_sgmac_set_frame_size,
-       .link_state     = xgene_enet_link_state
+       .link_state     = xgene_enet_link_state,
+       .enable_tx_pause = xgene_sgmac_enable_tx_pause,
+       .flowctl_tx     = xgene_sgmac_flowctl_tx,
+       .flowctl_rx     = xgene_sgmac_flowctl_rx
 };
 
 const struct xgene_port_ops xgene_sgport_ops = {
index 2a9761b9584104a84304c6812206edd057d3325f..727ef4b4da03d53d359ccc71ad77b62d880b2e0f 100644 (file)
@@ -101,6 +101,14 @@ static void xgene_enet_wr_pcs(struct xgene_enet_pdata *pdata,
                           wr_addr);
 }
 
+static void xgene_enet_wr_axg_csr(struct xgene_enet_pdata *pdata,
+                                 u32 offset, u32 val)
+{
+       void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
+
+       iowrite32(val, addr);
+}
+
 static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata,
                              u32 offset, u32 *val)
 {
@@ -174,6 +182,14 @@ static bool xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata,
        return success;
 }
 
+static void xgene_enet_rd_axg_csr(struct xgene_enet_pdata *pdata,
+                                 u32 offset, u32 *val)
+{
+       void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
+
+       *val = ioread32(addr);
+}
+
 static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
 {
        struct net_device *ndev = pdata->ndev;
@@ -265,6 +281,51 @@ static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata)
        return data;
 }
 
+static void xgene_xgmac_enable_tx_pause(struct xgene_enet_pdata *pdata,
+                                       bool enable)
+{
+       u32 data;
+
+       xgene_enet_rd_axg_csr(pdata, XGENET_CSR_ECM_CFG_0_ADDR, &data);
+
+       if (enable)
+               data |= MULTI_DPF_AUTOCTRL | PAUSE_XON_EN;
+       else
+               data &= ~(MULTI_DPF_AUTOCTRL | PAUSE_XON_EN);
+
+       xgene_enet_wr_axg_csr(pdata, XGENET_CSR_ECM_CFG_0_ADDR, data);
+}
+
+static void xgene_xgmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable)
+{
+       u32 data;
+
+       xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
+
+       if (enable)
+               data |= HSTTCTLEN;
+       else
+               data &= ~HSTTCTLEN;
+
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
+
+       pdata->mac_ops->enable_tx_pause(pdata, enable);
+}
+
+static void xgene_xgmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable)
+{
+       u32 data;
+
+       xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
+
+       if (enable)
+               data |= HSTRCTLEN;
+       else
+               data &= ~HSTRCTLEN;
+
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
+}
+
 static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
 {
        u32 data;
@@ -482,7 +543,10 @@ const struct xgene_mac_ops xgene_xgmac_ops = {
        .set_mac_addr = xgene_xgmac_set_mac_addr,
        .set_framesize = xgene_xgmac_set_frame_size,
        .set_mss = xgene_xgmac_set_mss,
-       .link_state = xgene_enet_link_state
+       .link_state = xgene_enet_link_state,
+       .enable_tx_pause = xgene_xgmac_enable_tx_pause,
+       .flowctl_rx = xgene_xgmac_flowctl_rx,
+       .flowctl_tx = xgene_xgmac_flowctl_tx
 };
 
 const struct xgene_port_ops xgene_xgport_ops = {
index 360ccbd9556654430c34bde6250d4759a9aed81b..9d75020b5672517c834b1e3e71e6f0d81e91cc65 100644 (file)
@@ -59,6 +59,7 @@
 #define HSTMAXFRAME_LENGTH_ADDR                0x0020
 
 #define XG_MCX_RX_DV_GATE_REG_0_ADDR   0x0004
+#define XG_MCX_ECM_CFG_0_ADDR          0x0074
 #define XG_RSIF_CONFIG_REG_ADDR                0x00a0
 #define XCLE_BYPASS_REG0_ADDR           0x0160
 #define XCLE_BYPASS_REG1_ADDR           0x0164
@@ -70,6 +71,7 @@
 #define XG_ENET_SPARE_CFG_REG_ADDR     0x040c
 #define XG_ENET_SPARE_CFG_REG_1_ADDR   0x0410
 #define XGENET_RX_DV_GATE_REG_0_ADDR   0x0804
+#define XGENET_CSR_ECM_CFG_0_ADDR      0x0880
 #define XG_MCX_ICM_CONFIG0_REG_0_ADDR  0x00e0
 #define XG_MCX_ICM_CONFIG2_REG_0_ADDR  0x00e8