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 no_effect; 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 no_effect; 70 /* Add new VLAN filter. */ 71 priv->vlan_filter[priv->vlan_filter_n] = vlan_id; 72 ++priv->vlan_filter_n; 73 } 74 return on ? mlx5_traffic_vlan_add(dev, vlan_id) : mlx5_traffic_vlan_remove(dev, vlan_id); 75 no_effect: 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_priv *rxq = mlx5_rxq_get(dev, queue); 94 struct mlx5_rxq_data *rxq_data = &rxq->ctrl->rxq; 95 int ret = 0; 96 97 MLX5_ASSERT(rxq != NULL && rxq->ctrl != NULL); 98 /* Validate hw support */ 99 if (!priv->sh->dev_cap.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_data->port_id, queue); 112 if (rxq->ctrl->obj == NULL) { 113 /* Update related bits in RX queue. */ 114 rxq_data->vlan_strip = !!on; 115 return; 116 } 117 ret = priv->obj_ops.rxq_obj_modify_vlan_strip(rxq, on); 118 if (ret) { 119 DRV_LOG(ERR, "Port %u failed to modify object stripping mode:" 120 " %s", dev->data->port_id, strerror(rte_errno)); 121 return; 122 } 123 /* Update related bits in RX queue. */ 124 rxq_data->vlan_strip = !!on; 125 } 126 127 /** 128 * Callback to set/reset VLAN offloads for a port. 129 * 130 * @param dev 131 * Pointer to Ethernet device structure. 132 * @param mask 133 * VLAN offload bit mask. 134 * 135 * @return 136 * 0 on success, a negative errno value otherwise and rte_errno is set. 137 */ 138 int 139 mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask) 140 { 141 struct mlx5_priv *priv = dev->data->dev_private; 142 unsigned int i; 143 144 if (mask & RTE_ETH_VLAN_STRIP_MASK) { 145 int hw_vlan_strip = !!(dev->data->dev_conf.rxmode.offloads & 146 RTE_ETH_RX_OFFLOAD_VLAN_STRIP); 147 148 if (!priv->sh->dev_cap.hw_vlan_strip) { 149 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 150 dev->data->port_id); 151 return 0; 152 } 153 /* Run on every RX queue and set/reset VLAN stripping. */ 154 for (i = 0; (i != priv->rxqs_n); i++) 155 mlx5_vlan_strip_queue_set(dev, i, hw_vlan_strip); 156 } 157 return 0; 158 } 159