18fd92a66SOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause 2e9086978SAdrien Mazarguil * Copyright 2015 6WIND S.A. 3e9086978SAdrien Mazarguil * Copyright 2015 Mellanox. 4e9086978SAdrien Mazarguil */ 5e9086978SAdrien Mazarguil 6e9086978SAdrien Mazarguil #include <stddef.h> 7e9086978SAdrien Mazarguil #include <errno.h> 8e9086978SAdrien Mazarguil #include <assert.h> 9e9086978SAdrien Mazarguil #include <stdint.h> 10e9086978SAdrien Mazarguil 110e83b8e5SNelio Laranjeiro /* Verbs headers do not support -pedantic. */ 120e83b8e5SNelio Laranjeiro #ifdef PEDANTIC 130e83b8e5SNelio Laranjeiro #pragma GCC diagnostic ignored "-Wpedantic" 140e83b8e5SNelio Laranjeiro #endif 150e83b8e5SNelio Laranjeiro #include <infiniband/mlx5dv.h> 160e83b8e5SNelio Laranjeiro #include <infiniband/verbs.h> 170e83b8e5SNelio Laranjeiro #ifdef PEDANTIC 180e83b8e5SNelio Laranjeiro #pragma GCC diagnostic error "-Wpedantic" 190e83b8e5SNelio Laranjeiro #endif 200e83b8e5SNelio Laranjeiro 21ffc905f3SFerruh Yigit #include <rte_ethdev_driver.h> 22e9086978SAdrien Mazarguil #include <rte_common.h> 23e9086978SAdrien Mazarguil 24e9086978SAdrien Mazarguil #include "mlx5_utils.h" 25e9086978SAdrien Mazarguil #include "mlx5.h" 26f3db9489SYaacov Hazan #include "mlx5_autoconf.h" 270e83b8e5SNelio Laranjeiro #include "mlx5_glue.h" 28e9086978SAdrien Mazarguil 29e9086978SAdrien Mazarguil /** 30e9086978SAdrien Mazarguil * DPDK callback to configure a VLAN filter. 31e9086978SAdrien Mazarguil * 32e9086978SAdrien Mazarguil * @param dev 33e9086978SAdrien Mazarguil * Pointer to Ethernet device structure. 34e9086978SAdrien Mazarguil * @param vlan_id 35e9086978SAdrien Mazarguil * VLAN ID to filter. 36e9086978SAdrien Mazarguil * @param on 37e9086978SAdrien Mazarguil * Toggle filter. 38e9086978SAdrien Mazarguil * 39e9086978SAdrien Mazarguil * @return 40a6d83b6aSNélio Laranjeiro * 0 on success, a negative errno value otherwise and rte_errno is set. 41e9086978SAdrien Mazarguil */ 42e9086978SAdrien Mazarguil int 43e9086978SAdrien Mazarguil mlx5_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 44e9086978SAdrien Mazarguil { 45e9086978SAdrien Mazarguil struct priv *priv = dev->data->dev_private; 46272733b5SNélio Laranjeiro unsigned int i; 47e9086978SAdrien Mazarguil 48*a170a30dSNélio Laranjeiro DRV_LOG(DEBUG, "port %u %s VLAN filter ID %" PRIu16, 490f99970bSNélio Laranjeiro dev->data->port_id, (on ? "enable" : "disable"), vlan_id); 50272733b5SNélio Laranjeiro assert(priv->vlan_filter_n <= RTE_DIM(priv->vlan_filter)); 51272733b5SNélio Laranjeiro for (i = 0; (i != priv->vlan_filter_n); ++i) 52272733b5SNélio Laranjeiro if (priv->vlan_filter[i] == vlan_id) 53272733b5SNélio Laranjeiro break; 54e4aefd6dSNélio Laranjeiro /* Check if there's room for another VLAN filter. */ 55e4aefd6dSNélio Laranjeiro if (i == RTE_DIM(priv->vlan_filter)) { 56a6d83b6aSNélio Laranjeiro rte_errno = ENOMEM; 57a6d83b6aSNélio Laranjeiro return -rte_errno; 58e4aefd6dSNélio Laranjeiro } 59272733b5SNélio Laranjeiro if (i < priv->vlan_filter_n) { 60272733b5SNélio Laranjeiro assert(priv->vlan_filter_n != 0); 61272733b5SNélio Laranjeiro /* Enabling an existing VLAN filter has no effect. */ 62272733b5SNélio Laranjeiro if (on) 63272733b5SNélio Laranjeiro goto out; 64272733b5SNélio Laranjeiro /* Remove VLAN filter from list. */ 65272733b5SNélio Laranjeiro --priv->vlan_filter_n; 66272733b5SNélio Laranjeiro memmove(&priv->vlan_filter[i], 67272733b5SNélio Laranjeiro &priv->vlan_filter[i + 1], 68272733b5SNélio Laranjeiro sizeof(priv->vlan_filter[i]) * 69272733b5SNélio Laranjeiro (priv->vlan_filter_n - i)); 70272733b5SNélio Laranjeiro priv->vlan_filter[priv->vlan_filter_n] = 0; 71272733b5SNélio Laranjeiro } else { 72272733b5SNélio Laranjeiro assert(i == priv->vlan_filter_n); 73272733b5SNélio Laranjeiro /* Disabling an unknown VLAN filter has no effect. */ 74272733b5SNélio Laranjeiro if (!on) 75272733b5SNélio Laranjeiro goto out; 76272733b5SNélio Laranjeiro /* Add new VLAN filter. */ 77272733b5SNélio Laranjeiro priv->vlan_filter[priv->vlan_filter_n] = vlan_id; 78272733b5SNélio Laranjeiro ++priv->vlan_filter_n; 79272733b5SNélio Laranjeiro } 80272733b5SNélio Laranjeiro out: 81a6d83b6aSNélio Laranjeiro if (dev->data->dev_started) 82a6d83b6aSNélio Laranjeiro return mlx5_traffic_restart(dev); 83a6d83b6aSNélio Laranjeiro return 0; 84e9086978SAdrien Mazarguil } 85f3db9489SYaacov Hazan 86f3db9489SYaacov Hazan /** 87f3db9489SYaacov Hazan * Callback to set/reset VLAN stripping for a specific queue. 88f3db9489SYaacov Hazan * 89f3db9489SYaacov Hazan * @param dev 90f3db9489SYaacov Hazan * Pointer to Ethernet device structure. 91f3db9489SYaacov Hazan * @param queue 92f3db9489SYaacov Hazan * RX queue index. 93f3db9489SYaacov Hazan * @param on 94f3db9489SYaacov Hazan * Enable/disable VLAN stripping. 95f3db9489SYaacov Hazan */ 96f3db9489SYaacov Hazan void 97f3db9489SYaacov Hazan mlx5_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on) 98f3db9489SYaacov Hazan { 99f3db9489SYaacov Hazan struct priv *priv = dev->data->dev_private; 100af4f09f2SNélio Laranjeiro struct mlx5_rxq_data *rxq = (*priv->rxqs)[queue]; 101af4f09f2SNélio Laranjeiro struct mlx5_rxq_ctrl *rxq_ctrl = 102af4f09f2SNélio Laranjeiro container_of(rxq, struct mlx5_rxq_ctrl, rxq); 103af4f09f2SNélio Laranjeiro struct ibv_wq_attr mod; 104af4f09f2SNélio Laranjeiro uint16_t vlan_offloads = 105af4f09f2SNélio Laranjeiro (on ? IBV_WQ_FLAGS_CVLAN_STRIPPING : 0) | 106af4f09f2SNélio Laranjeiro 0; 107a6d83b6aSNélio Laranjeiro int ret; 108f3db9489SYaacov Hazan 109f3db9489SYaacov Hazan /* Validate hw support */ 1107fe24446SShahaf Shuler if (!priv->config.hw_vlan_strip) { 111*a170a30dSNélio Laranjeiro DRV_LOG(ERR, "port %u VLAN stripping is not supported", 1120f99970bSNélio Laranjeiro dev->data->port_id); 113f3db9489SYaacov Hazan return; 114f3db9489SYaacov Hazan } 115f3db9489SYaacov Hazan /* Validate queue number */ 116f3db9489SYaacov Hazan if (queue >= priv->rxqs_n) { 117*a170a30dSNélio Laranjeiro DRV_LOG(ERR, "port %u VLAN stripping, invalid queue number %d", 1180f99970bSNélio Laranjeiro dev->data->port_id, queue); 119f3db9489SYaacov Hazan return; 120f3db9489SYaacov Hazan } 121*a170a30dSNélio Laranjeiro DRV_LOG(DEBUG, "port %u set VLAN offloads 0x%x for port %uqueue %d", 1220f99970bSNélio Laranjeiro dev->data->port_id, vlan_offloads, rxq->port_id, queue); 123af4f09f2SNélio Laranjeiro if (!rxq_ctrl->ibv) { 124af4f09f2SNélio Laranjeiro /* Update related bits in RX queue. */ 125af4f09f2SNélio Laranjeiro rxq->vlan_strip = !!on; 126af4f09f2SNélio Laranjeiro return; 127af4f09f2SNélio Laranjeiro } 128af4f09f2SNélio Laranjeiro mod = (struct ibv_wq_attr){ 129af4f09f2SNélio Laranjeiro .attr_mask = IBV_WQ_ATTR_FLAGS, 130af4f09f2SNélio Laranjeiro .flags_mask = IBV_WQ_FLAGS_CVLAN_STRIPPING, 131af4f09f2SNélio Laranjeiro .flags = vlan_offloads, 132af4f09f2SNélio Laranjeiro }; 133a6d83b6aSNélio Laranjeiro ret = mlx5_glue->modify_wq(rxq_ctrl->ibv->wq, &mod); 134a6d83b6aSNélio Laranjeiro if (ret) { 135*a170a30dSNélio Laranjeiro DRV_LOG(ERR, "port %u failed to modified stripping mode: %s", 1360f99970bSNélio Laranjeiro dev->data->port_id, strerror(rte_errno)); 137af4f09f2SNélio Laranjeiro return; 138af4f09f2SNélio Laranjeiro } 139af4f09f2SNélio Laranjeiro /* Update related bits in RX queue. */ 140af4f09f2SNélio Laranjeiro rxq->vlan_strip = !!on; 141f3db9489SYaacov Hazan } 142f3db9489SYaacov Hazan 143f3db9489SYaacov Hazan /** 144f3db9489SYaacov Hazan * Callback to set/reset VLAN offloads for a port. 145f3db9489SYaacov Hazan * 146f3db9489SYaacov Hazan * @param dev 147f3db9489SYaacov Hazan * Pointer to Ethernet device structure. 148f3db9489SYaacov Hazan * @param mask 149f3db9489SYaacov Hazan * VLAN offload bit mask. 150a6d83b6aSNélio Laranjeiro * 151a6d83b6aSNélio Laranjeiro * @return 152a6d83b6aSNélio Laranjeiro * 0 on success, a negative errno value otherwise and rte_errno is set. 153f3db9489SYaacov Hazan */ 154289ba0c0SDavid Harton int 155f3db9489SYaacov Hazan mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask) 156f3db9489SYaacov Hazan { 157f3db9489SYaacov Hazan struct priv *priv = dev->data->dev_private; 158f3db9489SYaacov Hazan unsigned int i; 159f3db9489SYaacov Hazan 160f3db9489SYaacov Hazan if (mask & ETH_VLAN_STRIP_MASK) { 16117b843ebSShahaf Shuler int hw_vlan_strip = !!(dev->data->dev_conf.rxmode.offloads & 16217b843ebSShahaf Shuler DEV_RX_OFFLOAD_VLAN_STRIP); 163f3db9489SYaacov Hazan 1647fe24446SShahaf Shuler if (!priv->config.hw_vlan_strip) { 165*a170a30dSNélio Laranjeiro DRV_LOG(ERR, "port %u VLAN stripping is not supported", 1660f99970bSNélio Laranjeiro dev->data->port_id); 167289ba0c0SDavid Harton return 0; 168f3db9489SYaacov Hazan } 169f3db9489SYaacov Hazan /* Run on every RX queue and set/reset VLAN stripping. */ 170f3db9489SYaacov Hazan for (i = 0; (i != priv->rxqs_n); i++) 171af4f09f2SNélio Laranjeiro mlx5_vlan_strip_queue_set(dev, i, hw_vlan_strip); 172f3db9489SYaacov Hazan } 173289ba0c0SDavid Harton return 0; 174f3db9489SYaacov Hazan } 175