Skip to content

Commit

Permalink
net: stmmac: re-init rx buffers when mac resume back
Browse files Browse the repository at this point in the history
During suspend/resume stress test, we found descriptor write back by DMA
could exhibit unusual behavior, e.g.:
	003 [0xc4310030]: 0x0 0x40 0x0 0xb5010040

We can see that desc3 write back is 0xb5010040, it is still ownd by DMA,
so application would not recycle this buffer. It will trigger fatal bus
error when DMA try to use this descriptor again. To fix this issue, we
should re-init all rx buffers when mac resume back.

Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Joakim Zhang authored and Jakub Kicinski committed Feb 26, 2021
1 parent 396e13e commit 9c63faa
Showing 1 changed file with 83 additions and 1 deletion.
84 changes: 83 additions & 1 deletion drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,88 @@ static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i)
}
}

/**
* stmmac_reinit_rx_buffers - reinit the RX descriptor buffer.
* @priv: driver private structure
* Description: this function is called to re-allocate a receive buffer, perform
* the DMA mapping and init the descriptor.
*/
static void stmmac_reinit_rx_buffers(struct stmmac_priv *priv)
{
u32 rx_count = priv->plat->rx_queues_to_use;
u32 queue;
int i;

for (queue = 0; queue < rx_count; queue++) {
struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];

for (i = 0; i < priv->dma_rx_size; i++) {
struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];

if (buf->page) {
page_pool_recycle_direct(rx_q->page_pool, buf->page);
buf->page = NULL;
}

if (priv->sph && buf->sec_page) {
page_pool_recycle_direct(rx_q->page_pool, buf->sec_page);
buf->sec_page = NULL;
}
}
}

for (queue = 0; queue < rx_count; queue++) {
struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];

for (i = 0; i < priv->dma_rx_size; i++) {
struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
struct dma_desc *p;

if (priv->extend_desc)
p = &((rx_q->dma_erx + i)->basic);
else
p = rx_q->dma_rx + i;

if (!buf->page) {
buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
if (!buf->page)
goto err_reinit_rx_buffers;

buf->addr = page_pool_get_dma_addr(buf->page);
}

if (priv->sph && !buf->sec_page) {
buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
if (!buf->sec_page)
goto err_reinit_rx_buffers;

buf->sec_addr = page_pool_get_dma_addr(buf->sec_page);
}

stmmac_set_desc_addr(priv, p, buf->addr);
if (priv->sph)
stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, true);
else
stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, false);
if (priv->dma_buf_sz == BUF_SIZE_16KiB)
stmmac_init_desc3(priv, p);
}
}

return;

err_reinit_rx_buffers:
do {
while (--i >= 0)
stmmac_free_rx_buffer(priv, queue, i);

if (queue == 0)
break;

i = priv->dma_rx_size;
} while (queue-- > 0);
}

/**
* init_dma_rx_desc_rings - init the RX descriptor rings
* @dev: net device structure
Expand Down Expand Up @@ -5343,7 +5425,7 @@ int stmmac_resume(struct device *dev)
mutex_lock(&priv->lock);

stmmac_reset_queues_param(priv);

stmmac_reinit_rx_buffers(priv);
stmmac_free_tx_skbufs(priv);
stmmac_clear_descriptors(priv);

Expand Down

0 comments on commit 9c63faa

Please sign in to comment.