Commit 38aab07c authored by Yevgeny Petrilin's avatar Yevgeny Petrilin Committed by David S. Miller

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: default avatarYevgeny Petrilin <yevgenyp@mellanox.co.il>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8e292916
...@@ -89,6 +89,9 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) ...@@ -89,6 +89,9 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
*cq->mcq.arm_db = 0; *cq->mcq.arm_db = 0;
memset(cq->buf, 0, cq->buf_size); memset(cq->buf, 0, cq->buf_size);
if (!cq->is_tx)
cq->size = priv->rx_ring[cq->ring].actual_size;
err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar, err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar,
cq->wqres.db.dma, &cq->mcq, cq->vector, cq->is_tx); cq->wqres.db.dma, &cq->mcq, cq->vector, cq->is_tx);
if (err) if (err)
......
...@@ -556,7 +556,6 @@ int mlx4_en_start_port(struct net_device *dev) ...@@ -556,7 +556,6 @@ int mlx4_en_start_port(struct net_device *dev)
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_cq *cq; struct mlx4_en_cq *cq;
struct mlx4_en_tx_ring *tx_ring; struct mlx4_en_tx_ring *tx_ring;
struct mlx4_en_rx_ring *rx_ring;
int rx_index = 0; int rx_index = 0;
int tx_index = 0; int tx_index = 0;
int err = 0; int err = 0;
...@@ -572,10 +571,15 @@ int mlx4_en_start_port(struct net_device *dev) ...@@ -572,10 +571,15 @@ int mlx4_en_start_port(struct net_device *dev)
dev->mtu = min(dev->mtu, priv->max_mtu); dev->mtu = min(dev->mtu, priv->max_mtu);
mlx4_en_calc_rx_buf(dev); mlx4_en_calc_rx_buf(dev);
mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size);
/* Configure rx cq's and rings */ /* Configure rx cq's and rings */
err = mlx4_en_activate_rx_rings(priv);
if (err) {
mlx4_err(mdev, "Failed to activate RX rings\n");
return err;
}
for (i = 0; i < priv->rx_ring_num; i++) { for (i = 0; i < priv->rx_ring_num; i++) {
cq = &priv->rx_cq[i]; cq = &priv->rx_cq[i];
rx_ring = &priv->rx_ring[i];
err = mlx4_en_activate_cq(priv, cq); err = mlx4_en_activate_cq(priv, cq);
if (err) { if (err) {
...@@ -591,20 +595,14 @@ int mlx4_en_start_port(struct net_device *dev) ...@@ -591,20 +595,14 @@ int mlx4_en_start_port(struct net_device *dev)
goto cq_err; goto cq_err;
} }
mlx4_en_arm_cq(priv, cq); mlx4_en_arm_cq(priv, cq);
priv->rx_ring[i].cqn = cq->mcq.cqn;
++rx_index; ++rx_index;
} }
err = mlx4_en_activate_rx_rings(priv);
if (err) {
mlx4_err(mdev, "Failed to activate RX rings\n");
goto cq_err;
}
err = mlx4_en_config_rss_steer(priv); err = mlx4_en_config_rss_steer(priv);
if (err) { if (err) {
mlx4_err(mdev, "Failed configuring rss steering\n"); mlx4_err(mdev, "Failed configuring rss steering\n");
goto rx_err; goto cq_err;
} }
/* Configure tx cq's and rings */ /* Configure tx cq's and rings */
...@@ -691,12 +689,11 @@ int mlx4_en_start_port(struct net_device *dev) ...@@ -691,12 +689,11 @@ int mlx4_en_start_port(struct net_device *dev)
} }
mlx4_en_release_rss_steer(priv); mlx4_en_release_rss_steer(priv);
rx_err:
for (i = 0; i < priv->rx_ring_num; i++)
mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
cq_err: cq_err:
while (rx_index--) while (rx_index--)
mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]); mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
for (i = 0; i < priv->rx_ring_num; i++)
mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
return err; /* need to close devices */ return err; /* need to close devices */
} }
......
...@@ -202,12 +202,35 @@ static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring) ...@@ -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); *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) static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
{ {
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_rx_ring *ring; struct mlx4_en_rx_ring *ring;
int ring_ind; int ring_ind;
int buf_ind; int buf_ind;
int new_size;
for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) { 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++) { 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) ...@@ -220,18 +243,30 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
"enough rx buffers\n"); "enough rx buffers\n");
return -ENOMEM; return -ENOMEM;
} else { } else {
if (netif_msg_rx_err(priv)) new_size = rounddown_pow_of_two(ring->actual_size);
mlx4_warn(mdev, mlx4_warn(mdev, "Only %d buffers allocated "
"Only %d buffers allocated\n", "reducing ring size to %d",
ring->actual_size); ring->actual_size, new_size);
goto out; goto reduce_rings;
} }
} }
ring->actual_size++; ring->actual_size++;
ring->prod++; 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; return 0;
} }
...@@ -255,7 +290,7 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev, ...@@ -255,7 +290,7 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev,
++num; ++num;
++ring->prod; ++ring->prod;
} }
if ((u32) (ring->prod - ring->cons) == ring->size) if ((u32) (ring->prod - ring->cons) == ring->actual_size)
ring->full = 1; ring->full = 1;
return num; return num;
...@@ -264,33 +299,17 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev, ...@@ -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, static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring *ring) 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 index;
int nr;
mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n",
ring->cons, ring->prod); ring->cons, ring->prod);
/* Unmap and free Rx buffers */ /* 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) { while (ring->cons != ring->prod) {
index = ring->cons & ring->size_mask; 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); mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index);
mlx4_en_free_rx_desc(priv, ring, 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);
}
++ring->cons; ++ring->cons;
} }
} }
...@@ -454,7 +473,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) ...@@ -454,7 +473,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
mlx4_en_update_rx_prod_db(ring); mlx4_en_update_rx_prod_db(ring);
/* Configure SRQ representing the 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.max_gs = max_gs;
ring->srq.wqe_shift = ilog2(ring->stride); ring->srq.wqe_shift = ilog2(ring->stride);
......
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