Commit 35e07d23 authored by Ilias Apalodimas's avatar Ilias Apalodimas Committed by David S. Miller

net: socionext: remove mmio reads on Tx

Currently the driver issues 2 mmio reads to figure out the number of
transmitted packets and clean them. We can get rid of the expensive
reads since BIT 31 of the Tx descriptor can be used for that.
We can also remove the budget counting of Tx completions since all of
the descriptors are not deliberately processed.

Performance numbers using pktgen are:
size  pre-patch(pps)  post-patch(pps)
64       362483           427916
128      358315           411686
256      352725           389683
512      215675           216464
1024     113812           114442
Signed-off-by: default avatarIlias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 17a12eaa
...@@ -257,7 +257,6 @@ struct netsec_desc_ring { ...@@ -257,7 +257,6 @@ struct netsec_desc_ring {
dma_addr_t desc_dma; dma_addr_t desc_dma;
struct netsec_desc *desc; struct netsec_desc *desc;
void *vaddr; void *vaddr;
u16 pkt_cnt;
u16 head, tail; u16 head, tail;
}; };
...@@ -598,33 +597,26 @@ static void netsec_set_rx_de(struct netsec_priv *priv, ...@@ -598,33 +597,26 @@ static void netsec_set_rx_de(struct netsec_priv *priv,
dring->desc[idx].len = desc->len; dring->desc[idx].len = desc->len;
} }
static int netsec_clean_tx_dring(struct netsec_priv *priv, int budget) static bool netsec_clean_tx_dring(struct netsec_priv *priv)
{ {
struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX]; struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
unsigned int pkts, bytes; unsigned int pkts, bytes;
struct netsec_de *entry;
dring->pkt_cnt += netsec_read(priv, NETSEC_REG_NRM_TX_DONE_PKTCNT); int tail = dring->tail;
int cnt = 0;
if (dring->pkt_cnt < budget)
budget = dring->pkt_cnt;
pkts = 0; pkts = 0;
bytes = 0; bytes = 0;
entry = dring->vaddr + DESC_SZ * tail;
while (pkts < budget) { while (!(entry->attr & (1U << NETSEC_TX_SHIFT_OWN_FIELD)) &&
cnt < DESC_NUM) {
struct netsec_desc *desc; struct netsec_desc *desc;
struct netsec_de *entry; int eop;
int tail, eop;
tail = dring->tail;
/* move tail ahead */
dring->tail = (tail + 1) % DESC_NUM;
desc = &dring->desc[tail]; desc = &dring->desc[tail];
entry = dring->vaddr + DESC_SZ * tail;
eop = (entry->attr >> NETSEC_TX_LAST) & 1; eop = (entry->attr >> NETSEC_TX_LAST) & 1;
dma_rmb();
dma_unmap_single(priv->dev, desc->dma_addr, desc->len, dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
DMA_TO_DEVICE); DMA_TO_DEVICE);
...@@ -633,38 +625,51 @@ static int netsec_clean_tx_dring(struct netsec_priv *priv, int budget) ...@@ -633,38 +625,51 @@ static int netsec_clean_tx_dring(struct netsec_priv *priv, int budget)
bytes += desc->skb->len; bytes += desc->skb->len;
dev_kfree_skb(desc->skb); dev_kfree_skb(desc->skb);
} }
/* clean up so netsec_uninit_pkt_dring() won't free the skb
* again
*/
*desc = (struct netsec_desc){}; *desc = (struct netsec_desc){};
/* entry->attr is not going to be accessed by the NIC until
* netsec_set_tx_de() is called. No need for a dma_wmb() here
*/
entry->attr = 1U << NETSEC_TX_SHIFT_OWN_FIELD;
/* move tail ahead */
dring->tail = (tail + 1) % DESC_NUM;
tail = dring->tail;
entry = dring->vaddr + DESC_SZ * tail;
cnt++;
} }
dring->pkt_cnt -= budget;
priv->ndev->stats.tx_packets += budget; if (!cnt)
return false;
/* reading the register clears the irq */
netsec_read(priv, NETSEC_REG_NRM_TX_DONE_PKTCNT);
priv->ndev->stats.tx_packets += cnt;
priv->ndev->stats.tx_bytes += bytes; priv->ndev->stats.tx_bytes += bytes;
netdev_completed_queue(priv->ndev, budget, bytes); netdev_completed_queue(priv->ndev, cnt, bytes);
return budget; return true;
} }
static int netsec_process_tx(struct netsec_priv *priv, int budget) static void netsec_process_tx(struct netsec_priv *priv)
{ {
struct net_device *ndev = priv->ndev; struct net_device *ndev = priv->ndev;
int new, done = 0; bool cleaned;
do { cleaned = netsec_clean_tx_dring(priv);
new = netsec_clean_tx_dring(priv, budget);
done += new;
budget -= new;
} while (new);
if (done && netif_queue_stopped(ndev)) { if (cleaned && netif_queue_stopped(ndev)) {
/* Make sure we update the value, anyone stopping the queue /* Make sure we update the value, anyone stopping the queue
* after this will read the proper consumer idx * after this will read the proper consumer idx
*/ */
smp_wmb(); smp_wmb();
netif_wake_queue(ndev); netif_wake_queue(ndev);
} }
return done;
} }
static void *netsec_alloc_rx_data(struct netsec_priv *priv, static void *netsec_alloc_rx_data(struct netsec_priv *priv,
...@@ -813,24 +818,17 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget) ...@@ -813,24 +818,17 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget)
static int netsec_napi_poll(struct napi_struct *napi, int budget) static int netsec_napi_poll(struct napi_struct *napi, int budget)
{ {
struct netsec_priv *priv; struct netsec_priv *priv;
int tx, rx, done, todo; int rx, done, todo;
priv = container_of(napi, struct netsec_priv, napi); priv = container_of(napi, struct netsec_priv, napi);
netsec_process_tx(priv);
todo = budget; todo = budget;
do { do {
if (!todo)
break;
tx = netsec_process_tx(priv, todo);
todo -= tx;
if (!todo)
break;
rx = netsec_process_rx(priv, todo); rx = netsec_process_rx(priv, todo);
todo -= rx; todo -= rx;
} while (rx || tx); } while (rx);
done = budget - todo; done = budget - todo;
...@@ -1007,7 +1005,6 @@ static void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id) ...@@ -1007,7 +1005,6 @@ static void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id)
dring->head = 0; dring->head = 0;
dring->tail = 0; dring->tail = 0;
dring->pkt_cnt = 0;
if (id == NETSEC_RING_TX) if (id == NETSEC_RING_TX)
netdev_reset_queue(priv->ndev); netdev_reset_queue(priv->ndev);
...@@ -1030,6 +1027,7 @@ static void netsec_free_dring(struct netsec_priv *priv, int id) ...@@ -1030,6 +1027,7 @@ static void netsec_free_dring(struct netsec_priv *priv, int id)
static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id) static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id)
{ {
struct netsec_desc_ring *dring = &priv->desc_ring[id]; struct netsec_desc_ring *dring = &priv->desc_ring[id];
int i;
dring->vaddr = dma_zalloc_coherent(priv->dev, DESC_SZ * DESC_NUM, dring->vaddr = dma_zalloc_coherent(priv->dev, DESC_SZ * DESC_NUM,
&dring->desc_dma, GFP_KERNEL); &dring->desc_dma, GFP_KERNEL);
...@@ -1040,6 +1038,19 @@ static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id) ...@@ -1040,6 +1038,19 @@ static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id)
if (!dring->desc) if (!dring->desc)
goto err; goto err;
if (id == NETSEC_RING_TX) {
for (i = 0; i < DESC_NUM; i++) {
struct netsec_de *de;
de = dring->vaddr + (DESC_SZ * i);
/* de->attr is not going to be accessed by the NIC
* until netsec_set_tx_de() is called.
* No need for a dma_wmb() here
*/
de->attr = 1U << NETSEC_TX_SHIFT_OWN_FIELD;
}
}
return 0; return 0;
err: err:
netsec_free_dring(priv, id); netsec_free_dring(priv, id);
......
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