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 <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_rx.h" 20 #include "mlx5_utils.h" 21 #include "mlx5_devx.h" 22 23 /** 24 * DPDK callback to configure a VLAN filter. 25 * 26 * @param dev 27 * Pointer to Ethernet device structure. 28 * @param vlan_id 29 * VLAN ID to filter. 30 * @param on 31 * Toggle filter. 32 * 33 * @return 34 * 0 on success, a negative errno value otherwise and rte_errno is set. 35 */ 36 int 37 mlx5_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 38 { 39 struct mlx5_priv *priv = dev->data->dev_private; 40 unsigned int i; 41 42 DRV_LOG(DEBUG, "port %u %s VLAN filter ID %" PRIu16, 43 dev->data->port_id, (on ? "enable" : "disable"), vlan_id); 44 MLX5_ASSERT(priv->vlan_filter_n <= RTE_DIM(priv->vlan_filter)); 45 for (i = 0; (i != priv->vlan_filter_n); ++i) 46 if (priv->vlan_filter[i] == vlan_id) 47 break; 48 /* Check if there's room for another VLAN filter. */ 49 if (i == RTE_DIM(priv->vlan_filter)) { 50 rte_errno = ENOMEM; 51 return -rte_errno; 52 } 53 if (i < priv->vlan_filter_n) { 54 MLX5_ASSERT(priv->vlan_filter_n != 0); 55 /* Enabling an existing VLAN filter has no effect. */ 56 if (on) 57 goto out; 58 /* Remove VLAN filter from list. */ 59 --priv->vlan_filter_n; 60 memmove(&priv->vlan_filter[i], 61 &priv->vlan_filter[i + 1], 62 sizeof(priv->vlan_filter[i]) * 63 (priv->vlan_filter_n - i)); 64 priv->vlan_filter[priv->vlan_filter_n] = 0; 65 } else { 66 MLX5_ASSERT(i == priv->vlan_filter_n); 67 /* Disabling an unknown VLAN filter has no effect. */ 68 if (!on) 69 goto out; 70 /* Add new VLAN filter. */ 71 priv->vlan_filter[priv->vlan_filter_n] = vlan_id; 72 ++priv->vlan_filter_n; 73 } 74 out: 75 if (dev->data->dev_started) 76 return mlx5_traffic_restart(dev); 77 return 0; 78 } 79 80 /** 81 * Callback to set/reset VLAN stripping for a specific queue. 82 * 83 * @param dev 84 * Pointer to Ethernet device structure. 85 * @param queue 86 * RX queue index. 87 * @param on 88 * Enable/disable VLAN stripping. 89 */ 90 void 91 mlx5_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on) 92 { 93 struct mlx5_priv *priv = dev->data->dev_private; 94 struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, queue); 95 struct mlx5_rxq_data *rxq_data = &rxq->ctrl->rxq; 96 int ret = 0; 97 98 MLX5_ASSERT(rxq != NULL && rxq->ctrl != NULL); 99 /* Validate hw support */ 100 if (!priv->config.hw_vlan_strip) { 101 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 102 dev->data->port_id); 103 return; 104 } 105 /* Validate queue number */ 106 if (queue >= priv->rxqs_n) { 107 DRV_LOG(ERR, "port %u VLAN stripping, invalid queue number %d", 108 dev->data->port_id, queue); 109 return; 110 } 111 DRV_LOG(DEBUG, "port %u set VLAN stripping offloads %d for port %uqueue %d", 112 dev->data->port_id, on, rxq_data->port_id, queue); 113 if (rxq->ctrl->obj == NULL) { 114 /* Update related bits in RX queue. */ 115 rxq_data->vlan_strip = !!on; 116 return; 117 } 118 ret = priv->obj_ops.rxq_obj_modify_vlan_strip(rxq, on); 119 if (ret) { 120 DRV_LOG(ERR, "Port %u failed to modify object stripping mode:" 121 " %s", dev->data->port_id, strerror(rte_errno)); 122 return; 123 } 124 /* Update related bits in RX queue. */ 125 rxq_data->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 & RTE_ETH_VLAN_STRIP_MASK) { 146 int hw_vlan_strip = !!(dev->data->dev_conf.rxmode.offloads & 147 RTE_ETH_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