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 = 0; 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->obj) { 131 /* Update related bits in RX queue. */ 132 rxq->vlan_strip = !!on; 133 return; 134 } 135 if (rxq_ctrl->obj->type == MLX5_RXQ_OBJ_TYPE_IBV) { 136 mod = (struct ibv_wq_attr){ 137 .attr_mask = IBV_WQ_ATTR_FLAGS, 138 .flags_mask = IBV_WQ_FLAGS_CVLAN_STRIPPING, 139 .flags = vlan_offloads, 140 }; 141 ret = mlx5_glue->modify_wq(rxq_ctrl->obj->wq, &mod); 142 } else if (rxq_ctrl->obj->type == MLX5_RXQ_OBJ_TYPE_DEVX_RQ) { 143 struct mlx5_devx_modify_rq_attr rq_attr; 144 145 memset(&rq_attr, 0, sizeof(rq_attr)); 146 rq_attr.rq_state = MLX5_RQC_STATE_RDY; 147 rq_attr.state = MLX5_RQC_STATE_RDY; 148 rq_attr.vsd = (on ? 0 : 1); 149 rq_attr.modify_bitmask = MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_VSD; 150 ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr); 151 } 152 if (ret) { 153 DRV_LOG(ERR, "port %u failed to modify object %d stripping " 154 "mode: %s", dev->data->port_id, 155 rxq_ctrl->obj->type, strerror(rte_errno)); 156 return; 157 } 158 /* Update related bits in RX queue. */ 159 rxq->vlan_strip = !!on; 160 } 161 162 /** 163 * Callback to set/reset VLAN offloads for a port. 164 * 165 * @param dev 166 * Pointer to Ethernet device structure. 167 * @param mask 168 * VLAN offload bit mask. 169 * 170 * @return 171 * 0 on success, a negative errno value otherwise and rte_errno is set. 172 */ 173 int 174 mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask) 175 { 176 struct mlx5_priv *priv = dev->data->dev_private; 177 unsigned int i; 178 179 if (mask & ETH_VLAN_STRIP_MASK) { 180 int hw_vlan_strip = !!(dev->data->dev_conf.rxmode.offloads & 181 DEV_RX_OFFLOAD_VLAN_STRIP); 182 183 if (!priv->config.hw_vlan_strip) { 184 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 185 dev->data->port_id); 186 return 0; 187 } 188 /* Run on every RX queue and set/reset VLAN stripping. */ 189 for (i = 0; (i != priv->rxqs_n); i++) 190 mlx5_vlan_strip_queue_set(dev, i, hw_vlan_strip); 191 } 192 return 0; 193 } 194