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 | #include "vcap_api_debugfs.h" |
8 | |
9 | #define STREAMSIZE (64 * 4) |
10 | |
11 | #define LAN966X_IS1_LOOKUPS 3 |
12 | #define LAN966X_IS2_LOOKUPS 2 |
13 | #define LAN966X_ES0_LOOKUPS 1 |
14 | |
15 | #define LAN966X_STAT_ESDX_GRN_BYTES 0x300 |
16 | #define LAN966X_STAT_ESDX_GRN_PKTS 0x301 |
17 | #define LAN966X_STAT_ESDX_YEL_BYTES 0x302 |
18 | #define LAN966X_STAT_ESDX_YEL_PKTS 0x303 |
19 | |
20 | static struct lan966x_vcap_inst { |
21 | enum vcap_type vtype; /* type of vcap */ |
22 | int tgt_inst; /* hardware instance number */ |
23 | int lookups; /* number of lookups in this vcap type */ |
24 | int first_cid; /* first chain id in this vcap */ |
25 | int last_cid; /* last chain id in this vcap */ |
26 | int count; /* number of available addresses */ |
27 | bool ingress; /* is vcap in the ingress path */ |
28 | } lan966x_vcap_inst_cfg[] = { |
29 | { |
30 | .vtype = VCAP_TYPE_ES0, |
31 | .tgt_inst = 0, |
32 | .lookups = LAN966X_ES0_LOOKUPS, |
33 | .first_cid = LAN966X_VCAP_CID_ES0_L0, |
34 | .last_cid = LAN966X_VCAP_CID_ES0_MAX, |
35 | .count = 64, |
36 | }, |
37 | { |
38 | .vtype = VCAP_TYPE_IS1, /* IS1-0 */ |
39 | .tgt_inst = 1, |
40 | .lookups = LAN966X_IS1_LOOKUPS, |
41 | .first_cid = LAN966X_VCAP_CID_IS1_L0, |
42 | .last_cid = LAN966X_VCAP_CID_IS1_MAX, |
43 | .count = 768, |
44 | .ingress = true, |
45 | }, |
46 | { |
47 | .vtype = VCAP_TYPE_IS2, /* IS2-0 */ |
48 | .tgt_inst = 2, |
49 | .lookups = LAN966X_IS2_LOOKUPS, |
50 | .first_cid = LAN966X_VCAP_CID_IS2_L0, |
51 | .last_cid = LAN966X_VCAP_CID_IS2_MAX, |
52 | .count = 256, |
53 | .ingress = true, |
54 | }, |
55 | }; |
56 | |
57 | struct lan966x_vcap_cmd_cb { |
58 | struct lan966x *lan966x; |
59 | u32 instance; |
60 | }; |
61 | |
62 | static u32 lan966x_vcap_read_update_ctrl(const struct lan966x_vcap_cmd_cb *cb) |
63 | { |
64 | return lan_rd(lan966x: cb->lan966x, VCAP_UPDATE_CTRL(cb->instance)); |
65 | } |
66 | |
67 | static void lan966x_vcap_wait_update(struct lan966x *lan966x, int instance) |
68 | { |
69 | const struct lan966x_vcap_cmd_cb cb = { .lan966x = lan966x, |
70 | .instance = instance }; |
71 | u32 val; |
72 | |
73 | readx_poll_timeout(lan966x_vcap_read_update_ctrl, &cb, val, |
74 | (val & VCAP_UPDATE_CTRL_UPDATE_SHOT) == 0, 10, |
75 | 100000); |
76 | } |
77 | |
78 | static void __lan966x_vcap_range_init(struct lan966x *lan966x, |
79 | struct vcap_admin *admin, |
80 | u32 addr, |
81 | u32 count) |
82 | { |
83 | lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) | |
84 | VCAP_MV_CFG_MV_SIZE_SET(count - 1), |
85 | lan966x, VCAP_MV_CFG(admin->tgt_inst)); |
86 | |
87 | lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) | |
88 | VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) | |
89 | VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) | |
90 | VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) | |
91 | VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) | |
92 | VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(true) | |
93 | VCAP_UPDATE_CTRL_UPDATE_SHOT_SET(1), |
94 | lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst)); |
95 | |
96 | lan966x_vcap_wait_update(lan966x, instance: admin->tgt_inst); |
97 | } |
98 | |
99 | static int lan966x_vcap_is1_cid_to_lookup(int cid) |
100 | { |
101 | int lookup = 0; |
102 | |
103 | if (cid >= LAN966X_VCAP_CID_IS1_L1 && |
104 | cid < LAN966X_VCAP_CID_IS1_L2) |
105 | lookup = 1; |
106 | else if (cid >= LAN966X_VCAP_CID_IS1_L2 && |
107 | cid < LAN966X_VCAP_CID_IS1_MAX) |
108 | lookup = 2; |
109 | |
110 | return lookup; |
111 | } |
112 | |
113 | static int lan966x_vcap_is2_cid_to_lookup(int cid) |
114 | { |
115 | if (cid >= LAN966X_VCAP_CID_IS2_L1 && |
116 | cid < LAN966X_VCAP_CID_IS2_MAX) |
117 | return 1; |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | /* Return the list of keysets for the vcap port configuration */ |
123 | static int |
124 | lan966x_vcap_is1_get_port_keysets(struct net_device *ndev, int lookup, |
125 | struct vcap_keyset_list *keysetlist, |
126 | u16 l3_proto) |
127 | { |
128 | struct lan966x_port *port = netdev_priv(dev: ndev); |
129 | struct lan966x *lan966x = port->lan966x; |
130 | u32 val; |
131 | |
132 | val = lan_rd(lan966x, ANA_VCAP_S1_CFG(port->chip_port, lookup)); |
133 | |
134 | /* Collect all keysets for the port in a list */ |
135 | if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) { |
136 | switch (ANA_VCAP_S1_CFG_KEY_IP4_CFG_GET(val)) { |
137 | case VCAP_IS1_PS_IPV4_7TUPLE: |
138 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_7TUPLE); |
139 | break; |
140 | case VCAP_IS1_PS_IPV4_5TUPLE_IP4: |
141 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_5TUPLE_IP4); |
142 | break; |
143 | case VCAP_IS1_PS_IPV4_NORMAL: |
144 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_NORMAL); |
145 | break; |
146 | } |
147 | } |
148 | |
149 | if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) { |
150 | switch (ANA_VCAP_S1_CFG_KEY_IP6_CFG_GET(val)) { |
151 | case VCAP_IS1_PS_IPV6_NORMAL: |
152 | case VCAP_IS1_PS_IPV6_NORMAL_IP6: |
153 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_NORMAL); |
154 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_NORMAL_IP6); |
155 | break; |
156 | case VCAP_IS1_PS_IPV6_5TUPLE_IP6: |
157 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_5TUPLE_IP6); |
158 | break; |
159 | case VCAP_IS1_PS_IPV6_7TUPLE: |
160 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_7TUPLE); |
161 | break; |
162 | case VCAP_IS1_PS_IPV6_5TUPLE_IP4: |
163 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_5TUPLE_IP4); |
164 | break; |
165 | case VCAP_IS1_PS_IPV6_DMAC_VID: |
166 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_DMAC_VID); |
167 | break; |
168 | } |
169 | } |
170 | |
171 | switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) { |
172 | case VCAP_IS1_PS_OTHER_7TUPLE: |
173 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_7TUPLE); |
174 | break; |
175 | case VCAP_IS1_PS_OTHER_NORMAL: |
176 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_NORMAL); |
177 | break; |
178 | } |
179 | |
180 | return 0; |
181 | } |
182 | |
183 | static int |
184 | lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup, |
185 | struct vcap_keyset_list *keysetlist, |
186 | u16 l3_proto) |
187 | { |
188 | struct lan966x_port *port = netdev_priv(dev); |
189 | struct lan966x *lan966x = port->lan966x; |
190 | bool found = false; |
191 | u32 val; |
192 | |
193 | val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port)); |
194 | |
195 | /* Collect all keysets for the port in a list */ |
196 | if (l3_proto == ETH_P_ALL) |
197 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_ETYPE); |
198 | |
199 | if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_SNAP) { |
200 | if (ANA_VCAP_S2_CFG_SNAP_DIS_GET(val) & (BIT(0) << lookup)) |
201 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_LLC); |
202 | else |
203 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_SNAP); |
204 | |
205 | found = true; |
206 | } |
207 | |
208 | if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_CFM) { |
209 | if (ANA_VCAP_S2_CFG_OAM_DIS_GET(val) & (BIT(0) << lookup)) |
210 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_ETYPE); |
211 | else |
212 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_OAM); |
213 | |
214 | found = true; |
215 | } |
216 | |
217 | if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) { |
218 | if (ANA_VCAP_S2_CFG_ARP_DIS_GET(val) & (BIT(0) << lookup)) |
219 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_ETYPE); |
220 | else |
221 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_ARP); |
222 | |
223 | found = true; |
224 | } |
225 | |
226 | if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) { |
227 | if (ANA_VCAP_S2_CFG_IP_OTHER_DIS_GET(val) & (BIT(0) << lookup)) |
228 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_ETYPE); |
229 | else |
230 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_IP4_OTHER); |
231 | |
232 | if (ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_GET(val) & (BIT(0) << lookup)) |
233 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_ETYPE); |
234 | else |
235 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_IP4_TCP_UDP); |
236 | |
237 | found = true; |
238 | } |
239 | |
240 | if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) { |
241 | switch (ANA_VCAP_S2_CFG_IP6_CFG_GET(val) & (0x3 << lookup)) { |
242 | case VCAP_IS2_PS_IPV6_TCPUDP_OTHER: |
243 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_IP6_OTHER); |
244 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_IP6_TCP_UDP); |
245 | break; |
246 | case VCAP_IS2_PS_IPV6_STD: |
247 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_IP6_STD); |
248 | break; |
249 | case VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER: |
250 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_IP4_OTHER); |
251 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_IP4_TCP_UDP); |
252 | break; |
253 | case VCAP_IS2_PS_IPV6_MAC_ETYPE: |
254 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_ETYPE); |
255 | break; |
256 | } |
257 | |
258 | found = true; |
259 | } |
260 | |
261 | if (!found) |
262 | vcap_keyset_list_add(keysetlist, keyset: VCAP_KFS_MAC_ETYPE); |
263 | |
264 | return 0; |
265 | } |
266 | |
267 | static enum vcap_keyfield_set |
268 | lan966x_vcap_validate_keyset(struct net_device *dev, |
269 | struct vcap_admin *admin, |
270 | struct vcap_rule *rule, |
271 | struct vcap_keyset_list *kslist, |
272 | u16 l3_proto) |
273 | { |
274 | struct vcap_keyset_list keysetlist = {}; |
275 | enum vcap_keyfield_set keysets[10] = {}; |
276 | int lookup; |
277 | int err; |
278 | |
279 | if (!kslist || kslist->cnt == 0) |
280 | return VCAP_KFS_NO_VALUE; |
281 | |
282 | keysetlist.max = ARRAY_SIZE(keysets); |
283 | keysetlist.keysets = keysets; |
284 | |
285 | switch (admin->vtype) { |
286 | case VCAP_TYPE_IS1: |
287 | lookup = lan966x_vcap_is1_cid_to_lookup(cid: rule->vcap_chain_id); |
288 | err = lan966x_vcap_is1_get_port_keysets(ndev: dev, lookup, keysetlist: &keysetlist, |
289 | l3_proto); |
290 | break; |
291 | case VCAP_TYPE_IS2: |
292 | lookup = lan966x_vcap_is2_cid_to_lookup(cid: rule->vcap_chain_id); |
293 | err = lan966x_vcap_is2_get_port_keysets(dev, lookup, keysetlist: &keysetlist, |
294 | l3_proto); |
295 | break; |
296 | case VCAP_TYPE_ES0: |
297 | return kslist->keysets[0]; |
298 | default: |
299 | pr_err("vcap type: %s not supported\n" , |
300 | lan966x_vcaps[admin->vtype].name); |
301 | return VCAP_KFS_NO_VALUE; |
302 | } |
303 | |
304 | if (err) |
305 | return VCAP_KFS_NO_VALUE; |
306 | |
307 | /* Check if there is a match and return the match */ |
308 | for (int i = 0; i < kslist->cnt; ++i) |
309 | for (int j = 0; j < keysetlist.cnt; ++j) |
310 | if (kslist->keysets[i] == keysets[j]) |
311 | return kslist->keysets[i]; |
312 | |
313 | return VCAP_KFS_NO_VALUE; |
314 | } |
315 | |
316 | static bool lan966x_vcap_is2_is_first_chain(struct vcap_rule *rule) |
317 | { |
318 | return (rule->vcap_chain_id >= LAN966X_VCAP_CID_IS2_L0 && |
319 | rule->vcap_chain_id < LAN966X_VCAP_CID_IS2_L1); |
320 | } |
321 | |
322 | static void lan966x_vcap_is1_add_default_fields(struct lan966x_port *port, |
323 | struct vcap_admin *admin, |
324 | struct vcap_rule *rule) |
325 | { |
326 | u32 value, mask; |
327 | u32 lookup; |
328 | |
329 | if (vcap_rule_get_key_u32(rule, key: VCAP_KF_IF_IGR_PORT_MASK, |
330 | value: &value, mask: &mask)) |
331 | vcap_rule_add_key_u32(rule, key: VCAP_KF_IF_IGR_PORT_MASK, value: 0, |
332 | mask: ~BIT(port->chip_port)); |
333 | |
334 | lookup = lan966x_vcap_is1_cid_to_lookup(cid: rule->vcap_chain_id); |
335 | vcap_rule_add_key_u32(rule, key: VCAP_KF_LOOKUP_INDEX, value: lookup, mask: 0x3); |
336 | } |
337 | |
338 | static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port, |
339 | struct vcap_admin *admin, |
340 | struct vcap_rule *rule) |
341 | { |
342 | u32 value, mask; |
343 | |
344 | if (vcap_rule_get_key_u32(rule, key: VCAP_KF_IF_IGR_PORT_MASK, |
345 | value: &value, mask: &mask)) |
346 | vcap_rule_add_key_u32(rule, key: VCAP_KF_IF_IGR_PORT_MASK, value: 0, |
347 | mask: ~BIT(port->chip_port)); |
348 | |
349 | if (lan966x_vcap_is2_is_first_chain(rule)) |
350 | vcap_rule_add_key_bit(rule, key: VCAP_KF_LOOKUP_FIRST_IS, |
351 | val: VCAP_BIT_1); |
352 | else |
353 | vcap_rule_add_key_bit(rule, key: VCAP_KF_LOOKUP_FIRST_IS, |
354 | val: VCAP_BIT_0); |
355 | } |
356 | |
357 | static void lan966x_vcap_es0_add_default_fields(struct lan966x_port *port, |
358 | struct vcap_admin *admin, |
359 | struct vcap_rule *rule) |
360 | { |
361 | vcap_rule_add_key_u32(rule, key: VCAP_KF_IF_EGR_PORT_NO, |
362 | value: port->chip_port, GENMASK(4, 0)); |
363 | } |
364 | |
365 | static void lan966x_vcap_add_default_fields(struct net_device *dev, |
366 | struct vcap_admin *admin, |
367 | struct vcap_rule *rule) |
368 | { |
369 | struct lan966x_port *port = netdev_priv(dev); |
370 | |
371 | switch (admin->vtype) { |
372 | case VCAP_TYPE_IS1: |
373 | lan966x_vcap_is1_add_default_fields(port, admin, rule); |
374 | break; |
375 | case VCAP_TYPE_IS2: |
376 | lan966x_vcap_is2_add_default_fields(port, admin, rule); |
377 | break; |
378 | case VCAP_TYPE_ES0: |
379 | lan966x_vcap_es0_add_default_fields(port, admin, rule); |
380 | break; |
381 | default: |
382 | pr_err("vcap type: %s not supported\n" , |
383 | lan966x_vcaps[admin->vtype].name); |
384 | break; |
385 | } |
386 | } |
387 | |
388 | static void lan966x_vcap_cache_erase(struct vcap_admin *admin) |
389 | { |
390 | memset(admin->cache.keystream, 0, STREAMSIZE); |
391 | memset(admin->cache.maskstream, 0, STREAMSIZE); |
392 | memset(admin->cache.actionstream, 0, STREAMSIZE); |
393 | memset(&admin->cache.counter, 0, sizeof(admin->cache.counter)); |
394 | } |
395 | |
396 | /* The ESDX counter is only used/incremented if the frame has been classified |
397 | * with an ISDX > 0 (e.g by a rule in IS0). This is not mentioned in the |
398 | * datasheet. |
399 | */ |
400 | static void lan966x_es0_read_esdx_counter(struct lan966x *lan966x, |
401 | struct vcap_admin *admin, u32 id) |
402 | { |
403 | u32 counter; |
404 | |
405 | id = id & 0xff; /* counter limit */ |
406 | mutex_lock(&lan966x->stats_lock); |
407 | lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG); |
408 | counter = lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS)) + |
409 | lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS)); |
410 | mutex_unlock(lock: &lan966x->stats_lock); |
411 | if (counter) |
412 | admin->cache.counter = counter; |
413 | } |
414 | |
415 | static void lan966x_es0_write_esdx_counter(struct lan966x *lan966x, |
416 | struct vcap_admin *admin, u32 id) |
417 | { |
418 | id = id & 0xff; /* counter limit */ |
419 | |
420 | mutex_lock(&lan966x->stats_lock); |
421 | lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG); |
422 | lan_wr(val: 0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_BYTES)); |
423 | lan_wr(val: admin->cache.counter, lan966x, |
424 | SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS)); |
425 | lan_wr(val: 0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_BYTES)); |
426 | lan_wr(val: 0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS)); |
427 | mutex_unlock(lock: &lan966x->stats_lock); |
428 | } |
429 | |
430 | static void lan966x_vcap_cache_write(struct net_device *dev, |
431 | struct vcap_admin *admin, |
432 | enum vcap_selection sel, |
433 | u32 start, |
434 | u32 count) |
435 | { |
436 | struct lan966x_port *port = netdev_priv(dev); |
437 | struct lan966x *lan966x = port->lan966x; |
438 | u32 *keystr, *mskstr, *actstr; |
439 | |
440 | keystr = &admin->cache.keystream[start]; |
441 | mskstr = &admin->cache.maskstream[start]; |
442 | actstr = &admin->cache.actionstream[start]; |
443 | |
444 | switch (sel) { |
445 | case VCAP_SEL_ENTRY: |
446 | for (int i = 0; i < count; ++i) { |
447 | lan_wr(val: keystr[i] & mskstr[i], lan966x, |
448 | VCAP_ENTRY_DAT(admin->tgt_inst, i)); |
449 | lan_wr(val: ~mskstr[i], lan966x, |
450 | VCAP_MASK_DAT(admin->tgt_inst, i)); |
451 | } |
452 | break; |
453 | case VCAP_SEL_ACTION: |
454 | for (int i = 0; i < count; ++i) |
455 | lan_wr(val: actstr[i], lan966x, |
456 | VCAP_ACTION_DAT(admin->tgt_inst, i)); |
457 | break; |
458 | case VCAP_SEL_COUNTER: |
459 | admin->cache.sticky = admin->cache.counter > 0; |
460 | lan_wr(val: admin->cache.counter, lan966x, |
461 | VCAP_CNT_DAT(admin->tgt_inst, 0)); |
462 | |
463 | if (admin->vtype == VCAP_TYPE_ES0) |
464 | lan966x_es0_write_esdx_counter(lan966x, admin, id: start); |
465 | break; |
466 | default: |
467 | break; |
468 | } |
469 | } |
470 | |
471 | static void lan966x_vcap_cache_read(struct net_device *dev, |
472 | struct vcap_admin *admin, |
473 | enum vcap_selection sel, |
474 | u32 start, |
475 | u32 count) |
476 | { |
477 | struct lan966x_port *port = netdev_priv(dev); |
478 | struct lan966x *lan966x = port->lan966x; |
479 | int instance = admin->tgt_inst; |
480 | u32 *keystr, *mskstr, *actstr; |
481 | |
482 | keystr = &admin->cache.keystream[start]; |
483 | mskstr = &admin->cache.maskstream[start]; |
484 | actstr = &admin->cache.actionstream[start]; |
485 | |
486 | if (sel & VCAP_SEL_ENTRY) { |
487 | for (int i = 0; i < count; ++i) { |
488 | keystr[i] = |
489 | lan_rd(lan966x, VCAP_ENTRY_DAT(instance, i)); |
490 | mskstr[i] = |
491 | ~lan_rd(lan966x, VCAP_MASK_DAT(instance, i)); |
492 | } |
493 | } |
494 | |
495 | if (sel & VCAP_SEL_ACTION) |
496 | for (int i = 0; i < count; ++i) |
497 | actstr[i] = |
498 | lan_rd(lan966x, VCAP_ACTION_DAT(instance, i)); |
499 | |
500 | if (sel & VCAP_SEL_COUNTER) { |
501 | admin->cache.counter = |
502 | lan_rd(lan966x, VCAP_CNT_DAT(instance, 0)); |
503 | admin->cache.sticky = admin->cache.counter > 0; |
504 | |
505 | if (admin->vtype == VCAP_TYPE_ES0) |
506 | lan966x_es0_read_esdx_counter(lan966x, admin, id: start); |
507 | } |
508 | } |
509 | |
510 | static void lan966x_vcap_range_init(struct net_device *dev, |
511 | struct vcap_admin *admin, |
512 | u32 addr, |
513 | u32 count) |
514 | { |
515 | struct lan966x_port *port = netdev_priv(dev); |
516 | struct lan966x *lan966x = port->lan966x; |
517 | |
518 | __lan966x_vcap_range_init(lan966x, admin, addr, count); |
519 | } |
520 | |
521 | static void lan966x_vcap_update(struct net_device *dev, |
522 | struct vcap_admin *admin, |
523 | enum vcap_command cmd, |
524 | enum vcap_selection sel, |
525 | u32 addr) |
526 | { |
527 | struct lan966x_port *port = netdev_priv(dev); |
528 | struct lan966x *lan966x = port->lan966x; |
529 | bool clear; |
530 | |
531 | clear = (cmd == VCAP_CMD_INITIALIZE); |
532 | |
533 | lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) | |
534 | VCAP_MV_CFG_MV_SIZE_SET(0), |
535 | lan966x, VCAP_MV_CFG(admin->tgt_inst)); |
536 | |
537 | lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) | |
538 | VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) | |
539 | VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) | |
540 | VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) | |
541 | VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) | |
542 | VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(clear) | |
543 | VCAP_UPDATE_CTRL_UPDATE_SHOT, |
544 | lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst)); |
545 | |
546 | lan966x_vcap_wait_update(lan966x, instance: admin->tgt_inst); |
547 | } |
548 | |
549 | static void lan966x_vcap_move(struct net_device *dev, |
550 | struct vcap_admin *admin, |
551 | u32 addr, int offset, int count) |
552 | { |
553 | struct lan966x_port *port = netdev_priv(dev); |
554 | struct lan966x *lan966x = port->lan966x; |
555 | enum vcap_command cmd; |
556 | u16 mv_num_pos; |
557 | u16 mv_size; |
558 | |
559 | mv_size = count - 1; |
560 | if (offset > 0) { |
561 | mv_num_pos = offset - 1; |
562 | cmd = VCAP_CMD_MOVE_DOWN; |
563 | } else { |
564 | mv_num_pos = -offset - 1; |
565 | cmd = VCAP_CMD_MOVE_UP; |
566 | } |
567 | |
568 | lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(mv_num_pos) | |
569 | VCAP_MV_CFG_MV_SIZE_SET(mv_size), |
570 | lan966x, VCAP_MV_CFG(admin->tgt_inst)); |
571 | |
572 | lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) | |
573 | VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) | |
574 | VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) | |
575 | VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) | |
576 | VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) | |
577 | VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(false) | |
578 | VCAP_UPDATE_CTRL_UPDATE_SHOT, |
579 | lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst)); |
580 | |
581 | lan966x_vcap_wait_update(lan966x, instance: admin->tgt_inst); |
582 | } |
583 | |
584 | static struct vcap_operations lan966x_vcap_ops = { |
585 | .validate_keyset = lan966x_vcap_validate_keyset, |
586 | .add_default_fields = lan966x_vcap_add_default_fields, |
587 | .cache_erase = lan966x_vcap_cache_erase, |
588 | .cache_write = lan966x_vcap_cache_write, |
589 | .cache_read = lan966x_vcap_cache_read, |
590 | .init = lan966x_vcap_range_init, |
591 | .update = lan966x_vcap_update, |
592 | .move = lan966x_vcap_move, |
593 | .port_info = lan966x_vcap_port_info, |
594 | }; |
595 | |
596 | static void lan966x_vcap_admin_free(struct vcap_admin *admin) |
597 | { |
598 | if (!admin) |
599 | return; |
600 | |
601 | kfree(objp: admin->cache.keystream); |
602 | kfree(objp: admin->cache.maskstream); |
603 | kfree(objp: admin->cache.actionstream); |
604 | mutex_destroy(lock: &admin->lock); |
605 | kfree(objp: admin); |
606 | } |
607 | |
608 | static struct vcap_admin * |
609 | lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl, |
610 | const struct lan966x_vcap_inst *cfg) |
611 | { |
612 | struct vcap_admin *admin; |
613 | |
614 | admin = kzalloc(size: sizeof(*admin), GFP_KERNEL); |
615 | if (!admin) |
616 | return ERR_PTR(error: -ENOMEM); |
617 | |
618 | mutex_init(&admin->lock); |
619 | INIT_LIST_HEAD(list: &admin->list); |
620 | INIT_LIST_HEAD(list: &admin->rules); |
621 | INIT_LIST_HEAD(list: &admin->enabled); |
622 | |
623 | admin->vtype = cfg->vtype; |
624 | admin->vinst = 0; |
625 | admin->ingress = cfg->ingress; |
626 | admin->w32be = true; |
627 | admin->tgt_inst = cfg->tgt_inst; |
628 | |
629 | admin->lookups = cfg->lookups; |
630 | admin->lookups_per_instance = cfg->lookups; |
631 | |
632 | admin->first_cid = cfg->first_cid; |
633 | admin->last_cid = cfg->last_cid; |
634 | |
635 | admin->cache.keystream = kzalloc(STREAMSIZE, GFP_KERNEL); |
636 | admin->cache.maskstream = kzalloc(STREAMSIZE, GFP_KERNEL); |
637 | admin->cache.actionstream = kzalloc(STREAMSIZE, GFP_KERNEL); |
638 | if (!admin->cache.keystream || |
639 | !admin->cache.maskstream || |
640 | !admin->cache.actionstream) { |
641 | lan966x_vcap_admin_free(admin); |
642 | return ERR_PTR(error: -ENOMEM); |
643 | } |
644 | |
645 | return admin; |
646 | } |
647 | |
648 | static void lan966x_vcap_block_init(struct lan966x *lan966x, |
649 | struct vcap_admin *admin, |
650 | struct lan966x_vcap_inst *cfg) |
651 | { |
652 | admin->first_valid_addr = 0; |
653 | admin->last_used_addr = cfg->count; |
654 | admin->last_valid_addr = cfg->count - 1; |
655 | |
656 | lan_wr(VCAP_CORE_IDX_CORE_IDX_SET(0), |
657 | lan966x, VCAP_CORE_IDX(admin->tgt_inst)); |
658 | lan_wr(VCAP_CORE_MAP_CORE_MAP_SET(1), |
659 | lan966x, VCAP_CORE_MAP(admin->tgt_inst)); |
660 | |
661 | __lan966x_vcap_range_init(lan966x, admin, addr: admin->first_valid_addr, |
662 | count: admin->last_valid_addr - |
663 | admin->first_valid_addr); |
664 | } |
665 | |
666 | static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x, |
667 | struct vcap_admin *admin) |
668 | { |
669 | u32 val; |
670 | |
671 | switch (admin->vtype) { |
672 | case VCAP_TYPE_IS1: |
673 | val = ANA_VCAP_S1_CFG_KEY_IP6_CFG_SET(VCAP_IS1_PS_IPV6_5TUPLE_IP6) | |
674 | ANA_VCAP_S1_CFG_KEY_IP4_CFG_SET(VCAP_IS1_PS_IPV4_5TUPLE_IP4) | |
675 | ANA_VCAP_S1_CFG_KEY_OTHER_CFG_SET(VCAP_IS1_PS_OTHER_NORMAL); |
676 | |
677 | for (int p = 0; p < lan966x->num_phys_ports; ++p) { |
678 | if (!lan966x->ports[p]) |
679 | continue; |
680 | |
681 | for (int l = 0; l < LAN966X_IS1_LOOKUPS; ++l) |
682 | lan_wr(val, lan966x, ANA_VCAP_S1_CFG(p, l)); |
683 | |
684 | lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true), |
685 | ANA_VCAP_CFG_S1_ENA, lan966x, |
686 | ANA_VCAP_CFG(p)); |
687 | } |
688 | |
689 | break; |
690 | case VCAP_TYPE_IS2: |
691 | for (int p = 0; p < lan966x->num_phys_ports; ++p) |
692 | lan_wr(val: 0, lan966x, ANA_VCAP_S2_CFG(p)); |
693 | |
694 | break; |
695 | case VCAP_TYPE_ES0: |
696 | for (int p = 0; p < lan966x->num_phys_ports; ++p) |
697 | lan_rmw(REW_PORT_CFG_ES0_EN_SET(false), |
698 | REW_PORT_CFG_ES0_EN, lan966x, |
699 | REW_PORT_CFG(p)); |
700 | break; |
701 | default: |
702 | pr_err("vcap type: %s not supported\n" , |
703 | lan966x_vcaps[admin->vtype].name); |
704 | break; |
705 | } |
706 | } |
707 | |
708 | int lan966x_vcap_init(struct lan966x *lan966x) |
709 | { |
710 | struct lan966x_vcap_inst *cfg; |
711 | struct vcap_control *ctrl; |
712 | struct vcap_admin *admin; |
713 | struct dentry *dir; |
714 | |
715 | ctrl = kzalloc(size: sizeof(*ctrl), GFP_KERNEL); |
716 | if (!ctrl) |
717 | return -ENOMEM; |
718 | |
719 | ctrl->vcaps = lan966x_vcaps; |
720 | ctrl->stats = &lan966x_vcap_stats; |
721 | ctrl->ops = &lan966x_vcap_ops; |
722 | |
723 | INIT_LIST_HEAD(list: &ctrl->list); |
724 | for (int i = 0; i < ARRAY_SIZE(lan966x_vcap_inst_cfg); ++i) { |
725 | cfg = &lan966x_vcap_inst_cfg[i]; |
726 | |
727 | admin = lan966x_vcap_admin_alloc(lan966x, ctrl, cfg); |
728 | if (IS_ERR(ptr: admin)) |
729 | return PTR_ERR(ptr: admin); |
730 | |
731 | lan966x_vcap_block_init(lan966x, admin, cfg); |
732 | lan966x_vcap_port_key_deselection(lan966x, admin); |
733 | |
734 | list_add_tail(new: &admin->list, head: &ctrl->list); |
735 | } |
736 | |
737 | dir = vcap_debugfs(dev: lan966x->dev, parent: lan966x->debugfs_root, vctrl: ctrl); |
738 | for (int p = 0; p < lan966x->num_phys_ports; ++p) { |
739 | if (lan966x->ports[p]) { |
740 | vcap_port_debugfs(dev: lan966x->dev, parent: dir, vctrl: ctrl, |
741 | ndev: lan966x->ports[p]->dev); |
742 | |
743 | lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(true), |
744 | ANA_VCAP_S2_CFG_ENA, lan966x, |
745 | ANA_VCAP_S2_CFG(lan966x->ports[p]->chip_port)); |
746 | |
747 | lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true), |
748 | ANA_VCAP_CFG_S1_ENA, lan966x, |
749 | ANA_VCAP_CFG(lan966x->ports[p]->chip_port)); |
750 | |
751 | lan_rmw(REW_PORT_CFG_ES0_EN_SET(true), |
752 | REW_PORT_CFG_ES0_EN, lan966x, |
753 | REW_PORT_CFG(lan966x->ports[p]->chip_port)); |
754 | } |
755 | } |
756 | |
757 | /* Statistics: Use ESDX from ES0 if hit, otherwise no counting */ |
758 | lan_rmw(REW_STAT_CFG_STAT_MODE_SET(1), |
759 | REW_STAT_CFG_STAT_MODE, lan966x, |
760 | REW_STAT_CFG); |
761 | |
762 | lan966x->vcap_ctrl = ctrl; |
763 | |
764 | return 0; |
765 | } |
766 | |
767 | void lan966x_vcap_deinit(struct lan966x *lan966x) |
768 | { |
769 | struct vcap_admin *admin, *admin_next; |
770 | struct vcap_control *ctrl; |
771 | |
772 | ctrl = lan966x->vcap_ctrl; |
773 | if (!ctrl) |
774 | return; |
775 | |
776 | list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) { |
777 | lan966x_vcap_port_key_deselection(lan966x, admin); |
778 | vcap_del_rules(vctrl: ctrl, admin); |
779 | list_del(entry: &admin->list); |
780 | lan966x_vcap_admin_free(admin); |
781 | } |
782 | |
783 | kfree(objp: ctrl); |
784 | } |
785 | |