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

drivers: net: xgene: Fix MSS programming

Current driver programs static value of MSS in hardware register for TSO
offload engine to segment the TCP payload regardless the MSS value
provided by network stack.

This patch fixes this by programming hardware registers with the
stack provided MSS value.

Since the hardware has the limitation of having only 4 MSS registers,
this patch uses reference count of mss values being used.
Signed-off-by: default avatarIyappan Subramanian <isubramanian@apm.com>
Signed-off-by: default avatarToan Le <toanle@apm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e12934d9
...@@ -237,6 +237,8 @@ enum xgene_enet_rm { ...@@ -237,6 +237,8 @@ enum xgene_enet_rm {
#define TCPHDR_LEN 6 #define TCPHDR_LEN 6
#define IPHDR_POS 6 #define IPHDR_POS 6
#define IPHDR_LEN 6 #define IPHDR_LEN 6
#define MSS_POS 20
#define MSS_LEN 2
#define EC_POS 22 /* Enable checksum */ #define EC_POS 22 /* Enable checksum */
#define EC_LEN 1 #define EC_LEN 1
#define ET_POS 23 /* Enable TSO */ #define ET_POS 23 /* Enable TSO */
...@@ -253,6 +255,11 @@ enum xgene_enet_rm { ...@@ -253,6 +255,11 @@ enum xgene_enet_rm {
#define LAST_BUFFER (0x7800ULL << BUFDATALEN_POS) #define LAST_BUFFER (0x7800ULL << BUFDATALEN_POS)
#define TSO_MSS0_POS 0
#define TSO_MSS0_LEN 14
#define TSO_MSS1_POS 16
#define TSO_MSS1_LEN 14
struct xgene_enet_raw_desc { struct xgene_enet_raw_desc {
__le64 m0; __le64 m0;
__le64 m1; __le64 m1;
......
...@@ -137,6 +137,7 @@ static irqreturn_t xgene_enet_rx_irq(const int irq, void *data) ...@@ -137,6 +137,7 @@ static irqreturn_t xgene_enet_rx_irq(const int irq, void *data)
static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
struct xgene_enet_raw_desc *raw_desc) struct xgene_enet_raw_desc *raw_desc)
{ {
struct xgene_enet_pdata *pdata = netdev_priv(cp_ring->ndev);
struct sk_buff *skb; struct sk_buff *skb;
struct device *dev; struct device *dev;
skb_frag_t *frag; skb_frag_t *frag;
...@@ -144,6 +145,7 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, ...@@ -144,6 +145,7 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
u16 skb_index; u16 skb_index;
u8 status; u8 status;
int i, ret = 0; int i, ret = 0;
u8 mss_index;
skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
skb = cp_ring->cp_skb[skb_index]; skb = cp_ring->cp_skb[skb_index];
...@@ -160,6 +162,13 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, ...@@ -160,6 +162,13 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
DMA_TO_DEVICE); DMA_TO_DEVICE);
} }
if (GET_BIT(ET, le64_to_cpu(raw_desc->m3))) {
mss_index = GET_VAL(MSS, le64_to_cpu(raw_desc->m3));
spin_lock(&pdata->mss_lock);
pdata->mss_refcnt[mss_index]--;
spin_unlock(&pdata->mss_lock);
}
/* Checking for error */ /* Checking for error */
status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
if (unlikely(status > 2)) { if (unlikely(status > 2)) {
...@@ -178,15 +187,53 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, ...@@ -178,15 +187,53 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
return ret; return ret;
} }
static u64 xgene_enet_work_msg(struct sk_buff *skb) static int xgene_enet_setup_mss(struct net_device *ndev, u32 mss)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
bool mss_index_found = false;
int mss_index;
int i;
spin_lock(&pdata->mss_lock);
/* Reuse the slot if MSS matches */
for (i = 0; !mss_index_found && i < NUM_MSS_REG; i++) {
if (pdata->mss[i] == mss) {
pdata->mss_refcnt[i]++;
mss_index = i;
mss_index_found = true;
}
}
/* Overwrite the slot with ref_count = 0 */
for (i = 0; !mss_index_found && i < NUM_MSS_REG; i++) {
if (!pdata->mss_refcnt[i]) {
pdata->mss_refcnt[i]++;
pdata->mac_ops->set_mss(pdata, mss, i);
pdata->mss[i] = mss;
mss_index = i;
mss_index_found = true;
}
}
spin_unlock(&pdata->mss_lock);
/* No slots with ref_count = 0 available, return busy */
if (!mss_index_found)
return -EBUSY;
return mss_index;
}
static int xgene_enet_work_msg(struct sk_buff *skb, u64 *hopinfo)
{ {
struct net_device *ndev = skb->dev; struct net_device *ndev = skb->dev;
struct iphdr *iph; struct iphdr *iph;
u8 l3hlen = 0, l4hlen = 0; u8 l3hlen = 0, l4hlen = 0;
u8 ethhdr, proto = 0, csum_enable = 0; u8 ethhdr, proto = 0, csum_enable = 0;
u64 hopinfo = 0;
u32 hdr_len, mss = 0; u32 hdr_len, mss = 0;
u32 i, len, nr_frags; u32 i, len, nr_frags;
int mss_index;
ethhdr = xgene_enet_hdr_len(skb->data); ethhdr = xgene_enet_hdr_len(skb->data);
...@@ -226,7 +273,11 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb) ...@@ -226,7 +273,11 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb)
if (!mss || ((skb->len - hdr_len) <= mss)) if (!mss || ((skb->len - hdr_len) <= mss))
goto out; goto out;
hopinfo |= SET_BIT(ET); mss_index = xgene_enet_setup_mss(ndev, mss);
if (unlikely(mss_index < 0))
return -EBUSY;
*hopinfo |= SET_BIT(ET) | SET_VAL(MSS, mss_index);
} }
} else if (iph->protocol == IPPROTO_UDP) { } else if (iph->protocol == IPPROTO_UDP) {
l4hlen = UDP_HDR_SIZE; l4hlen = UDP_HDR_SIZE;
...@@ -234,15 +285,15 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb) ...@@ -234,15 +285,15 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb)
} }
out: out:
l3hlen = ip_hdrlen(skb) >> 2; l3hlen = ip_hdrlen(skb) >> 2;
hopinfo |= SET_VAL(TCPHDR, l4hlen) | *hopinfo |= SET_VAL(TCPHDR, l4hlen) |
SET_VAL(IPHDR, l3hlen) | SET_VAL(IPHDR, l3hlen) |
SET_VAL(ETHHDR, ethhdr) | SET_VAL(ETHHDR, ethhdr) |
SET_VAL(EC, csum_enable) | SET_VAL(EC, csum_enable) |
SET_VAL(IS, proto) | SET_VAL(IS, proto) |
SET_BIT(IC) | SET_BIT(IC) |
SET_BIT(TYPE_ETH_WORK_MESSAGE); SET_BIT(TYPE_ETH_WORK_MESSAGE);
return hopinfo; return 0;
} }
static u16 xgene_enet_encode_len(u16 len) static u16 xgene_enet_encode_len(u16 len)
...@@ -282,20 +333,22 @@ static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring, ...@@ -282,20 +333,22 @@ static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring,
dma_addr_t dma_addr, pbuf_addr, *frag_dma_addr; dma_addr_t dma_addr, pbuf_addr, *frag_dma_addr;
skb_frag_t *frag; skb_frag_t *frag;
u16 tail = tx_ring->tail; u16 tail = tx_ring->tail;
u64 hopinfo; u64 hopinfo = 0;
u32 len, hw_len; u32 len, hw_len;
u8 ll = 0, nv = 0, idx = 0; u8 ll = 0, nv = 0, idx = 0;
bool split = false; bool split = false;
u32 size, offset, ell_bytes = 0; u32 size, offset, ell_bytes = 0;
u32 i, fidx, nr_frags, count = 1; u32 i, fidx, nr_frags, count = 1;
int ret;
raw_desc = &tx_ring->raw_desc[tail]; raw_desc = &tx_ring->raw_desc[tail];
tail = (tail + 1) & (tx_ring->slots - 1); tail = (tail + 1) & (tx_ring->slots - 1);
memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc)); memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc));
hopinfo = xgene_enet_work_msg(skb); ret = xgene_enet_work_msg(skb, &hopinfo);
if (!hopinfo) if (ret)
return -EINVAL; return ret;
raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) | raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) |
hopinfo); hopinfo);
...@@ -435,6 +488,9 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, ...@@ -435,6 +488,9 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
count = xgene_enet_setup_tx_desc(tx_ring, skb); count = xgene_enet_setup_tx_desc(tx_ring, skb);
if (count == -EBUSY)
return NETDEV_TX_BUSY;
if (count <= 0) { if (count <= 0) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -1669,7 +1725,7 @@ static int xgene_enet_probe(struct platform_device *pdev) ...@@ -1669,7 +1725,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
ndev->features |= NETIF_F_TSO; ndev->features |= NETIF_F_TSO;
pdata->mss = XGENE_ENET_MSS; spin_lock_init(&pdata->mss_lock);
} }
ndev->hw_features = ndev->features; ndev->hw_features = ndev->features;
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
#define NUM_PKT_BUF 64 #define NUM_PKT_BUF 64
#define NUM_BUFPOOL 32 #define NUM_BUFPOOL 32
#define MAX_EXP_BUFFS 256 #define MAX_EXP_BUFFS 256
#define XGENE_ENET_MSS 1448 #define NUM_MSS_REG 4
#define XGENE_MIN_ENET_FRAME_SIZE 60 #define XGENE_MIN_ENET_FRAME_SIZE 60
#define XGENE_MAX_ENET_IRQ 16 #define XGENE_MAX_ENET_IRQ 16
...@@ -143,7 +143,7 @@ struct xgene_mac_ops { ...@@ -143,7 +143,7 @@ struct xgene_mac_ops {
void (*rx_disable)(struct xgene_enet_pdata *pdata); void (*rx_disable)(struct xgene_enet_pdata *pdata);
void (*set_speed)(struct xgene_enet_pdata *pdata); void (*set_speed)(struct xgene_enet_pdata *pdata);
void (*set_mac_addr)(struct xgene_enet_pdata *pdata); void (*set_mac_addr)(struct xgene_enet_pdata *pdata);
void (*set_mss)(struct xgene_enet_pdata *pdata); 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);
}; };
...@@ -212,7 +212,9 @@ struct xgene_enet_pdata { ...@@ -212,7 +212,9 @@ struct xgene_enet_pdata {
u8 eth_bufnum; u8 eth_bufnum;
u8 bp_bufnum; u8 bp_bufnum;
u16 ring_num; u16 ring_num;
u32 mss; u32 mss[NUM_MSS_REG];
u32 mss_refcnt[NUM_MSS_REG];
spinlock_t mss_lock; /* mss lock */
u8 tx_delay; u8 tx_delay;
u8 rx_delay; u8 rx_delay;
bool mdio_driver; bool mdio_driver;
......
...@@ -232,9 +232,22 @@ static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata) ...@@ -232,9 +232,22 @@ static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata)
xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1); xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1);
} }
static void xgene_xgmac_set_mss(struct xgene_enet_pdata *pdata) static void xgene_xgmac_set_mss(struct xgene_enet_pdata *pdata,
u16 mss, u8 index)
{ {
xgene_enet_wr_csr(pdata, XG_TSIF_MSS_REG0_ADDR, pdata->mss); u8 offset;
u32 data;
offset = (index < 2) ? 0 : 4;
xgene_enet_rd_csr(pdata, XG_TSIF_MSS_REG0_ADDR + offset, &data);
if (!(index & 0x1))
data = SET_VAL(TSO_MSS1, data >> TSO_MSS1_POS) |
SET_VAL(TSO_MSS0, mss);
else
data = SET_VAL(TSO_MSS1, mss) | SET_VAL(TSO_MSS0, data);
xgene_enet_wr_csr(pdata, XG_TSIF_MSS_REG0_ADDR + offset, data);
} }
static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata) static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata)
...@@ -258,7 +271,6 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata) ...@@ -258,7 +271,6 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
xgene_xgmac_set_mac_addr(pdata); xgene_xgmac_set_mac_addr(pdata);
xgene_xgmac_set_mss(pdata);
xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data); xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data);
data |= CFG_RSIF_FPBUFF_TIMEOUT_EN; data |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
......
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