xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/err.h>
5*4882a593Smuzhiyun #include <linux/gfp.h>
6*4882a593Smuzhiyun #include <linux/kernel.h>
7*4882a593Smuzhiyun #include <linux/list.h>
8*4882a593Smuzhiyun #include <linux/netlink.h>
9*4882a593Smuzhiyun #include <linux/rtnetlink.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <net/inet_ecn.h>
12*4882a593Smuzhiyun #include <net/ipv6.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "reg.h"
15*4882a593Smuzhiyun #include "spectrum.h"
16*4882a593Smuzhiyun #include "spectrum_nve.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[] = {
19*4882a593Smuzhiyun 	[MLXSW_SP_NVE_TYPE_VXLAN]	= &mlxsw_sp1_nve_vxlan_ops,
20*4882a593Smuzhiyun };
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun const struct mlxsw_sp_nve_ops *mlxsw_sp2_nve_ops_arr[] = {
23*4882a593Smuzhiyun 	[MLXSW_SP_NVE_TYPE_VXLAN]	= &mlxsw_sp2_nve_vxlan_ops,
24*4882a593Smuzhiyun };
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_entry;
27*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_record;
28*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_list;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_record_ops {
31*4882a593Smuzhiyun 	enum mlxsw_reg_tnumt_record_type type;
32*4882a593Smuzhiyun 	int (*entry_add)(struct mlxsw_sp_nve_mc_record *mc_record,
33*4882a593Smuzhiyun 			 struct mlxsw_sp_nve_mc_entry *mc_entry,
34*4882a593Smuzhiyun 			 const union mlxsw_sp_l3addr *addr);
35*4882a593Smuzhiyun 	void (*entry_del)(const struct mlxsw_sp_nve_mc_record *mc_record,
36*4882a593Smuzhiyun 			  const struct mlxsw_sp_nve_mc_entry *mc_entry);
37*4882a593Smuzhiyun 	void (*entry_set)(const struct mlxsw_sp_nve_mc_record *mc_record,
38*4882a593Smuzhiyun 			  const struct mlxsw_sp_nve_mc_entry *mc_entry,
39*4882a593Smuzhiyun 			  char *tnumt_pl, unsigned int entry_index);
40*4882a593Smuzhiyun 	bool (*entry_compare)(const struct mlxsw_sp_nve_mc_record *mc_record,
41*4882a593Smuzhiyun 			      const struct mlxsw_sp_nve_mc_entry *mc_entry,
42*4882a593Smuzhiyun 			      const union mlxsw_sp_l3addr *addr);
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_list_key {
46*4882a593Smuzhiyun 	u16 fid_index;
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_ipv6_entry {
50*4882a593Smuzhiyun 	struct in6_addr addr6;
51*4882a593Smuzhiyun 	u32 addr6_kvdl_index;
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_entry {
55*4882a593Smuzhiyun 	union {
56*4882a593Smuzhiyun 		__be32 addr4;
57*4882a593Smuzhiyun 		struct mlxsw_sp_nve_mc_ipv6_entry ipv6_entry;
58*4882a593Smuzhiyun 	};
59*4882a593Smuzhiyun 	u8 valid:1;
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_record {
63*4882a593Smuzhiyun 	struct list_head list;
64*4882a593Smuzhiyun 	enum mlxsw_sp_l3proto proto;
65*4882a593Smuzhiyun 	unsigned int num_entries;
66*4882a593Smuzhiyun 	struct mlxsw_sp *mlxsw_sp;
67*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list;
68*4882a593Smuzhiyun 	const struct mlxsw_sp_nve_mc_record_ops *ops;
69*4882a593Smuzhiyun 	u32 kvdl_index;
70*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_entry entries[];
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun struct mlxsw_sp_nve_mc_list {
74*4882a593Smuzhiyun 	struct list_head records_list;
75*4882a593Smuzhiyun 	struct rhash_head ht_node;
76*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list_key key;
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static const struct rhashtable_params mlxsw_sp_nve_mc_list_ht_params = {
80*4882a593Smuzhiyun 	.key_len = sizeof(struct mlxsw_sp_nve_mc_list_key),
81*4882a593Smuzhiyun 	.key_offset = offsetof(struct mlxsw_sp_nve_mc_list, key),
82*4882a593Smuzhiyun 	.head_offset = offsetof(struct mlxsw_sp_nve_mc_list, ht_node),
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun static int
mlxsw_sp_nve_mc_record_ipv4_entry_add(struct mlxsw_sp_nve_mc_record * mc_record,struct mlxsw_sp_nve_mc_entry * mc_entry,const union mlxsw_sp_l3addr * addr)86*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv4_entry_add(struct mlxsw_sp_nve_mc_record *mc_record,
87*4882a593Smuzhiyun 				      struct mlxsw_sp_nve_mc_entry *mc_entry,
88*4882a593Smuzhiyun 				      const union mlxsw_sp_l3addr *addr)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	mc_entry->addr4 = addr->addr4;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	return 0;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_record_ipv4_entry_del(const struct mlxsw_sp_nve_mc_record * mc_record,const struct mlxsw_sp_nve_mc_entry * mc_entry)96*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv4_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record,
97*4882a593Smuzhiyun 				      const struct mlxsw_sp_nve_mc_entry *mc_entry)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_record_ipv4_entry_set(const struct mlxsw_sp_nve_mc_record * mc_record,const struct mlxsw_sp_nve_mc_entry * mc_entry,char * tnumt_pl,unsigned int entry_index)102*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv4_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record,
103*4882a593Smuzhiyun 				      const struct mlxsw_sp_nve_mc_entry *mc_entry,
104*4882a593Smuzhiyun 				      char *tnumt_pl, unsigned int entry_index)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	u32 udip = be32_to_cpu(mc_entry->addr4);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	mlxsw_reg_tnumt_udip_set(tnumt_pl, entry_index, udip);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun static bool
mlxsw_sp_nve_mc_record_ipv4_entry_compare(const struct mlxsw_sp_nve_mc_record * mc_record,const struct mlxsw_sp_nve_mc_entry * mc_entry,const union mlxsw_sp_l3addr * addr)112*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv4_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record,
113*4882a593Smuzhiyun 					  const struct mlxsw_sp_nve_mc_entry *mc_entry,
114*4882a593Smuzhiyun 					  const union mlxsw_sp_l3addr *addr)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	return mc_entry->addr4 == addr->addr4;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static const struct mlxsw_sp_nve_mc_record_ops
120*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv4_ops = {
121*4882a593Smuzhiyun 	.type		= MLXSW_REG_TNUMT_RECORD_TYPE_IPV4,
122*4882a593Smuzhiyun 	.entry_add	= &mlxsw_sp_nve_mc_record_ipv4_entry_add,
123*4882a593Smuzhiyun 	.entry_del	= &mlxsw_sp_nve_mc_record_ipv4_entry_del,
124*4882a593Smuzhiyun 	.entry_set	= &mlxsw_sp_nve_mc_record_ipv4_entry_set,
125*4882a593Smuzhiyun 	.entry_compare	= &mlxsw_sp_nve_mc_record_ipv4_entry_compare,
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun static int
mlxsw_sp_nve_mc_record_ipv6_entry_add(struct mlxsw_sp_nve_mc_record * mc_record,struct mlxsw_sp_nve_mc_entry * mc_entry,const union mlxsw_sp_l3addr * addr)129*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv6_entry_add(struct mlxsw_sp_nve_mc_record *mc_record,
130*4882a593Smuzhiyun 				      struct mlxsw_sp_nve_mc_entry *mc_entry,
131*4882a593Smuzhiyun 				      const union mlxsw_sp_l3addr *addr)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	WARN_ON(1);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return -EINVAL;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_record_ipv6_entry_del(const struct mlxsw_sp_nve_mc_record * mc_record,const struct mlxsw_sp_nve_mc_entry * mc_entry)139*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv6_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record,
140*4882a593Smuzhiyun 				      const struct mlxsw_sp_nve_mc_entry *mc_entry)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_record_ipv6_entry_set(const struct mlxsw_sp_nve_mc_record * mc_record,const struct mlxsw_sp_nve_mc_entry * mc_entry,char * tnumt_pl,unsigned int entry_index)145*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv6_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record,
146*4882a593Smuzhiyun 				      const struct mlxsw_sp_nve_mc_entry *mc_entry,
147*4882a593Smuzhiyun 				      char *tnumt_pl, unsigned int entry_index)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	u32 udip_ptr = mc_entry->ipv6_entry.addr6_kvdl_index;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	mlxsw_reg_tnumt_udip_ptr_set(tnumt_pl, entry_index, udip_ptr);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun static bool
mlxsw_sp_nve_mc_record_ipv6_entry_compare(const struct mlxsw_sp_nve_mc_record * mc_record,const struct mlxsw_sp_nve_mc_entry * mc_entry,const union mlxsw_sp_l3addr * addr)155*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv6_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record,
156*4882a593Smuzhiyun 					  const struct mlxsw_sp_nve_mc_entry *mc_entry,
157*4882a593Smuzhiyun 					  const union mlxsw_sp_l3addr *addr)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	return ipv6_addr_equal(&mc_entry->ipv6_entry.addr6, &addr->addr6);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun static const struct mlxsw_sp_nve_mc_record_ops
163*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ipv6_ops = {
164*4882a593Smuzhiyun 	.type		= MLXSW_REG_TNUMT_RECORD_TYPE_IPV6,
165*4882a593Smuzhiyun 	.entry_add	= &mlxsw_sp_nve_mc_record_ipv6_entry_add,
166*4882a593Smuzhiyun 	.entry_del	= &mlxsw_sp_nve_mc_record_ipv6_entry_del,
167*4882a593Smuzhiyun 	.entry_set	= &mlxsw_sp_nve_mc_record_ipv6_entry_set,
168*4882a593Smuzhiyun 	.entry_compare	= &mlxsw_sp_nve_mc_record_ipv6_entry_compare,
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun static const struct mlxsw_sp_nve_mc_record_ops *
172*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ops_arr[] = {
173*4882a593Smuzhiyun 	[MLXSW_SP_L3_PROTO_IPV4] = &mlxsw_sp_nve_mc_record_ipv4_ops,
174*4882a593Smuzhiyun 	[MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_nve_mc_record_ipv6_ops,
175*4882a593Smuzhiyun };
176*4882a593Smuzhiyun 
mlxsw_sp_nve_learned_ip_resolve(struct mlxsw_sp * mlxsw_sp,u32 uip,enum mlxsw_sp_l3proto proto,union mlxsw_sp_l3addr * addr)177*4882a593Smuzhiyun int mlxsw_sp_nve_learned_ip_resolve(struct mlxsw_sp *mlxsw_sp, u32 uip,
178*4882a593Smuzhiyun 				    enum mlxsw_sp_l3proto proto,
179*4882a593Smuzhiyun 				    union mlxsw_sp_l3addr *addr)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	switch (proto) {
182*4882a593Smuzhiyun 	case MLXSW_SP_L3_PROTO_IPV4:
183*4882a593Smuzhiyun 		addr->addr4 = cpu_to_be32(uip);
184*4882a593Smuzhiyun 		return 0;
185*4882a593Smuzhiyun 	default:
186*4882a593Smuzhiyun 		WARN_ON(1);
187*4882a593Smuzhiyun 		return -EINVAL;
188*4882a593Smuzhiyun 	}
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun static struct mlxsw_sp_nve_mc_list *
mlxsw_sp_nve_mc_list_find(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_nve_mc_list_key * key)192*4882a593Smuzhiyun mlxsw_sp_nve_mc_list_find(struct mlxsw_sp *mlxsw_sp,
193*4882a593Smuzhiyun 			  const struct mlxsw_sp_nve_mc_list_key *key)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return rhashtable_lookup_fast(&nve->mc_list_ht, key,
198*4882a593Smuzhiyun 				      mlxsw_sp_nve_mc_list_ht_params);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun static struct mlxsw_sp_nve_mc_list *
mlxsw_sp_nve_mc_list_create(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_nve_mc_list_key * key)202*4882a593Smuzhiyun mlxsw_sp_nve_mc_list_create(struct mlxsw_sp *mlxsw_sp,
203*4882a593Smuzhiyun 			    const struct mlxsw_sp_nve_mc_list_key *key)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
206*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list;
207*4882a593Smuzhiyun 	int err;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	mc_list = kmalloc(sizeof(*mc_list), GFP_KERNEL);
210*4882a593Smuzhiyun 	if (!mc_list)
211*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	INIT_LIST_HEAD(&mc_list->records_list);
214*4882a593Smuzhiyun 	mc_list->key = *key;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	err = rhashtable_insert_fast(&nve->mc_list_ht, &mc_list->ht_node,
217*4882a593Smuzhiyun 				     mlxsw_sp_nve_mc_list_ht_params);
218*4882a593Smuzhiyun 	if (err)
219*4882a593Smuzhiyun 		goto err_rhashtable_insert;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	return mc_list;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun err_rhashtable_insert:
224*4882a593Smuzhiyun 	kfree(mc_list);
225*4882a593Smuzhiyun 	return ERR_PTR(err);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
mlxsw_sp_nve_mc_list_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nve_mc_list * mc_list)228*4882a593Smuzhiyun static void mlxsw_sp_nve_mc_list_destroy(struct mlxsw_sp *mlxsw_sp,
229*4882a593Smuzhiyun 					 struct mlxsw_sp_nve_mc_list *mc_list)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	rhashtable_remove_fast(&nve->mc_list_ht, &mc_list->ht_node,
234*4882a593Smuzhiyun 			       mlxsw_sp_nve_mc_list_ht_params);
235*4882a593Smuzhiyun 	WARN_ON(!list_empty(&mc_list->records_list));
236*4882a593Smuzhiyun 	kfree(mc_list);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun static struct mlxsw_sp_nve_mc_list *
mlxsw_sp_nve_mc_list_get(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_nve_mc_list_key * key)240*4882a593Smuzhiyun mlxsw_sp_nve_mc_list_get(struct mlxsw_sp *mlxsw_sp,
241*4882a593Smuzhiyun 			 const struct mlxsw_sp_nve_mc_list_key *key)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, key);
246*4882a593Smuzhiyun 	if (mc_list)
247*4882a593Smuzhiyun 		return mc_list;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	return mlxsw_sp_nve_mc_list_create(mlxsw_sp, key);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_list_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nve_mc_list * mc_list)253*4882a593Smuzhiyun mlxsw_sp_nve_mc_list_put(struct mlxsw_sp *mlxsw_sp,
254*4882a593Smuzhiyun 			 struct mlxsw_sp_nve_mc_list *mc_list)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	if (!list_empty(&mc_list->records_list))
257*4882a593Smuzhiyun 		return;
258*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_list_destroy(mlxsw_sp, mc_list);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun static struct mlxsw_sp_nve_mc_record *
mlxsw_sp_nve_mc_record_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nve_mc_list * mc_list,enum mlxsw_sp_l3proto proto)262*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_create(struct mlxsw_sp *mlxsw_sp,
263*4882a593Smuzhiyun 			      struct mlxsw_sp_nve_mc_list *mc_list,
264*4882a593Smuzhiyun 			      enum mlxsw_sp_l3proto proto)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	unsigned int num_max_entries = mlxsw_sp->nve->num_max_mc_entries[proto];
267*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *mc_record;
268*4882a593Smuzhiyun 	int err;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	mc_record = kzalloc(struct_size(mc_record, entries, num_max_entries),
271*4882a593Smuzhiyun 			    GFP_KERNEL);
272*4882a593Smuzhiyun 	if (!mc_record)
273*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, 1,
276*4882a593Smuzhiyun 				  &mc_record->kvdl_index);
277*4882a593Smuzhiyun 	if (err)
278*4882a593Smuzhiyun 		goto err_kvdl_alloc;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	mc_record->ops = mlxsw_sp_nve_mc_record_ops_arr[proto];
281*4882a593Smuzhiyun 	mc_record->mlxsw_sp = mlxsw_sp;
282*4882a593Smuzhiyun 	mc_record->mc_list = mc_list;
283*4882a593Smuzhiyun 	mc_record->proto = proto;
284*4882a593Smuzhiyun 	list_add_tail(&mc_record->list, &mc_list->records_list);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	return mc_record;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun err_kvdl_alloc:
289*4882a593Smuzhiyun 	kfree(mc_record);
290*4882a593Smuzhiyun 	return ERR_PTR(err);
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_record_destroy(struct mlxsw_sp_nve_mc_record * mc_record)294*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_destroy(struct mlxsw_sp_nve_mc_record *mc_record)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct mlxsw_sp *mlxsw_sp = mc_record->mlxsw_sp;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	list_del(&mc_record->list);
299*4882a593Smuzhiyun 	mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, 1,
300*4882a593Smuzhiyun 			   mc_record->kvdl_index);
301*4882a593Smuzhiyun 	WARN_ON(mc_record->num_entries);
302*4882a593Smuzhiyun 	kfree(mc_record);
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun static struct mlxsw_sp_nve_mc_record *
mlxsw_sp_nve_mc_record_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nve_mc_list * mc_list,enum mlxsw_sp_l3proto proto)306*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_get(struct mlxsw_sp *mlxsw_sp,
307*4882a593Smuzhiyun 			   struct mlxsw_sp_nve_mc_list *mc_list,
308*4882a593Smuzhiyun 			   enum mlxsw_sp_l3proto proto)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *mc_record;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	list_for_each_entry_reverse(mc_record, &mc_list->records_list, list) {
313*4882a593Smuzhiyun 		unsigned int num_entries = mc_record->num_entries;
314*4882a593Smuzhiyun 		struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 		if (mc_record->proto == proto &&
317*4882a593Smuzhiyun 		    num_entries < nve->num_max_mc_entries[proto])
318*4882a593Smuzhiyun 			return mc_record;
319*4882a593Smuzhiyun 	}
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	return mlxsw_sp_nve_mc_record_create(mlxsw_sp, mc_list, proto);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_record_put(struct mlxsw_sp_nve_mc_record * mc_record)325*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_put(struct mlxsw_sp_nve_mc_record *mc_record)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	if (mc_record->num_entries != 0)
328*4882a593Smuzhiyun 		return;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_record_destroy(mc_record);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun static struct mlxsw_sp_nve_mc_entry *
mlxsw_sp_nve_mc_free_entry_find(struct mlxsw_sp_nve_mc_record * mc_record)334*4882a593Smuzhiyun mlxsw_sp_nve_mc_free_entry_find(struct mlxsw_sp_nve_mc_record *mc_record)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
337*4882a593Smuzhiyun 	unsigned int num_max_entries;
338*4882a593Smuzhiyun 	int i;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	num_max_entries = nve->num_max_mc_entries[mc_record->proto];
341*4882a593Smuzhiyun 	for (i = 0; i < num_max_entries; i++) {
342*4882a593Smuzhiyun 		if (mc_record->entries[i].valid)
343*4882a593Smuzhiyun 			continue;
344*4882a593Smuzhiyun 		return &mc_record->entries[i];
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return NULL;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun static int
mlxsw_sp_nve_mc_record_refresh(struct mlxsw_sp_nve_mc_record * mc_record)351*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_refresh(struct mlxsw_sp_nve_mc_record *mc_record)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun 	enum mlxsw_reg_tnumt_record_type type = mc_record->ops->type;
354*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
355*4882a593Smuzhiyun 	struct mlxsw_sp *mlxsw_sp = mc_record->mlxsw_sp;
356*4882a593Smuzhiyun 	char tnumt_pl[MLXSW_REG_TNUMT_LEN];
357*4882a593Smuzhiyun 	unsigned int num_max_entries;
358*4882a593Smuzhiyun 	unsigned int num_entries = 0;
359*4882a593Smuzhiyun 	u32 next_kvdl_index = 0;
360*4882a593Smuzhiyun 	bool next_valid = false;
361*4882a593Smuzhiyun 	int i;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (!list_is_last(&mc_record->list, &mc_list->records_list)) {
364*4882a593Smuzhiyun 		struct mlxsw_sp_nve_mc_record *next_record;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 		next_record = list_next_entry(mc_record, list);
367*4882a593Smuzhiyun 		next_kvdl_index = next_record->kvdl_index;
368*4882a593Smuzhiyun 		next_valid = true;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	mlxsw_reg_tnumt_pack(tnumt_pl, type, MLXSW_REG_TNUMT_TUNNEL_PORT_NVE,
372*4882a593Smuzhiyun 			     mc_record->kvdl_index, next_valid,
373*4882a593Smuzhiyun 			     next_kvdl_index, mc_record->num_entries);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	num_max_entries = mlxsw_sp->nve->num_max_mc_entries[mc_record->proto];
376*4882a593Smuzhiyun 	for (i = 0; i < num_max_entries; i++) {
377*4882a593Smuzhiyun 		struct mlxsw_sp_nve_mc_entry *mc_entry;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 		mc_entry = &mc_record->entries[i];
380*4882a593Smuzhiyun 		if (!mc_entry->valid)
381*4882a593Smuzhiyun 			continue;
382*4882a593Smuzhiyun 		mc_record->ops->entry_set(mc_record, mc_entry, tnumt_pl,
383*4882a593Smuzhiyun 					  num_entries++);
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	WARN_ON(num_entries != mc_record->num_entries);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnumt), tnumt_pl);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun static bool
mlxsw_sp_nve_mc_record_is_first(struct mlxsw_sp_nve_mc_record * mc_record)392*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_is_first(struct mlxsw_sp_nve_mc_record *mc_record)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
395*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *first_record;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	first_record = list_first_entry(&mc_list->records_list,
398*4882a593Smuzhiyun 					struct mlxsw_sp_nve_mc_record, list);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	return mc_record == first_record;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun static struct mlxsw_sp_nve_mc_entry *
mlxsw_sp_nve_mc_entry_find(struct mlxsw_sp_nve_mc_record * mc_record,union mlxsw_sp_l3addr * addr)404*4882a593Smuzhiyun mlxsw_sp_nve_mc_entry_find(struct mlxsw_sp_nve_mc_record *mc_record,
405*4882a593Smuzhiyun 			   union mlxsw_sp_l3addr *addr)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
408*4882a593Smuzhiyun 	unsigned int num_max_entries;
409*4882a593Smuzhiyun 	int i;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	num_max_entries = nve->num_max_mc_entries[mc_record->proto];
412*4882a593Smuzhiyun 	for (i = 0; i < num_max_entries; i++) {
413*4882a593Smuzhiyun 		struct mlxsw_sp_nve_mc_entry *mc_entry;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 		mc_entry = &mc_record->entries[i];
416*4882a593Smuzhiyun 		if (!mc_entry->valid)
417*4882a593Smuzhiyun 			continue;
418*4882a593Smuzhiyun 		if (mc_record->ops->entry_compare(mc_record, mc_entry, addr))
419*4882a593Smuzhiyun 			return mc_entry;
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	return NULL;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun static int
mlxsw_sp_nve_mc_record_ip_add(struct mlxsw_sp_nve_mc_record * mc_record,union mlxsw_sp_l3addr * addr)426*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_ip_add(struct mlxsw_sp_nve_mc_record *mc_record,
427*4882a593Smuzhiyun 			      union mlxsw_sp_l3addr *addr)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_entry *mc_entry = NULL;
430*4882a593Smuzhiyun 	int err;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	mc_entry = mlxsw_sp_nve_mc_free_entry_find(mc_record);
433*4882a593Smuzhiyun 	if (WARN_ON(!mc_entry))
434*4882a593Smuzhiyun 		return -EINVAL;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	err = mc_record->ops->entry_add(mc_record, mc_entry, addr);
437*4882a593Smuzhiyun 	if (err)
438*4882a593Smuzhiyun 		return err;
439*4882a593Smuzhiyun 	mc_record->num_entries++;
440*4882a593Smuzhiyun 	mc_entry->valid = true;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	err = mlxsw_sp_nve_mc_record_refresh(mc_record);
443*4882a593Smuzhiyun 	if (err)
444*4882a593Smuzhiyun 		goto err_record_refresh;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	/* If this is a new record and not the first one, then we need to
447*4882a593Smuzhiyun 	 * update the next pointer of the previous entry
448*4882a593Smuzhiyun 	 */
449*4882a593Smuzhiyun 	if (mc_record->num_entries != 1 ||
450*4882a593Smuzhiyun 	    mlxsw_sp_nve_mc_record_is_first(mc_record))
451*4882a593Smuzhiyun 		return 0;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	err = mlxsw_sp_nve_mc_record_refresh(list_prev_entry(mc_record, list));
454*4882a593Smuzhiyun 	if (err)
455*4882a593Smuzhiyun 		goto err_prev_record_refresh;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	return 0;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun err_prev_record_refresh:
460*4882a593Smuzhiyun err_record_refresh:
461*4882a593Smuzhiyun 	mc_entry->valid = false;
462*4882a593Smuzhiyun 	mc_record->num_entries--;
463*4882a593Smuzhiyun 	mc_record->ops->entry_del(mc_record, mc_entry);
464*4882a593Smuzhiyun 	return err;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_record_entry_del(struct mlxsw_sp_nve_mc_record * mc_record,struct mlxsw_sp_nve_mc_entry * mc_entry)468*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_entry_del(struct mlxsw_sp_nve_mc_record *mc_record,
469*4882a593Smuzhiyun 				 struct mlxsw_sp_nve_mc_entry *mc_entry)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	mc_entry->valid = false;
474*4882a593Smuzhiyun 	mc_record->num_entries--;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	/* When the record continues to exist we only need to invalidate
477*4882a593Smuzhiyun 	 * the requested entry
478*4882a593Smuzhiyun 	 */
479*4882a593Smuzhiyun 	if (mc_record->num_entries != 0) {
480*4882a593Smuzhiyun 		mlxsw_sp_nve_mc_record_refresh(mc_record);
481*4882a593Smuzhiyun 		mc_record->ops->entry_del(mc_record, mc_entry);
482*4882a593Smuzhiyun 		return;
483*4882a593Smuzhiyun 	}
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	/* If the record needs to be deleted, but it is not the first,
486*4882a593Smuzhiyun 	 * then we need to make sure that the previous record no longer
487*4882a593Smuzhiyun 	 * points to it. Remove deleted record from the list to reflect
488*4882a593Smuzhiyun 	 * that and then re-add it at the end, so that it could be
489*4882a593Smuzhiyun 	 * properly removed by the record destruction code
490*4882a593Smuzhiyun 	 */
491*4882a593Smuzhiyun 	if (!mlxsw_sp_nve_mc_record_is_first(mc_record)) {
492*4882a593Smuzhiyun 		struct mlxsw_sp_nve_mc_record *prev_record;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 		prev_record = list_prev_entry(mc_record, list);
495*4882a593Smuzhiyun 		list_del(&mc_record->list);
496*4882a593Smuzhiyun 		mlxsw_sp_nve_mc_record_refresh(prev_record);
497*4882a593Smuzhiyun 		list_add_tail(&mc_record->list, &mc_list->records_list);
498*4882a593Smuzhiyun 		mc_record->ops->entry_del(mc_record, mc_entry);
499*4882a593Smuzhiyun 		return;
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	/* If the first record needs to be deleted, but the list is not
503*4882a593Smuzhiyun 	 * singular, then the second record needs to be written in the
504*4882a593Smuzhiyun 	 * first record's address, as this address is stored as a property
505*4882a593Smuzhiyun 	 * of the FID
506*4882a593Smuzhiyun 	 */
507*4882a593Smuzhiyun 	if (mlxsw_sp_nve_mc_record_is_first(mc_record) &&
508*4882a593Smuzhiyun 	    !list_is_singular(&mc_list->records_list)) {
509*4882a593Smuzhiyun 		struct mlxsw_sp_nve_mc_record *next_record;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 		next_record = list_next_entry(mc_record, list);
512*4882a593Smuzhiyun 		swap(mc_record->kvdl_index, next_record->kvdl_index);
513*4882a593Smuzhiyun 		mlxsw_sp_nve_mc_record_refresh(next_record);
514*4882a593Smuzhiyun 		mc_record->ops->entry_del(mc_record, mc_entry);
515*4882a593Smuzhiyun 		return;
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	/* This is the last case where the last remaining record needs to
519*4882a593Smuzhiyun 	 * be deleted. Simply delete the entry
520*4882a593Smuzhiyun 	 */
521*4882a593Smuzhiyun 	mc_record->ops->entry_del(mc_record, mc_entry);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun static struct mlxsw_sp_nve_mc_record *
mlxsw_sp_nve_mc_record_find(struct mlxsw_sp_nve_mc_list * mc_list,enum mlxsw_sp_l3proto proto,union mlxsw_sp_l3addr * addr,struct mlxsw_sp_nve_mc_entry ** mc_entry)525*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_find(struct mlxsw_sp_nve_mc_list *mc_list,
526*4882a593Smuzhiyun 			    enum mlxsw_sp_l3proto proto,
527*4882a593Smuzhiyun 			    union mlxsw_sp_l3addr *addr,
528*4882a593Smuzhiyun 			    struct mlxsw_sp_nve_mc_entry **mc_entry)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *mc_record;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	list_for_each_entry(mc_record, &mc_list->records_list, list) {
533*4882a593Smuzhiyun 		if (mc_record->proto != proto)
534*4882a593Smuzhiyun 			continue;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 		*mc_entry = mlxsw_sp_nve_mc_entry_find(mc_record, addr);
537*4882a593Smuzhiyun 		if (*mc_entry)
538*4882a593Smuzhiyun 			return mc_record;
539*4882a593Smuzhiyun 	}
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	return NULL;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
mlxsw_sp_nve_mc_list_ip_add(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nve_mc_list * mc_list,enum mlxsw_sp_l3proto proto,union mlxsw_sp_l3addr * addr)544*4882a593Smuzhiyun static int mlxsw_sp_nve_mc_list_ip_add(struct mlxsw_sp *mlxsw_sp,
545*4882a593Smuzhiyun 				       struct mlxsw_sp_nve_mc_list *mc_list,
546*4882a593Smuzhiyun 				       enum mlxsw_sp_l3proto proto,
547*4882a593Smuzhiyun 				       union mlxsw_sp_l3addr *addr)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *mc_record;
550*4882a593Smuzhiyun 	int err;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	mc_record = mlxsw_sp_nve_mc_record_get(mlxsw_sp, mc_list, proto);
553*4882a593Smuzhiyun 	if (IS_ERR(mc_record))
554*4882a593Smuzhiyun 		return PTR_ERR(mc_record);
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	err = mlxsw_sp_nve_mc_record_ip_add(mc_record, addr);
557*4882a593Smuzhiyun 	if (err)
558*4882a593Smuzhiyun 		goto err_ip_add;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	return 0;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun err_ip_add:
563*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_record_put(mc_record);
564*4882a593Smuzhiyun 	return err;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun 
mlxsw_sp_nve_mc_list_ip_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nve_mc_list * mc_list,enum mlxsw_sp_l3proto proto,union mlxsw_sp_l3addr * addr)567*4882a593Smuzhiyun static void mlxsw_sp_nve_mc_list_ip_del(struct mlxsw_sp *mlxsw_sp,
568*4882a593Smuzhiyun 					struct mlxsw_sp_nve_mc_list *mc_list,
569*4882a593Smuzhiyun 					enum mlxsw_sp_l3proto proto,
570*4882a593Smuzhiyun 					union mlxsw_sp_l3addr *addr)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *mc_record;
573*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_entry *mc_entry;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	mc_record = mlxsw_sp_nve_mc_record_find(mc_list, proto, addr,
576*4882a593Smuzhiyun 						&mc_entry);
577*4882a593Smuzhiyun 	if (!mc_record)
578*4882a593Smuzhiyun 		return;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_record_entry_del(mc_record, mc_entry);
581*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_record_put(mc_record);
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun static int
mlxsw_sp_nve_fid_flood_index_set(struct mlxsw_sp_fid * fid,struct mlxsw_sp_nve_mc_list * mc_list)585*4882a593Smuzhiyun mlxsw_sp_nve_fid_flood_index_set(struct mlxsw_sp_fid *fid,
586*4882a593Smuzhiyun 				 struct mlxsw_sp_nve_mc_list *mc_list)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *mc_record;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	/* The address of the first record in the list is a property of
591*4882a593Smuzhiyun 	 * the FID and we never change it. It only needs to be set when
592*4882a593Smuzhiyun 	 * a new list is created
593*4882a593Smuzhiyun 	 */
594*4882a593Smuzhiyun 	if (mlxsw_sp_fid_nve_flood_index_is_set(fid))
595*4882a593Smuzhiyun 		return 0;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	mc_record = list_first_entry(&mc_list->records_list,
598*4882a593Smuzhiyun 				     struct mlxsw_sp_nve_mc_record, list);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	return mlxsw_sp_fid_nve_flood_index_set(fid, mc_record->kvdl_index);
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun static void
mlxsw_sp_nve_fid_flood_index_clear(struct mlxsw_sp_fid * fid,struct mlxsw_sp_nve_mc_list * mc_list)604*4882a593Smuzhiyun mlxsw_sp_nve_fid_flood_index_clear(struct mlxsw_sp_fid *fid,
605*4882a593Smuzhiyun 				   struct mlxsw_sp_nve_mc_list *mc_list)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *mc_record;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	/* The address of the first record needs to be invalidated only when
610*4882a593Smuzhiyun 	 * the last record is about to be removed
611*4882a593Smuzhiyun 	 */
612*4882a593Smuzhiyun 	if (!list_is_singular(&mc_list->records_list))
613*4882a593Smuzhiyun 		return;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	mc_record = list_first_entry(&mc_list->records_list,
616*4882a593Smuzhiyun 				     struct mlxsw_sp_nve_mc_record, list);
617*4882a593Smuzhiyun 	if (mc_record->num_entries != 1)
618*4882a593Smuzhiyun 		return;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	return mlxsw_sp_fid_nve_flood_index_clear(fid);
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun 
mlxsw_sp_nve_flood_ip_add(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid * fid,enum mlxsw_sp_l3proto proto,union mlxsw_sp_l3addr * addr)623*4882a593Smuzhiyun int mlxsw_sp_nve_flood_ip_add(struct mlxsw_sp *mlxsw_sp,
624*4882a593Smuzhiyun 			      struct mlxsw_sp_fid *fid,
625*4882a593Smuzhiyun 			      enum mlxsw_sp_l3proto proto,
626*4882a593Smuzhiyun 			      union mlxsw_sp_l3addr *addr)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list_key key = { 0 };
629*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list;
630*4882a593Smuzhiyun 	int err;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	key.fid_index = mlxsw_sp_fid_index(fid);
633*4882a593Smuzhiyun 	mc_list = mlxsw_sp_nve_mc_list_get(mlxsw_sp, &key);
634*4882a593Smuzhiyun 	if (IS_ERR(mc_list))
635*4882a593Smuzhiyun 		return PTR_ERR(mc_list);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	err = mlxsw_sp_nve_mc_list_ip_add(mlxsw_sp, mc_list, proto, addr);
638*4882a593Smuzhiyun 	if (err)
639*4882a593Smuzhiyun 		goto err_add_ip;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	err = mlxsw_sp_nve_fid_flood_index_set(fid, mc_list);
642*4882a593Smuzhiyun 	if (err)
643*4882a593Smuzhiyun 		goto err_fid_flood_index_set;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	return 0;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun err_fid_flood_index_set:
648*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_list_ip_del(mlxsw_sp, mc_list, proto, addr);
649*4882a593Smuzhiyun err_add_ip:
650*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
651*4882a593Smuzhiyun 	return err;
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun 
mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid * fid,enum mlxsw_sp_l3proto proto,union mlxsw_sp_l3addr * addr)654*4882a593Smuzhiyun void mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp *mlxsw_sp,
655*4882a593Smuzhiyun 			       struct mlxsw_sp_fid *fid,
656*4882a593Smuzhiyun 			       enum mlxsw_sp_l3proto proto,
657*4882a593Smuzhiyun 			       union mlxsw_sp_l3addr *addr)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list_key key = { 0 };
660*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	key.fid_index = mlxsw_sp_fid_index(fid);
663*4882a593Smuzhiyun 	mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, &key);
664*4882a593Smuzhiyun 	if (!mc_list)
665*4882a593Smuzhiyun 		return;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	mlxsw_sp_nve_fid_flood_index_clear(fid, mc_list);
668*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_list_ip_del(mlxsw_sp, mc_list, proto, addr);
669*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun static void
mlxsw_sp_nve_mc_record_delete(struct mlxsw_sp_nve_mc_record * mc_record)673*4882a593Smuzhiyun mlxsw_sp_nve_mc_record_delete(struct mlxsw_sp_nve_mc_record *mc_record)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
676*4882a593Smuzhiyun 	unsigned int num_max_entries;
677*4882a593Smuzhiyun 	int i;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	num_max_entries = nve->num_max_mc_entries[mc_record->proto];
680*4882a593Smuzhiyun 	for (i = 0; i < num_max_entries; i++) {
681*4882a593Smuzhiyun 		struct mlxsw_sp_nve_mc_entry *mc_entry = &mc_record->entries[i];
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 		if (!mc_entry->valid)
684*4882a593Smuzhiyun 			continue;
685*4882a593Smuzhiyun 		mlxsw_sp_nve_mc_record_entry_del(mc_record, mc_entry);
686*4882a593Smuzhiyun 	}
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	WARN_ON(mc_record->num_entries);
689*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_record_put(mc_record);
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun 
mlxsw_sp_nve_flood_ip_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid * fid)692*4882a593Smuzhiyun static void mlxsw_sp_nve_flood_ip_flush(struct mlxsw_sp *mlxsw_sp,
693*4882a593Smuzhiyun 					struct mlxsw_sp_fid *fid)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_record *mc_record, *tmp;
696*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list_key key = { 0 };
697*4882a593Smuzhiyun 	struct mlxsw_sp_nve_mc_list *mc_list;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	if (!mlxsw_sp_fid_nve_flood_index_is_set(fid))
700*4882a593Smuzhiyun 		return;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	mlxsw_sp_fid_nve_flood_index_clear(fid);
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	key.fid_index = mlxsw_sp_fid_index(fid);
705*4882a593Smuzhiyun 	mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, &key);
706*4882a593Smuzhiyun 	if (WARN_ON(!mc_list))
707*4882a593Smuzhiyun 		return;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	list_for_each_entry_safe(mc_record, tmp, &mc_list->records_list, list)
710*4882a593Smuzhiyun 		mlxsw_sp_nve_mc_record_delete(mc_record);
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	WARN_ON(!list_empty(&mc_list->records_list));
713*4882a593Smuzhiyun 	mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun 
mlxsw_sp_nve_tunnel_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nve_config * config)716*4882a593Smuzhiyun static int mlxsw_sp_nve_tunnel_init(struct mlxsw_sp *mlxsw_sp,
717*4882a593Smuzhiyun 				    struct mlxsw_sp_nve_config *config)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
720*4882a593Smuzhiyun 	const struct mlxsw_sp_nve_ops *ops;
721*4882a593Smuzhiyun 	int err;
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	if (nve->num_nve_tunnels++ != 0)
724*4882a593Smuzhiyun 		return 0;
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	nve->config = *config;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
729*4882a593Smuzhiyun 				  &nve->tunnel_index);
730*4882a593Smuzhiyun 	if (err)
731*4882a593Smuzhiyun 		goto err_kvdl_alloc;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	ops = nve->nve_ops_arr[config->type];
734*4882a593Smuzhiyun 	err = ops->init(nve, config);
735*4882a593Smuzhiyun 	if (err)
736*4882a593Smuzhiyun 		goto err_ops_init;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	return 0;
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun err_ops_init:
741*4882a593Smuzhiyun 	mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
742*4882a593Smuzhiyun 			   nve->tunnel_index);
743*4882a593Smuzhiyun err_kvdl_alloc:
744*4882a593Smuzhiyun 	memset(&nve->config, 0, sizeof(nve->config));
745*4882a593Smuzhiyun 	nve->num_nve_tunnels--;
746*4882a593Smuzhiyun 	return err;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun 
mlxsw_sp_nve_tunnel_fini(struct mlxsw_sp * mlxsw_sp)749*4882a593Smuzhiyun static void mlxsw_sp_nve_tunnel_fini(struct mlxsw_sp *mlxsw_sp)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
752*4882a593Smuzhiyun 	const struct mlxsw_sp_nve_ops *ops;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	ops = nve->nve_ops_arr[nve->config.type];
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	if (mlxsw_sp->nve->num_nve_tunnels == 1) {
757*4882a593Smuzhiyun 		ops->fini(nve);
758*4882a593Smuzhiyun 		mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
759*4882a593Smuzhiyun 				   nve->tunnel_index);
760*4882a593Smuzhiyun 		memset(&nve->config, 0, sizeof(nve->config));
761*4882a593Smuzhiyun 	}
762*4882a593Smuzhiyun 	nve->num_nve_tunnels--;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun 
mlxsw_sp_nve_fdb_flush_by_fid(struct mlxsw_sp * mlxsw_sp,u16 fid_index)765*4882a593Smuzhiyun static void mlxsw_sp_nve_fdb_flush_by_fid(struct mlxsw_sp *mlxsw_sp,
766*4882a593Smuzhiyun 					  u16 fid_index)
767*4882a593Smuzhiyun {
768*4882a593Smuzhiyun 	char sfdf_pl[MLXSW_REG_SFDF_LEN];
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_NVE_AND_FID);
771*4882a593Smuzhiyun 	mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index);
772*4882a593Smuzhiyun 	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl);
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun 
mlxsw_sp_nve_fdb_clear_offload(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev,__be32 vni)775*4882a593Smuzhiyun static void mlxsw_sp_nve_fdb_clear_offload(struct mlxsw_sp *mlxsw_sp,
776*4882a593Smuzhiyun 					   const struct mlxsw_sp_fid *fid,
777*4882a593Smuzhiyun 					   const struct net_device *nve_dev,
778*4882a593Smuzhiyun 					   __be32 vni)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun 	const struct mlxsw_sp_nve_ops *ops;
781*4882a593Smuzhiyun 	enum mlxsw_sp_nve_type type;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	if (WARN_ON(mlxsw_sp_fid_nve_type(fid, &type)))
784*4882a593Smuzhiyun 		return;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	ops = mlxsw_sp->nve->nve_ops_arr[type];
787*4882a593Smuzhiyun 	ops->fdb_clear_offload(nve_dev, vni);
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun 
mlxsw_sp_nve_fid_enable(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid * fid,struct mlxsw_sp_nve_params * params,struct netlink_ext_ack * extack)790*4882a593Smuzhiyun int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
791*4882a593Smuzhiyun 			    struct mlxsw_sp_nve_params *params,
792*4882a593Smuzhiyun 			    struct netlink_ext_ack *extack)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
795*4882a593Smuzhiyun 	const struct mlxsw_sp_nve_ops *ops;
796*4882a593Smuzhiyun 	struct mlxsw_sp_nve_config config;
797*4882a593Smuzhiyun 	int err;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	ops = nve->nve_ops_arr[params->type];
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	if (!ops->can_offload(nve, params->dev, extack))
802*4882a593Smuzhiyun 		return -EINVAL;
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	memset(&config, 0, sizeof(config));
805*4882a593Smuzhiyun 	ops->nve_config(nve, params->dev, &config);
806*4882a593Smuzhiyun 	if (nve->num_nve_tunnels &&
807*4882a593Smuzhiyun 	    memcmp(&config, &nve->config, sizeof(config))) {
808*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Conflicting NVE tunnels configuration");
809*4882a593Smuzhiyun 		return -EINVAL;
810*4882a593Smuzhiyun 	}
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	err = mlxsw_sp_nve_tunnel_init(mlxsw_sp, &config);
813*4882a593Smuzhiyun 	if (err) {
814*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Failed to initialize NVE tunnel");
815*4882a593Smuzhiyun 		return err;
816*4882a593Smuzhiyun 	}
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	err = mlxsw_sp_fid_vni_set(fid, params->type, params->vni,
819*4882a593Smuzhiyun 				   params->dev->ifindex);
820*4882a593Smuzhiyun 	if (err) {
821*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Failed to set VNI on FID");
822*4882a593Smuzhiyun 		goto err_fid_vni_set;
823*4882a593Smuzhiyun 	}
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	err = ops->fdb_replay(params->dev, params->vni, extack);
826*4882a593Smuzhiyun 	if (err)
827*4882a593Smuzhiyun 		goto err_fdb_replay;
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	return 0;
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun err_fdb_replay:
832*4882a593Smuzhiyun 	mlxsw_sp_fid_vni_clear(fid);
833*4882a593Smuzhiyun err_fid_vni_set:
834*4882a593Smuzhiyun 	mlxsw_sp_nve_tunnel_fini(mlxsw_sp);
835*4882a593Smuzhiyun 	return err;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
mlxsw_sp_nve_fid_disable(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid * fid)838*4882a593Smuzhiyun void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp,
839*4882a593Smuzhiyun 			      struct mlxsw_sp_fid *fid)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun 	u16 fid_index = mlxsw_sp_fid_index(fid);
842*4882a593Smuzhiyun 	struct net_device *nve_dev;
843*4882a593Smuzhiyun 	int nve_ifindex;
844*4882a593Smuzhiyun 	__be32 vni;
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	mlxsw_sp_nve_flood_ip_flush(mlxsw_sp, fid);
847*4882a593Smuzhiyun 	mlxsw_sp_nve_fdb_flush_by_fid(mlxsw_sp, fid_index);
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	if (WARN_ON(mlxsw_sp_fid_nve_ifindex(fid, &nve_ifindex) ||
850*4882a593Smuzhiyun 		    mlxsw_sp_fid_vni(fid, &vni)))
851*4882a593Smuzhiyun 		goto out;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	nve_dev = dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex);
854*4882a593Smuzhiyun 	if (!nve_dev)
855*4882a593Smuzhiyun 		goto out;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	mlxsw_sp_nve_fdb_clear_offload(mlxsw_sp, fid, nve_dev, vni);
858*4882a593Smuzhiyun 	mlxsw_sp_fid_fdb_clear_offload(fid, nve_dev);
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	dev_put(nve_dev);
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun out:
863*4882a593Smuzhiyun 	mlxsw_sp_fid_vni_clear(fid);
864*4882a593Smuzhiyun 	mlxsw_sp_nve_tunnel_fini(mlxsw_sp);
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun 
mlxsw_sp_port_nve_init(struct mlxsw_sp_port * mlxsw_sp_port)867*4882a593Smuzhiyun int mlxsw_sp_port_nve_init(struct mlxsw_sp_port *mlxsw_sp_port)
868*4882a593Smuzhiyun {
869*4882a593Smuzhiyun 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
870*4882a593Smuzhiyun 	char tnqdr_pl[MLXSW_REG_TNQDR_LEN];
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 	mlxsw_reg_tnqdr_pack(tnqdr_pl, mlxsw_sp_port->local_port);
873*4882a593Smuzhiyun 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnqdr), tnqdr_pl);
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun 
mlxsw_sp_port_nve_fini(struct mlxsw_sp_port * mlxsw_sp_port)876*4882a593Smuzhiyun void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port)
877*4882a593Smuzhiyun {
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun 
mlxsw_sp_nve_qos_init(struct mlxsw_sp * mlxsw_sp)880*4882a593Smuzhiyun static int mlxsw_sp_nve_qos_init(struct mlxsw_sp *mlxsw_sp)
881*4882a593Smuzhiyun {
882*4882a593Smuzhiyun 	char tnqcr_pl[MLXSW_REG_TNQCR_LEN];
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	mlxsw_reg_tnqcr_pack(tnqcr_pl);
885*4882a593Smuzhiyun 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnqcr), tnqcr_pl);
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun 
mlxsw_sp_nve_ecn_encap_init(struct mlxsw_sp * mlxsw_sp)888*4882a593Smuzhiyun static int mlxsw_sp_nve_ecn_encap_init(struct mlxsw_sp *mlxsw_sp)
889*4882a593Smuzhiyun {
890*4882a593Smuzhiyun 	int i;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	/* Iterate over inner ECN values */
893*4882a593Smuzhiyun 	for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
894*4882a593Smuzhiyun 		u8 outer_ecn = INET_ECN_encapsulate(0, i);
895*4882a593Smuzhiyun 		char tneem_pl[MLXSW_REG_TNEEM_LEN];
896*4882a593Smuzhiyun 		int err;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 		mlxsw_reg_tneem_pack(tneem_pl, i, outer_ecn);
899*4882a593Smuzhiyun 		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tneem),
900*4882a593Smuzhiyun 				      tneem_pl);
901*4882a593Smuzhiyun 		if (err)
902*4882a593Smuzhiyun 			return err;
903*4882a593Smuzhiyun 	}
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	return 0;
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun 
__mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp * mlxsw_sp,u8 inner_ecn,u8 outer_ecn)908*4882a593Smuzhiyun static int __mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp *mlxsw_sp,
909*4882a593Smuzhiyun 					 u8 inner_ecn, u8 outer_ecn)
910*4882a593Smuzhiyun {
911*4882a593Smuzhiyun 	char tndem_pl[MLXSW_REG_TNDEM_LEN];
912*4882a593Smuzhiyun 	u8 new_inner_ecn;
913*4882a593Smuzhiyun 	bool trap_en;
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	new_inner_ecn = mlxsw_sp_tunnel_ecn_decap(outer_ecn, inner_ecn,
916*4882a593Smuzhiyun 						  &trap_en);
917*4882a593Smuzhiyun 	mlxsw_reg_tndem_pack(tndem_pl, outer_ecn, inner_ecn, new_inner_ecn,
918*4882a593Smuzhiyun 			     trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0);
919*4882a593Smuzhiyun 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tndem), tndem_pl);
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun 
mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp * mlxsw_sp)922*4882a593Smuzhiyun static int mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp *mlxsw_sp)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun 	int i;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	/* Iterate over inner ECN values */
927*4882a593Smuzhiyun 	for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
928*4882a593Smuzhiyun 		int j;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 		/* Iterate over outer ECN values */
931*4882a593Smuzhiyun 		for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) {
932*4882a593Smuzhiyun 			int err;
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 			err = __mlxsw_sp_nve_ecn_decap_init(mlxsw_sp, i, j);
935*4882a593Smuzhiyun 			if (err)
936*4882a593Smuzhiyun 				return err;
937*4882a593Smuzhiyun 		}
938*4882a593Smuzhiyun 	}
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	return 0;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun 
mlxsw_sp_nve_ecn_init(struct mlxsw_sp * mlxsw_sp)943*4882a593Smuzhiyun static int mlxsw_sp_nve_ecn_init(struct mlxsw_sp *mlxsw_sp)
944*4882a593Smuzhiyun {
945*4882a593Smuzhiyun 	int err;
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	err = mlxsw_sp_nve_ecn_encap_init(mlxsw_sp);
948*4882a593Smuzhiyun 	if (err)
949*4882a593Smuzhiyun 		return err;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	return mlxsw_sp_nve_ecn_decap_init(mlxsw_sp);
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun 
mlxsw_sp_nve_resources_query(struct mlxsw_sp * mlxsw_sp)954*4882a593Smuzhiyun static int mlxsw_sp_nve_resources_query(struct mlxsw_sp *mlxsw_sp)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun 	unsigned int max;
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV4) ||
959*4882a593Smuzhiyun 	    !MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV6))
960*4882a593Smuzhiyun 		return -EIO;
961*4882a593Smuzhiyun 	max = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV4);
962*4882a593Smuzhiyun 	mlxsw_sp->nve->num_max_mc_entries[MLXSW_SP_L3_PROTO_IPV4] = max;
963*4882a593Smuzhiyun 	max = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV6);
964*4882a593Smuzhiyun 	mlxsw_sp->nve->num_max_mc_entries[MLXSW_SP_L3_PROTO_IPV6] = max;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	return 0;
967*4882a593Smuzhiyun }
968*4882a593Smuzhiyun 
mlxsw_sp_nve_init(struct mlxsw_sp * mlxsw_sp)969*4882a593Smuzhiyun int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp)
970*4882a593Smuzhiyun {
971*4882a593Smuzhiyun 	struct mlxsw_sp_nve *nve;
972*4882a593Smuzhiyun 	int err;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	nve = kzalloc(sizeof(*mlxsw_sp->nve), GFP_KERNEL);
975*4882a593Smuzhiyun 	if (!nve)
976*4882a593Smuzhiyun 		return -ENOMEM;
977*4882a593Smuzhiyun 	mlxsw_sp->nve = nve;
978*4882a593Smuzhiyun 	nve->mlxsw_sp = mlxsw_sp;
979*4882a593Smuzhiyun 	nve->nve_ops_arr = mlxsw_sp->nve_ops_arr;
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	err = rhashtable_init(&nve->mc_list_ht,
982*4882a593Smuzhiyun 			      &mlxsw_sp_nve_mc_list_ht_params);
983*4882a593Smuzhiyun 	if (err)
984*4882a593Smuzhiyun 		goto err_rhashtable_init;
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	err = mlxsw_sp_nve_qos_init(mlxsw_sp);
987*4882a593Smuzhiyun 	if (err)
988*4882a593Smuzhiyun 		goto err_nve_qos_init;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	err = mlxsw_sp_nve_ecn_init(mlxsw_sp);
991*4882a593Smuzhiyun 	if (err)
992*4882a593Smuzhiyun 		goto err_nve_ecn_init;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	err = mlxsw_sp_nve_resources_query(mlxsw_sp);
995*4882a593Smuzhiyun 	if (err)
996*4882a593Smuzhiyun 		goto err_nve_resources_query;
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	return 0;
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun err_nve_resources_query:
1001*4882a593Smuzhiyun err_nve_ecn_init:
1002*4882a593Smuzhiyun err_nve_qos_init:
1003*4882a593Smuzhiyun 	rhashtable_destroy(&nve->mc_list_ht);
1004*4882a593Smuzhiyun err_rhashtable_init:
1005*4882a593Smuzhiyun 	mlxsw_sp->nve = NULL;
1006*4882a593Smuzhiyun 	kfree(nve);
1007*4882a593Smuzhiyun 	return err;
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun 
mlxsw_sp_nve_fini(struct mlxsw_sp * mlxsw_sp)1010*4882a593Smuzhiyun void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp)
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun 	WARN_ON(mlxsw_sp->nve->num_nve_tunnels);
1013*4882a593Smuzhiyun 	rhashtable_destroy(&mlxsw_sp->nve->mc_list_ht);
1014*4882a593Smuzhiyun 	kfree(mlxsw_sp->nve);
1015*4882a593Smuzhiyun 	mlxsw_sp->nve = NULL;
1016*4882a593Smuzhiyun }
1017