Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0+
  2
  3#include "lan966x_main.h"
  4#include "lan966x_vcap_ag_api.h"
  5#include "vcap_api.h"
  6#include "vcap_api_client.h"
  7
  8#define STREAMSIZE (64 * 4)
  9
 10#define LAN966X_IS2_LOOKUPS 2
 11
 12enum vcap_is2_port_sel_ipv6 {
 13	VCAP_IS2_PS_IPV6_TCPUDP_OTHER,
 14	VCAP_IS2_PS_IPV6_STD,
 15	VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER,
 16	VCAP_IS2_PS_IPV6_MAC_ETYPE,
 17};
 18
 19static struct lan966x_vcap_inst {
 20	enum vcap_type vtype; /* type of vcap */
 21	int tgt_inst; /* hardware instance number */
 22	int lookups; /* number of lookups in this vcap type */
 23	int first_cid; /* first chain id in this vcap */
 24	int last_cid; /* last chain id in this vcap */
 25	int count; /* number of available addresses */
 26} lan966x_vcap_inst_cfg[] = {
 27	{
 28		.vtype = VCAP_TYPE_IS2, /* IS2-0 */
 29		.tgt_inst = 2,
 30		.lookups = LAN966X_IS2_LOOKUPS,
 31		.first_cid = LAN966X_VCAP_CID_IS2_L0,
 32		.last_cid = LAN966X_VCAP_CID_IS2_MAX,
 33		.count = 256,
 34	},
 35};
 36
 37struct lan966x_vcap_cmd_cb {
 38	struct lan966x *lan966x;
 39	u32 instance;
 40};
 41
 42static u32 lan966x_vcap_read_update_ctrl(const struct lan966x_vcap_cmd_cb *cb)
 43{
 44	return lan_rd(cb->lan966x, VCAP_UPDATE_CTRL(cb->instance));
 45}
 46
 47static void lan966x_vcap_wait_update(struct lan966x *lan966x, int instance)
 48{
 49	const struct lan966x_vcap_cmd_cb cb = { .lan966x = lan966x,
 50						.instance = instance };
 51	u32 val;
 52
 53	readx_poll_timeout(lan966x_vcap_read_update_ctrl, &cb, val,
 54			   (val & VCAP_UPDATE_CTRL_UPDATE_SHOT) == 0, 10,
 55			   100000);
 56}
 57
 58static void __lan966x_vcap_range_init(struct lan966x *lan966x,
 59				      struct vcap_admin *admin,
 60				      u32 addr,
 61				      u32 count)
 62{
 63	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
 64	       VCAP_MV_CFG_MV_SIZE_SET(count - 1),
 65	       lan966x, VCAP_MV_CFG(admin->tgt_inst));
 66
 67	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |
 68	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
 69	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
 70	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
 71	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
 72	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(true) |
 73	       VCAP_UPDATE_CTRL_UPDATE_SHOT_SET(1),
 74	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
 75
 76	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
 77}
 78
 79static int lan966x_vcap_cid_to_lookup(int cid)
 80{
 81	if (cid >= LAN966X_VCAP_CID_IS2_L1 &&
 82	    cid < LAN966X_VCAP_CID_IS2_MAX)
 83		return 1;
 84
 85	return 0;
 86}
 87
 88static int
 89lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,
 90				  struct vcap_keyset_list *keysetlist,
 91				  u16 l3_proto)
 92{
 93	struct lan966x_port *port = netdev_priv(dev);
 94	struct lan966x *lan966x = port->lan966x;
 95	bool found = false;
 96	u32 val;
 97
 98	val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port));
 99
100	/* Collect all keysets for the port in a list */
101	if (l3_proto == ETH_P_ALL)
102		vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
103
104	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_SNAP) {
105		if (ANA_VCAP_S2_CFG_SNAP_DIS_GET(val) & (BIT(0) << lookup))
106			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_LLC);
107		else
108			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_SNAP);
109
110		found = true;
111	}
112
113	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_CFM) {
114		if (ANA_VCAP_S2_CFG_OAM_DIS_GET(val) & (BIT(0) << lookup))
115			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
116		else
117			vcap_keyset_list_add(keysetlist, VCAP_KFS_OAM);
118
119		found = true;
120	}
121
122	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {
123		if (ANA_VCAP_S2_CFG_ARP_DIS_GET(val) & (BIT(0) << lookup))
124			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
125		else
126			vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);
127
128		found = true;
129	}
130
131	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
132		if (ANA_VCAP_S2_CFG_IP_OTHER_DIS_GET(val) & (BIT(0) << lookup))
133			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
134		else
135			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
136
137		if (ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_GET(val) & (BIT(0) << lookup))
138			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
139		else
140			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
141
142		found = true;
143	}
144
145	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
146		switch (ANA_VCAP_S2_CFG_IP6_CFG_GET(val) & (0x3 << lookup)) {
147		case VCAP_IS2_PS_IPV6_TCPUDP_OTHER:
148			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_OTHER);
149			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_TCP_UDP);
150			break;
151		case VCAP_IS2_PS_IPV6_STD:
152			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
153			break;
154		case VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER:
155			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
156			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
157			break;
158		case VCAP_IS2_PS_IPV6_MAC_ETYPE:
159			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
160			break;
161		}
162
163		found = true;
164	}
165
166	if (!found)
167		vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
168
169	return 0;
170}
171
172static enum vcap_keyfield_set
173lan966x_vcap_validate_keyset(struct net_device *dev,
174			     struct vcap_admin *admin,
175			     struct vcap_rule *rule,
176			     struct vcap_keyset_list *kslist,
177			     u16 l3_proto)
178{
179	struct vcap_keyset_list keysetlist = {};
180	enum vcap_keyfield_set keysets[10] = {};
181	int lookup;
182	int err;
183
184	if (!kslist || kslist->cnt == 0)
185		return VCAP_KFS_NO_VALUE;
186
187	lookup = lan966x_vcap_cid_to_lookup(rule->vcap_chain_id);
188	keysetlist.max = ARRAY_SIZE(keysets);
189	keysetlist.keysets = keysets;
190	err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,
191						l3_proto);
192	if (err)
193		return VCAP_KFS_NO_VALUE;
194
195	/* Check if there is a match and return the match */
196	for (int i = 0; i < kslist->cnt; ++i)
197		for (int j = 0; j < keysetlist.cnt; ++j)
198			if (kslist->keysets[i] == keysets[j])
199				return kslist->keysets[i];
200
201	return VCAP_KFS_NO_VALUE;
202}
203
204static bool lan966x_vcap_is_first_chain(struct vcap_rule *rule)
205{
206	return (rule->vcap_chain_id >= LAN966X_VCAP_CID_IS2_L0 &&
207		rule->vcap_chain_id < LAN966X_VCAP_CID_IS2_L1);
208}
209
210static void lan966x_vcap_add_default_fields(struct net_device *dev,
211					    struct vcap_admin *admin,
212					    struct vcap_rule *rule)
213{
214	struct lan966x_port *port = netdev_priv(dev);
215	u32 value, mask;
216
217	if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
218				  &value, &mask))
219		vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
220				      ~BIT(port->chip_port));
221
222	if (lan966x_vcap_is_first_chain(rule))
223		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
224				      VCAP_BIT_1);
225	else
226		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
227				      VCAP_BIT_0);
228}
229
230static void lan966x_vcap_cache_erase(struct vcap_admin *admin)
231{
232	memset(admin->cache.keystream, 0, STREAMSIZE);
233	memset(admin->cache.maskstream, 0, STREAMSIZE);
234	memset(admin->cache.actionstream, 0, STREAMSIZE);
235	memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));
236}
237
238static void lan966x_vcap_cache_write(struct net_device *dev,
239				     struct vcap_admin *admin,
240				     enum vcap_selection sel,
241				     u32 start,
242				     u32 count)
243{
244	struct lan966x_port *port = netdev_priv(dev);
245	struct lan966x *lan966x = port->lan966x;
246	u32 *keystr, *mskstr, *actstr;
247
248	keystr = &admin->cache.keystream[start];
249	mskstr = &admin->cache.maskstream[start];
250	actstr = &admin->cache.actionstream[start];
251
252	switch (sel) {
253	case VCAP_SEL_ENTRY:
254		for (int i = 0; i < count; ++i) {
255			lan_wr(keystr[i] & mskstr[i], lan966x,
256			       VCAP_ENTRY_DAT(admin->tgt_inst, i));
257			lan_wr(~mskstr[i], lan966x,
258			       VCAP_MASK_DAT(admin->tgt_inst, i));
259		}
260		break;
261	case VCAP_SEL_ACTION:
262		for (int i = 0; i < count; ++i)
263			lan_wr(actstr[i], lan966x,
264			       VCAP_ACTION_DAT(admin->tgt_inst, i));
265		break;
266	case VCAP_SEL_COUNTER:
267		admin->cache.sticky = admin->cache.counter > 0;
268		lan_wr(admin->cache.counter, lan966x,
269		       VCAP_CNT_DAT(admin->tgt_inst, 0));
270		break;
271	default:
272		break;
273	}
274}
275
276static void lan966x_vcap_cache_read(struct net_device *dev,
277				    struct vcap_admin *admin,
278				    enum vcap_selection sel,
279				    u32 start,
280				    u32 count)
281{
282	struct lan966x_port *port = netdev_priv(dev);
283	struct lan966x *lan966x = port->lan966x;
284	int instance = admin->tgt_inst;
285	u32 *keystr, *mskstr, *actstr;
286
287	keystr = &admin->cache.keystream[start];
288	mskstr = &admin->cache.maskstream[start];
289	actstr = &admin->cache.actionstream[start];
290
291	if (sel & VCAP_SEL_ENTRY) {
292		for (int i = 0; i < count; ++i) {
293			keystr[i] =
294				lan_rd(lan966x, VCAP_ENTRY_DAT(instance, i));
295			mskstr[i] =
296				~lan_rd(lan966x, VCAP_MASK_DAT(instance, i));
297		}
298	}
299
300	if (sel & VCAP_SEL_ACTION)
301		for (int i = 0; i < count; ++i)
302			actstr[i] =
303				lan_rd(lan966x, VCAP_ACTION_DAT(instance, i));
304
305	if (sel & VCAP_SEL_COUNTER) {
306		admin->cache.counter =
307			lan_rd(lan966x, VCAP_CNT_DAT(instance, 0));
308		admin->cache.sticky = admin->cache.counter > 0;
309	}
310}
311
312static void lan966x_vcap_range_init(struct net_device *dev,
313				    struct vcap_admin *admin,
314				    u32 addr,
315				    u32 count)
316{
317	struct lan966x_port *port = netdev_priv(dev);
318	struct lan966x *lan966x = port->lan966x;
319
320	__lan966x_vcap_range_init(lan966x, admin, addr, count);
321}
322
323static void lan966x_vcap_update(struct net_device *dev,
324				struct vcap_admin *admin,
325				enum vcap_command cmd,
326				enum vcap_selection sel,
327				u32 addr)
328{
329	struct lan966x_port *port = netdev_priv(dev);
330	struct lan966x *lan966x = port->lan966x;
331	bool clear;
332
333	clear = (cmd == VCAP_CMD_INITIALIZE);
334
335	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
336	       VCAP_MV_CFG_MV_SIZE_SET(0),
337	       lan966x, VCAP_MV_CFG(admin->tgt_inst));
338
339	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
340	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |
341	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |
342	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |
343	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
344	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(clear) |
345	       VCAP_UPDATE_CTRL_UPDATE_SHOT,
346	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
347
348	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
349}
350
351static void lan966x_vcap_move(struct net_device *dev,
352			      struct vcap_admin *admin,
353			      u32 addr, int offset, int count)
354{
355	struct lan966x_port *port = netdev_priv(dev);
356	struct lan966x *lan966x = port->lan966x;
357	enum vcap_command cmd;
358	u16 mv_num_pos;
359	u16 mv_size;
360
361	mv_size = count - 1;
362	if (offset > 0) {
363		mv_num_pos = offset - 1;
364		cmd = VCAP_CMD_MOVE_DOWN;
365	} else {
366		mv_num_pos = -offset - 1;
367		cmd = VCAP_CMD_MOVE_UP;
368	}
369
370	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(mv_num_pos) |
371	       VCAP_MV_CFG_MV_SIZE_SET(mv_size),
372	       lan966x, VCAP_MV_CFG(admin->tgt_inst));
373
374	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
375	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
376	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
377	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
378	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
379	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(false) |
380	       VCAP_UPDATE_CTRL_UPDATE_SHOT,
381	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
382
383	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
384}
385
386static int lan966x_vcap_port_info(struct net_device *dev,
387				  struct vcap_admin *admin,
388				  struct vcap_output_print *out)
389{
390	return 0;
391}
392
393static int lan966x_vcap_enable(struct net_device *dev,
394			       struct vcap_admin *admin,
395			       bool enable)
396{
397	struct lan966x_port *port = netdev_priv(dev);
398	struct lan966x *lan966x = port->lan966x;
399
400	lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(enable),
401		ANA_VCAP_S2_CFG_ENA,
402		lan966x, ANA_VCAP_S2_CFG(port->chip_port));
403
404	return 0;
405}
406
407static struct vcap_operations lan966x_vcap_ops = {
408	.validate_keyset = lan966x_vcap_validate_keyset,
409	.add_default_fields = lan966x_vcap_add_default_fields,
410	.cache_erase = lan966x_vcap_cache_erase,
411	.cache_write = lan966x_vcap_cache_write,
412	.cache_read = lan966x_vcap_cache_read,
413	.init = lan966x_vcap_range_init,
414	.update = lan966x_vcap_update,
415	.move = lan966x_vcap_move,
416	.port_info = lan966x_vcap_port_info,
417	.enable = lan966x_vcap_enable,
418};
419
420static void lan966x_vcap_admin_free(struct vcap_admin *admin)
421{
422	if (!admin)
423		return;
424
425	kfree(admin->cache.keystream);
426	kfree(admin->cache.maskstream);
427	kfree(admin->cache.actionstream);
428	mutex_destroy(&admin->lock);
429	kfree(admin);
430}
431
432static struct vcap_admin *
433lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl,
434			 const struct lan966x_vcap_inst *cfg)
435{
436	struct vcap_admin *admin;
437
438	admin = kzalloc(sizeof(*admin), GFP_KERNEL);
439	if (!admin)
440		return ERR_PTR(-ENOMEM);
441
442	mutex_init(&admin->lock);
443	INIT_LIST_HEAD(&admin->list);
444	INIT_LIST_HEAD(&admin->rules);
445	INIT_LIST_HEAD(&admin->enabled);
446
447	admin->vtype = cfg->vtype;
448	admin->vinst = 0;
449	admin->w32be = true;
450	admin->tgt_inst = cfg->tgt_inst;
451
452	admin->lookups = cfg->lookups;
453	admin->lookups_per_instance = cfg->lookups;
454
455	admin->first_cid = cfg->first_cid;
456	admin->last_cid = cfg->last_cid;
457
458	admin->cache.keystream = kzalloc(STREAMSIZE, GFP_KERNEL);
459	admin->cache.maskstream = kzalloc(STREAMSIZE, GFP_KERNEL);
460	admin->cache.actionstream = kzalloc(STREAMSIZE, GFP_KERNEL);
461	if (!admin->cache.keystream ||
462	    !admin->cache.maskstream ||
463	    !admin->cache.actionstream) {
464		lan966x_vcap_admin_free(admin);
465		return ERR_PTR(-ENOMEM);
466	}
467
468	return admin;
469}
470
471static void lan966x_vcap_block_init(struct lan966x *lan966x,
472				    struct vcap_admin *admin,
473				    struct lan966x_vcap_inst *cfg)
474{
475	admin->first_valid_addr = 0;
476	admin->last_used_addr = cfg->count;
477	admin->last_valid_addr = cfg->count - 1;
478
479	lan_wr(VCAP_CORE_IDX_CORE_IDX_SET(0),
480	       lan966x, VCAP_CORE_IDX(admin->tgt_inst));
481	lan_wr(VCAP_CORE_MAP_CORE_MAP_SET(1),
482	       lan966x, VCAP_CORE_MAP(admin->tgt_inst));
483
484	__lan966x_vcap_range_init(lan966x, admin, admin->first_valid_addr,
485				  admin->last_valid_addr -
486					admin->first_valid_addr);
487}
488
489static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x,
490					      struct vcap_admin *admin)
491{
492	for (int p = 0; p < lan966x->num_phys_ports; ++p)
493		lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));
494}
495
496int lan966x_vcap_init(struct lan966x *lan966x)
497{
498	struct lan966x_vcap_inst *cfg;
499	struct vcap_control *ctrl;
500	struct vcap_admin *admin;
501
502	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
503	if (!ctrl)
504		return -ENOMEM;
505
506	ctrl->vcaps = lan966x_vcaps;
507	ctrl->stats = &lan966x_vcap_stats;
508	ctrl->ops = &lan966x_vcap_ops;
509
510	INIT_LIST_HEAD(&ctrl->list);
511	for (int i = 0; i < ARRAY_SIZE(lan966x_vcap_inst_cfg); ++i) {
512		cfg = &lan966x_vcap_inst_cfg[i];
513
514		admin = lan966x_vcap_admin_alloc(lan966x, ctrl, cfg);
515		if (IS_ERR(admin))
516			return PTR_ERR(admin);
517
518		lan966x_vcap_block_init(lan966x, admin, cfg);
519		lan966x_vcap_port_key_deselection(lan966x, admin);
520
521		list_add_tail(&admin->list, &ctrl->list);
522	}
523
524	lan966x->vcap_ctrl = ctrl;
525
526	return 0;
527}
528
529void lan966x_vcap_deinit(struct lan966x *lan966x)
530{
531	struct vcap_admin *admin, *admin_next;
532	struct vcap_control *ctrl;
533
534	ctrl = lan966x->vcap_ctrl;
535	if (!ctrl)
536		return;
537
538	list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) {
539		lan966x_vcap_port_key_deselection(lan966x, admin);
540		vcap_del_rules(ctrl, admin);
541		list_del(&admin->list);
542		lan966x_vcap_admin_free(admin);
543	}
544
545	kfree(ctrl);
546}