#pragma GCC diagnostic error "-Wpedantic"
#endif
+#include <rte_bus_pci.h>
#include <rte_errno.h>
#include <rte_ethdev.h>
#include <rte_ether.h>
+#include <rte_flow.h>
#include <rte_pci.h>
#include "mlx4.h"
+#include "mlx4_flow.h"
#include "mlx4_rxtx.h"
#include "mlx4_utils.h"
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;
}
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.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param index
+ * MAC address index.
+ */
+void
+mlx4_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+ struct priv *priv = dev->data->dev_private;
+ struct rte_flow_error error;
+
+ if (index >= RTE_DIM(priv->mac)) {
+ rte_errno = EINVAL;
+ return;
+ }
+ memset(&priv->mac[index], 0, sizeof(priv->mac[index]));
+ if (!mlx4_flow_sync(priv, &error))
+ return;
+ ERROR("failed to synchronize flow rules after removing MAC address"
+ " at index %d (code %d, \"%s\"),"
+ " flow error type %d, cause %p, message: %s",
+ index, rte_errno, strerror(rte_errno), error.type, error.cause,
+ error.message ? error.message : "(unspecified)");
+}
+
+/**
+ * DPDK callback to add a MAC address.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param mac_addr
+ * MAC address to register.
+ * @param index
+ * MAC address index.
+ * @param vmdq
+ * VMDq pool index to associate address with (ignored).
+ *
+ * @return
+ * 0 on success, negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx4_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
+ uint32_t index, uint32_t vmdq)
+{
+ struct priv *priv = dev->data->dev_private;
+ struct rte_flow_error error;
+ int ret;
+
+ (void)vmdq;
+ if (index >= RTE_DIM(priv->mac)) {
+ rte_errno = EINVAL;
+ return -rte_errno;
+ }
+ memcpy(&priv->mac[index], mac_addr, sizeof(priv->mac[index]));
+ ret = mlx4_flow_sync(priv, &error);
+ if (!ret)
+ return 0;
+ ERROR("failed to synchronize flow rules after adding MAC address"
+ " at index %d (code %d, \"%s\"),"
+ " flow error type %d, cause %p, message: %s",
+ index, rte_errno, strerror(rte_errno), error.type, error.cause,
+ error.message ? error.message : "(unspecified)");
+ 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.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param mac_addr
+ * MAC address to register.
+ */
+void
+mlx4_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
+{
+ mlx4_mac_addr_add(dev, mac_addr, 0, 0);
+}
+
/**
* DPDK callback to get information about the device.
*
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;
max = 65535;
info->max_rx_queues = max;
info->max_tx_queues = max;
- /* Last array entry is reserved for broadcast. */
- info->max_mac_addrs = 1;
+ 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 |
* @param[out] stats
* Stats structure output buffer.
*/
-void
+int
mlx4_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
{
- struct priv *priv = dev->data->dev_private;
struct rte_eth_stats tmp;
unsigned int i;
unsigned int idx;
- if (priv == NULL)
- return;
memset(&tmp, 0, sizeof(tmp));
/* Add software counters. */
- for (i = 0; (i != priv->rxqs_n); ++i) {
- struct rxq *rxq = (*priv->rxqs)[i];
+ for (i = 0; i != dev->data->nb_rx_queues; ++i) {
+ struct rxq *rxq = dev->data->rx_queues[i];
if (rxq == NULL)
continue;
tmp.ierrors += rxq->stats.idropped;
tmp.rx_nombuf += rxq->stats.rx_nombuf;
}
- for (i = 0; (i != priv->txqs_n); ++i) {
- struct txq *txq = (*priv->txqs)[i];
+ for (i = 0; i != dev->data->nb_tx_queues; ++i) {
+ struct txq *txq = dev->data->tx_queues[i];
if (txq == NULL)
continue;
tmp.oerrors += txq->stats.odropped;
}
*stats = tmp;
+ return 0;
}
/**
void
mlx4_stats_reset(struct rte_eth_dev *dev)
{
- struct priv *priv = dev->data->dev_private;
unsigned int i;
- unsigned int idx;
- if (priv == NULL)
- return;
- for (i = 0; (i != priv->rxqs_n); ++i) {
- if ((*priv->rxqs)[i] == NULL)
- continue;
- idx = (*priv->rxqs)[i]->stats.idx;
- (*priv->rxqs)[i]->stats =
- (struct mlx4_rxq_stats){ .idx = idx };
+ for (i = 0; i != dev->data->nb_rx_queues; ++i) {
+ struct rxq *rxq = dev->data->rx_queues[i];
+
+ if (rxq)
+ rxq->stats = (struct mlx4_rxq_stats){
+ .idx = rxq->stats.idx,
+ };
}
- for (i = 0; (i != priv->txqs_n); ++i) {
- if ((*priv->txqs)[i] == NULL)
- continue;
- idx = (*priv->txqs)[i]->stats.idx;
- (*priv->txqs)[i]->stats =
- (struct mlx4_txq_stats){ .idx = idx };
+ for (i = 0; i != dev->data->nb_tx_queues; ++i) {
+ struct txq *txq = dev->data->tx_queues[i];
+
+ if (txq)
+ txq->stats = (struct mlx4_txq_stats){
+ .idx = txq->stats.idx,
+ };
}
}
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;
+}