#include <linux/ethtool.h>
#include <fcntl.h>
-/* Verbs header. */
-/* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
-#ifdef PEDANTIC
-#pragma GCC diagnostic ignored "-Wpedantic"
-#endif
-#include <infiniband/verbs.h>
-#ifdef PEDANTIC
-#pragma GCC diagnostic error "-Wpedantic"
-#endif
-
#include <rte_malloc.h>
#include <rte_ethdev_driver.h>
#include <rte_ethdev_pci.h>
#define MLX5DV_CONTEXT_FLAGS_CQE_128B_COMP (1 << 4)
#endif
+static const char *MZ_MLX5_PMD_SHARED_DATA = "mlx5_pmd_shared_data";
+
+/* Spinlock for mlx5_shared_data allocation. */
+static rte_spinlock_t mlx5_shared_data_lock = RTE_SPINLOCK_INITIALIZER;
+
+/* Process local data for secondary processes. */
+static struct mlx5_local_data mlx5_local_data;
+
/**
- * Get MAC address by querying netdevice.
+ * Set the completion channel file descriptor interrupt as non-blocking.
*
- * @param[in] dev
- * Pointer to Ethernet device.
- * @param[out] mac
- * MAC address output buffer.
+ * @param[in] rxq_obj
+ * Pointer to RQ channel object, which includes the channel fd
+ *
+ * @param[out] fd
+ * The file descriptor (representing the intetrrupt) used in this channel.
*
* @return
- * 0 on success, a negative errno value otherwise and rte_errno is set.
+ * 0 on successfully setting the fd to non-blocking, non-zero otherwise.
*/
-static int
-mlx5_get_mac(struct rte_eth_dev *dev, uint8_t (*mac)[RTE_ETHER_ADDR_LEN])
+int
+mlx5_os_set_nonblock_channel_fd(int fd)
{
- struct ifreq request;
- int ret;
+ int flags;
- ret = mlx5_ifreq(dev, SIOCGIFHWADDR, &request);
- if (ret)
- return ret;
- memcpy(mac, request.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
- return 0;
+ flags = fcntl(fd, F_GETFL);
+ return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
/**
mlx5_free_table_hash_list(priv);
}
+/**
+ * Initialize shared data between primary and secondary process.
+ *
+ * A memzone is reserved by primary process and secondary processes attach to
+ * the memzone.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_init_shared_data(void)
+{
+ const struct rte_memzone *mz;
+ int ret = 0;
+
+ rte_spinlock_lock(&mlx5_shared_data_lock);
+ if (mlx5_shared_data == NULL) {
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ /* Allocate shared memory. */
+ mz = rte_memzone_reserve(MZ_MLX5_PMD_SHARED_DATA,
+ sizeof(*mlx5_shared_data),
+ SOCKET_ID_ANY, 0);
+ if (mz == NULL) {
+ DRV_LOG(ERR,
+ "Cannot allocate mlx5 shared data");
+ ret = -rte_errno;
+ goto error;
+ }
+ mlx5_shared_data = mz->addr;
+ memset(mlx5_shared_data, 0, sizeof(*mlx5_shared_data));
+ rte_spinlock_init(&mlx5_shared_data->lock);
+ } else {
+ /* Lookup allocated shared memory. */
+ mz = rte_memzone_lookup(MZ_MLX5_PMD_SHARED_DATA);
+ if (mz == NULL) {
+ DRV_LOG(ERR,
+ "Cannot attach mlx5 shared data");
+ ret = -rte_errno;
+ goto error;
+ }
+ mlx5_shared_data = mz->addr;
+ memset(&mlx5_local_data, 0, sizeof(mlx5_local_data));
+ }
+ }
+error:
+ rte_spinlock_unlock(&mlx5_shared_data_lock);
+ return ret;
+}
+
+/**
+ * PMD global initialization.
+ *
+ * Independent from individual device, this function initializes global
+ * per-PMD data structures distinguishing primary and secondary processes.
+ * Hence, each initialization is called once per a process.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_init_once(void)
+{
+ struct mlx5_shared_data *sd;
+ struct mlx5_local_data *ld = &mlx5_local_data;
+ int ret = 0;
+
+ if (mlx5_init_shared_data())
+ return -rte_errno;
+ sd = mlx5_shared_data;
+ MLX5_ASSERT(sd);
+ rte_spinlock_lock(&sd->lock);
+ switch (rte_eal_process_type()) {
+ case RTE_PROC_PRIMARY:
+ if (sd->init_done)
+ break;
+ LIST_INIT(&sd->mem_event_cb_list);
+ rte_rwlock_init(&sd->mem_event_rwlock);
+ rte_mem_event_callback_register("MLX5_MEM_EVENT_CB",
+ mlx5_mr_mem_event_cb, NULL);
+ ret = mlx5_mp_init_primary(MLX5_MP_NAME,
+ mlx5_mp_os_primary_handle);
+ if (ret)
+ goto out;
+ sd->init_done = true;
+ break;
+ case RTE_PROC_SECONDARY:
+ if (ld->init_done)
+ break;
+ ret = mlx5_mp_init_secondary(MLX5_MP_NAME,
+ mlx5_mp_os_secondary_handle);
+ if (ret)
+ goto out;
+ ++sd->secondary_cnt;
+ ld->init_done = true;
+ break;
+ default:
+ break;
+ }
+out:
+ rte_spinlock_unlock(&sd->lock);
+ return ret;
+}
+
/**
* Spawn an Ethernet device from Verbs information.
*
return 1;
}
-/**
- * Read device counters table.
- *
- * @param dev
- * Pointer to Ethernet device.
- * @param[out] stats
- * Counters table output buffer.
- *
- * @return
- * 0 on success and stats is filled, negative errno value otherwise and
- * rte_errno is set.
- */
-int
-mlx5_os_read_dev_counters(struct rte_eth_dev *dev, uint64_t *stats)
-{
- struct mlx5_priv *priv = dev->data->dev_private;
- struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
- unsigned int i;
- struct ifreq ifr;
- unsigned int stats_sz = xstats_ctrl->stats_n * sizeof(uint64_t);
- unsigned char et_stat_buf[sizeof(struct ethtool_stats) + stats_sz];
- struct ethtool_stats *et_stats = (struct ethtool_stats *)et_stat_buf;
- int ret;
-
- et_stats->cmd = ETHTOOL_GSTATS;
- et_stats->n_stats = xstats_ctrl->stats_n;
- ifr.ifr_data = (caddr_t)et_stats;
- ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
- if (ret) {
- DRV_LOG(WARNING,
- "port %u unable to read statistic values from device",
- dev->data->port_id);
- return ret;
- }
- for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) {
- if (xstats_ctrl->info[i].dev) {
- ret = mlx5_os_read_dev_stat(priv,
- xstats_ctrl->info[i].ctr_name,
- &stats[i]);
- /* return last xstats counter if fail to read. */
- if (ret == 0)
- xstats_ctrl->xstats[i] = stats[i];
- else
- stats[i] = xstats_ctrl->xstats[i];
- } else {
- stats[i] = (uint64_t)
- et_stats->data[xstats_ctrl->dev_table_idx[i]];
- }
- }
- return 0;
-}
-
-/**
- * Query the number of statistics provided by ETHTOOL.
- *
- * @param dev
- * Pointer to Ethernet device.
- *
- * @return
- * Number of statistics on success, negative errno value otherwise and
- * rte_errno is set.
- */
-int
-mlx5_os_get_stats_n(struct rte_eth_dev *dev)
-{
- struct ethtool_drvinfo drvinfo;
- struct ifreq ifr;
- int ret;
-
- drvinfo.cmd = ETHTOOL_GDRVINFO;
- ifr.ifr_data = (caddr_t)&drvinfo;
- ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
- if (ret) {
- DRV_LOG(WARNING, "port %u unable to query number of statistics",
- dev->data->port_id);
- return ret;
- }
- return drvinfo.n_stats;
-}
-
-static const struct mlx5_counter_ctrl mlx5_counters_init[] = {
- {
- .dpdk_name = "rx_port_unicast_bytes",
- .ctr_name = "rx_vport_unicast_bytes",
- },
- {
- .dpdk_name = "rx_port_multicast_bytes",
- .ctr_name = "rx_vport_multicast_bytes",
- },
- {
- .dpdk_name = "rx_port_broadcast_bytes",
- .ctr_name = "rx_vport_broadcast_bytes",
- },
- {
- .dpdk_name = "rx_port_unicast_packets",
- .ctr_name = "rx_vport_unicast_packets",
- },
- {
- .dpdk_name = "rx_port_multicast_packets",
- .ctr_name = "rx_vport_multicast_packets",
- },
- {
- .dpdk_name = "rx_port_broadcast_packets",
- .ctr_name = "rx_vport_broadcast_packets",
- },
- {
- .dpdk_name = "tx_port_unicast_bytes",
- .ctr_name = "tx_vport_unicast_bytes",
- },
- {
- .dpdk_name = "tx_port_multicast_bytes",
- .ctr_name = "tx_vport_multicast_bytes",
- },
- {
- .dpdk_name = "tx_port_broadcast_bytes",
- .ctr_name = "tx_vport_broadcast_bytes",
- },
- {
- .dpdk_name = "tx_port_unicast_packets",
- .ctr_name = "tx_vport_unicast_packets",
- },
- {
- .dpdk_name = "tx_port_multicast_packets",
- .ctr_name = "tx_vport_multicast_packets",
- },
- {
- .dpdk_name = "tx_port_broadcast_packets",
- .ctr_name = "tx_vport_broadcast_packets",
- },
- {
- .dpdk_name = "rx_wqe_err",
- .ctr_name = "rx_wqe_err",
- },
- {
- .dpdk_name = "rx_crc_errors_phy",
- .ctr_name = "rx_crc_errors_phy",
- },
- {
- .dpdk_name = "rx_in_range_len_errors_phy",
- .ctr_name = "rx_in_range_len_errors_phy",
- },
- {
- .dpdk_name = "rx_symbol_err_phy",
- .ctr_name = "rx_symbol_err_phy",
- },
- {
- .dpdk_name = "tx_errors_phy",
- .ctr_name = "tx_errors_phy",
- },
- {
- .dpdk_name = "rx_out_of_buffer",
- .ctr_name = "out_of_buffer",
- .dev = 1,
- },
- {
- .dpdk_name = "tx_packets_phy",
- .ctr_name = "tx_packets_phy",
- },
- {
- .dpdk_name = "rx_packets_phy",
- .ctr_name = "rx_packets_phy",
- },
- {
- .dpdk_name = "tx_discards_phy",
- .ctr_name = "tx_discards_phy",
- },
- {
- .dpdk_name = "rx_discards_phy",
- .ctr_name = "rx_discards_phy",
- },
- {
- .dpdk_name = "tx_bytes_phy",
- .ctr_name = "tx_bytes_phy",
- },
- {
- .dpdk_name = "rx_bytes_phy",
- .ctr_name = "rx_bytes_phy",
- },
- /* Representor only */
- {
- .dpdk_name = "rx_packets",
- .ctr_name = "vport_rx_packets",
- },
- {
- .dpdk_name = "rx_bytes",
- .ctr_name = "vport_rx_bytes",
- },
- {
- .dpdk_name = "tx_packets",
- .ctr_name = "vport_tx_packets",
- },
- {
- .dpdk_name = "tx_bytes",
- .ctr_name = "vport_tx_bytes",
- },
-};
-
-static const unsigned int xstats_n = RTE_DIM(mlx5_counters_init);
-
-/**
- * Init the structures to read device counters.
- *
- * @param dev
- * Pointer to Ethernet device.
- */
-void
-mlx5_os_stats_init(struct rte_eth_dev *dev)
-{
- struct mlx5_priv *priv = dev->data->dev_private;
- struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
- struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
- unsigned int i;
- unsigned int j;
- struct ifreq ifr;
- struct ethtool_gstrings *strings = NULL;
- unsigned int dev_stats_n;
- unsigned int str_sz;
- int ret;
-
- /* So that it won't aggregate for each init. */
- xstats_ctrl->mlx5_stats_n = 0;
- ret = mlx5_os_get_stats_n(dev);
- if (ret < 0) {
- DRV_LOG(WARNING, "port %u no extended statistics available",
- dev->data->port_id);
- return;
- }
- dev_stats_n = ret;
- /* Allocate memory to grab stat names and values. */
- str_sz = dev_stats_n * ETH_GSTRING_LEN;
- strings = (struct ethtool_gstrings *)
- mlx5_malloc(0, str_sz + sizeof(struct ethtool_gstrings), 0,
- SOCKET_ID_ANY);
- if (!strings) {
- DRV_LOG(WARNING, "port %u unable to allocate memory for xstats",
- dev->data->port_id);
- return;
- }
- strings->cmd = ETHTOOL_GSTRINGS;
- strings->string_set = ETH_SS_STATS;
- strings->len = dev_stats_n;
- ifr.ifr_data = (caddr_t)strings;
- ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
- if (ret) {
- DRV_LOG(WARNING, "port %u unable to get statistic names",
- dev->data->port_id);
- goto free;
- }
- for (i = 0; i != dev_stats_n; ++i) {
- const char *curr_string = (const char *)
- &strings->data[i * ETH_GSTRING_LEN];
-
- for (j = 0; j != xstats_n; ++j) {
- if (!strcmp(mlx5_counters_init[j].ctr_name,
- curr_string)) {
- unsigned int idx = xstats_ctrl->mlx5_stats_n++;
-
- xstats_ctrl->dev_table_idx[idx] = i;
- xstats_ctrl->info[idx] = mlx5_counters_init[j];
- break;
- }
- }
- }
- /* Add dev counters. */
- for (i = 0; i != xstats_n; ++i) {
- if (mlx5_counters_init[i].dev) {
- unsigned int idx = xstats_ctrl->mlx5_stats_n++;
-
- xstats_ctrl->info[idx] = mlx5_counters_init[i];
- xstats_ctrl->hw_stats[idx] = 0;
- }
- }
- MLX5_ASSERT(xstats_ctrl->mlx5_stats_n <= MLX5_MAX_XSTATS);
- xstats_ctrl->stats_n = dev_stats_n;
- /* Copy to base at first time. */
- ret = mlx5_os_read_dev_counters(dev, xstats_ctrl->base);
- if (ret)
- DRV_LOG(ERR, "port %u cannot read device counters: %s",
- dev->data->port_id, strerror(rte_errno));
- mlx5_os_read_dev_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
- stats_ctrl->imissed = 0;
-free:
- mlx5_free(strings);
-}
-
/**
* Set the reg_mr and dereg_mr call backs
*
(priv->nl_socket_route, iface_idx, mac_addr, vf_index);
}
+/**
+ * Set device promiscuous mode
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param enable
+ * 0 - promiscuous is disabled, otherwise - enabled
+ *
+ * @return
+ * 0 on success, a negative error value otherwise
+ */
+int
+mlx5_os_set_promisc(struct rte_eth_dev *dev, int enable)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+
+ return mlx5_nl_promisc(priv->nl_socket_route,
+ mlx5_ifindex(dev), !!enable);
+}
+
+/**
+ * Set device promiscuous mode
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param enable
+ * 0 - all multicase is disabled, otherwise - enabled
+ *
+ * @return
+ * 0 on success, a negative error value otherwise
+ */
+int
+mlx5_os_set_allmulti(struct rte_eth_dev *dev, int enable)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+
+ return mlx5_nl_allmulti(priv->nl_socket_route,
+ mlx5_ifindex(dev), !!enable);
+}
+
const struct eth_dev_ops mlx5_os_dev_ops = {
.dev_configure = mlx5_dev_configure,
.dev_start = mlx5_dev_start,
.tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
.rx_queue_release = mlx5_rx_queue_release,
.tx_queue_release = mlx5_tx_queue_release,
+ .rx_queue_start = mlx5_rx_queue_start,
+ .rx_queue_stop = mlx5_rx_queue_stop,
+ .tx_queue_start = mlx5_tx_queue_start,
+ .tx_queue_stop = mlx5_tx_queue_stop,
.flow_ctrl_get = mlx5_dev_get_flow_ctrl,
.flow_ctrl_set = mlx5_dev_set_flow_ctrl,
.mac_addr_remove = mlx5_mac_addr_remove,
.fw_version_get = mlx5_fw_version_get,
.dev_infos_get = mlx5_dev_infos_get,
.read_clock = mlx5_txpp_read_clock,
+ .rx_queue_start = mlx5_rx_queue_start,
+ .rx_queue_stop = mlx5_rx_queue_stop,
+ .tx_queue_start = mlx5_tx_queue_start,
+ .tx_queue_stop = mlx5_tx_queue_stop,
.rx_descriptor_status = mlx5_rx_descriptor_status,
.tx_descriptor_status = mlx5_tx_descriptor_status,
.rxq_info_get = mlx5_rxq_info_get,
.tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
.rx_queue_release = mlx5_rx_queue_release,
.tx_queue_release = mlx5_tx_queue_release,
+ .rx_queue_start = mlx5_rx_queue_start,
+ .rx_queue_stop = mlx5_rx_queue_stop,
+ .tx_queue_start = mlx5_tx_queue_start,
+ .tx_queue_stop = mlx5_tx_queue_stop,
.flow_ctrl_get = mlx5_dev_get_flow_ctrl,
.flow_ctrl_set = mlx5_dev_set_flow_ctrl,
.mac_addr_remove = mlx5_mac_addr_remove,