net/mlx4_en: Optimize loopback related checks in data path
authorYan Burman <yanb@mellanox.com>
Thu, 7 Feb 2013 02:25:19 +0000 (02:25 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 8 Feb 2013 04:26:12 +0000 (23:26 -0500)
Currently there are relatively complex conditional checks in the fast path,
for TX loopback enabling and resulting RX filter logic.
Move elaborate if's out of data path, replace them with a single flag
for each state and update that state from appropriate places.
Also, in native (non SRIOV) mode and not in loopback or in selftest,
there is no need to try and filter out packets that HW loopback-ed,
as in native mode we do not loopback packets anymore.

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_selftest.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h

index f3c7961a271fa598c7f66a46bc90ad639c22f02e..e3c3d122979ece44ed976b99488c619f7fd9e881 100644 (file)
@@ -95,6 +95,28 @@ int en_print(const char *level, const struct mlx4_en_priv *priv,
        return i;
 }
 
+void mlx4_en_update_loopback_state(struct net_device *dev,
+                                  netdev_features_t features)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+
+       priv->flags &= ~(MLX4_EN_FLAG_RX_FILTER_NEEDED|
+                       MLX4_EN_FLAG_ENABLE_HW_LOOPBACK);
+
+       /* Drop the packet if SRIOV is not enabled
+        * and not performing the selftest or flb disabled
+        */
+       if (mlx4_is_mfunc(priv->mdev->dev) &&
+           !(features & NETIF_F_LOOPBACK) && !priv->validate_loopback)
+               priv->flags |= MLX4_EN_FLAG_RX_FILTER_NEEDED;
+
+       /* Set dmac in Tx WQE if we are in SRIOV mode or if loopback selftest
+        * is requested
+        */
+       if (mlx4_is_mfunc(priv->mdev->dev) || priv->validate_loopback)
+               priv->flags |= MLX4_EN_FLAG_ENABLE_HW_LOOPBACK;
+}
+
 static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
 {
        struct mlx4_en_profile *params = &mdev->profile;
index ac1c14f7424a5f1a9e835756a8c2fcbc5b1f07ed..551ef688a8dfa28369a8ee060391a251a7112435 100644 (file)
@@ -1563,6 +1563,8 @@ static int mlx4_en_set_features(struct net_device *netdev,
                priv->ctrl_flags &=
                        cpu_to_be32(~MLX4_WQE_CTRL_FORCE_LOOPBACK);
 
+       mlx4_en_update_loopback_state(netdev, features);
+
        return 0;
 
 }
@@ -1731,6 +1733,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
        en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
 
+       mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+
        /* Configure port */
        mlx4_en_calc_rx_buf(dev);
        err = mlx4_SET_PORT_general(mdev->dev, priv->port,
index fed26d867f4e3f6bc1452bfcd3ab1136a48c8628..ed214d05dd71586f8a84db2432cd977fc0afaf16 100644 (file)
@@ -563,9 +563,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
        unsigned int length;
        int polled = 0;
        int ip_summed;
-       struct ethhdr *ethh;
-       dma_addr_t dma;
-       u64 s_mac;
        int factor = priv->cqe_factor;
 
        if (!priv->port_up)
@@ -603,21 +600,27 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                        goto next;
                }
 
-               /* Get pointer to first fragment since we haven't skb yet and
-                * cast it to ethhdr struct */
-               dma = be64_to_cpu(rx_desc->data[0].addr);
-               dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
-                                       DMA_FROM_DEVICE);
-               ethh = (struct ethhdr *)(page_address(frags[0].page) +
-                                        frags[0].offset);
-               s_mac = mlx4_en_mac_to_u64(ethh->h_source);
-
-               /* If source MAC is equal to our own MAC and not performing
-                * the selftest or flb disabled - drop the packet */
-               if (s_mac == priv->mac &&
-                   !((dev->features & NETIF_F_LOOPBACK) ||
-                     priv->validate_loopback))
-                       goto next;
+               /* Check if we need to drop the packet if SRIOV is not enabled
+                * and not performing the selftest or flb disabled
+                */
+               if (priv->flags & MLX4_EN_FLAG_RX_FILTER_NEEDED) {
+                       struct ethhdr *ethh;
+                       dma_addr_t dma;
+                       u64 s_mac;
+                       /* Get pointer to first fragment since we haven't
+                        * skb yet and cast it to ethhdr struct
+                        */
+                       dma = be64_to_cpu(rx_desc->data[0].addr);
+                       dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
+                                               DMA_FROM_DEVICE);
+                       ethh = (struct ethhdr *)(page_address(frags[0].page) +
+                                                frags[0].offset);
+
+                       /* Drop the packet, since HW loopback-ed it */
+                       s_mac = mlx4_en_mac_to_u64(ethh->h_source);
+                       if (s_mac == priv->mac)
+                               goto next;
+               }
 
                /*
                 * Packet is OK - process it.
index bf2e5d3f177c21ed599b0768276201512946106c..3488c6d9e6b53cb496f43d84d224342802c2e45f 100644 (file)
@@ -87,6 +87,8 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
         priv->loopback_ok = 0;
        priv->validate_loopback = 1;
 
+       mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+
        /* xmit */
        if (mlx4_en_test_loopback_xmit(priv)) {
                en_err(priv, "Transmitting loopback packet failed\n");
@@ -107,6 +109,7 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
 mlx4_en_test_loopback_exit:
 
        priv->validate_loopback = 0;
+       mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
        return !loopback_ok;
 }
 
index 30724d811115717ec1a39bcc93a726be5e593d82..3b28e167b05b608034845faa61c81891bee5a2c7 100644 (file)
@@ -640,7 +640,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                ring->tx_csum++;
        }
 
-       if (mlx4_is_mfunc(mdev->dev) || priv->validate_loopback) {
+       if (priv->flags & MLX4_EN_FLAG_ENABLE_HW_LOOPBACK) {
                /* Copy dst mac address to wqe. This allows loopback in eSwitch,
                 * so that VFs and PF can communicate with each other
                 */
index 43f01650e58541767a2734ddb7f108301f5bad8e..696dcf33619fe253500e22e6f1983a49abfb791a 100644 (file)
@@ -432,6 +432,17 @@ struct ethtool_flow_id {
        u64 id;
 };
 
+enum {
+       MLX4_EN_FLAG_PROMISC            = (1 << 0),
+       MLX4_EN_FLAG_MC_PROMISC         = (1 << 1),
+       /* whether we need to enable hardware loopback by putting dmac
+        * in Tx WQE
+        */
+       MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2),
+       /* whether we need to drop packets that hardware loopback-ed */
+       MLX4_EN_FLAG_RX_FILTER_NEEDED   = (1 << 3)
+};
+
 struct mlx4_en_priv {
        struct mlx4_en_dev *mdev;
        struct mlx4_en_port_profile *prof;
@@ -481,8 +492,6 @@ struct mlx4_en_priv {
        struct mlx4_en_rss_map rss_map;
        __be32 ctrl_flags;
        u32 flags;
-#define MLX4_EN_FLAG_PROMISC   0x1
-#define MLX4_EN_FLAG_MC_PROMISC        0x2
        u8 num_tx_rings_p_up;
        u32 tx_ring_num;
        u32 rx_ring_num;
@@ -534,6 +543,9 @@ enum mlx4_en_wol {
 
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
+void mlx4_en_update_loopback_state(struct net_device *dev,
+                                  netdev_features_t features);
+
 void mlx4_en_destroy_netdev(struct net_device *dev);
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                        struct mlx4_en_port_profile *prof);