1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2021 NVIDIA Corporation & Affiliates
4 #include <rte_malloc.h>
5 #include <mlx5_devx_cmds.h>
6 #include <mlx5_malloc.h>
10 static_assert(sizeof(uint32_t) * CHAR_BIT >= MLX5_PORT_FLEX_ITEM_NUM,
11 "Flex item maximal number exceeds uint32_t bit width");
14 * Routine called once on port initialization to init flex item
15 * related infrastructure initialization
18 * Ethernet device to perform flex item initialization
21 * 0 on success, a negative errno value otherwise and rte_errno is set.
24 mlx5_flex_item_port_init(struct rte_eth_dev *dev)
26 struct mlx5_priv *priv = dev->data->dev_private;
28 rte_spinlock_init(&priv->flex_item_sl);
29 MLX5_ASSERT(!priv->flex_item_map);
34 * Routine called once on port close to perform flex item
35 * related infrastructure cleanup.
38 * Ethernet device to perform cleanup
41 mlx5_flex_item_port_cleanup(struct rte_eth_dev *dev)
43 struct mlx5_priv *priv = dev->data->dev_private;
46 for (i = 0; i < MLX5_PORT_FLEX_ITEM_NUM && priv->flex_item_map ; i++) {
47 if (priv->flex_item_map & (1 << i)) {
48 /* DevX object dereferencing should be provided here. */
49 priv->flex_item_map &= ~(1 << i);
55 mlx5_flex_index(struct mlx5_priv *priv, struct mlx5_flex_item *item)
57 uintptr_t start = (uintptr_t)&priv->flex_item[0];
58 uintptr_t entry = (uintptr_t)item;
59 uintptr_t idx = (entry - start) / sizeof(struct mlx5_flex_item);
62 idx >= MLX5_PORT_FLEX_ITEM_NUM ||
63 (entry - start) % sizeof(struct mlx5_flex_item) ||
64 !(priv->flex_item_map & (1u << idx)))
69 static struct mlx5_flex_item *
70 mlx5_flex_alloc(struct mlx5_priv *priv)
72 struct mlx5_flex_item *item = NULL;
74 rte_spinlock_lock(&priv->flex_item_sl);
75 if (~priv->flex_item_map) {
76 uint32_t idx = rte_bsf32(~priv->flex_item_map);
78 if (idx < MLX5_PORT_FLEX_ITEM_NUM) {
79 item = &priv->flex_item[idx];
80 MLX5_ASSERT(!item->refcnt);
81 MLX5_ASSERT(!item->devx_fp);
83 __atomic_store_n(&item->refcnt, 0, __ATOMIC_RELEASE);
84 priv->flex_item_map |= 1u << idx;
87 rte_spinlock_unlock(&priv->flex_item_sl);
92 mlx5_flex_free(struct mlx5_priv *priv, struct mlx5_flex_item *item)
94 int idx = mlx5_flex_index(priv, item);
96 MLX5_ASSERT(idx >= 0 &&
97 idx < MLX5_PORT_FLEX_ITEM_NUM &&
98 (priv->flex_item_map & (1u << idx)));
100 rte_spinlock_lock(&priv->flex_item_sl);
101 MLX5_ASSERT(!item->refcnt);
102 MLX5_ASSERT(!item->devx_fp);
103 item->devx_fp = NULL;
104 __atomic_store_n(&item->refcnt, 0, __ATOMIC_RELEASE);
105 priv->flex_item_map &= ~(1u << idx);
106 rte_spinlock_unlock(&priv->flex_item_sl);
111 * Create the flex item with specified configuration over the Ethernet device.
114 * Ethernet device to create flex item on.
116 * Flex item configuration.
118 * Perform verbose error reporting if not NULL. PMDs initialize this
119 * structure in case of error only.
122 * Non-NULL opaque pointer on success, NULL otherwise and rte_errno is set.
124 struct rte_flow_item_flex_handle *
125 flow_dv_item_create(struct rte_eth_dev *dev,
126 const struct rte_flow_item_flex_conf *conf,
127 struct rte_flow_error *error)
129 struct mlx5_priv *priv = dev->data->dev_private;
130 struct mlx5_flex_item *flex;
132 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
133 flex = mlx5_flex_alloc(priv);
135 rte_flow_error_set(error, ENOMEM,
136 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
137 "too many flex items created on the port");
141 /* Mark initialized flex item valid. */
142 __atomic_add_fetch(&flex->refcnt, 1, __ATOMIC_RELEASE);
143 return (struct rte_flow_item_flex_handle *)flex;
147 * Release the flex item on the specified Ethernet device.
150 * Ethernet device to destroy flex item on.
152 * Handle of the item existing on the specified device.
154 * Perform verbose error reporting if not NULL. PMDs initialize this
155 * structure in case of error only.
158 * 0 on success, a negative errno value otherwise and rte_errno is set.
161 flow_dv_item_release(struct rte_eth_dev *dev,
162 const struct rte_flow_item_flex_handle *handle,
163 struct rte_flow_error *error)
165 struct mlx5_priv *priv = dev->data->dev_private;
166 struct mlx5_flex_item *flex =
167 (struct mlx5_flex_item *)(uintptr_t)handle;
168 uint32_t old_refcnt = 1;
170 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
171 rte_spinlock_lock(&priv->flex_item_sl);
172 if (mlx5_flex_index(priv, flex) < 0) {
173 rte_spinlock_unlock(&priv->flex_item_sl);
174 return rte_flow_error_set(error, EINVAL,
175 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
176 "invalid flex item handle value");
178 if (!__atomic_compare_exchange_n(&flex->refcnt, &old_refcnt, 0, 0,
179 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
180 rte_spinlock_unlock(&priv->flex_item_sl);
181 return rte_flow_error_set(error, EBUSY,
182 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
183 "flex item has flow references");
185 /* Flex item is marked as invalid, we can leave locked section. */
186 rte_spinlock_unlock(&priv->flex_item_sl);
187 mlx5_flex_free(priv, flex);