Skip to content

Commit

Permalink
drivers: net: xgene: Fix MSS programming
Browse files Browse the repository at this point in the history
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: Iyappan Subramanian <isubramanian@apm.com>
Signed-off-by: Toan Le <toanle@apm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Iyappan Subramanian authored and David S. Miller committed Sep 23, 2016
1 parent e12934d commit e397867
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 23 deletions.
7 changes: 7 additions & 0 deletions drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ enum xgene_enet_rm {
#define TCPHDR_LEN 6
#define IPHDR_POS 6
#define IPHDR_LEN 6
#define MSS_POS 20
#define MSS_LEN 2
#define EC_POS 22 /* Enable checksum */
#define EC_LEN 1
#define ET_POS 23 /* Enable TSO */
Expand All @@ -253,6 +255,11 @@ enum xgene_enet_rm {

#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 {
__le64 m0;
__le64 m1;
Expand Down
90 changes: 73 additions & 17 deletions drivers/net/ethernet/apm/xgene/xgene_enet_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,15 @@ 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,
struct xgene_enet_raw_desc *raw_desc)
{
struct xgene_enet_pdata *pdata = netdev_priv(cp_ring->ndev);
struct sk_buff *skb;
struct device *dev;
skb_frag_t *frag;
dma_addr_t *frag_dma_addr;
u16 skb_index;
u8 status;
int i, ret = 0;
u8 mss_index;

skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
skb = cp_ring->cp_skb[skb_index];
Expand All @@ -160,6 +162,13 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
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 */
status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
if (unlikely(status > 2)) {
Expand All @@ -178,15 +187,53 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
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 iphdr *iph;
u8 l3hlen = 0, l4hlen = 0;
u8 ethhdr, proto = 0, csum_enable = 0;
u64 hopinfo = 0;
u32 hdr_len, mss = 0;
u32 i, len, nr_frags;
int mss_index;

ethhdr = xgene_enet_hdr_len(skb->data);

Expand Down Expand Up @@ -226,23 +273,27 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb)
if (!mss || ((skb->len - hdr_len) <= mss))
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) {
l4hlen = UDP_HDR_SIZE;
csum_enable = 1;
}
out:
l3hlen = ip_hdrlen(skb) >> 2;
hopinfo |= SET_VAL(TCPHDR, l4hlen) |
SET_VAL(IPHDR, l3hlen) |
SET_VAL(ETHHDR, ethhdr) |
SET_VAL(EC, csum_enable) |
SET_VAL(IS, proto) |
SET_BIT(IC) |
SET_BIT(TYPE_ETH_WORK_MESSAGE);

return hopinfo;
*hopinfo |= SET_VAL(TCPHDR, l4hlen) |
SET_VAL(IPHDR, l3hlen) |
SET_VAL(ETHHDR, ethhdr) |
SET_VAL(EC, csum_enable) |
SET_VAL(IS, proto) |
SET_BIT(IC) |
SET_BIT(TYPE_ETH_WORK_MESSAGE);

return 0;
}

static u16 xgene_enet_encode_len(u16 len)
Expand Down Expand Up @@ -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;
skb_frag_t *frag;
u16 tail = tx_ring->tail;
u64 hopinfo;
u64 hopinfo = 0;
u32 len, hw_len;
u8 ll = 0, nv = 0, idx = 0;
bool split = false;
u32 size, offset, ell_bytes = 0;
u32 i, fidx, nr_frags, count = 1;
int ret;

raw_desc = &tx_ring->raw_desc[tail];
tail = (tail + 1) & (tx_ring->slots - 1);
memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc));

hopinfo = xgene_enet_work_msg(skb);
if (!hopinfo)
return -EINVAL;
ret = xgene_enet_work_msg(skb, &hopinfo);
if (ret)
return ret;

raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) |
hopinfo);

Expand Down Expand Up @@ -435,6 +488,9 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;

count = xgene_enet_setup_tx_desc(tx_ring, skb);
if (count == -EBUSY)
return NETDEV_TX_BUSY;

if (count <= 0) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
Expand Down Expand Up @@ -1669,7 +1725,7 @@ static int xgene_enet_probe(struct platform_device *pdev)

if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
ndev->features |= NETIF_F_TSO;
pdata->mss = XGENE_ENET_MSS;
spin_lock_init(&pdata->mss_lock);
}
ndev->hw_features = ndev->features;

Expand Down
8 changes: 5 additions & 3 deletions drivers/net/ethernet/apm/xgene/xgene_enet_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
#define NUM_PKT_BUF 64
#define NUM_BUFPOOL 32
#define MAX_EXP_BUFFS 256
#define XGENE_ENET_MSS 1448
#define NUM_MSS_REG 4
#define XGENE_MIN_ENET_FRAME_SIZE 60

#define XGENE_MAX_ENET_IRQ 16
Expand Down Expand Up @@ -143,7 +143,7 @@ struct xgene_mac_ops {
void (*rx_disable)(struct xgene_enet_pdata *pdata);
void (*set_speed)(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);
};

Expand Down Expand Up @@ -212,7 +212,9 @@ struct xgene_enet_pdata {
u8 eth_bufnum;
u8 bp_bufnum;
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 rx_delay;
bool mdio_driver;
Expand Down
18 changes: 15 additions & 3 deletions drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

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)
Expand All @@ -258,7 +271,6 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);

xgene_xgmac_set_mac_addr(pdata);
xgene_xgmac_set_mss(pdata);

xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data);
data |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
Expand Down

0 comments on commit e397867

Please sign in to comment.