net/mlx4: fix Rx packet type offloads
[dpdk.git] / drivers / net / mlx4 / mlx4_ethdev.c
index 52924df..2f69e7d 100644 (file)
@@ -61,6 +61,7 @@
 #pragma GCC diagnostic error "-Wpedantic"
 #endif
 
+#include <rte_bus_pci.h>
 #include <rte_errno.h>
 #include <rte_ethdev.h>
 #include <rte_ether.h>
@@ -467,20 +468,16 @@ mlx4_set_flags(struct priv *priv, unsigned int keep, unsigned int flags)
 static int
 mlx4_dev_set_link(struct priv *priv, int up)
 {
-       struct rte_eth_dev *dev = priv->dev;
        int err;
 
        if (up) {
                err = mlx4_set_flags(priv, ~IFF_UP, IFF_UP);
                if (err)
                        return err;
-               dev->rx_pkt_burst = mlx4_rx_burst;
        } else {
                err = mlx4_set_flags(priv, ~IFF_UP, ~IFF_UP);
                if (err)
                        return err;
-               dev->rx_pkt_burst = mlx4_rx_burst_removed;
-               dev->tx_pkt_burst = mlx4_tx_burst_removed;
        }
        return 0;
 }
@@ -519,6 +516,101 @@ mlx4_dev_set_link_up(struct rte_eth_dev *dev)
        return mlx4_dev_set_link(priv, 1);
 }
 
+/**
+ * Supported Rx mode toggles.
+ *
+ * Even and odd values respectively stand for off and on.
+ */
+enum rxmode_toggle {
+       RXMODE_TOGGLE_PROMISC_OFF,
+       RXMODE_TOGGLE_PROMISC_ON,
+       RXMODE_TOGGLE_ALLMULTI_OFF,
+       RXMODE_TOGGLE_ALLMULTI_ON,
+};
+
+/**
+ * Helper function to toggle promiscuous and all multicast modes.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param toggle
+ *   Toggle to set.
+ */
+static void
+mlx4_rxmode_toggle(struct rte_eth_dev *dev, enum rxmode_toggle toggle)
+{
+       struct priv *priv = dev->data->dev_private;
+       const char *mode;
+       struct rte_flow_error error;
+
+       switch (toggle) {
+       case RXMODE_TOGGLE_PROMISC_OFF:
+       case RXMODE_TOGGLE_PROMISC_ON:
+               mode = "promiscuous";
+               dev->data->promiscuous = toggle & 1;
+               break;
+       case RXMODE_TOGGLE_ALLMULTI_OFF:
+       case RXMODE_TOGGLE_ALLMULTI_ON:
+               mode = "all multicast";
+               dev->data->all_multicast = toggle & 1;
+               break;
+       }
+       if (!mlx4_flow_sync(priv, &error))
+               return;
+       ERROR("cannot toggle %s mode (code %d, \"%s\"),"
+             " flow error type %d, cause %p, message: %s",
+             mode, rte_errno, strerror(rte_errno), error.type, error.cause,
+             error.message ? error.message : "(unspecified)");
+}
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+mlx4_promiscuous_enable(struct rte_eth_dev *dev)
+{
+       mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_PROMISC_ON);
+}
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+mlx4_promiscuous_disable(struct rte_eth_dev *dev)
+{
+       mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_PROMISC_OFF);
+}
+
+/**
+ * DPDK callback to enable all multicast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+mlx4_allmulticast_enable(struct rte_eth_dev *dev)
+{
+       mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_ALLMULTI_ON);
+}
+
+/**
+ * DPDK callback to disable all multicast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+mlx4_allmulticast_disable(struct rte_eth_dev *dev)
+{
+       mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_ALLMULTI_OFF);
+}
+
 /**
  * DPDK callback to remove a MAC address.
  *
@@ -587,6 +679,48 @@ mlx4_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
        return ret;
 }
 
+/**
+ * DPDK callback to configure a VLAN filter.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param vlan_id
+ *   VLAN ID to filter.
+ * @param on
+ *   Toggle filter.
+ *
+ * @return
+ *   0 on success, negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx4_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+       struct priv *priv = dev->data->dev_private;
+       struct rte_flow_error error;
+       unsigned int vidx = vlan_id / 64;
+       unsigned int vbit = vlan_id % 64;
+       uint64_t *v;
+       int ret;
+
+       if (vidx >= RTE_DIM(dev->data->vlan_filter_conf.ids)) {
+               rte_errno = EINVAL;
+               return -rte_errno;
+       }
+       v = &dev->data->vlan_filter_conf.ids[vidx];
+       *v &= ~(UINT64_C(1) << vbit);
+       *v |= (uint64_t)!!on << vbit;
+       ret = mlx4_flow_sync(priv, &error);
+       if (!ret)
+               return 0;
+       ERROR("failed to synchronize flow rules after %s VLAN filter on ID %u"
+             " (code %d, \"%s\"), "
+             " flow error type %d, cause %p, message: %s",
+             on ? "enabling" : "disabling", vlan_id,
+             rte_errno, strerror(rte_errno), error.type, error.cause,
+             error.message ? error.message : "(unspecified)");
+       return ret;
+}
+
 /**
  * DPDK callback to set the primary MAC address.
  *
@@ -617,8 +751,6 @@ mlx4_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
        char ifname[IF_NAMESIZE];
 
        info->pci_dev = RTE_ETH_DEV_TO_PCI(dev);
-       if (priv == NULL)
-               return;
        /* FIXME: we should ask the device for these values. */
        info->min_rx_bufsize = 32;
        info->max_rx_pktlen = 65536;
@@ -636,8 +768,19 @@ mlx4_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
        info->max_mac_addrs = RTE_DIM(priv->mac);
        info->rx_offload_capa = 0;
        info->tx_offload_capa = 0;
+       if (priv->hw_csum) {
+               info->tx_offload_capa |= (DEV_TX_OFFLOAD_IPV4_CKSUM |
+                                         DEV_TX_OFFLOAD_UDP_CKSUM |
+                                         DEV_TX_OFFLOAD_TCP_CKSUM);
+               info->rx_offload_capa |= (DEV_RX_OFFLOAD_IPV4_CKSUM |
+                                         DEV_RX_OFFLOAD_UDP_CKSUM |
+                                         DEV_RX_OFFLOAD_TCP_CKSUM);
+       }
+       if (priv->hw_csum_l2tun)
+               info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
        if (mlx4_get_ifname(priv, &ifname) == 0)
                info->if_index = if_nametoindex(ifname);
+       info->hash_key_size = MLX4_RSS_HASH_KEY_SIZE;
        info->speed_capa =
                        ETH_LINK_SPEED_1G |
                        ETH_LINK_SPEED_10G |
@@ -870,3 +1013,50 @@ out:
        assert(ret >= 0);
        return -ret;
 }
+
+/**
+ * DPDK callback to retrieve the received packet types that are recognized
+ * by the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   Pointer to an array of recognized packet types if in Rx burst mode,
+ *   NULL otherwise.
+ */
+const uint32_t *
+mlx4_dev_supported_ptypes_get(struct rte_eth_dev *dev)
+{
+       static const uint32_t ptypes[] = {
+               /* refers to rxq_cq_to_pkt_type() */
+               RTE_PTYPE_L2_ETHER,
+               RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+               RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
+               RTE_PTYPE_L4_FRAG,
+               RTE_PTYPE_L4_TCP,
+               RTE_PTYPE_L4_UDP,
+               RTE_PTYPE_UNKNOWN
+       };
+       static const uint32_t ptypes_l2tun[] = {
+               /* refers to rxq_cq_to_pkt_type() */
+               RTE_PTYPE_L2_ETHER,
+               RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+               RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
+               RTE_PTYPE_L4_FRAG,
+               RTE_PTYPE_L4_TCP,
+               RTE_PTYPE_L4_UDP,
+               RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
+               RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
+               RTE_PTYPE_UNKNOWN
+       };
+       struct priv *priv = dev->data->dev_private;
+
+       if (dev->rx_pkt_burst == mlx4_rx_burst) {
+               if (priv->hw_csum_l2tun)
+                       return ptypes_l2tun;
+               else
+                       return ptypes;
+       }
+       return NULL;
+}