xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1d8782ec5SAmit Cohen // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2d8782ec5SAmit Cohen /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3d8782ec5SAmit Cohen 
4d8782ec5SAmit Cohen #include <linux/refcount.h>
5d8782ec5SAmit Cohen #include <linux/idr.h>
6d8782ec5SAmit Cohen 
7d8782ec5SAmit Cohen #include "spectrum.h"
8d8782ec5SAmit Cohen #include "reg.h"
9d8782ec5SAmit Cohen 
10d8782ec5SAmit Cohen struct mlxsw_sp_pgt {
11d8782ec5SAmit Cohen 	struct idr pgt_idr;
12d8782ec5SAmit Cohen 	u16 end_index; /* Exclusive. */
13d8782ec5SAmit Cohen 	struct mutex lock; /* Protects PGT. */
14a1697d11SAmit Cohen 	bool smpe_index_valid;
15d8782ec5SAmit Cohen };
16d8782ec5SAmit Cohen 
17a3a7992bSAmit Cohen struct mlxsw_sp_pgt_entry {
18a3a7992bSAmit Cohen 	struct list_head ports_list;
19a3a7992bSAmit Cohen 	u16 index;
20a3a7992bSAmit Cohen 	u16 smpe_index;
21a3a7992bSAmit Cohen };
22a3a7992bSAmit Cohen 
23a3a7992bSAmit Cohen struct mlxsw_sp_pgt_entry_port {
24a3a7992bSAmit Cohen 	struct list_head list; /* Member of 'ports_list'. */
25a3a7992bSAmit Cohen 	u16 local_port;
26a3a7992bSAmit Cohen };
27a3a7992bSAmit Cohen 
mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp * mlxsw_sp,u16 * p_mid)28d8782ec5SAmit Cohen int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid)
29d8782ec5SAmit Cohen {
30d8782ec5SAmit Cohen 	int index, err = 0;
31d8782ec5SAmit Cohen 
32d8782ec5SAmit Cohen 	mutex_lock(&mlxsw_sp->pgt->lock);
33d8782ec5SAmit Cohen 	index = idr_alloc(&mlxsw_sp->pgt->pgt_idr, NULL, 0,
34d8782ec5SAmit Cohen 			  mlxsw_sp->pgt->end_index, GFP_KERNEL);
35d8782ec5SAmit Cohen 
36d8782ec5SAmit Cohen 	if (index < 0) {
37d8782ec5SAmit Cohen 		err = index;
38d8782ec5SAmit Cohen 		goto err_idr_alloc;
39d8782ec5SAmit Cohen 	}
40d8782ec5SAmit Cohen 
41d8782ec5SAmit Cohen 	*p_mid = index;
42d8782ec5SAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
43d8782ec5SAmit Cohen 	return 0;
44d8782ec5SAmit Cohen 
45d8782ec5SAmit Cohen err_idr_alloc:
46d8782ec5SAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
47d8782ec5SAmit Cohen 	return err;
48d8782ec5SAmit Cohen }
49d8782ec5SAmit Cohen 
mlxsw_sp_pgt_mid_free(struct mlxsw_sp * mlxsw_sp,u16 mid_base)50d8782ec5SAmit Cohen void mlxsw_sp_pgt_mid_free(struct mlxsw_sp *mlxsw_sp, u16 mid_base)
51d8782ec5SAmit Cohen {
52d8782ec5SAmit Cohen 	mutex_lock(&mlxsw_sp->pgt->lock);
53d8782ec5SAmit Cohen 	WARN_ON(idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base));
54d8782ec5SAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
55d8782ec5SAmit Cohen }
56d8782ec5SAmit Cohen 
57d8782ec5SAmit Cohen int
mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp * mlxsw_sp,u16 mid_base,u16 count)58d8782ec5SAmit Cohen mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count)
59d8782ec5SAmit Cohen {
60d8782ec5SAmit Cohen 	unsigned int idr_cursor;
61d8782ec5SAmit Cohen 	int i, err;
62d8782ec5SAmit Cohen 
63d8782ec5SAmit Cohen 	mutex_lock(&mlxsw_sp->pgt->lock);
64d8782ec5SAmit Cohen 
65d8782ec5SAmit Cohen 	/* This function is supposed to be called several times as part of
66d8782ec5SAmit Cohen 	 * driver init, in specific order. Verify that the mid_index is the
67d8782ec5SAmit Cohen 	 * first free index in the idr, to be able to free the indexes in case
68d8782ec5SAmit Cohen 	 * of error.
69d8782ec5SAmit Cohen 	 */
70d8782ec5SAmit Cohen 	idr_cursor = idr_get_cursor(&mlxsw_sp->pgt->pgt_idr);
71d8782ec5SAmit Cohen 	if (WARN_ON(idr_cursor != mid_base)) {
72d8782ec5SAmit Cohen 		err = -EINVAL;
73d8782ec5SAmit Cohen 		goto err_idr_cursor;
74d8782ec5SAmit Cohen 	}
75d8782ec5SAmit Cohen 
76d8782ec5SAmit Cohen 	for (i = 0; i < count; i++) {
77d8782ec5SAmit Cohen 		err = idr_alloc_cyclic(&mlxsw_sp->pgt->pgt_idr, NULL,
78d8782ec5SAmit Cohen 				       mid_base, mid_base + count, GFP_KERNEL);
79d8782ec5SAmit Cohen 		if (err < 0)
80d8782ec5SAmit Cohen 			goto err_idr_alloc_cyclic;
81d8782ec5SAmit Cohen 	}
82d8782ec5SAmit Cohen 
83d8782ec5SAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
84d8782ec5SAmit Cohen 	return 0;
85d8782ec5SAmit Cohen 
86d8782ec5SAmit Cohen err_idr_alloc_cyclic:
87d8782ec5SAmit Cohen 	for (i--; i >= 0; i--)
88d8782ec5SAmit Cohen 		idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base + i);
89d8782ec5SAmit Cohen err_idr_cursor:
90d8782ec5SAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
91d8782ec5SAmit Cohen 	return err;
92d8782ec5SAmit Cohen }
93d8782ec5SAmit Cohen 
94d8782ec5SAmit Cohen void
mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp * mlxsw_sp,u16 mid_base,u16 count)95d8782ec5SAmit Cohen mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count)
96d8782ec5SAmit Cohen {
97d8782ec5SAmit Cohen 	struct idr *pgt_idr = &mlxsw_sp->pgt->pgt_idr;
98d8782ec5SAmit Cohen 	int i;
99d8782ec5SAmit Cohen 
100d8782ec5SAmit Cohen 	mutex_lock(&mlxsw_sp->pgt->lock);
101d8782ec5SAmit Cohen 
102d8782ec5SAmit Cohen 	for (i = 0; i < count; i++)
103d8782ec5SAmit Cohen 		WARN_ON_ONCE(idr_remove(pgt_idr, mid_base + i));
104d8782ec5SAmit Cohen 
105d8782ec5SAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
106d8782ec5SAmit Cohen }
107d8782ec5SAmit Cohen 
108a3a7992bSAmit Cohen static struct mlxsw_sp_pgt_entry_port *
mlxsw_sp_pgt_entry_port_lookup(struct mlxsw_sp_pgt_entry * pgt_entry,u16 local_port)109a3a7992bSAmit Cohen mlxsw_sp_pgt_entry_port_lookup(struct mlxsw_sp_pgt_entry *pgt_entry,
110a3a7992bSAmit Cohen 			       u16 local_port)
111a3a7992bSAmit Cohen {
112a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry_port *pgt_entry_port;
113a3a7992bSAmit Cohen 
114a3a7992bSAmit Cohen 	list_for_each_entry(pgt_entry_port, &pgt_entry->ports_list, list) {
115a3a7992bSAmit Cohen 		if (pgt_entry_port->local_port == local_port)
116a3a7992bSAmit Cohen 			return pgt_entry_port;
117a3a7992bSAmit Cohen 	}
118a3a7992bSAmit Cohen 
119a3a7992bSAmit Cohen 	return NULL;
120a3a7992bSAmit Cohen }
121a3a7992bSAmit Cohen 
122a3a7992bSAmit Cohen static struct mlxsw_sp_pgt_entry *
mlxsw_sp_pgt_entry_create(struct mlxsw_sp_pgt * pgt,u16 mid,u16 smpe)123a3a7992bSAmit Cohen mlxsw_sp_pgt_entry_create(struct mlxsw_sp_pgt *pgt, u16 mid, u16 smpe)
124a3a7992bSAmit Cohen {
125a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry *pgt_entry;
126a3a7992bSAmit Cohen 	void *ret;
127a3a7992bSAmit Cohen 	int err;
128a3a7992bSAmit Cohen 
129a3a7992bSAmit Cohen 	pgt_entry = kzalloc(sizeof(*pgt_entry), GFP_KERNEL);
130a3a7992bSAmit Cohen 	if (!pgt_entry)
131a3a7992bSAmit Cohen 		return ERR_PTR(-ENOMEM);
132a3a7992bSAmit Cohen 
133a3a7992bSAmit Cohen 	ret = idr_replace(&pgt->pgt_idr, pgt_entry, mid);
134a3a7992bSAmit Cohen 	if (IS_ERR(ret)) {
135a3a7992bSAmit Cohen 		err = PTR_ERR(ret);
136a3a7992bSAmit Cohen 		goto err_idr_replace;
137a3a7992bSAmit Cohen 	}
138a3a7992bSAmit Cohen 
139a3a7992bSAmit Cohen 	INIT_LIST_HEAD(&pgt_entry->ports_list);
140a3a7992bSAmit Cohen 	pgt_entry->index = mid;
141a3a7992bSAmit Cohen 	pgt_entry->smpe_index = smpe;
142a3a7992bSAmit Cohen 	return pgt_entry;
143a3a7992bSAmit Cohen 
144a3a7992bSAmit Cohen err_idr_replace:
145a3a7992bSAmit Cohen 	kfree(pgt_entry);
146a3a7992bSAmit Cohen 	return ERR_PTR(err);
147a3a7992bSAmit Cohen }
148a3a7992bSAmit Cohen 
mlxsw_sp_pgt_entry_destroy(struct mlxsw_sp_pgt * pgt,struct mlxsw_sp_pgt_entry * pgt_entry)149a3a7992bSAmit Cohen static void mlxsw_sp_pgt_entry_destroy(struct mlxsw_sp_pgt *pgt,
150a3a7992bSAmit Cohen 				       struct mlxsw_sp_pgt_entry *pgt_entry)
151a3a7992bSAmit Cohen {
152a3a7992bSAmit Cohen 	WARN_ON(!list_empty(&pgt_entry->ports_list));
153a3a7992bSAmit Cohen 
154a3a7992bSAmit Cohen 	pgt_entry = idr_replace(&pgt->pgt_idr, NULL, pgt_entry->index);
155a3a7992bSAmit Cohen 	if (WARN_ON(IS_ERR(pgt_entry)))
156a3a7992bSAmit Cohen 		return;
157a3a7992bSAmit Cohen 
158a3a7992bSAmit Cohen 	kfree(pgt_entry);
159a3a7992bSAmit Cohen }
160a3a7992bSAmit Cohen 
161a3a7992bSAmit Cohen static struct mlxsw_sp_pgt_entry *
mlxsw_sp_pgt_entry_get(struct mlxsw_sp_pgt * pgt,u16 mid,u16 smpe)162a3a7992bSAmit Cohen mlxsw_sp_pgt_entry_get(struct mlxsw_sp_pgt *pgt, u16 mid, u16 smpe)
163a3a7992bSAmit Cohen {
164a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry *pgt_entry;
165a3a7992bSAmit Cohen 
166a3a7992bSAmit Cohen 	pgt_entry = idr_find(&pgt->pgt_idr, mid);
167a3a7992bSAmit Cohen 	if (pgt_entry)
168a3a7992bSAmit Cohen 		return pgt_entry;
169a3a7992bSAmit Cohen 
170a3a7992bSAmit Cohen 	return mlxsw_sp_pgt_entry_create(pgt, mid, smpe);
171a3a7992bSAmit Cohen }
172a3a7992bSAmit Cohen 
mlxsw_sp_pgt_entry_put(struct mlxsw_sp_pgt * pgt,u16 mid)173a3a7992bSAmit Cohen static void mlxsw_sp_pgt_entry_put(struct mlxsw_sp_pgt *pgt, u16 mid)
174a3a7992bSAmit Cohen {
175a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry *pgt_entry;
176a3a7992bSAmit Cohen 
177a3a7992bSAmit Cohen 	pgt_entry = idr_find(&pgt->pgt_idr, mid);
178a3a7992bSAmit Cohen 	if (WARN_ON(!pgt_entry))
179a3a7992bSAmit Cohen 		return;
180a3a7992bSAmit Cohen 
181a3a7992bSAmit Cohen 	if (list_empty(&pgt_entry->ports_list))
182a3a7992bSAmit Cohen 		mlxsw_sp_pgt_entry_destroy(pgt, pgt_entry);
183a3a7992bSAmit Cohen }
184a3a7992bSAmit Cohen 
mlxsw_sp_pgt_smid2_port_set(char * smid2_pl,u16 local_port,bool member)185a3a7992bSAmit Cohen static void mlxsw_sp_pgt_smid2_port_set(char *smid2_pl, u16 local_port,
186a3a7992bSAmit Cohen 					bool member)
187a3a7992bSAmit Cohen {
188a3a7992bSAmit Cohen 	mlxsw_reg_smid2_port_set(smid2_pl, local_port, member);
189a3a7992bSAmit Cohen 	mlxsw_reg_smid2_port_mask_set(smid2_pl, local_port, 1);
190a3a7992bSAmit Cohen }
191a3a7992bSAmit Cohen 
192a3a7992bSAmit Cohen static int
mlxsw_sp_pgt_entry_port_write(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_pgt_entry * pgt_entry,u16 local_port,bool member)193a3a7992bSAmit Cohen mlxsw_sp_pgt_entry_port_write(struct mlxsw_sp *mlxsw_sp,
194a3a7992bSAmit Cohen 			      const struct mlxsw_sp_pgt_entry *pgt_entry,
195a3a7992bSAmit Cohen 			      u16 local_port, bool member)
196a3a7992bSAmit Cohen {
197a3a7992bSAmit Cohen 	char *smid2_pl;
198a3a7992bSAmit Cohen 	int err;
199a3a7992bSAmit Cohen 
200a3a7992bSAmit Cohen 	smid2_pl = kmalloc(MLXSW_REG_SMID2_LEN, GFP_KERNEL);
201a3a7992bSAmit Cohen 	if (!smid2_pl)
202a3a7992bSAmit Cohen 		return -ENOMEM;
203a3a7992bSAmit Cohen 
204*77b7f83dSAmit Cohen 	mlxsw_reg_smid2_pack(smid2_pl, pgt_entry->index, 0, 0,
205*77b7f83dSAmit Cohen 			     mlxsw_sp->pgt->smpe_index_valid,
206*77b7f83dSAmit Cohen 			     pgt_entry->smpe_index);
207a3a7992bSAmit Cohen 
208a3a7992bSAmit Cohen 	mlxsw_sp_pgt_smid2_port_set(smid2_pl, local_port, member);
209a3a7992bSAmit Cohen 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid2), smid2_pl);
210a3a7992bSAmit Cohen 
211a3a7992bSAmit Cohen 	kfree(smid2_pl);
212a3a7992bSAmit Cohen 
213a3a7992bSAmit Cohen 	return err;
214a3a7992bSAmit Cohen }
215a3a7992bSAmit Cohen 
216a3a7992bSAmit Cohen static struct mlxsw_sp_pgt_entry_port *
mlxsw_sp_pgt_entry_port_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_pgt_entry * pgt_entry,u16 local_port)217a3a7992bSAmit Cohen mlxsw_sp_pgt_entry_port_create(struct mlxsw_sp *mlxsw_sp,
218a3a7992bSAmit Cohen 			       struct mlxsw_sp_pgt_entry *pgt_entry,
219a3a7992bSAmit Cohen 			       u16 local_port)
220a3a7992bSAmit Cohen {
221a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry_port *pgt_entry_port;
222a3a7992bSAmit Cohen 	int err;
223a3a7992bSAmit Cohen 
224a3a7992bSAmit Cohen 	pgt_entry_port = kzalloc(sizeof(*pgt_entry_port), GFP_KERNEL);
225a3a7992bSAmit Cohen 	if (!pgt_entry_port)
226a3a7992bSAmit Cohen 		return ERR_PTR(-ENOMEM);
227a3a7992bSAmit Cohen 
228a3a7992bSAmit Cohen 	err = mlxsw_sp_pgt_entry_port_write(mlxsw_sp, pgt_entry, local_port,
229a3a7992bSAmit Cohen 					    true);
230a3a7992bSAmit Cohen 	if (err)
231a3a7992bSAmit Cohen 		goto err_pgt_entry_port_write;
232a3a7992bSAmit Cohen 
233a3a7992bSAmit Cohen 	pgt_entry_port->local_port = local_port;
234a3a7992bSAmit Cohen 	list_add(&pgt_entry_port->list, &pgt_entry->ports_list);
235a3a7992bSAmit Cohen 
236a3a7992bSAmit Cohen 	return pgt_entry_port;
237a3a7992bSAmit Cohen 
238a3a7992bSAmit Cohen err_pgt_entry_port_write:
239a3a7992bSAmit Cohen 	kfree(pgt_entry_port);
240a3a7992bSAmit Cohen 	return ERR_PTR(err);
241a3a7992bSAmit Cohen }
242a3a7992bSAmit Cohen 
243a3a7992bSAmit Cohen static void
mlxsw_sp_pgt_entry_port_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_pgt_entry * pgt_entry,struct mlxsw_sp_pgt_entry_port * pgt_entry_port)244a3a7992bSAmit Cohen mlxsw_sp_pgt_entry_port_destroy(struct mlxsw_sp *mlxsw_sp,
245a3a7992bSAmit Cohen 				struct mlxsw_sp_pgt_entry *pgt_entry,
246a3a7992bSAmit Cohen 				struct mlxsw_sp_pgt_entry_port *pgt_entry_port)
247a3a7992bSAmit Cohen 
248a3a7992bSAmit Cohen {
249a3a7992bSAmit Cohen 	list_del(&pgt_entry_port->list);
250a3a7992bSAmit Cohen 	mlxsw_sp_pgt_entry_port_write(mlxsw_sp, pgt_entry,
251a3a7992bSAmit Cohen 				      pgt_entry_port->local_port, false);
252a3a7992bSAmit Cohen 	kfree(pgt_entry_port);
253a3a7992bSAmit Cohen }
254a3a7992bSAmit Cohen 
mlxsw_sp_pgt_entry_port_add(struct mlxsw_sp * mlxsw_sp,u16 mid,u16 smpe,u16 local_port)255a3a7992bSAmit Cohen static int mlxsw_sp_pgt_entry_port_add(struct mlxsw_sp *mlxsw_sp, u16 mid,
256a3a7992bSAmit Cohen 				       u16 smpe, u16 local_port)
257a3a7992bSAmit Cohen {
258a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry_port *pgt_entry_port;
259a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry *pgt_entry;
260a3a7992bSAmit Cohen 	int err;
261a3a7992bSAmit Cohen 
262a3a7992bSAmit Cohen 	mutex_lock(&mlxsw_sp->pgt->lock);
263a3a7992bSAmit Cohen 
264a3a7992bSAmit Cohen 	pgt_entry = mlxsw_sp_pgt_entry_get(mlxsw_sp->pgt, mid, smpe);
265a3a7992bSAmit Cohen 	if (IS_ERR(pgt_entry)) {
266a3a7992bSAmit Cohen 		err = PTR_ERR(pgt_entry);
267a3a7992bSAmit Cohen 		goto err_pgt_entry_get;
268a3a7992bSAmit Cohen 	}
269a3a7992bSAmit Cohen 
270a3a7992bSAmit Cohen 	pgt_entry_port = mlxsw_sp_pgt_entry_port_create(mlxsw_sp, pgt_entry,
271a3a7992bSAmit Cohen 							local_port);
272a3a7992bSAmit Cohen 	if (IS_ERR(pgt_entry_port)) {
273a3a7992bSAmit Cohen 		err = PTR_ERR(pgt_entry_port);
274a3a7992bSAmit Cohen 		goto err_pgt_entry_port_get;
275a3a7992bSAmit Cohen 	}
276a3a7992bSAmit Cohen 
277a3a7992bSAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
278a3a7992bSAmit Cohen 	return 0;
279a3a7992bSAmit Cohen 
280a3a7992bSAmit Cohen err_pgt_entry_port_get:
281a3a7992bSAmit Cohen 	mlxsw_sp_pgt_entry_put(mlxsw_sp->pgt, mid);
282a3a7992bSAmit Cohen err_pgt_entry_get:
283a3a7992bSAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
284a3a7992bSAmit Cohen 	return err;
285a3a7992bSAmit Cohen }
286a3a7992bSAmit Cohen 
mlxsw_sp_pgt_entry_port_del(struct mlxsw_sp * mlxsw_sp,u16 mid,u16 smpe,u16 local_port)287a3a7992bSAmit Cohen static void mlxsw_sp_pgt_entry_port_del(struct mlxsw_sp *mlxsw_sp,
288a3a7992bSAmit Cohen 					u16 mid, u16 smpe, u16 local_port)
289a3a7992bSAmit Cohen {
290a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry_port *pgt_entry_port;
291a3a7992bSAmit Cohen 	struct mlxsw_sp_pgt_entry *pgt_entry;
292a3a7992bSAmit Cohen 
293a3a7992bSAmit Cohen 	mutex_lock(&mlxsw_sp->pgt->lock);
294a3a7992bSAmit Cohen 
295a3a7992bSAmit Cohen 	pgt_entry = idr_find(&mlxsw_sp->pgt->pgt_idr, mid);
296a3a7992bSAmit Cohen 	if (!pgt_entry)
297a3a7992bSAmit Cohen 		goto out;
298a3a7992bSAmit Cohen 
299a3a7992bSAmit Cohen 	pgt_entry_port = mlxsw_sp_pgt_entry_port_lookup(pgt_entry, local_port);
300a3a7992bSAmit Cohen 	if (!pgt_entry_port)
301a3a7992bSAmit Cohen 		goto out;
302a3a7992bSAmit Cohen 
303a3a7992bSAmit Cohen 	mlxsw_sp_pgt_entry_port_destroy(mlxsw_sp, pgt_entry, pgt_entry_port);
304a3a7992bSAmit Cohen 	mlxsw_sp_pgt_entry_put(mlxsw_sp->pgt, mid);
305a3a7992bSAmit Cohen 
306a3a7992bSAmit Cohen out:
307a3a7992bSAmit Cohen 	mutex_unlock(&mlxsw_sp->pgt->lock);
308a3a7992bSAmit Cohen }
309a3a7992bSAmit Cohen 
mlxsw_sp_pgt_entry_port_set(struct mlxsw_sp * mlxsw_sp,u16 mid,u16 smpe,u16 local_port,bool member)310a3a7992bSAmit Cohen int mlxsw_sp_pgt_entry_port_set(struct mlxsw_sp *mlxsw_sp, u16 mid,
311a3a7992bSAmit Cohen 				u16 smpe, u16 local_port, bool member)
312a3a7992bSAmit Cohen {
313a3a7992bSAmit Cohen 	if (member)
314a3a7992bSAmit Cohen 		return mlxsw_sp_pgt_entry_port_add(mlxsw_sp, mid, smpe,
315a3a7992bSAmit Cohen 						   local_port);
316a3a7992bSAmit Cohen 
317a3a7992bSAmit Cohen 	mlxsw_sp_pgt_entry_port_del(mlxsw_sp, mid, smpe, local_port);
318a3a7992bSAmit Cohen 	return 0;
319a3a7992bSAmit Cohen }
320a3a7992bSAmit Cohen 
mlxsw_sp_pgt_init(struct mlxsw_sp * mlxsw_sp)321d8782ec5SAmit Cohen int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp)
322d8782ec5SAmit Cohen {
323d8782ec5SAmit Cohen 	struct mlxsw_sp_pgt *pgt;
324d8782ec5SAmit Cohen 
325d8782ec5SAmit Cohen 	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, PGT_SIZE))
326d8782ec5SAmit Cohen 		return -EIO;
327d8782ec5SAmit Cohen 
328d8782ec5SAmit Cohen 	pgt = kzalloc(sizeof(*mlxsw_sp->pgt), GFP_KERNEL);
329d8782ec5SAmit Cohen 	if (!pgt)
330d8782ec5SAmit Cohen 		return -ENOMEM;
331d8782ec5SAmit Cohen 
332d8782ec5SAmit Cohen 	idr_init(&pgt->pgt_idr);
333d8782ec5SAmit Cohen 	pgt->end_index = MLXSW_CORE_RES_GET(mlxsw_sp->core, PGT_SIZE);
334d8782ec5SAmit Cohen 	mutex_init(&pgt->lock);
335a1697d11SAmit Cohen 	pgt->smpe_index_valid = mlxsw_sp->pgt_smpe_index_valid;
336d8782ec5SAmit Cohen 	mlxsw_sp->pgt = pgt;
337d8782ec5SAmit Cohen 	return 0;
338d8782ec5SAmit Cohen }
339d8782ec5SAmit Cohen 
mlxsw_sp_pgt_fini(struct mlxsw_sp * mlxsw_sp)340d8782ec5SAmit Cohen void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp)
341d8782ec5SAmit Cohen {
342d8782ec5SAmit Cohen 	mutex_destroy(&mlxsw_sp->pgt->lock);
343d8782ec5SAmit Cohen 	WARN_ON(!idr_is_empty(&mlxsw_sp->pgt->pgt_idr));
344d8782ec5SAmit Cohen 	idr_destroy(&mlxsw_sp->pgt->pgt_idr);
345d8782ec5SAmit Cohen 	kfree(mlxsw_sp->pgt);
346d8782ec5SAmit Cohen }
347