#include <linux/slab.h>
 #include <linux/hash.h>
 #include <net/ip.h>
+#include <net/ll_poll.h>
 
 #include <linux/mlx4/driver.h>
 #include <linux/mlx4/device.h>
        return 0;
 }
 
+#ifdef CONFIG_NET_LL_RX_POLL
+/* must be called with local_bh_disable()d */
+static int mlx4_en_low_latency_recv(struct napi_struct *napi)
+{
+       struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi);
+       struct net_device *dev = cq->dev;
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       struct mlx4_en_rx_ring *rx_ring = &priv->rx_ring[cq->ring];
+       int done;
+
+       if (!priv->port_up)
+               return LL_FLUSH_FAILED;
+
+       if (!mlx4_en_cq_lock_poll(cq))
+               return LL_FLUSH_BUSY;
+
+       done = mlx4_en_process_rx_cq(dev, cq, 4);
+
+       mlx4_en_cq_unlock_poll(cq);
+
+       return done;
+}
+#endif /* CONFIG_NET_LL_RX_POLL */
+
 #ifdef CONFIG_RFS_ACCEL
 
 struct mlx4_en_filter {
        for (i = 0; i < priv->rx_ring_num; i++) {
                cq = &priv->rx_cq[i];
 
+               mlx4_en_cq_init_lock(cq);
+
                err = mlx4_en_activate_cq(priv, cq, i);
                if (err) {
                        en_err(priv, "Failed activating Rx CQ\n");
 
        /* Free RX Rings */
        for (i = 0; i < priv->rx_ring_num; i++) {
+               struct mlx4_en_cq *cq = &priv->rx_cq[i];
+
+               local_bh_disable();
+               while (!mlx4_en_cq_lock_napi(cq)) {
+                       pr_info("CQ %d locked\n", i);
+                       mdelay(1);
+               }
+               local_bh_enable();
+
                mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
-               while (test_bit(NAPI_STATE_SCHED, &priv->rx_cq[i].napi.state))
+               while (test_bit(NAPI_STATE_SCHED, &cq->napi.state))
                        msleep(1);
-               mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]);
+               mlx4_en_deactivate_cq(priv, cq);
        }
 
        /* close port*/
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
+#ifdef CONFIG_NET_LL_RX_POLL
+       .ndo_ll_poll            = mlx4_en_low_latency_recv,
+#endif
 };
 
 static const struct net_device_ops mlx4_netdev_ops_master = {
 
  *
  */
 
+#include <net/ll_poll.h>
 #include <linux/mlx4/cq.h>
 #include <linux/slab.h>
 #include <linux/mlx4/qp.h>
                                 * - DIX Ethernet (type interpretation)
                                 * - TCP/IP (v4)
                                 * - without IP options
-                                * - not an IP fragment */
-                               if (dev->features & NETIF_F_GRO) {
+                                * - not an IP fragment
+                                * - no LLS polling in progress
+                                */
+                               if (!mlx4_en_cq_ll_polling(cq) &&
+                                   (dev->features & NETIF_F_GRO)) {
                                        struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
                                        if (!gro_skb)
                                                goto next;
                                               timestamp);
                }
 
+               skb_mark_ll(skb, &cq->napi);
+
                /* Push it up the stack */
                netif_receive_skb(skb);
 
        struct mlx4_en_priv *priv = netdev_priv(dev);
        int done;
 
+       if (!mlx4_en_cq_lock_napi(cq))
+               return budget;
+
        done = mlx4_en_process_rx_cq(dev, cq, budget);
 
+       mlx4_en_cq_unlock_napi(cq);
+
        /* If we used up all the quota - we're probably not done yet... */
        if (done == budget)
                INC_PERF_COUNTER(priv->pstats.napi_quota);
 
        u16 moder_cnt;
        struct mlx4_cqe *buf;
 #define MLX4_EN_OPCODE_ERROR   0x1e
+
+#ifdef CONFIG_NET_LL_RX_POLL
+       unsigned int state;
+#define MLX4_EN_CQ_STATE_IDLE        0
+#define MLX4_EN_CQ_STATE_NAPI     1    /* NAPI owns this CQ */
+#define MLX4_EN_CQ_STATE_POLL     2    /* poll owns this CQ */
+#define MLX4_CQ_LOCKED (MLX4_EN_CQ_STATE_NAPI | MLX4_EN_CQ_STATE_POLL)
+#define MLX4_EN_CQ_STATE_NAPI_YIELD  4    /* NAPI yielded this CQ */
+#define MLX4_EN_CQ_STATE_POLL_YIELD  8    /* poll yielded this CQ */
+#define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD)
+#define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
+       spinlock_t poll_lock; /* protects from LLS/napi conflicts */
+#endif  /* CONFIG_NET_LL_RX_POLL */
 };
 
 struct mlx4_en_port_profile {
        struct rcu_head rcu;
 };
 
+#ifdef CONFIG_NET_LL_RX_POLL
+static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
+{
+       spin_lock_init(&cq->poll_lock);
+       cq->state = MLX4_EN_CQ_STATE_IDLE;
+}
+
+/* called from the device poll rutine to get ownership of a cq */
+static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq)
+{
+       int rc = true;
+       spin_lock(&cq->poll_lock);
+       if (cq->state & MLX4_CQ_LOCKED) {
+               WARN_ON(cq->state & MLX4_EN_CQ_STATE_NAPI);
+               cq->state |= MLX4_EN_CQ_STATE_NAPI_YIELD;
+               rc = false;
+       } else
+               /* we don't care if someone yielded */
+               cq->state = MLX4_EN_CQ_STATE_NAPI;
+       spin_unlock(&cq->poll_lock);
+       return rc;
+}
+
+/* returns true is someone tried to get the cq while napi had it */
+static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq)
+{
+       int rc = false;
+       spin_lock(&cq->poll_lock);
+       WARN_ON(cq->state & (MLX4_EN_CQ_STATE_POLL |
+                              MLX4_EN_CQ_STATE_NAPI_YIELD));
+
+       if (cq->state & MLX4_EN_CQ_STATE_POLL_YIELD)
+               rc = true;
+       cq->state = MLX4_EN_CQ_STATE_IDLE;
+       spin_unlock(&cq->poll_lock);
+       return rc;
+}
+
+/* called from mlx4_en_low_latency_poll() */
+static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq)
+{
+       int rc = true;
+       spin_lock_bh(&cq->poll_lock);
+       if ((cq->state & MLX4_CQ_LOCKED)) {
+               struct net_device *dev = cq->dev;
+               struct mlx4_en_priv *priv = netdev_priv(dev);
+               struct mlx4_en_rx_ring *rx_ring = &priv->rx_ring[cq->ring];
+
+               cq->state |= MLX4_EN_CQ_STATE_POLL_YIELD;
+               rc = false;
+       } else
+               /* preserve yield marks */
+               cq->state |= MLX4_EN_CQ_STATE_POLL;
+       spin_unlock_bh(&cq->poll_lock);
+       return rc;
+}
+
+/* returns true if someone tried to get the cq while it was locked */
+static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq)
+{
+       int rc = false;
+       spin_lock_bh(&cq->poll_lock);
+       WARN_ON(cq->state & (MLX4_EN_CQ_STATE_NAPI));
+
+       if (cq->state & MLX4_EN_CQ_STATE_POLL_YIELD)
+               rc = true;
+       cq->state = MLX4_EN_CQ_STATE_IDLE;
+       spin_unlock_bh(&cq->poll_lock);
+       return rc;
+}
+
+/* true if a socket is polling, even if it did not get the lock */
+static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
+{
+       WARN_ON(!(cq->state & MLX4_CQ_LOCKED));
+       return cq->state & CQ_USER_PEND;
+}
+#else
+static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
+{
+}
+
+static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq)
+{
+       return true;
+}
+
+static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq)
+{
+       return false;
+}
+
+static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq)
+{
+       return false;
+}
+
+static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq)
+{
+       return false;
+}
+
+static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
+{
+       return false;
+}
+#endif /* CONFIG_NET_LL_RX_POLL */
+
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
 void mlx4_en_update_loopback_state(struct net_device *dev,