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 <stdint.h> 9 #include <unistd.h> 10 11 #include <rte_ethdev_driver.h> 12 #include <rte_common.h> 13 #include <rte_malloc.h> 14 #include <rte_hypervisor.h> 15 16 #include "mlx5.h" 17 #include "mlx5_autoconf.h" 18 #include "mlx5_rxtx.h" 19 #include "mlx5_utils.h" 20 #include "mlx5_devx.h" 21 22 /** 23 * DPDK callback to configure a VLAN filter. 24 * 25 * @param dev 26 * Pointer to Ethernet device structure. 27 * @param vlan_id 28 * VLAN ID to filter. 29 * @param on 30 * Toggle filter. 31 * 32 * @return 33 * 0 on success, a negative errno value otherwise and rte_errno is set. 34 */ 35 int 36 mlx5_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 37 { 38 struct mlx5_priv *priv = dev->data->dev_private; 39 unsigned int i; 40 41 DRV_LOG(DEBUG, "port %u %s VLAN filter ID %" PRIu16, 42 dev->data->port_id, (on ? "enable" : "disable"), vlan_id); 43 MLX5_ASSERT(priv->vlan_filter_n <= RTE_DIM(priv->vlan_filter)); 44 for (i = 0; (i != priv->vlan_filter_n); ++i) 45 if (priv->vlan_filter[i] == vlan_id) 46 break; 47 /* Check if there's room for another VLAN filter. */ 48 if (i == RTE_DIM(priv->vlan_filter)) { 49 rte_errno = ENOMEM; 50 return -rte_errno; 51 } 52 if (i < priv->vlan_filter_n) { 53 MLX5_ASSERT(priv->vlan_filter_n != 0); 54 /* Enabling an existing VLAN filter has no effect. */ 55 if (on) 56 goto out; 57 /* Remove VLAN filter from list. */ 58 --priv->vlan_filter_n; 59 memmove(&priv->vlan_filter[i], 60 &priv->vlan_filter[i + 1], 61 sizeof(priv->vlan_filter[i]) * 62 (priv->vlan_filter_n - i)); 63 priv->vlan_filter[priv->vlan_filter_n] = 0; 64 } else { 65 MLX5_ASSERT(i == priv->vlan_filter_n); 66 /* Disabling an unknown VLAN filter has no effect. */ 67 if (!on) 68 goto out; 69 /* Add new VLAN filter. */ 70 priv->vlan_filter[priv->vlan_filter_n] = vlan_id; 71 ++priv->vlan_filter_n; 72 } 73 out: 74 if (dev->data->dev_started) 75 return mlx5_traffic_restart(dev); 76 return 0; 77 } 78 79 /** 80 * Callback to set/reset VLAN stripping for a specific queue. 81 * 82 * @param dev 83 * Pointer to Ethernet device structure. 84 * @param queue 85 * RX queue index. 86 * @param on 87 * Enable/disable VLAN stripping. 88 */ 89 void 90 mlx5_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on) 91 { 92 struct mlx5_priv *priv = dev->data->dev_private; 93 struct mlx5_rxq_data *rxq = (*priv->rxqs)[queue]; 94 struct mlx5_rxq_ctrl *rxq_ctrl = 95 container_of(rxq, struct mlx5_rxq_ctrl, rxq); 96 int ret = 0; 97 98 /* Validate hw support */ 99 if (!priv->config.hw_vlan_strip) { 100 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 101 dev->data->port_id); 102 return; 103 } 104 /* Validate queue number */ 105 if (queue >= priv->rxqs_n) { 106 DRV_LOG(ERR, "port %u VLAN stripping, invalid queue number %d", 107 dev->data->port_id, queue); 108 return; 109 } 110 DRV_LOG(DEBUG, "port %u set VLAN stripping offloads %d for port %uqueue %d", 111 dev->data->port_id, on, rxq->port_id, queue); 112 if (!rxq_ctrl->obj) { 113 /* Update related bits in RX queue. */ 114 rxq->vlan_strip = !!on; 115 return; 116 } 117 ret = priv->obj_ops.rxq_obj_modify_vlan_strip(rxq_ctrl->obj, on); 118 if (ret) { 119 DRV_LOG(ERR, "port %u failed to modify object %d stripping " 120 "mode: %s", dev->data->port_id, 121 rxq_ctrl->obj->type, strerror(rte_errno)); 122 return; 123 } 124 /* Update related bits in RX queue. */ 125 rxq->vlan_strip = !!on; 126 } 127 128 /** 129 * Callback to set/reset VLAN offloads for a port. 130 * 131 * @param dev 132 * Pointer to Ethernet device structure. 133 * @param mask 134 * VLAN offload bit mask. 135 * 136 * @return 137 * 0 on success, a negative errno value otherwise and rte_errno is set. 138 */ 139 int 140 mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask) 141 { 142 struct mlx5_priv *priv = dev->data->dev_private; 143 unsigned int i; 144 145 if (mask & ETH_VLAN_STRIP_MASK) { 146 int hw_vlan_strip = !!(dev->data->dev_conf.rxmode.offloads & 147 DEV_RX_OFFLOAD_VLAN_STRIP); 148 149 if (!priv->config.hw_vlan_strip) { 150 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 151 dev->data->port_id); 152 return 0; 153 } 154 /* Run on every RX queue and set/reset VLAN stripping. */ 155 for (i = 0; (i != priv->rxqs_n); i++) 156 mlx5_vlan_strip_queue_set(dev, i, hw_vlan_strip); 157 } 158 return 0; 159 } 160