forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/net/ethernet/ti/cpsw_ale.c
....@@ -1,17 +1,12 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
23 * Texas Instruments N-Port Ethernet Switch Address Lookup Engine
34 *
45 * Copyright (C) 2012 Texas Instruments
56 *
6
- * This program is free software; you can redistribute it and/or
7
- * modify it under the terms of the GNU General Public License as
8
- * published by the Free Software Foundation version 2.
9
- *
10
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11
- * kind, whether express or implied; without even the implied warranty
12
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- * GNU General Public License for more details.
147 */
8
+#include <linux/bitmap.h>
9
+#include <linux/if_vlan.h>
1510 #include <linux/kernel.h>
1611 #include <linux/module.h>
1712 #include <linux/platform_device.h>
....@@ -37,6 +32,7 @@
3732 #define ALE_STATUS 0x04
3833 #define ALE_CONTROL 0x08
3934 #define ALE_PRESCALE 0x10
35
+#define ALE_AGING_TIMER 0x14
4036 #define ALE_UNKNOWNVLAN 0x18
4137 #define ALE_TABLE_CONTROL 0x20
4238 #define ALE_TABLE 0x34
....@@ -48,6 +44,48 @@
4844 #define ALE_UNKNOWNVLAN_REG_MCAST_FLOOD 0x98
4945 #define ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS 0x9C
5046 #define ALE_VLAN_MASK_MUX(reg) (0xc0 + (0x4 * (reg)))
47
+
48
+#define AM65_CPSW_ALE_THREAD_DEF_REG 0x134
49
+
50
+/* ALE_AGING_TIMER */
51
+#define ALE_AGING_TIMER_MASK GENMASK(23, 0)
52
+
53
+/**
54
+ * struct ale_entry_fld - The ALE tbl entry field description
55
+ * @start_bit: field start bit
56
+ * @num_bits: field bit length
57
+ * @flags: field flags
58
+ */
59
+struct ale_entry_fld {
60
+ u8 start_bit;
61
+ u8 num_bits;
62
+ u8 flags;
63
+};
64
+
65
+enum {
66
+ CPSW_ALE_F_STATUS_REG = BIT(0), /* Status register present */
67
+ CPSW_ALE_F_HW_AUTOAGING = BIT(1), /* HW auto aging */
68
+
69
+ CPSW_ALE_F_COUNT
70
+};
71
+
72
+/**
73
+ * struct ale_dev_id - The ALE version/SoC specific configuration
74
+ * @dev_id: ALE version/SoC id
75
+ * @features: features supported by ALE
76
+ * @tbl_entries: number of ALE entries
77
+ * @major_ver_mask: mask of ALE Major Version Value in ALE_IDVER reg.
78
+ * @nu_switch_ale: NU Switch ALE
79
+ * @vlan_entry_tbl: ALE vlan entry fields description tbl
80
+ */
81
+struct cpsw_ale_dev_id {
82
+ const char *dev_id;
83
+ u32 features;
84
+ u32 tbl_entries;
85
+ u32 major_ver_mask;
86
+ bool nu_switch_ale;
87
+ const struct ale_entry_fld *vlan_entry_tbl;
88
+};
5189
5290 #define ALE_TABLE_WRITE BIT(31)
5391
....@@ -63,7 +101,6 @@
63101
64102 #define ALE_TABLE_SIZE_MULTIPLIER 1024
65103 #define ALE_STATUS_SIZE_MASK 0x1f
66
-#define ALE_TABLE_SIZE_DEFAULT 64
67104
68105 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
69106 {
....@@ -109,6 +146,59 @@
109146 cpsw_ale_set_field(ale_entry, start, bits, value); \
110147 }
111148
149
+enum {
150
+ ALE_ENT_VID_MEMBER_LIST = 0,
151
+ ALE_ENT_VID_UNREG_MCAST_MSK,
152
+ ALE_ENT_VID_REG_MCAST_MSK,
153
+ ALE_ENT_VID_FORCE_UNTAGGED_MSK,
154
+ ALE_ENT_VID_UNREG_MCAST_IDX,
155
+ ALE_ENT_VID_REG_MCAST_IDX,
156
+ ALE_ENT_VID_LAST,
157
+};
158
+
159
+#define ALE_FLD_ALLOWED BIT(0)
160
+#define ALE_FLD_SIZE_PORT_MASK_BITS BIT(1)
161
+#define ALE_FLD_SIZE_PORT_NUM_BITS BIT(2)
162
+
163
+#define ALE_ENTRY_FLD(id, start, bits) \
164
+[id] = { \
165
+ .start_bit = start, \
166
+ .num_bits = bits, \
167
+ .flags = ALE_FLD_ALLOWED, \
168
+}
169
+
170
+#define ALE_ENTRY_FLD_DYN_MSK_SIZE(id, start) \
171
+[id] = { \
172
+ .start_bit = start, \
173
+ .num_bits = 0, \
174
+ .flags = ALE_FLD_ALLOWED | \
175
+ ALE_FLD_SIZE_PORT_MASK_BITS, \
176
+}
177
+
178
+/* dm814x, am3/am4/am5, k2hk */
179
+static const struct ale_entry_fld vlan_entry_cpsw[ALE_ENT_VID_LAST] = {
180
+ ALE_ENTRY_FLD(ALE_ENT_VID_MEMBER_LIST, 0, 3),
181
+ ALE_ENTRY_FLD(ALE_ENT_VID_UNREG_MCAST_MSK, 8, 3),
182
+ ALE_ENTRY_FLD(ALE_ENT_VID_REG_MCAST_MSK, 16, 3),
183
+ ALE_ENTRY_FLD(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24, 3),
184
+};
185
+
186
+/* k2e/k2l, k3 am65/j721e cpsw2g */
187
+static const struct ale_entry_fld vlan_entry_nu[ALE_ENT_VID_LAST] = {
188
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_MEMBER_LIST, 0),
189
+ ALE_ENTRY_FLD(ALE_ENT_VID_UNREG_MCAST_IDX, 20, 3),
190
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24),
191
+ ALE_ENTRY_FLD(ALE_ENT_VID_REG_MCAST_IDX, 44, 3),
192
+};
193
+
194
+/* K3 j721e/j7200 cpsw9g/5g, am64x cpsw3g */
195
+static const struct ale_entry_fld vlan_entry_k3_cpswxg[] = {
196
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_MEMBER_LIST, 0),
197
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_UNREG_MCAST_MSK, 12),
198
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24),
199
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_REG_MCAST_MSK, 36),
200
+};
201
+
112202 DEFINE_ALE_FIELD(entry_type, 60, 2)
113203 DEFINE_ALE_FIELD(vlan_id, 48, 12)
114204 DEFINE_ALE_FIELD(mcast_state, 62, 2)
....@@ -118,14 +208,75 @@
118208 DEFINE_ALE_FIELD1(port_num, 66)
119209 DEFINE_ALE_FIELD(blocked, 65, 1)
120210 DEFINE_ALE_FIELD(secure, 64, 1)
121
-DEFINE_ALE_FIELD1(vlan_untag_force, 24)
122
-DEFINE_ALE_FIELD1(vlan_reg_mcast, 16)
123
-DEFINE_ALE_FIELD1(vlan_unreg_mcast, 8)
124
-DEFINE_ALE_FIELD1(vlan_member_list, 0)
125211 DEFINE_ALE_FIELD(mcast, 40, 1)
126
-/* ALE NetCP nu switch specific */
127
-DEFINE_ALE_FIELD(vlan_unreg_mcast_idx, 20, 3)
128
-DEFINE_ALE_FIELD(vlan_reg_mcast_idx, 44, 3)
212
+
213
+#define NU_VLAN_UNREG_MCAST_IDX 1
214
+
215
+static int cpsw_ale_entry_get_fld(struct cpsw_ale *ale,
216
+ u32 *ale_entry,
217
+ const struct ale_entry_fld *entry_tbl,
218
+ int fld_id)
219
+{
220
+ const struct ale_entry_fld *entry_fld;
221
+ u32 bits;
222
+
223
+ if (!ale || !ale_entry)
224
+ return -EINVAL;
225
+
226
+ entry_fld = &entry_tbl[fld_id];
227
+ if (!(entry_fld->flags & ALE_FLD_ALLOWED)) {
228
+ dev_err(ale->params.dev, "get: wrong ale fld id %d\n", fld_id);
229
+ return -ENOENT;
230
+ }
231
+
232
+ bits = entry_fld->num_bits;
233
+ if (entry_fld->flags & ALE_FLD_SIZE_PORT_MASK_BITS)
234
+ bits = ale->port_mask_bits;
235
+
236
+ return cpsw_ale_get_field(ale_entry, entry_fld->start_bit, bits);
237
+}
238
+
239
+static void cpsw_ale_entry_set_fld(struct cpsw_ale *ale,
240
+ u32 *ale_entry,
241
+ const struct ale_entry_fld *entry_tbl,
242
+ int fld_id,
243
+ u32 value)
244
+{
245
+ const struct ale_entry_fld *entry_fld;
246
+ u32 bits;
247
+
248
+ if (!ale || !ale_entry)
249
+ return;
250
+
251
+ entry_fld = &entry_tbl[fld_id];
252
+ if (!(entry_fld->flags & ALE_FLD_ALLOWED)) {
253
+ dev_err(ale->params.dev, "set: wrong ale fld id %d\n", fld_id);
254
+ return;
255
+ }
256
+
257
+ bits = entry_fld->num_bits;
258
+ if (entry_fld->flags & ALE_FLD_SIZE_PORT_MASK_BITS)
259
+ bits = ale->port_mask_bits;
260
+
261
+ cpsw_ale_set_field(ale_entry, entry_fld->start_bit, bits, value);
262
+}
263
+
264
+static int cpsw_ale_vlan_get_fld(struct cpsw_ale *ale,
265
+ u32 *ale_entry,
266
+ int fld_id)
267
+{
268
+ return cpsw_ale_entry_get_fld(ale, ale_entry,
269
+ ale->vlan_entry_tbl, fld_id);
270
+}
271
+
272
+static void cpsw_ale_vlan_set_fld(struct cpsw_ale *ale,
273
+ u32 *ale_entry,
274
+ int fld_id,
275
+ u32 value)
276
+{
277
+ cpsw_ale_entry_set_fld(ale, ale_entry,
278
+ ale->vlan_entry_tbl, fld_id, value);
279
+}
129280
130281 /* The MAC address field in the ALE entry cannot be macroized as above */
131282 static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
....@@ -136,7 +287,7 @@
136287 addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
137288 }
138289
139
-static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr)
290
+static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr)
140291 {
141292 int i;
142293
....@@ -175,7 +326,7 @@
175326 return idx;
176327 }
177328
178
-static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
329
+static int cpsw_ale_match_addr(struct cpsw_ale *ale, const u8 *addr, u16 vid)
179330 {
180331 u32 ale_entry[ALE_ENTRY_WORDS];
181332 int type, idx;
....@@ -287,6 +438,9 @@
287438 if (cpsw_ale_get_mcast(ale_entry)) {
288439 u8 addr[6];
289440
441
+ if (cpsw_ale_get_super(ale_entry))
442
+ continue;
443
+
290444 cpsw_ale_get_addr(ale_entry, addr);
291445 if (!is_broadcast_ether_addr(addr))
292446 cpsw_ale_flush_mcast(ale, ale_entry, port_mask);
....@@ -296,7 +450,6 @@
296450 }
297451 return 0;
298452 }
299
-EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast);
300453
301454 static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
302455 int flags, u16 vid)
....@@ -309,7 +462,7 @@
309462 }
310463 }
311464
312
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
465
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
313466 int flags, u16 vid)
314467 {
315468 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
....@@ -334,9 +487,8 @@
334487 cpsw_ale_write(ale, idx, ale_entry);
335488 return 0;
336489 }
337
-EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast);
338490
339
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
491
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
340492 int flags, u16 vid)
341493 {
342494 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
....@@ -350,9 +502,8 @@
350502 cpsw_ale_write(ale, idx, ale_entry);
351503 return 0;
352504 }
353
-EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast);
354505
355
-int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
506
+int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
356507 int flags, u16 vid, int mcast_state)
357508 {
358509 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
....@@ -365,7 +516,7 @@
365516 cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
366517
367518 cpsw_ale_set_addr(ale_entry, addr);
368
- cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
519
+ cpsw_ale_set_super(ale_entry, (flags & ALE_SUPER) ? 1 : 0);
369520 cpsw_ale_set_mcast_state(ale_entry, mcast_state);
370521
371522 mask = cpsw_ale_get_port_mask(ale_entry,
....@@ -384,12 +535,12 @@
384535 cpsw_ale_write(ale, idx, ale_entry);
385536 return 0;
386537 }
387
-EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast);
388538
389
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
539
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
390540 int flags, u16 vid)
391541 {
392542 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
543
+ int mcast_members = 0;
393544 int idx;
394545
395546 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
....@@ -398,8 +549,14 @@
398549
399550 cpsw_ale_read(ale, idx, ale_entry);
400551
401
- if (port_mask)
402
- cpsw_ale_set_port_mask(ale_entry, port_mask,
552
+ if (port_mask) {
553
+ mcast_members = cpsw_ale_get_port_mask(ale_entry,
554
+ ale->port_mask_bits);
555
+ mcast_members &= ~port_mask;
556
+ }
557
+
558
+ if (mcast_members)
559
+ cpsw_ale_set_port_mask(ale_entry, mcast_members,
403560 ale->port_mask_bits);
404561 else
405562 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
....@@ -407,7 +564,6 @@
407564 cpsw_ale_write(ale, idx, ale_entry);
408565 return 0;
409566 }
410
-EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast);
411567
412568 /* ALE NetCP NU switch specific vlan functions */
413569 static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry,
....@@ -416,15 +572,29 @@
416572 int idx;
417573
418574 /* Set VLAN registered multicast flood mask */
419
- idx = cpsw_ale_get_vlan_reg_mcast_idx(ale_entry);
575
+ idx = cpsw_ale_vlan_get_fld(ale, ale_entry,
576
+ ALE_ENT_VID_REG_MCAST_IDX);
420577 writel(reg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
421578
422579 /* Set VLAN unregistered multicast flood mask */
423
- idx = cpsw_ale_get_vlan_unreg_mcast_idx(ale_entry);
580
+ idx = cpsw_ale_vlan_get_fld(ale, ale_entry,
581
+ ALE_ENT_VID_UNREG_MCAST_IDX);
424582 writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
425583 }
426584
427
-int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
585
+static void cpsw_ale_set_vlan_untag(struct cpsw_ale *ale, u32 *ale_entry,
586
+ u16 vid, int untag_mask)
587
+{
588
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
589
+ ALE_ENT_VID_FORCE_UNTAGGED_MSK,
590
+ untag_mask);
591
+ if (untag_mask & ALE_PORT_HOST)
592
+ bitmap_set(ale->p0_untag_vid_mask, vid, 1);
593
+ else
594
+ bitmap_clear(ale->p0_untag_vid_mask, vid, 1);
595
+}
596
+
597
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag,
428598 int reg_mcast, int unreg_mcast)
429599 {
430600 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
....@@ -436,17 +606,22 @@
436606
437607 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
438608 cpsw_ale_set_vlan_id(ale_entry, vid);
609
+ cpsw_ale_set_vlan_untag(ale, ale_entry, vid, untag);
439610
440
- cpsw_ale_set_vlan_untag_force(ale_entry, untag, ale->vlan_field_bits);
441611 if (!ale->params.nu_switch_ale) {
442
- cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast,
443
- ale->vlan_field_bits);
444
- cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast,
445
- ale->vlan_field_bits);
612
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
613
+ ALE_ENT_VID_REG_MCAST_MSK, reg_mcast);
614
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
615
+ ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast);
446616 } else {
617
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
618
+ ALE_ENT_VID_UNREG_MCAST_IDX,
619
+ NU_VLAN_UNREG_MCAST_IDX);
447620 cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, unreg_mcast);
448621 }
449
- cpsw_ale_set_vlan_member_list(ale_entry, port, ale->vlan_field_bits);
622
+
623
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
624
+ ALE_ENT_VID_MEMBER_LIST, port_mask);
450625
451626 if (idx < 0)
452627 idx = cpsw_ale_match_free(ale);
....@@ -458,7 +633,45 @@
458633 cpsw_ale_write(ale, idx, ale_entry);
459634 return 0;
460635 }
461
-EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan);
636
+
637
+static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry,
638
+ u16 vid, int port_mask)
639
+{
640
+ int reg_mcast, unreg_mcast;
641
+ int members, untag;
642
+
643
+ members = cpsw_ale_vlan_get_fld(ale, ale_entry,
644
+ ALE_ENT_VID_MEMBER_LIST);
645
+ members &= ~port_mask;
646
+ if (!members) {
647
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
648
+ return;
649
+ }
650
+
651
+ untag = cpsw_ale_vlan_get_fld(ale, ale_entry,
652
+ ALE_ENT_VID_FORCE_UNTAGGED_MSK);
653
+ reg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry,
654
+ ALE_ENT_VID_REG_MCAST_MSK);
655
+ unreg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry,
656
+ ALE_ENT_VID_UNREG_MCAST_MSK);
657
+ untag &= members;
658
+ reg_mcast &= members;
659
+ unreg_mcast &= members;
660
+
661
+ cpsw_ale_set_vlan_untag(ale, ale_entry, vid, untag);
662
+
663
+ if (!ale->params.nu_switch_ale) {
664
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
665
+ ALE_ENT_VID_REG_MCAST_MSK, reg_mcast);
666
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
667
+ ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast);
668
+ } else {
669
+ cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast,
670
+ unreg_mcast);
671
+ }
672
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
673
+ ALE_ENT_VID_MEMBER_LIST, members);
674
+}
462675
463676 int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
464677 {
....@@ -471,29 +684,63 @@
471684
472685 cpsw_ale_read(ale, idx, ale_entry);
473686
474
- if (port_mask)
475
- cpsw_ale_set_vlan_member_list(ale_entry, port_mask,
476
- ale->vlan_field_bits);
477
- else
687
+ if (port_mask) {
688
+ cpsw_ale_del_vlan_modify(ale, ale_entry, vid, port_mask);
689
+ } else {
690
+ cpsw_ale_set_vlan_untag(ale, ale_entry, vid, 0);
478691 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
692
+ }
479693
480694 cpsw_ale_write(ale, idx, ale_entry);
695
+
481696 return 0;
482697 }
483
-EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan);
484698
485
-void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
699
+int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask,
700
+ int untag_mask, int reg_mask, int unreg_mask)
701
+{
702
+ u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
703
+ int reg_mcast_members, unreg_mcast_members;
704
+ int vlan_members, untag_members;
705
+ int idx, ret = 0;
706
+
707
+ idx = cpsw_ale_match_vlan(ale, vid);
708
+ if (idx >= 0)
709
+ cpsw_ale_read(ale, idx, ale_entry);
710
+
711
+ vlan_members = cpsw_ale_vlan_get_fld(ale, ale_entry,
712
+ ALE_ENT_VID_MEMBER_LIST);
713
+ reg_mcast_members = cpsw_ale_vlan_get_fld(ale, ale_entry,
714
+ ALE_ENT_VID_REG_MCAST_MSK);
715
+ unreg_mcast_members =
716
+ cpsw_ale_vlan_get_fld(ale, ale_entry,
717
+ ALE_ENT_VID_UNREG_MCAST_MSK);
718
+ untag_members = cpsw_ale_vlan_get_fld(ale, ale_entry,
719
+ ALE_ENT_VID_FORCE_UNTAGGED_MSK);
720
+
721
+ vlan_members |= port_mask;
722
+ untag_members = (untag_members & ~port_mask) | untag_mask;
723
+ reg_mcast_members = (reg_mcast_members & ~port_mask) | reg_mask;
724
+ unreg_mcast_members = (unreg_mcast_members & ~port_mask) | unreg_mask;
725
+
726
+ ret = cpsw_ale_add_vlan(ale, vid, vlan_members, untag_members,
727
+ reg_mcast_members, unreg_mcast_members);
728
+ if (ret) {
729
+ dev_err(ale->params.dev, "Unable to add vlan\n");
730
+ return ret;
731
+ }
732
+ dev_dbg(ale->params.dev, "port mask 0x%x untag 0x%x\n", vlan_members,
733
+ untag_mask);
734
+
735
+ return ret;
736
+}
737
+
738
+void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask,
739
+ bool add)
486740 {
487741 u32 ale_entry[ALE_ENTRY_WORDS];
742
+ int unreg_members = 0;
488743 int type, idx;
489
- int unreg_mcast = 0;
490
-
491
- /* Only bother doing the work if the setting is actually changing */
492
- if (ale->allmulti == allmulti)
493
- return;
494
-
495
- /* Remember the new setting to check against next time */
496
- ale->allmulti = allmulti;
497744
498745 for (idx = 0; idx < ale->params.ale_entries; idx++) {
499746 cpsw_ale_read(ale, idx, ale_entry);
....@@ -501,19 +748,84 @@
501748 if (type != ALE_TYPE_VLAN)
502749 continue;
503750
504
- unreg_mcast =
505
- cpsw_ale_get_vlan_unreg_mcast(ale_entry,
506
- ale->vlan_field_bits);
507
- if (allmulti)
508
- unreg_mcast |= 1;
751
+ unreg_members =
752
+ cpsw_ale_vlan_get_fld(ale, ale_entry,
753
+ ALE_ENT_VID_UNREG_MCAST_MSK);
754
+ if (add)
755
+ unreg_members |= unreg_mcast_mask;
509756 else
510
- unreg_mcast &= ~1;
511
- cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast,
512
- ale->vlan_field_bits);
757
+ unreg_members &= ~unreg_mcast_mask;
758
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
759
+ ALE_ENT_VID_UNREG_MCAST_MSK,
760
+ unreg_members);
513761 cpsw_ale_write(ale, idx, ale_entry);
514762 }
515763 }
516
-EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti);
764
+
765
+static void cpsw_ale_vlan_set_unreg_mcast(struct cpsw_ale *ale, u32 *ale_entry,
766
+ int allmulti)
767
+{
768
+ int unreg_mcast;
769
+
770
+ unreg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry,
771
+ ALE_ENT_VID_UNREG_MCAST_MSK);
772
+ if (allmulti)
773
+ unreg_mcast |= ALE_PORT_HOST;
774
+ else
775
+ unreg_mcast &= ~ALE_PORT_HOST;
776
+
777
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
778
+ ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast);
779
+}
780
+
781
+static void
782
+cpsw_ale_vlan_set_unreg_mcast_idx(struct cpsw_ale *ale, u32 *ale_entry,
783
+ int allmulti)
784
+{
785
+ int unreg_mcast;
786
+ int idx;
787
+
788
+ idx = cpsw_ale_vlan_get_fld(ale, ale_entry,
789
+ ALE_ENT_VID_UNREG_MCAST_IDX);
790
+
791
+ unreg_mcast = readl(ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
792
+
793
+ if (allmulti)
794
+ unreg_mcast |= ALE_PORT_HOST;
795
+ else
796
+ unreg_mcast &= ~ALE_PORT_HOST;
797
+
798
+ writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
799
+}
800
+
801
+void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port)
802
+{
803
+ u32 ale_entry[ALE_ENTRY_WORDS];
804
+ int type, idx;
805
+
806
+ for (idx = 0; idx < ale->params.ale_entries; idx++) {
807
+ int vlan_members;
808
+
809
+ cpsw_ale_read(ale, idx, ale_entry);
810
+ type = cpsw_ale_get_entry_type(ale_entry);
811
+ if (type != ALE_TYPE_VLAN)
812
+ continue;
813
+
814
+ vlan_members = cpsw_ale_vlan_get_fld(ale, ale_entry,
815
+ ALE_ENT_VID_MEMBER_LIST);
816
+
817
+ if (port != -1 && !(vlan_members & BIT(port)))
818
+ continue;
819
+
820
+ if (!ale->params.nu_switch_ale)
821
+ cpsw_ale_vlan_set_unreg_mcast(ale, ale_entry, allmulti);
822
+ else
823
+ cpsw_ale_vlan_set_unreg_mcast_idx(ale, ale_entry,
824
+ allmulti);
825
+
826
+ cpsw_ale_write(ale, idx, ale_entry);
827
+ }
828
+}
517829
518830 struct ale_control_info {
519831 const char *name;
....@@ -659,6 +971,22 @@
659971 .port_shift = 0,
660972 .bits = 1,
661973 },
974
+ [ALE_PORT_MACONLY] = {
975
+ .name = "mac_only_port_mode",
976
+ .offset = ALE_PORTCTL,
977
+ .port_offset = 4,
978
+ .shift = 11,
979
+ .port_shift = 0,
980
+ .bits = 1,
981
+ },
982
+ [ALE_PORT_MACONLY_CAF] = {
983
+ .name = "mac_only_port_caf",
984
+ .offset = ALE_PORTCTL,
985
+ .port_offset = 4,
986
+ .shift = 13,
987
+ .port_shift = 0,
988
+ .bits = 1,
989
+ },
662990 [ALE_PORT_MCAST_LIMIT] = {
663991 .name = "mcast_limit",
664992 .offset = ALE_PORTCTL,
....@@ -707,6 +1035,22 @@
7071035 .port_shift = 0,
7081036 .bits = 6,
7091037 },
1038
+ [ALE_DEFAULT_THREAD_ID] = {
1039
+ .name = "default_thread_id",
1040
+ .offset = AM65_CPSW_ALE_THREAD_DEF_REG,
1041
+ .port_offset = 0,
1042
+ .shift = 0,
1043
+ .port_shift = 0,
1044
+ .bits = 6,
1045
+ },
1046
+ [ALE_DEFAULT_THREAD_ENABLE] = {
1047
+ .name = "default_thread_id_enable",
1048
+ .offset = AM65_CPSW_ALE_THREAD_DEF_REG,
1049
+ .port_offset = 0,
1050
+ .shift = 15,
1051
+ .port_shift = 0,
1052
+ .bits = 1,
1053
+ },
7101054 };
7111055
7121056 int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control,
....@@ -739,7 +1083,6 @@
7391083
7401084 return 0;
7411085 }
742
-EXPORT_SYMBOL_GPL(cpsw_ale_control_set);
7431086
7441087 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
7451088 {
....@@ -763,7 +1106,6 @@
7631106 tmp = readl_relaxed(ale->params.ale_regs + offset) >> shift;
7641107 return tmp & BITMASK(info->bits);
7651108 }
766
-EXPORT_SYMBOL_GPL(cpsw_ale_control_get);
7671109
7681110 static void cpsw_ale_timer(struct timer_list *t)
7691111 {
....@@ -777,42 +1119,163 @@
7771119 }
7781120 }
7791121
1122
+static void cpsw_ale_hw_aging_timer_start(struct cpsw_ale *ale)
1123
+{
1124
+ u32 aging_timer;
1125
+
1126
+ aging_timer = ale->params.bus_freq / 1000000;
1127
+ aging_timer *= ale->params.ale_ageout;
1128
+
1129
+ if (aging_timer & ~ALE_AGING_TIMER_MASK) {
1130
+ aging_timer = ALE_AGING_TIMER_MASK;
1131
+ dev_warn(ale->params.dev,
1132
+ "ALE aging timer overflow, set to max\n");
1133
+ }
1134
+
1135
+ writel(aging_timer, ale->params.ale_regs + ALE_AGING_TIMER);
1136
+}
1137
+
1138
+static void cpsw_ale_hw_aging_timer_stop(struct cpsw_ale *ale)
1139
+{
1140
+ writel(0, ale->params.ale_regs + ALE_AGING_TIMER);
1141
+}
1142
+
1143
+static void cpsw_ale_aging_start(struct cpsw_ale *ale)
1144
+{
1145
+ if (!ale->params.ale_ageout)
1146
+ return;
1147
+
1148
+ if (ale->features & CPSW_ALE_F_HW_AUTOAGING) {
1149
+ cpsw_ale_hw_aging_timer_start(ale);
1150
+ return;
1151
+ }
1152
+
1153
+ timer_setup(&ale->timer, cpsw_ale_timer, 0);
1154
+ ale->timer.expires = jiffies + ale->ageout;
1155
+ add_timer(&ale->timer);
1156
+}
1157
+
1158
+static void cpsw_ale_aging_stop(struct cpsw_ale *ale)
1159
+{
1160
+ if (!ale->params.ale_ageout)
1161
+ return;
1162
+
1163
+ if (ale->features & CPSW_ALE_F_HW_AUTOAGING) {
1164
+ cpsw_ale_hw_aging_timer_stop(ale);
1165
+ return;
1166
+ }
1167
+
1168
+ del_timer_sync(&ale->timer);
1169
+}
1170
+
7801171 void cpsw_ale_start(struct cpsw_ale *ale)
7811172 {
7821173 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1);
7831174 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
7841175
785
- timer_setup(&ale->timer, cpsw_ale_timer, 0);
786
- if (ale->ageout) {
787
- ale->timer.expires = jiffies + ale->ageout;
788
- add_timer(&ale->timer);
789
- }
1176
+ cpsw_ale_aging_start(ale);
7901177 }
791
-EXPORT_SYMBOL_GPL(cpsw_ale_start);
7921178
7931179 void cpsw_ale_stop(struct cpsw_ale *ale)
7941180 {
795
- del_timer_sync(&ale->timer);
1181
+ cpsw_ale_aging_stop(ale);
7961182 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
7971183 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
7981184 }
799
-EXPORT_SYMBOL_GPL(cpsw_ale_stop);
1185
+
1186
+static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = {
1187
+ {
1188
+ /* am3/4/5, dra7. dm814x, 66ak2hk-gbe */
1189
+ .dev_id = "cpsw",
1190
+ .tbl_entries = 1024,
1191
+ .major_ver_mask = 0xff,
1192
+ .vlan_entry_tbl = vlan_entry_cpsw,
1193
+ },
1194
+ {
1195
+ /* 66ak2h_xgbe */
1196
+ .dev_id = "66ak2h-xgbe",
1197
+ .tbl_entries = 2048,
1198
+ .major_ver_mask = 0xff,
1199
+ .vlan_entry_tbl = vlan_entry_cpsw,
1200
+ },
1201
+ {
1202
+ .dev_id = "66ak2el",
1203
+ .features = CPSW_ALE_F_STATUS_REG,
1204
+ .major_ver_mask = 0x7,
1205
+ .nu_switch_ale = true,
1206
+ .vlan_entry_tbl = vlan_entry_nu,
1207
+ },
1208
+ {
1209
+ .dev_id = "66ak2g",
1210
+ .features = CPSW_ALE_F_STATUS_REG,
1211
+ .tbl_entries = 64,
1212
+ .major_ver_mask = 0x7,
1213
+ .nu_switch_ale = true,
1214
+ .vlan_entry_tbl = vlan_entry_nu,
1215
+ },
1216
+ {
1217
+ .dev_id = "am65x-cpsw2g",
1218
+ .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING,
1219
+ .tbl_entries = 64,
1220
+ .major_ver_mask = 0x7,
1221
+ .nu_switch_ale = true,
1222
+ .vlan_entry_tbl = vlan_entry_nu,
1223
+ },
1224
+ {
1225
+ .dev_id = "j721e-cpswxg",
1226
+ .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING,
1227
+ .major_ver_mask = 0x7,
1228
+ .vlan_entry_tbl = vlan_entry_k3_cpswxg,
1229
+ },
1230
+ { },
1231
+};
1232
+
1233
+static const struct
1234
+cpsw_ale_dev_id *cpsw_ale_match_id(const struct cpsw_ale_dev_id *id,
1235
+ const char *dev_id)
1236
+{
1237
+ if (!dev_id)
1238
+ return NULL;
1239
+
1240
+ while (id->dev_id) {
1241
+ if (strcmp(dev_id, id->dev_id) == 0)
1242
+ return id;
1243
+ id++;
1244
+ }
1245
+ return NULL;
1246
+}
8001247
8011248 struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
8021249 {
1250
+ const struct cpsw_ale_dev_id *ale_dev_id;
8031251 struct cpsw_ale *ale;
8041252 u32 rev, ale_entries;
8051253
1254
+ ale_dev_id = cpsw_ale_match_id(cpsw_ale_id_match, params->dev_id);
1255
+ if (!ale_dev_id)
1256
+ return ERR_PTR(-EINVAL);
1257
+
1258
+ params->ale_entries = ale_dev_id->tbl_entries;
1259
+ params->major_ver_mask = ale_dev_id->major_ver_mask;
1260
+ params->nu_switch_ale = ale_dev_id->nu_switch_ale;
1261
+
8061262 ale = devm_kzalloc(params->dev, sizeof(*ale), GFP_KERNEL);
8071263 if (!ale)
808
- return NULL;
1264
+ return ERR_PTR(-ENOMEM);
1265
+
1266
+ ale->p0_untag_vid_mask =
1267
+ devm_kmalloc_array(params->dev, BITS_TO_LONGS(VLAN_N_VID),
1268
+ sizeof(unsigned long),
1269
+ GFP_KERNEL);
1270
+ if (!ale->p0_untag_vid_mask)
1271
+ return ERR_PTR(-ENOMEM);
8091272
8101273 ale->params = *params;
8111274 ale->ageout = ale->params.ale_ageout * HZ;
1275
+ ale->features = ale_dev_id->features;
1276
+ ale->vlan_entry_tbl = ale_dev_id->vlan_entry_tbl;
8121277
8131278 rev = readl_relaxed(ale->params.ale_regs + ALE_IDVER);
814
- if (!ale->params.major_ver_mask)
815
- ale->params.major_ver_mask = 0xff;
8161279 ale->version =
8171280 (ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask) << 8) |
8181281 ALE_VERSION_MINOR(rev);
....@@ -820,7 +1283,8 @@
8201283 ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask),
8211284 ALE_VERSION_MINOR(rev));
8221285
823
- if (!ale->params.ale_entries) {
1286
+ if (ale->features & CPSW_ALE_F_STATUS_REG &&
1287
+ !ale->params.ale_entries) {
8241288 ale_entries =
8251289 readl_relaxed(ale->params.ale_regs + ALE_STATUS) &
8261290 ALE_STATUS_SIZE_MASK;
....@@ -829,16 +1293,12 @@
8291293 * table which shows the size as a multiple of 1024 entries.
8301294 * For these, params.ale_entries will be set to zero. So
8311295 * read the register and update the value of ale_entries.
832
- * ALE table on NetCP lite, is much smaller and is indicated
833
- * by a value of zero in ALE_STATUS. So use a default value
834
- * of ALE_TABLE_SIZE_DEFAULT for this. Caller is expected
835
- * to set the value of ale_entries for all other versions
836
- * of ALE.
1296
+ * return error if ale_entries is zero in ALE_STATUS.
8371297 */
8381298 if (!ale_entries)
839
- ale_entries = ALE_TABLE_SIZE_DEFAULT;
840
- else
841
- ale_entries *= ALE_TABLE_SIZE_MULTIPLIER;
1299
+ return ERR_PTR(-EINVAL);
1300
+
1301
+ ale_entries *= ALE_TABLE_SIZE_MULTIPLIER;
8421302 ale->params.ale_entries = ale_entries;
8431303 }
8441304 dev_info(ale->params.dev,
....@@ -881,7 +1341,6 @@
8811341 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
8821342 return ale;
8831343 }
884
-EXPORT_SYMBOL_GPL(cpsw_ale_create);
8851344
8861345 void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data)
8871346 {
....@@ -892,8 +1351,8 @@
8921351 data += ALE_ENTRY_WORDS;
8931352 }
8941353 }
895
-EXPORT_SYMBOL_GPL(cpsw_ale_dump);
8961354
897
-MODULE_LICENSE("GPL v2");
898
-MODULE_DESCRIPTION("TI CPSW ALE driver");
899
-MODULE_AUTHOR("Texas Instruments");
1355
+u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale)
1356
+{
1357
+ return ale ? ale->params.ale_entries : 0;
1358
+}