Commit b5015854 authored by Marcin Wojtas's avatar Marcin Wojtas Committed by David S. Miller

net: mvpp2: fix refilling BM pools in RX path

In hitherto code in case of RX buffer allocation error during refill,
original buffer is pushed to the network stack, but the amount of
available buffer pointers in BM pool is decreased.

This commit fixes the situation by moving refill call before skb_put(),
and returning original buffer pointer to the pool in case of an error.
Signed-off-by: default avatarMarcin Wojtas <mw@semihalf.com>

Fixes: 3f518509 ("ethernet: Add new driver for Marvell Armada 375
network unit")

Cc: <stable@vger.kernel.org> # v3.18+
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4229d502
...@@ -5099,7 +5099,8 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, ...@@ -5099,7 +5099,8 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
struct mvpp2_rx_queue *rxq) struct mvpp2_rx_queue *rxq)
{ {
struct net_device *dev = port->dev; struct net_device *dev = port->dev;
int rx_received, rx_filled, i; int rx_received;
int rx_done = 0;
u32 rcvd_pkts = 0; u32 rcvd_pkts = 0;
u32 rcvd_bytes = 0; u32 rcvd_bytes = 0;
...@@ -5108,17 +5109,18 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, ...@@ -5108,17 +5109,18 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
if (rx_todo > rx_received) if (rx_todo > rx_received)
rx_todo = rx_received; rx_todo = rx_received;
rx_filled = 0; while (rx_done < rx_todo) {
for (i = 0; i < rx_todo; i++) {
struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq);
struct mvpp2_bm_pool *bm_pool; struct mvpp2_bm_pool *bm_pool;
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t phys_addr;
u32 bm, rx_status; u32 bm, rx_status;
int pool, rx_bytes, err; int pool, rx_bytes, err;
rx_filled++; rx_done++;
rx_status = rx_desc->status; rx_status = rx_desc->status;
rx_bytes = rx_desc->data_size - MVPP2_MH_SIZE; rx_bytes = rx_desc->data_size - MVPP2_MH_SIZE;
phys_addr = rx_desc->buf_phys_addr;
bm = mvpp2_bm_cookie_build(rx_desc); bm = mvpp2_bm_cookie_build(rx_desc);
pool = mvpp2_bm_cookie_pool_get(bm); pool = mvpp2_bm_cookie_pool_get(bm);
...@@ -5135,8 +5137,10 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, ...@@ -5135,8 +5137,10 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
* comprised by the RX descriptor. * comprised by the RX descriptor.
*/ */
if (rx_status & MVPP2_RXD_ERR_SUMMARY) { if (rx_status & MVPP2_RXD_ERR_SUMMARY) {
err_drop_frame:
dev->stats.rx_errors++; dev->stats.rx_errors++;
mvpp2_rx_error(port, rx_desc); mvpp2_rx_error(port, rx_desc);
/* Return the buffer to the pool */
mvpp2_pool_refill(port, bm, rx_desc->buf_phys_addr, mvpp2_pool_refill(port, bm, rx_desc->buf_phys_addr,
rx_desc->buf_cookie); rx_desc->buf_cookie);
continue; continue;
...@@ -5144,7 +5148,13 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, ...@@ -5144,7 +5148,13 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
skb = (struct sk_buff *)rx_desc->buf_cookie; skb = (struct sk_buff *)rx_desc->buf_cookie;
dma_unmap_single(dev->dev.parent, rx_desc->buf_phys_addr, err = mvpp2_rx_refill(port, bm_pool, bm, 0);
if (err) {
netdev_err(port->dev, "failed to refill BM pools\n");
goto err_drop_frame;
}
dma_unmap_single(dev->dev.parent, phys_addr,
bm_pool->buf_size, DMA_FROM_DEVICE); bm_pool->buf_size, DMA_FROM_DEVICE);
rcvd_pkts++; rcvd_pkts++;
...@@ -5157,12 +5167,6 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, ...@@ -5157,12 +5167,6 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
mvpp2_rx_csum(port, rx_status, skb); mvpp2_rx_csum(port, rx_status, skb);
napi_gro_receive(&port->napi, skb); napi_gro_receive(&port->napi, skb);
err = mvpp2_rx_refill(port, bm_pool, bm, 0);
if (err) {
netdev_err(port->dev, "failed to refill BM pools\n");
rx_filled--;
}
} }
if (rcvd_pkts) { if (rcvd_pkts) {
...@@ -5176,7 +5180,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, ...@@ -5176,7 +5180,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
/* Update Rx queue management counters */ /* Update Rx queue management counters */
wmb(); wmb();
mvpp2_rxq_status_update(port, rxq->id, rx_todo, rx_filled); mvpp2_rxq_status_update(port, rxq->id, rx_done, rx_done);
return rx_todo; return rx_todo;
} }
......
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