diff options
author | Yevgeny Petrilin <yevgenyp@mellanox.co.il> | 2009-05-24 07:17:11 +0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-25 11:35:53 +0400 |
commit | 38aab07c14adbf3c7257793d764a91923341e96a (patch) | |
tree | ac27575621410056b4ec970db6b233a50600d15b /drivers/net/mlx4/en_rx.c | |
parent | 8e29291650ee53a8609d9cc3a303dcbe9aa9b542 (diff) | |
download | linux-38aab07c14adbf3c7257793d764a91923341e96a.tar.xz |
mlx4_en: Fix partial rings feature
In case of allocation failure, the actual ring size is rounded down to
nearest power of 2. The remaining descriptors are freed.
The CQ and SRQ are allocated with the actual size and the mask is updated.
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/mlx4/en_rx.c')
-rw-r--r-- | drivers/net/mlx4/en_rx.c | 71 |
1 files changed, 45 insertions, 26 deletions
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 9ee873e872b3..6bfab6e5ba1d 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -202,12 +202,35 @@ static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring) *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff); } +static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, + int index) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct skb_frag_struct *skb_frags; + struct mlx4_en_rx_desc *rx_desc = ring->buf + (index << ring->log_stride); + dma_addr_t dma; + int nr; + + skb_frags = ring->rx_info + (index << priv->log_rx_info); + for (nr = 0; nr < priv->num_frags; nr++) { + mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr); + dma = be64_to_cpu(rx_desc->data[nr].addr); + + mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); + pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, + PCI_DMA_FROMDEVICE); + put_page(skb_frags[nr].page); + } +} + static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) { struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_rx_ring *ring; int ring_ind; int buf_ind; + int new_size; for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) { for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { @@ -220,18 +243,30 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) "enough rx buffers\n"); return -ENOMEM; } else { - if (netif_msg_rx_err(priv)) - mlx4_warn(mdev, - "Only %d buffers allocated\n", - ring->actual_size); - goto out; + new_size = rounddown_pow_of_two(ring->actual_size); + mlx4_warn(mdev, "Only %d buffers allocated " + "reducing ring size to %d", + ring->actual_size, new_size); + goto reduce_rings; } } ring->actual_size++; ring->prod++; } } -out: + return 0; + +reduce_rings: + for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { + ring = &priv->rx_ring[ring_ind]; + while (ring->actual_size > new_size) { + ring->actual_size--; + ring->prod--; + mlx4_en_free_rx_desc(priv, ring, ring->actual_size); + } + ring->size_mask = ring->actual_size - 1; + } + return 0; } @@ -255,7 +290,7 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev, ++num; ++ring->prod; } - if ((u32) (ring->prod - ring->cons) == ring->size) + if ((u32) (ring->prod - ring->cons) == ring->actual_size) ring->full = 1; return num; @@ -264,33 +299,17 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev, static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring) { - struct mlx4_en_dev *mdev = priv->mdev; - struct skb_frag_struct *skb_frags; - struct mlx4_en_rx_desc *rx_desc; - dma_addr_t dma; int index; - int nr; mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", ring->cons, ring->prod); /* Unmap and free Rx buffers */ - BUG_ON((u32) (ring->prod - ring->cons) > ring->size); + BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); while (ring->cons != ring->prod) { index = ring->cons & ring->size_mask; - rx_desc = ring->buf + (index << ring->log_stride); - skb_frags = ring->rx_info + (index << priv->log_rx_info); mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index); - - for (nr = 0; nr < priv->num_frags; nr++) { - mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr); - dma = be64_to_cpu(rx_desc->data[nr].addr); - - mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); - pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, - PCI_DMA_FROMDEVICE); - put_page(skb_frags[nr].page); - } + mlx4_en_free_rx_desc(priv, ring, index); ++ring->cons; } } @@ -454,7 +473,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) mlx4_en_update_rx_prod_db(ring); /* Configure SRQ representing the ring */ - ring->srq.max = ring->size; + ring->srq.max = ring->actual_size; ring->srq.max_gs = max_gs; ring->srq.wqe_shift = ilog2(ring->stride); |