Commit bb64fa09 authored by Iyappan Subramanian's avatar Iyappan Subramanian Committed by David S. Miller

drivers: net: xgene: Add flow control configuration

This patch adds functions to configure mac, when flow control
and pause frame settings change.
Signed-off-by: default avatarIyappan Subramanian <isubramanian@apm.com>
Signed-off-by: default avatarQuan Nguyen <qnguyen@apm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a809701f
...@@ -509,6 +509,51 @@ static void xgene_enet_set_frame_size(struct xgene_enet_pdata *pdata, int size) ...@@ -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); 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) static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
{ {
u32 value; u32 value;
...@@ -909,6 +954,9 @@ const struct xgene_mac_ops xgene_gmac_ops = { ...@@ -909,6 +954,9 @@ const struct xgene_mac_ops xgene_gmac_ops = {
.set_speed = xgene_gmac_set_speed, .set_speed = xgene_gmac_set_speed,
.set_mac_addr = xgene_gmac_set_mac_addr, .set_mac_addr = xgene_gmac_set_mac_addr,
.set_framesize = xgene_enet_set_frame_size, .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 = { const struct xgene_port_ops xgene_gport_ops = {
......
...@@ -170,6 +170,10 @@ enum xgene_enet_rm { ...@@ -170,6 +170,10 @@ enum xgene_enet_rm {
#define CFG_WAITASYNCRD_SET(dst, val) xgene_set_bits(dst, val, 0, 16) #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_DSTQID0(val) ((val) & GENMASK(11, 0))
#define CFG_CLE_FPSEL0(val) (((val) << 16) & GENMASK(19, 16)) #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 CFG_CLE_NXTFPSEL0(val) (((val) << 20) & GENMASK(23, 20))
#define ICM_CONFIG0_REG_0_ADDR 0x0400 #define ICM_CONFIG0_REG_0_ADDR 0x0400
#define ICM_CONFIG2_REG_0_ADDR 0x0410 #define ICM_CONFIG2_REG_0_ADDR 0x0410
...@@ -198,6 +202,8 @@ enum xgene_enet_rm { ...@@ -198,6 +202,8 @@ enum xgene_enet_rm {
#define SOFT_RESET1 BIT(31) #define SOFT_RESET1 BIT(31)
#define TX_EN BIT(0) #define TX_EN BIT(0)
#define RX_EN BIT(2) #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_LHD_MODE BIT(25)
#define ENET_GHD_MODE BIT(26) #define ENET_GHD_MODE BIT(26)
#define FULL_DUPLEX2 BIT(0) #define FULL_DUPLEX2 BIT(0)
......
...@@ -159,6 +159,9 @@ struct xgene_mac_ops { ...@@ -159,6 +159,9 @@ struct xgene_mac_ops {
void (*set_framesize)(struct xgene_enet_pdata *pdata, int framesize); void (*set_framesize)(struct xgene_enet_pdata *pdata, int framesize);
void (*set_mss)(struct xgene_enet_pdata *pdata, u16 mss, u8 index); void (*set_mss)(struct xgene_enet_pdata *pdata, u16 mss, u8 index);
void (*link_state)(struct work_struct *work); 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 { struct xgene_port_ops {
...@@ -234,6 +237,9 @@ struct xgene_enet_pdata { ...@@ -234,6 +237,9 @@ struct xgene_enet_pdata {
bool mdio_driver; bool mdio_driver;
struct gpio_desc *sfp_rdy; struct gpio_desc *sfp_rdy;
bool sfp_gpio_en; bool sfp_gpio_en;
u32 pause_autoneg;
bool tx_pause;
bool rx_pause;
}; };
struct xgene_indirect_ctl { struct xgene_indirect_ctl {
......
...@@ -365,6 +365,32 @@ static void xgene_sgmii_enable_autoneg(struct xgene_enet_pdata *p) ...@@ -365,6 +365,32 @@ static void xgene_sgmii_enable_autoneg(struct xgene_enet_pdata *p)
netdev_err(p->ndev, "Auto-negotiation failed\n"); 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) static void xgene_sgmac_init(struct xgene_enet_pdata *p)
{ {
u32 enet_spare_cfg_reg, rsif_config_reg; u32 enet_spare_cfg_reg, rsif_config_reg;
...@@ -411,20 +437,6 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) ...@@ -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); 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) static void xgene_sgmac_rx_enable(struct xgene_enet_pdata *p)
{ {
xgene_sgmac_rxtx(p, RX_EN, true); xgene_sgmac_rxtx(p, RX_EN, true);
...@@ -591,6 +603,25 @@ static void xgene_enet_link_state(struct work_struct *work) ...@@ -591,6 +603,25 @@ static void xgene_enet_link_state(struct work_struct *work)
schedule_delayed_work(&p->link_work, poll_interval); 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 = { const struct xgene_mac_ops xgene_sgmac_ops = {
.init = xgene_sgmac_init, .init = xgene_sgmac_init,
.reset = xgene_sgmac_reset, .reset = xgene_sgmac_reset,
...@@ -601,7 +632,10 @@ const struct xgene_mac_ops xgene_sgmac_ops = { ...@@ -601,7 +632,10 @@ const struct xgene_mac_ops xgene_sgmac_ops = {
.set_speed = xgene_sgmac_set_speed, .set_speed = xgene_sgmac_set_speed,
.set_mac_addr = xgene_sgmac_set_mac_addr, .set_mac_addr = xgene_sgmac_set_mac_addr,
.set_framesize = xgene_sgmac_set_frame_size, .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 = { const struct xgene_port_ops xgene_sgport_ops = {
......
...@@ -101,6 +101,14 @@ static void xgene_enet_wr_pcs(struct xgene_enet_pdata *pdata, ...@@ -101,6 +101,14 @@ static void xgene_enet_wr_pcs(struct xgene_enet_pdata *pdata,
wr_addr); 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, static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata,
u32 offset, u32 *val) u32 offset, u32 *val)
{ {
...@@ -174,6 +182,14 @@ static bool xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata, ...@@ -174,6 +182,14 @@ static bool xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata,
return success; 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) static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
{ {
struct net_device *ndev = pdata->ndev; struct net_device *ndev = pdata->ndev;
...@@ -265,6 +281,51 @@ static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata) ...@@ -265,6 +281,51 @@ static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata)
return data; 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) static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
{ {
u32 data; u32 data;
...@@ -482,7 +543,10 @@ const struct xgene_mac_ops xgene_xgmac_ops = { ...@@ -482,7 +543,10 @@ const struct xgene_mac_ops xgene_xgmac_ops = {
.set_mac_addr = xgene_xgmac_set_mac_addr, .set_mac_addr = xgene_xgmac_set_mac_addr,
.set_framesize = xgene_xgmac_set_frame_size, .set_framesize = xgene_xgmac_set_frame_size,
.set_mss = xgene_xgmac_set_mss, .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 = { const struct xgene_port_ops xgene_xgport_ops = {
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#define HSTMAXFRAME_LENGTH_ADDR 0x0020 #define HSTMAXFRAME_LENGTH_ADDR 0x0020
#define XG_MCX_RX_DV_GATE_REG_0_ADDR 0x0004 #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 XG_RSIF_CONFIG_REG_ADDR 0x00a0
#define XCLE_BYPASS_REG0_ADDR 0x0160 #define XCLE_BYPASS_REG0_ADDR 0x0160
#define XCLE_BYPASS_REG1_ADDR 0x0164 #define XCLE_BYPASS_REG1_ADDR 0x0164
...@@ -70,6 +71,7 @@ ...@@ -70,6 +71,7 @@
#define XG_ENET_SPARE_CFG_REG_ADDR 0x040c #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c
#define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410
#define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 #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_CONFIG0_REG_0_ADDR 0x00e0
#define XG_MCX_ICM_CONFIG2_REG_0_ADDR 0x00e8 #define XG_MCX_ICM_CONFIG2_REG_0_ADDR 0x00e8
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment