1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2015 6WIND S.A. 3 * Copyright 2015 Mellanox Technologies, Ltd 4 */ 5 6 #include <stddef.h> 7 #include <errno.h> 8 #include <assert.h> 9 #include <stdint.h> 10 11 /* 12 * Not needed by this file; included to work around the lack of off_t 13 * definition for mlx5dv.h with unpatched rdma-core versions. 14 */ 15 #include <sys/types.h> 16 17 /* Verbs headers do not support -pedantic. */ 18 #ifdef PEDANTIC 19 #pragma GCC diagnostic ignored "-Wpedantic" 20 #endif 21 #include <infiniband/mlx5dv.h> 22 #include <infiniband/verbs.h> 23 #ifdef PEDANTIC 24 #pragma GCC diagnostic error "-Wpedantic" 25 #endif 26 27 #include <rte_ethdev_driver.h> 28 #include <rte_common.h> 29 30 #include "mlx5.h" 31 #include "mlx5_autoconf.h" 32 #include "mlx5_glue.h" 33 #include "mlx5_rxtx.h" 34 #include "mlx5_utils.h" 35 36 /** 37 * DPDK callback to configure a VLAN filter. 38 * 39 * @param dev 40 * Pointer to Ethernet device structure. 41 * @param vlan_id 42 * VLAN ID to filter. 43 * @param on 44 * Toggle filter. 45 * 46 * @return 47 * 0 on success, a negative errno value otherwise and rte_errno is set. 48 */ 49 int 50 mlx5_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 51 { 52 struct mlx5_priv *priv = dev->data->dev_private; 53 unsigned int i; 54 55 DRV_LOG(DEBUG, "port %u %s VLAN filter ID %" PRIu16, 56 dev->data->port_id, (on ? "enable" : "disable"), vlan_id); 57 assert(priv->vlan_filter_n <= RTE_DIM(priv->vlan_filter)); 58 for (i = 0; (i != priv->vlan_filter_n); ++i) 59 if (priv->vlan_filter[i] == vlan_id) 60 break; 61 /* Check if there's room for another VLAN filter. */ 62 if (i == RTE_DIM(priv->vlan_filter)) { 63 rte_errno = ENOMEM; 64 return -rte_errno; 65 } 66 if (i < priv->vlan_filter_n) { 67 assert(priv->vlan_filter_n != 0); 68 /* Enabling an existing VLAN filter has no effect. */ 69 if (on) 70 goto out; 71 /* Remove VLAN filter from list. */ 72 --priv->vlan_filter_n; 73 memmove(&priv->vlan_filter[i], 74 &priv->vlan_filter[i + 1], 75 sizeof(priv->vlan_filter[i]) * 76 (priv->vlan_filter_n - i)); 77 priv->vlan_filter[priv->vlan_filter_n] = 0; 78 } else { 79 assert(i == priv->vlan_filter_n); 80 /* Disabling an unknown VLAN filter has no effect. */ 81 if (!on) 82 goto out; 83 /* Add new VLAN filter. */ 84 priv->vlan_filter[priv->vlan_filter_n] = vlan_id; 85 ++priv->vlan_filter_n; 86 } 87 out: 88 if (dev->data->dev_started) 89 return mlx5_traffic_restart(dev); 90 return 0; 91 } 92 93 /** 94 * Callback to set/reset VLAN stripping for a specific queue. 95 * 96 * @param dev 97 * Pointer to Ethernet device structure. 98 * @param queue 99 * RX queue index. 100 * @param on 101 * Enable/disable VLAN stripping. 102 */ 103 void 104 mlx5_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on) 105 { 106 struct mlx5_priv *priv = dev->data->dev_private; 107 struct mlx5_rxq_data *rxq = (*priv->rxqs)[queue]; 108 struct mlx5_rxq_ctrl *rxq_ctrl = 109 container_of(rxq, struct mlx5_rxq_ctrl, rxq); 110 struct ibv_wq_attr mod; 111 uint16_t vlan_offloads = 112 (on ? IBV_WQ_FLAGS_CVLAN_STRIPPING : 0) | 113 0; 114 int ret; 115 116 /* Validate hw support */ 117 if (!priv->config.hw_vlan_strip) { 118 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 119 dev->data->port_id); 120 return; 121 } 122 /* Validate queue number */ 123 if (queue >= priv->rxqs_n) { 124 DRV_LOG(ERR, "port %u VLAN stripping, invalid queue number %d", 125 dev->data->port_id, queue); 126 return; 127 } 128 DRV_LOG(DEBUG, "port %u set VLAN offloads 0x%x for port %uqueue %d", 129 dev->data->port_id, vlan_offloads, rxq->port_id, queue); 130 if (!rxq_ctrl->ibv) { 131 /* Update related bits in RX queue. */ 132 rxq->vlan_strip = !!on; 133 return; 134 } 135 mod = (struct ibv_wq_attr){ 136 .attr_mask = IBV_WQ_ATTR_FLAGS, 137 .flags_mask = IBV_WQ_FLAGS_CVLAN_STRIPPING, 138 .flags = vlan_offloads, 139 }; 140 ret = mlx5_glue->modify_wq(rxq_ctrl->ibv->wq, &mod); 141 if (ret) { 142 DRV_LOG(ERR, "port %u failed to modified stripping mode: %s", 143 dev->data->port_id, strerror(rte_errno)); 144 return; 145 } 146 /* Update related bits in RX queue. */ 147 rxq->vlan_strip = !!on; 148 } 149 150 /** 151 * Callback to set/reset VLAN offloads for a port. 152 * 153 * @param dev 154 * Pointer to Ethernet device structure. 155 * @param mask 156 * VLAN offload bit mask. 157 * 158 * @return 159 * 0 on success, a negative errno value otherwise and rte_errno is set. 160 */ 161 int 162 mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask) 163 { 164 struct mlx5_priv *priv = dev->data->dev_private; 165 unsigned int i; 166 167 if (mask & ETH_VLAN_STRIP_MASK) { 168 int hw_vlan_strip = !!(dev->data->dev_conf.rxmode.offloads & 169 DEV_RX_OFFLOAD_VLAN_STRIP); 170 171 if (!priv->config.hw_vlan_strip) { 172 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 173 dev->data->port_id); 174 return 0; 175 } 176 /* Run on every RX queue and set/reset VLAN stripping. */ 177 for (i = 0; (i != priv->rxqs_n); i++) 178 mlx5_vlan_strip_queue_set(dev, i, hw_vlan_strip); 179 } 180 return 0; 181 } 182