]> Pileus Git - ~andy/linux/blobdiff - drivers/net/ethernet/mellanox/mlx4/en_tx.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[~andy/linux] / drivers / net / ethernet / mellanox / mlx4 / en_tx.c
index a7fcd593b2dbb397bdf3d2a810ff42f71d0806b6..8e8a7eb43a2ce861249d678e1f1053be9b7b0ac5 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/if_vlan.h>
 #include <linux/vmalloc.h>
 #include <linux/tcp.h>
+#include <linux/ip.h>
 #include <linux/moduleparam.h>
 
 #include "mlx4_en.h"
@@ -55,7 +56,7 @@ MODULE_PARM_DESC(inline_thold, "threshold for using inline data");
 
 int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
                           struct mlx4_en_tx_ring **pring, int qpn, u32 size,
-                          u16 stride, int node)
+                          u16 stride, int node, int queue_index)
 {
        struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_en_tx_ring *ring;
@@ -140,6 +141,10 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
                ring->bf_enabled = true;
 
        ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type;
+       ring->queue_index = queue_index;
+
+       if (queue_index < priv->num_tx_rings_p_up && cpu_online(queue_index))
+               cpumask_set_cpu(queue_index, &ring->affinity_mask);
 
        *pring = ring;
        return 0;
@@ -206,6 +211,9 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
 
        err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context,
                               &ring->qp, &ring->qp_state);
+       if (!user_prio && cpu_online(ring->queue_index))
+               netif_set_xps_queue(priv->dev, &ring->affinity_mask,
+                                   ring->queue_index);
 
        return err;
 }
@@ -317,7 +325,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                        }
                }
        }
-       dev_kfree_skb_any(skb);
+       dev_kfree_skb(skb);
        return tx_info->nr_txbb;
 }
 
@@ -354,7 +362,9 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
        return cnt;
 }
 
-static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
+static int mlx4_en_process_tx_cq(struct net_device *dev,
+                                struct mlx4_en_cq *cq,
+                                int budget)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_cq *mcq = &cq->mcq;
@@ -372,9 +382,10 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
        u32 bytes = 0;
        int factor = priv->cqe_factor;
        u64 timestamp = 0;
+       int done = 0;
 
        if (!priv->port_up)
-               return;
+               return 0;
 
        index = cons_index & size_mask;
        cqe = &buf[(index << factor) + factor];
@@ -383,7 +394,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
 
        /* Process all completed CQEs */
        while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK,
-                       cons_index & size)) {
+                       cons_index & size) && (done < budget)) {
                /*
                 * make sure we read the CQE after we read the
                 * ownership bit
@@ -421,7 +432,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
                        txbbs_stamp = txbbs_skipped;
                        packets++;
                        bytes += ring->tx_info[ring_index].nr_bytes;
-               } while (ring_index != new_index);
+               } while ((++done < budget) && (ring_index != new_index));
 
                ++cons_index;
                index = cons_index & size_mask;
@@ -447,6 +458,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
                netif_tx_wake_queue(ring->tx_queue);
                priv->port_stats.wake_queue++;
        }
+       return done;
 }
 
 void mlx4_en_tx_irq(struct mlx4_cq *mcq)
@@ -454,10 +466,31 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq)
        struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq);
        struct mlx4_en_priv *priv = netdev_priv(cq->dev);
 
-       mlx4_en_process_tx_cq(cq->dev, cq);
-       mlx4_en_arm_cq(priv, cq);
+       if (priv->port_up)
+               napi_schedule(&cq->napi);
+       else
+               mlx4_en_arm_cq(priv, cq);
 }
 
+/* TX CQ polling - called by NAPI */
+int mlx4_en_poll_tx_cq(struct napi_struct *napi, int budget)
+{
+       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);
+       int done;
+
+       done = mlx4_en_process_tx_cq(dev, cq, budget);
+
+       /* If we used up all the quota - we're probably not done yet... */
+       if (done < budget) {
+               /* Done for now */
+               napi_complete(napi);
+               mlx4_en_arm_cq(priv, cq);
+               return done;
+       }
+       return budget;
+}
 
 static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
                                                      struct mlx4_en_tx_ring *ring,
@@ -528,7 +561,10 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev,
        int real_size;
 
        if (skb_is_gso(skb)) {
-               *lso_header_size = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               if (skb->encapsulation)
+                       *lso_header_size = (skb_inner_transport_header(skb) - skb->data) + inner_tcp_hdrlen(skb);
+               else
+                       *lso_header_size = skb_transport_offset(skb) + tcp_hdrlen(skb);
                real_size = CTRL_SIZE + skb_shinfo(skb)->nr_frags * DS_SIZE +
                        ALIGN(*lso_header_size + 4, DS_SIZE);
                if (unlikely(*lso_header_size != skb_headlen(skb))) {
@@ -828,6 +864,14 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                tx_info->inl = 1;
        }
 
+       if (skb->encapsulation) {
+               struct iphdr *ipv4 = (struct iphdr *)skb_inner_network_header(skb);
+               if (ipv4->protocol == IPPROTO_TCP || ipv4->protocol == IPPROTO_UDP)
+                       op_own |= cpu_to_be32(MLX4_WQE_CTRL_IIP | MLX4_WQE_CTRL_ILP);
+               else
+                       op_own |= cpu_to_be32(MLX4_WQE_CTRL_IIP);
+       }
+
        ring->prod += nr_txbb;
 
        /* If we used a bounce buffer then copy descriptor back into place */