aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Vadai <amirv@mellanox.com>2013-06-18 09:18:27 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-19 21:32:16 -0400
commit9e77a2b837bbd7197da966f0915e8f1ddb2ca850 (patch)
treefaf28979465bc6909513170b41a3cbe5f811ea45
parentdc3d807d6fd983603c82e7bcdbaa49cdb4239691 (diff)
net/mlx4_en: Add Low Latency Socket (LLS) support
Add basic support for LLS. Signed-off-by: Amir Vadai <amirv@mellanox.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_cq.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c43
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c15
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h121
4 files changed, 178 insertions, 4 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index 1e6c594d6d04..3e2d5047cdb3 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
@@ -139,6 +139,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
139 139
140 if (!cq->is_tx) { 140 if (!cq->is_tx) {
141 netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64); 141 netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64);
142 napi_hash_add(&cq->napi);
142 napi_enable(&cq->napi); 143 napi_enable(&cq->napi);
143 } 144 }
144 145
@@ -162,6 +163,8 @@ void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
162{ 163{
163 if (!cq->is_tx) { 164 if (!cq->is_tx) {
164 napi_disable(&cq->napi); 165 napi_disable(&cq->napi);
166 napi_hash_del(&cq->napi);
167 synchronize_rcu();
165 netif_napi_del(&cq->napi); 168 netif_napi_del(&cq->napi);
166 } 169 }
167 170
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index ade276cca0e6..ab9ec91d1f70 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -38,6 +38,7 @@
38#include <linux/slab.h> 38#include <linux/slab.h>
39#include <linux/hash.h> 39#include <linux/hash.h>
40#include <net/ip.h> 40#include <net/ip.h>
41#include <net/ll_poll.h>
41 42
42#include <linux/mlx4/driver.h> 43#include <linux/mlx4/driver.h>
43#include <linux/mlx4/device.h> 44#include <linux/mlx4/device.h>
@@ -67,6 +68,30 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up)
67 return 0; 68 return 0;
68} 69}
69 70
71#ifdef CONFIG_NET_LL_RX_POLL
72/* must be called with local_bh_disable()d */
73static int mlx4_en_low_latency_recv(struct napi_struct *napi)
74{
75 struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi);
76 struct net_device *dev = cq->dev;
77 struct mlx4_en_priv *priv = netdev_priv(dev);
78 struct mlx4_en_rx_ring *rx_ring = &priv->rx_ring[cq->ring];
79 int done;
80
81 if (!priv->port_up)
82 return LL_FLUSH_FAILED;
83
84 if (!mlx4_en_cq_lock_poll(cq))
85 return LL_FLUSH_BUSY;
86
87 done = mlx4_en_process_rx_cq(dev, cq, 4);
88
89 mlx4_en_cq_unlock_poll(cq);
90
91 return done;
92}
93#endif /* CONFIG_NET_LL_RX_POLL */
94
70#ifdef CONFIG_RFS_ACCEL 95#ifdef CONFIG_RFS_ACCEL
71 96
72struct mlx4_en_filter { 97struct mlx4_en_filter {
@@ -1445,6 +1470,8 @@ int mlx4_en_start_port(struct net_device *dev)
1445 for (i = 0; i < priv->rx_ring_num; i++) { 1470 for (i = 0; i < priv->rx_ring_num; i++) {
1446 cq = &priv->rx_cq[i]; 1471 cq = &priv->rx_cq[i];
1447 1472
1473 mlx4_en_cq_init_lock(cq);
1474
1448 err = mlx4_en_activate_cq(priv, cq, i); 1475 err = mlx4_en_activate_cq(priv, cq, i);
1449 if (err) { 1476 if (err) {
1450 en_err(priv, "Failed activating Rx CQ\n"); 1477 en_err(priv, "Failed activating Rx CQ\n");
@@ -1694,10 +1721,19 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
1694 1721
1695 /* Free RX Rings */ 1722 /* Free RX Rings */
1696 for (i = 0; i < priv->rx_ring_num; i++) { 1723 for (i = 0; i < priv->rx_ring_num; i++) {
1724 struct mlx4_en_cq *cq = &priv->rx_cq[i];
1725
1726 local_bh_disable();
1727 while (!mlx4_en_cq_lock_napi(cq)) {
1728 pr_info("CQ %d locked\n", i);
1729 mdelay(1);
1730 }
1731 local_bh_enable();
1732
1697 mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); 1733 mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
1698 while (test_bit(NAPI_STATE_SCHED, &priv->rx_cq[i].napi.state)) 1734 while (test_bit(NAPI_STATE_SCHED, &cq->napi.state))
1699 msleep(1); 1735 msleep(1);
1700 mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]); 1736 mlx4_en_deactivate_cq(priv, cq);
1701 } 1737 }
1702 1738
1703 /* close port*/ 1739 /* close port*/
@@ -2090,6 +2126,9 @@ static const struct net_device_ops mlx4_netdev_ops = {
2090#ifdef CONFIG_RFS_ACCEL 2126#ifdef CONFIG_RFS_ACCEL
2091 .ndo_rx_flow_steer = mlx4_en_filter_rfs, 2127 .ndo_rx_flow_steer = mlx4_en_filter_rfs,
2092#endif 2128#endif
2129#ifdef CONFIG_NET_LL_RX_POLL
2130 .ndo_ll_poll = mlx4_en_low_latency_recv,
2131#endif
2093}; 2132};
2094 2133
2095static const struct net_device_ops mlx4_netdev_ops_master = { 2134static const struct net_device_ops mlx4_netdev_ops_master = {
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 02aee1ebd203..9c57581b021c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -31,6 +31,7 @@
31 * 31 *
32 */ 32 */
33 33
34#include <net/ll_poll.h>
34#include <linux/mlx4/cq.h> 35#include <linux/mlx4/cq.h>
35#include <linux/slab.h> 36#include <linux/slab.h>
36#include <linux/mlx4/qp.h> 37#include <linux/mlx4/qp.h>
@@ -656,8 +657,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
656 * - DIX Ethernet (type interpretation) 657 * - DIX Ethernet (type interpretation)
657 * - TCP/IP (v4) 658 * - TCP/IP (v4)
658 * - without IP options 659 * - without IP options
659 * - not an IP fragment */ 660 * - not an IP fragment
660 if (dev->features & NETIF_F_GRO) { 661 * - no LLS polling in progress
662 */
663 if (!mlx4_en_cq_ll_polling(cq) &&
664 (dev->features & NETIF_F_GRO)) {
661 struct sk_buff *gro_skb = napi_get_frags(&cq->napi); 665 struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
662 if (!gro_skb) 666 if (!gro_skb)
663 goto next; 667 goto next;
@@ -737,6 +741,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
737 timestamp); 741 timestamp);
738 } 742 }
739 743
744 skb_mark_ll(skb, &cq->napi);
745
740 /* Push it up the stack */ 746 /* Push it up the stack */
741 netif_receive_skb(skb); 747 netif_receive_skb(skb);
742 748
@@ -781,8 +787,13 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget)
781 struct mlx4_en_priv *priv = netdev_priv(dev); 787 struct mlx4_en_priv *priv = netdev_priv(dev);
782 int done; 788 int done;
783 789
790 if (!mlx4_en_cq_lock_napi(cq))
791 return budget;
792
784 done = mlx4_en_process_rx_cq(dev, cq, budget); 793 done = mlx4_en_process_rx_cq(dev, cq, budget);
785 794
795 mlx4_en_cq_unlock_napi(cq);
796
786 /* If we used up all the quota - we're probably not done yet... */ 797 /* If we used up all the quota - we're probably not done yet... */
787 if (done == budget) 798 if (done == budget)
788 INC_PERF_COUNTER(priv->pstats.napi_quota); 799 INC_PERF_COUNTER(priv->pstats.napi_quota);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index b1f51c1f635c..11c862e4e69d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -310,6 +310,19 @@ struct mlx4_en_cq {
310 u16 moder_cnt; 310 u16 moder_cnt;
311 struct mlx4_cqe *buf; 311 struct mlx4_cqe *buf;
312#define MLX4_EN_OPCODE_ERROR 0x1e 312#define MLX4_EN_OPCODE_ERROR 0x1e
313
314#ifdef CONFIG_NET_LL_RX_POLL
315 unsigned int state;
316#define MLX4_EN_CQ_STATE_IDLE 0
317#define MLX4_EN_CQ_STATE_NAPI 1 /* NAPI owns this CQ */
318#define MLX4_EN_CQ_STATE_POLL 2 /* poll owns this CQ */
319#define MLX4_CQ_LOCKED (MLX4_EN_CQ_STATE_NAPI | MLX4_EN_CQ_STATE_POLL)
320#define MLX4_EN_CQ_STATE_NAPI_YIELD 4 /* NAPI yielded this CQ */
321#define MLX4_EN_CQ_STATE_POLL_YIELD 8 /* poll yielded this CQ */
322#define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD)
323#define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
324 spinlock_t poll_lock; /* protects from LLS/napi conflicts */
325#endif /* CONFIG_NET_LL_RX_POLL */
313}; 326};
314 327
315struct mlx4_en_port_profile { 328struct mlx4_en_port_profile {
@@ -562,6 +575,114 @@ struct mlx4_mac_entry {
562 struct rcu_head rcu; 575 struct rcu_head rcu;
563}; 576};
564 577
578#ifdef CONFIG_NET_LL_RX_POLL
579static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
580{
581 spin_lock_init(&cq->poll_lock);
582 cq->state = MLX4_EN_CQ_STATE_IDLE;
583}
584
585/* called from the device poll rutine to get ownership of a cq */
586static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq)
587{
588 int rc = true;
589 spin_lock(&cq->poll_lock);
590 if (cq->state & MLX4_CQ_LOCKED) {
591 WARN_ON(cq->state & MLX4_EN_CQ_STATE_NAPI);
592 cq->state |= MLX4_EN_CQ_STATE_NAPI_YIELD;
593 rc = false;
594 } else
595 /* we don't care if someone yielded */
596 cq->state = MLX4_EN_CQ_STATE_NAPI;
597 spin_unlock(&cq->poll_lock);
598 return rc;
599}
600
601/* returns true is someone tried to get the cq while napi had it */
602static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq)
603{
604 int rc = false;
605 spin_lock(&cq->poll_lock);
606 WARN_ON(cq->state & (MLX4_EN_CQ_STATE_POLL |
607 MLX4_EN_CQ_STATE_NAPI_YIELD));
608
609 if (cq->state & MLX4_EN_CQ_STATE_POLL_YIELD)
610 rc = true;
611 cq->state = MLX4_EN_CQ_STATE_IDLE;
612 spin_unlock(&cq->poll_lock);
613 return rc;
614}
615
616/* called from mlx4_en_low_latency_poll() */
617static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq)
618{
619 int rc = true;
620 spin_lock_bh(&cq->poll_lock);
621 if ((cq->state & MLX4_CQ_LOCKED)) {
622 struct net_device *dev = cq->dev;
623 struct mlx4_en_priv *priv = netdev_priv(dev);
624 struct mlx4_en_rx_ring *rx_ring = &priv->rx_ring[cq->ring];
625
626 cq->state |= MLX4_EN_CQ_STATE_POLL_YIELD;
627 rc = false;
628 } else
629 /* preserve yield marks */
630 cq->state |= MLX4_EN_CQ_STATE_POLL;
631 spin_unlock_bh(&cq->poll_lock);
632 return rc;
633}
634
635/* returns true if someone tried to get the cq while it was locked */
636static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq)
637{
638 int rc = false;
639 spin_lock_bh(&cq->poll_lock);
640 WARN_ON(cq->state & (MLX4_EN_CQ_STATE_NAPI));
641
642 if (cq->state & MLX4_EN_CQ_STATE_POLL_YIELD)
643 rc = true;
644 cq->state = MLX4_EN_CQ_STATE_IDLE;
645 spin_unlock_bh(&cq->poll_lock);
646 return rc;
647}
648
649/* true if a socket is polling, even if it did not get the lock */
650static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
651{
652 WARN_ON(!(cq->state & MLX4_CQ_LOCKED));
653 return cq->state & CQ_USER_PEND;
654}
655#else
656static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
657{
658}
659
660static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq)
661{
662 return true;
663}
664
665static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq)
666{
667 return false;
668}
669
670static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq)
671{
672 return false;
673}
674
675static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq)
676{
677 return false;
678}
679
680static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
681{
682 return false;
683}
684#endif /* CONFIG_NET_LL_RX_POLL */
685
565#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63) 686#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
566 687
567void mlx4_en_update_loopback_state(struct net_device *dev, 688void mlx4_en_update_loopback_state(struct net_device *dev,