xref: /dpdk/drivers/net/mlx5/mlx5_vlan.c (revision a170a30d22a8c34c36541d0dd6bcc2fcc4c9ee2f)
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