aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorIdo Shamay <idos@mellanox.com>2015-04-30 10:32:46 -0400
committerDavid S. Miller <davem@davemloft.net>2015-04-30 16:47:50 -0400
commit07841f9d94c11afe00c0498cf242edf4075729f4 (patch)
treec92c000d3119f222b8fcee9fe732bd796804f193 /drivers/net
parentc232d8a8bb1416f7ec21bb1aabc7c4ec8a5a899e (diff)
net/mlx4_en: Schedule napi when RX buffers allocation fails
When system is out of memory, refilling of RX buffers fails while the driver continue to pass the received packets to the kernel stack. At some point, when all RX buffers deplete, driver may fall into a sleep, and not recover when memory for new RX buffers is once again availible. This is because hardware does not have valid descriptors, so no interrupt will be generated for the driver to return to work in napi context. Fix it by schedule the napi poll function from stats_task delayed workqueue, as long as the allocations fail. Signed-off-by: Ido Shamay <idos@mellanox.com> Signed-off-by: Amir Vadai <amirv@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c26
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h1
3 files changed, 26 insertions, 2 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index bf173d7b873b..32f5ec737472 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1467,6 +1467,7 @@ static void mlx4_en_service_task(struct work_struct *work)
1467 if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 1467 if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
1468 mlx4_en_ptp_overflow_check(mdev); 1468 mlx4_en_ptp_overflow_check(mdev);
1469 1469
1470 mlx4_en_recover_from_oom(priv);
1470 queue_delayed_work(mdev->workqueue, &priv->service_task, 1471 queue_delayed_work(mdev->workqueue, &priv->service_task,
1471 SERVICE_TASK_DELAY); 1472 SERVICE_TASK_DELAY);
1472 } 1473 }
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 4fdd3c37e47b..2a77a6b19121 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -244,6 +244,12 @@ static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
244 return mlx4_en_alloc_frags(priv, rx_desc, frags, ring->page_alloc, gfp); 244 return mlx4_en_alloc_frags(priv, rx_desc, frags, ring->page_alloc, gfp);
245} 245}
246 246
247static inline bool mlx4_en_is_ring_empty(struct mlx4_en_rx_ring *ring)
248{
249 BUG_ON((u32)(ring->prod - ring->cons) > ring->actual_size);
250 return ring->prod == ring->cons;
251}
252
247static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring) 253static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring)
248{ 254{
249 *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff); 255 *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff);
@@ -315,8 +321,7 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
315 ring->cons, ring->prod); 321 ring->cons, ring->prod);
316 322
317 /* Unmap and free Rx buffers */ 323 /* Unmap and free Rx buffers */
318 BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); 324 while (!mlx4_en_is_ring_empty(ring)) {
319 while (ring->cons != ring->prod) {
320 index = ring->cons & ring->size_mask; 325 index = ring->cons & ring->size_mask;
321 en_dbg(DRV, priv, "Processing descriptor:%d\n", index); 326 en_dbg(DRV, priv, "Processing descriptor:%d\n", index);
322 mlx4_en_free_rx_desc(priv, ring, index); 327 mlx4_en_free_rx_desc(priv, ring, index);
@@ -491,6 +496,23 @@ err_allocator:
491 return err; 496 return err;
492} 497}
493 498
499/* We recover from out of memory by scheduling our napi poll
500 * function (mlx4_en_process_cq), which tries to allocate
501 * all missing RX buffers (call to mlx4_en_refill_rx_buffers).
502 */
503void mlx4_en_recover_from_oom(struct mlx4_en_priv *priv)
504{
505 int ring;
506
507 if (!priv->port_up)
508 return;
509
510 for (ring = 0; ring < priv->rx_ring_num; ring++) {
511 if (mlx4_en_is_ring_empty(priv->rx_ring[ring]))
512 napi_reschedule(&priv->rx_cq[ring]->napi);
513 }
514}
515
494void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, 516void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
495 struct mlx4_en_rx_ring **pring, 517 struct mlx4_en_rx_ring **pring,
496 u32 size, u16 stride) 518 u32 size, u16 stride)
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 9de30216b146..d021f079f181 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -774,6 +774,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
774void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, 774void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
775 struct mlx4_en_tx_ring *ring); 775 struct mlx4_en_tx_ring *ring);
776void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev); 776void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev);
777void mlx4_en_recover_from_oom(struct mlx4_en_priv *priv);
777int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, 778int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
778 struct mlx4_en_rx_ring **pring, 779 struct mlx4_en_rx_ring **pring,
779 u32 size, u16 stride, int node); 780 u32 size, u16 stride, int node);