1 /*- 2 * BSD LICENSE 3 * 4 * Copyright 2015 6WIND S.A. 5 * Copyright 2015 Mellanox. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of 6WIND S.A. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stddef.h> 35 #include <errno.h> 36 #include <assert.h> 37 #include <stdint.h> 38 39 #include <rte_ethdev.h> 40 #include <rte_common.h> 41 42 #include "mlx5_utils.h" 43 #include "mlx5.h" 44 #include "mlx5_autoconf.h" 45 46 /** 47 * DPDK callback to configure a VLAN filter. 48 * 49 * @param dev 50 * Pointer to Ethernet device structure. 51 * @param vlan_id 52 * VLAN ID to filter. 53 * @param on 54 * Toggle filter. 55 * 56 * @return 57 * 0 on success, a negative errno value otherwise and rte_errno is set. 58 */ 59 int 60 mlx5_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 61 { 62 struct priv *priv = dev->data->dev_private; 63 unsigned int i; 64 65 DRV_LOG(DEBUG, "port %u %s VLAN filter ID %" PRIu16, 66 dev->data->port_id, (on ? "enable" : "disable"), vlan_id); 67 assert(priv->vlan_filter_n <= RTE_DIM(priv->vlan_filter)); 68 for (i = 0; (i != priv->vlan_filter_n); ++i) 69 if (priv->vlan_filter[i] == vlan_id) 70 break; 71 /* Check if there's room for another VLAN filter. */ 72 if (i == RTE_DIM(priv->vlan_filter)) { 73 rte_errno = ENOMEM; 74 return -rte_errno; 75 } 76 if (i < priv->vlan_filter_n) { 77 assert(priv->vlan_filter_n != 0); 78 /* Enabling an existing VLAN filter has no effect. */ 79 if (on) 80 goto out; 81 /* Remove VLAN filter from list. */ 82 --priv->vlan_filter_n; 83 memmove(&priv->vlan_filter[i], 84 &priv->vlan_filter[i + 1], 85 sizeof(priv->vlan_filter[i]) * 86 (priv->vlan_filter_n - i)); 87 priv->vlan_filter[priv->vlan_filter_n] = 0; 88 } else { 89 assert(i == priv->vlan_filter_n); 90 /* Disabling an unknown VLAN filter has no effect. */ 91 if (!on) 92 goto out; 93 /* Add new VLAN filter. */ 94 priv->vlan_filter[priv->vlan_filter_n] = vlan_id; 95 ++priv->vlan_filter_n; 96 } 97 out: 98 if (dev->data->dev_started) 99 return mlx5_traffic_restart(dev); 100 return 0; 101 } 102 103 /** 104 * Callback to set/reset VLAN stripping for a specific queue. 105 * 106 * @param dev 107 * Pointer to Ethernet device structure. 108 * @param queue 109 * RX queue index. 110 * @param on 111 * Enable/disable VLAN stripping. 112 */ 113 void 114 mlx5_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on) 115 { 116 struct priv *priv = dev->data->dev_private; 117 struct mlx5_rxq_data *rxq = (*priv->rxqs)[queue]; 118 struct mlx5_rxq_ctrl *rxq_ctrl = 119 container_of(rxq, struct mlx5_rxq_ctrl, rxq); 120 struct ibv_wq_attr mod; 121 uint16_t vlan_offloads = 122 (on ? IBV_WQ_FLAGS_CVLAN_STRIPPING : 0) | 123 0; 124 int ret; 125 126 /* Validate hw support */ 127 if (!priv->hw_vlan_strip) { 128 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 129 dev->data->port_id); 130 return; 131 } 132 /* Validate queue number */ 133 if (queue >= priv->rxqs_n) { 134 DRV_LOG(ERR, "port %u VLAN stripping, invalid queue number %d", 135 dev->data->port_id, queue); 136 return; 137 } 138 DRV_LOG(DEBUG, "port %u set VLAN offloads 0x%x for port %uqueue %d", 139 dev->data->port_id, vlan_offloads, rxq->port_id, queue); 140 if (!rxq_ctrl->ibv) { 141 /* Update related bits in RX queue. */ 142 rxq->vlan_strip = !!on; 143 return; 144 } 145 mod = (struct ibv_wq_attr){ 146 .attr_mask = IBV_WQ_ATTR_FLAGS, 147 .flags_mask = IBV_WQ_FLAGS_CVLAN_STRIPPING, 148 .flags = vlan_offloads, 149 }; 150 ret = ibv_modify_wq(rxq_ctrl->ibv->wq, &mod); 151 if (ret) { 152 DRV_LOG(ERR, "port %u failed to modified stripping mode: %s", 153 dev->data->port_id, strerror(rte_errno)); 154 return; 155 } 156 /* Update related bits in RX queue. */ 157 rxq->vlan_strip = !!on; 158 } 159 160 /** 161 * Callback to set/reset VLAN offloads for a port. 162 * 163 * @param dev 164 * Pointer to Ethernet device structure. 165 * @param mask 166 * VLAN offload bit mask. 167 * 168 * @return 169 * 0 on success, a negative errno value otherwise and rte_errno is set. 170 */ 171 int 172 mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask) 173 { 174 struct priv *priv = dev->data->dev_private; 175 unsigned int i; 176 177 if (mask & ETH_VLAN_STRIP_MASK) { 178 int hw_vlan_strip = !!dev->data->dev_conf.rxmode.hw_vlan_strip; 179 180 if (!priv->hw_vlan_strip) { 181 DRV_LOG(ERR, "port %u VLAN stripping is not supported", 182 dev->data->port_id); 183 return 0; 184 } 185 /* Run on every RX queue and set/reset VLAN stripping. */ 186 for (i = 0; (i != priv->rxqs_n); i++) 187 mlx5_vlan_strip_queue_set(dev, i, hw_vlan_strip); 188 } 189 return 0; 190 } 191