Commit 3c01352d authored by David S. Miller's avatar David S. Miller

Merge branch 'mlx4'

Amir Vadai says:

====================
net/mlx4_en: Fix pages never dma unmapped on rx

This patchset fixes a bug introduced by commit 51151a16 (mlx4: allow order-0
memory allocations in RX path). Where dma_unmap_page wasn't called.

Changes from V0:
- Added "Rename name of mlx4_en_rx_alloc members". Old names were confusing.
- Last frag in page calculation was wrong. Since all frags in page are of the
  same size, need to add this frag_stride to end of frag offset, and not the
  size of next frag in skb.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2c6221e4 021f1107
...@@ -70,14 +70,15 @@ static int mlx4_alloc_pages(struct mlx4_en_priv *priv, ...@@ -70,14 +70,15 @@ static int mlx4_alloc_pages(struct mlx4_en_priv *priv,
put_page(page); put_page(page);
return -ENOMEM; return -ENOMEM;
} }
page_alloc->size = PAGE_SIZE << order; page_alloc->page_size = PAGE_SIZE << order;
page_alloc->page = page; page_alloc->page = page;
page_alloc->dma = dma; page_alloc->dma = dma;
page_alloc->offset = frag_info->frag_align; page_alloc->page_offset = frag_info->frag_align;
/* Not doing get_page() for each frag is a big win /* Not doing get_page() for each frag is a big win
* on asymetric workloads. * on asymetric workloads.
*/ */
atomic_set(&page->_count, page_alloc->size / frag_info->frag_stride); atomic_set(&page->_count,
page_alloc->page_size / frag_info->frag_stride);
return 0; return 0;
} }
...@@ -96,16 +97,19 @@ static int mlx4_en_alloc_frags(struct mlx4_en_priv *priv, ...@@ -96,16 +97,19 @@ static int mlx4_en_alloc_frags(struct mlx4_en_priv *priv,
for (i = 0; i < priv->num_frags; i++) { for (i = 0; i < priv->num_frags; i++) {
frag_info = &priv->frag_info[i]; frag_info = &priv->frag_info[i];
page_alloc[i] = ring_alloc[i]; page_alloc[i] = ring_alloc[i];
page_alloc[i].offset += frag_info->frag_stride; page_alloc[i].page_offset += frag_info->frag_stride;
if (page_alloc[i].offset + frag_info->frag_stride <= ring_alloc[i].size)
if (page_alloc[i].page_offset + frag_info->frag_stride <=
ring_alloc[i].page_size)
continue; continue;
if (mlx4_alloc_pages(priv, &page_alloc[i], frag_info, gfp)) if (mlx4_alloc_pages(priv, &page_alloc[i], frag_info, gfp))
goto out; goto out;
} }
for (i = 0; i < priv->num_frags; i++) { for (i = 0; i < priv->num_frags; i++) {
frags[i] = ring_alloc[i]; frags[i] = ring_alloc[i];
dma = ring_alloc[i].dma + ring_alloc[i].offset; dma = ring_alloc[i].dma + ring_alloc[i].page_offset;
ring_alloc[i] = page_alloc[i]; ring_alloc[i] = page_alloc[i];
rx_desc->data[i].addr = cpu_to_be64(dma); rx_desc->data[i].addr = cpu_to_be64(dma);
} }
...@@ -117,7 +121,7 @@ static int mlx4_en_alloc_frags(struct mlx4_en_priv *priv, ...@@ -117,7 +121,7 @@ static int mlx4_en_alloc_frags(struct mlx4_en_priv *priv,
frag_info = &priv->frag_info[i]; frag_info = &priv->frag_info[i];
if (page_alloc[i].page != ring_alloc[i].page) { if (page_alloc[i].page != ring_alloc[i].page) {
dma_unmap_page(priv->ddev, page_alloc[i].dma, dma_unmap_page(priv->ddev, page_alloc[i].dma,
page_alloc[i].size, PCI_DMA_FROMDEVICE); page_alloc[i].page_size, PCI_DMA_FROMDEVICE);
page = page_alloc[i].page; page = page_alloc[i].page;
atomic_set(&page->_count, 1); atomic_set(&page->_count, 1);
put_page(page); put_page(page);
...@@ -131,10 +135,12 @@ static void mlx4_en_free_frag(struct mlx4_en_priv *priv, ...@@ -131,10 +135,12 @@ static void mlx4_en_free_frag(struct mlx4_en_priv *priv,
int i) int i)
{ {
const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i]; const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i];
u32 next_frag_end = frags[i].page_offset + 2 * frag_info->frag_stride;
if (frags[i].offset + frag_info->frag_stride > frags[i].size) if (next_frag_end > frags[i].page_size)
dma_unmap_page(priv->ddev, frags[i].dma, frags[i].size, dma_unmap_page(priv->ddev, frags[i].dma, frags[i].page_size,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
if (frags[i].page) if (frags[i].page)
put_page(frags[i].page); put_page(frags[i].page);
...@@ -161,7 +167,7 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, ...@@ -161,7 +167,7 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv,
page_alloc = &ring->page_alloc[i]; page_alloc = &ring->page_alloc[i];
dma_unmap_page(priv->ddev, page_alloc->dma, dma_unmap_page(priv->ddev, page_alloc->dma,
page_alloc->size, PCI_DMA_FROMDEVICE); page_alloc->page_size, PCI_DMA_FROMDEVICE);
page = page_alloc->page; page = page_alloc->page;
atomic_set(&page->_count, 1); atomic_set(&page->_count, 1);
put_page(page); put_page(page);
...@@ -184,10 +190,11 @@ static void mlx4_en_destroy_allocator(struct mlx4_en_priv *priv, ...@@ -184,10 +190,11 @@ static void mlx4_en_destroy_allocator(struct mlx4_en_priv *priv,
i, page_count(page_alloc->page)); i, page_count(page_alloc->page));
dma_unmap_page(priv->ddev, page_alloc->dma, dma_unmap_page(priv->ddev, page_alloc->dma,
page_alloc->size, PCI_DMA_FROMDEVICE); page_alloc->page_size, PCI_DMA_FROMDEVICE);
while (page_alloc->offset + frag_info->frag_stride < page_alloc->size) { while (page_alloc->page_offset + frag_info->frag_stride <
page_alloc->page_size) {
put_page(page_alloc->page); put_page(page_alloc->page);
page_alloc->offset += frag_info->frag_stride; page_alloc->page_offset += frag_info->frag_stride;
} }
page_alloc->page = NULL; page_alloc->page = NULL;
} }
...@@ -478,7 +485,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, ...@@ -478,7 +485,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
/* Save page reference in skb */ /* Save page reference in skb */
__skb_frag_set_page(&skb_frags_rx[nr], frags[nr].page); __skb_frag_set_page(&skb_frags_rx[nr], frags[nr].page);
skb_frag_size_set(&skb_frags_rx[nr], frag_info->frag_size); skb_frag_size_set(&skb_frags_rx[nr], frag_info->frag_size);
skb_frags_rx[nr].page_offset = frags[nr].offset; skb_frags_rx[nr].page_offset = frags[nr].page_offset;
skb->truesize += frag_info->frag_stride; skb->truesize += frag_info->frag_stride;
frags[nr].page = NULL; frags[nr].page = NULL;
} }
...@@ -517,7 +524,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv, ...@@ -517,7 +524,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
/* Get pointer to first fragment so we could copy the headers into the /* Get pointer to first fragment so we could copy the headers into the
* (linear part of the) skb */ * (linear part of the) skb */
va = page_address(frags[0].page) + frags[0].offset; va = page_address(frags[0].page) + frags[0].page_offset;
if (length <= SMALL_PACKET_SIZE) { if (length <= SMALL_PACKET_SIZE) {
/* We are copying all relevant data to the skb - temporarily /* We are copying all relevant data to the skb - temporarily
...@@ -645,7 +652,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud ...@@ -645,7 +652,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh), dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
ethh = (struct ethhdr *)(page_address(frags[0].page) + ethh = (struct ethhdr *)(page_address(frags[0].page) +
frags[0].offset); frags[0].page_offset);
if (is_multicast_ether_addr(ethh->h_dest)) { if (is_multicast_ether_addr(ethh->h_dest)) {
struct mlx4_mac_entry *entry; struct mlx4_mac_entry *entry;
......
...@@ -237,8 +237,8 @@ struct mlx4_en_tx_desc { ...@@ -237,8 +237,8 @@ struct mlx4_en_tx_desc {
struct mlx4_en_rx_alloc { struct mlx4_en_rx_alloc {
struct page *page; struct page *page;
dma_addr_t dma; dma_addr_t dma;
u32 offset; u32 page_offset;
u32 size; u32 page_size;
}; };
struct mlx4_en_tx_ring { struct mlx4_en_tx_ring {
......
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