Commit 3caa61c2 authored by Jose Abreu's avatar Jose Abreu Committed by David S. Miller

net: stmmac: Sync RX Buffer upon allocation

With recent changes that introduced support for Page Pool in stmmac, Jon
reported that NFS boot was no longer working on an ARM64 based platform
that had the IP behind an IOMMU.

As Page Pool API does not guarantee DMA syncing because of the use of
DMA_ATTR_SKIP_CPU_SYNC flag, we have to explicit sync the whole buffer upon
re-allocation because we are always re-using same pages.

In fact, ARM64 code invalidates the DMA area upon two situations [1]:
	- sync_single_for_cpu(): Invalidates if direction != DMA_TO_DEVICE
	- sync_single_for_device(): Invalidates if direction == DMA_FROM_DEVICE

So, as we must invalidate both the current RX buffer and the newly allocated
buffer we propose this fix.

[1] arch/arm64/mm/cache.S
Reported-by: default avatarJon Hunter <jonathanh@nvidia.com>
Tested-by: default avatarJon Hunter <jonathanh@nvidia.com>
Fixes: 2af6106a ("net: stmmac: Introducing support for Page Pool")
Signed-off-by: default avatarJose Abreu <joabreu@synopsys.com>
Tested-by: default avatarEzequiel Garcia <ezequiel@collabora.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2ad07086
...@@ -3271,9 +3271,11 @@ static inline int stmmac_rx_threshold_count(struct stmmac_rx_queue *rx_q) ...@@ -3271,9 +3271,11 @@ static inline int stmmac_rx_threshold_count(struct stmmac_rx_queue *rx_q)
static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
{ {
struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
int dirty = stmmac_rx_dirty(priv, queue); int len, dirty = stmmac_rx_dirty(priv, queue);
unsigned int entry = rx_q->dirty_rx; unsigned int entry = rx_q->dirty_rx;
len = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE) * PAGE_SIZE;
while (dirty-- > 0) { while (dirty-- > 0) {
struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry]; struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry];
struct dma_desc *p; struct dma_desc *p;
...@@ -3291,6 +3293,13 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) ...@@ -3291,6 +3293,13 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
} }
buf->addr = page_pool_get_dma_addr(buf->page); buf->addr = page_pool_get_dma_addr(buf->page);
/* Sync whole allocation to device. This will invalidate old
* data.
*/
dma_sync_single_for_device(priv->device, buf->addr, len,
DMA_FROM_DEVICE);
stmmac_set_desc_addr(priv, p, buf->addr); stmmac_set_desc_addr(priv, p, buf->addr);
stmmac_refill_desc3(priv, rx_q, p); stmmac_refill_desc3(priv, rx_q, p);
...@@ -3425,8 +3434,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) ...@@ -3425,8 +3434,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
skb_copy_to_linear_data(skb, page_address(buf->page), skb_copy_to_linear_data(skb, page_address(buf->page),
frame_len); frame_len);
skb_put(skb, frame_len); skb_put(skb, frame_len);
dma_sync_single_for_device(priv->device, buf->addr,
frame_len, DMA_FROM_DEVICE);
if (netif_msg_pktdata(priv)) { if (netif_msg_pktdata(priv)) {
netdev_dbg(priv->dev, "frame received (%dbytes)", netdev_dbg(priv->dev, "frame received (%dbytes)",
......
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