forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
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,27 +101,40 @@
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 {
70
- int idx;
107
+ int idx, idx2;
108
+ u32 hi_val = 0;
71109
72110 idx = start / 32;
111
+ idx2 = (start + bits - 1) / 32;
112
+ /* Check if bits to be fetched exceed a word */
113
+ if (idx != idx2) {
114
+ idx2 = 2 - idx2; /* flip */
115
+ hi_val = ale_entry[idx2] << ((idx2 * 32) - start);
116
+ }
73117 start -= idx * 32;
74118 idx = 2 - idx; /* flip */
75
- return (ale_entry[idx] >> start) & BITMASK(bits);
119
+ return (hi_val + (ale_entry[idx] >> start)) & BITMASK(bits);
76120 }
77121
78122 static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
79123 u32 value)
80124 {
81
- int idx;
125
+ int idx, idx2;
82126
83127 value &= BITMASK(bits);
84
- idx = start / 32;
128
+ idx = start / 32;
129
+ idx2 = (start + bits - 1) / 32;
130
+ /* Check if bits to be set exceed a word */
131
+ if (idx != idx2) {
132
+ idx2 = 2 - idx2; /* flip */
133
+ ale_entry[idx2] &= ~(BITMASK(bits + start - (idx2 * 32)));
134
+ ale_entry[idx2] |= (value >> ((idx2 * 32) - start));
135
+ }
85136 start -= idx * 32;
86
- idx = 2 - idx; /* flip */
137
+ idx = 2 - idx; /* flip */
87138 ale_entry[idx] &= ~(BITMASK(bits) << start);
88139 ale_entry[idx] |= (value << start);
89140 }
....@@ -109,6 +160,59 @@
109160 cpsw_ale_set_field(ale_entry, start, bits, value); \
110161 }
111162
163
+enum {
164
+ ALE_ENT_VID_MEMBER_LIST = 0,
165
+ ALE_ENT_VID_UNREG_MCAST_MSK,
166
+ ALE_ENT_VID_REG_MCAST_MSK,
167
+ ALE_ENT_VID_FORCE_UNTAGGED_MSK,
168
+ ALE_ENT_VID_UNREG_MCAST_IDX,
169
+ ALE_ENT_VID_REG_MCAST_IDX,
170
+ ALE_ENT_VID_LAST,
171
+};
172
+
173
+#define ALE_FLD_ALLOWED BIT(0)
174
+#define ALE_FLD_SIZE_PORT_MASK_BITS BIT(1)
175
+#define ALE_FLD_SIZE_PORT_NUM_BITS BIT(2)
176
+
177
+#define ALE_ENTRY_FLD(id, start, bits) \
178
+[id] = { \
179
+ .start_bit = start, \
180
+ .num_bits = bits, \
181
+ .flags = ALE_FLD_ALLOWED, \
182
+}
183
+
184
+#define ALE_ENTRY_FLD_DYN_MSK_SIZE(id, start) \
185
+[id] = { \
186
+ .start_bit = start, \
187
+ .num_bits = 0, \
188
+ .flags = ALE_FLD_ALLOWED | \
189
+ ALE_FLD_SIZE_PORT_MASK_BITS, \
190
+}
191
+
192
+/* dm814x, am3/am4/am5, k2hk */
193
+static const struct ale_entry_fld vlan_entry_cpsw[ALE_ENT_VID_LAST] = {
194
+ ALE_ENTRY_FLD(ALE_ENT_VID_MEMBER_LIST, 0, 3),
195
+ ALE_ENTRY_FLD(ALE_ENT_VID_UNREG_MCAST_MSK, 8, 3),
196
+ ALE_ENTRY_FLD(ALE_ENT_VID_REG_MCAST_MSK, 16, 3),
197
+ ALE_ENTRY_FLD(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24, 3),
198
+};
199
+
200
+/* k2e/k2l, k3 am65/j721e cpsw2g */
201
+static const struct ale_entry_fld vlan_entry_nu[ALE_ENT_VID_LAST] = {
202
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_MEMBER_LIST, 0),
203
+ ALE_ENTRY_FLD(ALE_ENT_VID_UNREG_MCAST_IDX, 20, 3),
204
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24),
205
+ ALE_ENTRY_FLD(ALE_ENT_VID_REG_MCAST_IDX, 44, 3),
206
+};
207
+
208
+/* K3 j721e/j7200 cpsw9g/5g, am64x cpsw3g */
209
+static const struct ale_entry_fld vlan_entry_k3_cpswxg[] = {
210
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_MEMBER_LIST, 0),
211
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_UNREG_MCAST_MSK, 12),
212
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24),
213
+ ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_REG_MCAST_MSK, 36),
214
+};
215
+
112216 DEFINE_ALE_FIELD(entry_type, 60, 2)
113217 DEFINE_ALE_FIELD(vlan_id, 48, 12)
114218 DEFINE_ALE_FIELD(mcast_state, 62, 2)
....@@ -118,14 +222,75 @@
118222 DEFINE_ALE_FIELD1(port_num, 66)
119223 DEFINE_ALE_FIELD(blocked, 65, 1)
120224 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)
125225 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)
226
+
227
+#define NU_VLAN_UNREG_MCAST_IDX 1
228
+
229
+static int cpsw_ale_entry_get_fld(struct cpsw_ale *ale,
230
+ u32 *ale_entry,
231
+ const struct ale_entry_fld *entry_tbl,
232
+ int fld_id)
233
+{
234
+ const struct ale_entry_fld *entry_fld;
235
+ u32 bits;
236
+
237
+ if (!ale || !ale_entry)
238
+ return -EINVAL;
239
+
240
+ entry_fld = &entry_tbl[fld_id];
241
+ if (!(entry_fld->flags & ALE_FLD_ALLOWED)) {
242
+ dev_err(ale->params.dev, "get: wrong ale fld id %d\n", fld_id);
243
+ return -ENOENT;
244
+ }
245
+
246
+ bits = entry_fld->num_bits;
247
+ if (entry_fld->flags & ALE_FLD_SIZE_PORT_MASK_BITS)
248
+ bits = ale->port_mask_bits;
249
+
250
+ return cpsw_ale_get_field(ale_entry, entry_fld->start_bit, bits);
251
+}
252
+
253
+static void cpsw_ale_entry_set_fld(struct cpsw_ale *ale,
254
+ u32 *ale_entry,
255
+ const struct ale_entry_fld *entry_tbl,
256
+ int fld_id,
257
+ u32 value)
258
+{
259
+ const struct ale_entry_fld *entry_fld;
260
+ u32 bits;
261
+
262
+ if (!ale || !ale_entry)
263
+ return;
264
+
265
+ entry_fld = &entry_tbl[fld_id];
266
+ if (!(entry_fld->flags & ALE_FLD_ALLOWED)) {
267
+ dev_err(ale->params.dev, "set: wrong ale fld id %d\n", fld_id);
268
+ return;
269
+ }
270
+
271
+ bits = entry_fld->num_bits;
272
+ if (entry_fld->flags & ALE_FLD_SIZE_PORT_MASK_BITS)
273
+ bits = ale->port_mask_bits;
274
+
275
+ cpsw_ale_set_field(ale_entry, entry_fld->start_bit, bits, value);
276
+}
277
+
278
+static int cpsw_ale_vlan_get_fld(struct cpsw_ale *ale,
279
+ u32 *ale_entry,
280
+ int fld_id)
281
+{
282
+ return cpsw_ale_entry_get_fld(ale, ale_entry,
283
+ ale->vlan_entry_tbl, fld_id);
284
+}
285
+
286
+static void cpsw_ale_vlan_set_fld(struct cpsw_ale *ale,
287
+ u32 *ale_entry,
288
+ int fld_id,
289
+ u32 value)
290
+{
291
+ cpsw_ale_entry_set_fld(ale, ale_entry,
292
+ ale->vlan_entry_tbl, fld_id, value);
293
+}
129294
130295 /* The MAC address field in the ALE entry cannot be macroized as above */
131296 static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
....@@ -136,7 +301,7 @@
136301 addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
137302 }
138303
139
-static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr)
304
+static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr)
140305 {
141306 int i;
142307
....@@ -175,7 +340,7 @@
175340 return idx;
176341 }
177342
178
-static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
343
+static int cpsw_ale_match_addr(struct cpsw_ale *ale, const u8 *addr, u16 vid)
179344 {
180345 u32 ale_entry[ALE_ENTRY_WORDS];
181346 int type, idx;
....@@ -287,6 +452,9 @@
287452 if (cpsw_ale_get_mcast(ale_entry)) {
288453 u8 addr[6];
289454
455
+ if (cpsw_ale_get_super(ale_entry))
456
+ continue;
457
+
290458 cpsw_ale_get_addr(ale_entry, addr);
291459 if (!is_broadcast_ether_addr(addr))
292460 cpsw_ale_flush_mcast(ale, ale_entry, port_mask);
....@@ -296,7 +464,6 @@
296464 }
297465 return 0;
298466 }
299
-EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast);
300467
301468 static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
302469 int flags, u16 vid)
....@@ -309,7 +476,7 @@
309476 }
310477 }
311478
312
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
479
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
313480 int flags, u16 vid)
314481 {
315482 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
....@@ -334,9 +501,8 @@
334501 cpsw_ale_write(ale, idx, ale_entry);
335502 return 0;
336503 }
337
-EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast);
338504
339
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
505
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
340506 int flags, u16 vid)
341507 {
342508 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
....@@ -350,9 +516,8 @@
350516 cpsw_ale_write(ale, idx, ale_entry);
351517 return 0;
352518 }
353
-EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast);
354519
355
-int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
520
+int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
356521 int flags, u16 vid, int mcast_state)
357522 {
358523 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
....@@ -365,7 +530,7 @@
365530 cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
366531
367532 cpsw_ale_set_addr(ale_entry, addr);
368
- cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
533
+ cpsw_ale_set_super(ale_entry, (flags & ALE_SUPER) ? 1 : 0);
369534 cpsw_ale_set_mcast_state(ale_entry, mcast_state);
370535
371536 mask = cpsw_ale_get_port_mask(ale_entry,
....@@ -384,12 +549,12 @@
384549 cpsw_ale_write(ale, idx, ale_entry);
385550 return 0;
386551 }
387
-EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast);
388552
389
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
553
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
390554 int flags, u16 vid)
391555 {
392556 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
557
+ int mcast_members = 0;
393558 int idx;
394559
395560 idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
....@@ -398,8 +563,14 @@
398563
399564 cpsw_ale_read(ale, idx, ale_entry);
400565
401
- if (port_mask)
402
- cpsw_ale_set_port_mask(ale_entry, port_mask,
566
+ if (port_mask) {
567
+ mcast_members = cpsw_ale_get_port_mask(ale_entry,
568
+ ale->port_mask_bits);
569
+ mcast_members &= ~port_mask;
570
+ }
571
+
572
+ if (mcast_members)
573
+ cpsw_ale_set_port_mask(ale_entry, mcast_members,
403574 ale->port_mask_bits);
404575 else
405576 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
....@@ -407,7 +578,6 @@
407578 cpsw_ale_write(ale, idx, ale_entry);
408579 return 0;
409580 }
410
-EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast);
411581
412582 /* ALE NetCP NU switch specific vlan functions */
413583 static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry,
....@@ -416,15 +586,29 @@
416586 int idx;
417587
418588 /* Set VLAN registered multicast flood mask */
419
- idx = cpsw_ale_get_vlan_reg_mcast_idx(ale_entry);
589
+ idx = cpsw_ale_vlan_get_fld(ale, ale_entry,
590
+ ALE_ENT_VID_REG_MCAST_IDX);
420591 writel(reg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
421592
422593 /* Set VLAN unregistered multicast flood mask */
423
- idx = cpsw_ale_get_vlan_unreg_mcast_idx(ale_entry);
594
+ idx = cpsw_ale_vlan_get_fld(ale, ale_entry,
595
+ ALE_ENT_VID_UNREG_MCAST_IDX);
424596 writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
425597 }
426598
427
-int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
599
+static void cpsw_ale_set_vlan_untag(struct cpsw_ale *ale, u32 *ale_entry,
600
+ u16 vid, int untag_mask)
601
+{
602
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
603
+ ALE_ENT_VID_FORCE_UNTAGGED_MSK,
604
+ untag_mask);
605
+ if (untag_mask & ALE_PORT_HOST)
606
+ bitmap_set(ale->p0_untag_vid_mask, vid, 1);
607
+ else
608
+ bitmap_clear(ale->p0_untag_vid_mask, vid, 1);
609
+}
610
+
611
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag,
428612 int reg_mcast, int unreg_mcast)
429613 {
430614 u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
....@@ -436,17 +620,22 @@
436620
437621 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
438622 cpsw_ale_set_vlan_id(ale_entry, vid);
623
+ cpsw_ale_set_vlan_untag(ale, ale_entry, vid, untag);
439624
440
- cpsw_ale_set_vlan_untag_force(ale_entry, untag, ale->vlan_field_bits);
441625 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);
626
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
627
+ ALE_ENT_VID_REG_MCAST_MSK, reg_mcast);
628
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
629
+ ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast);
446630 } else {
631
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
632
+ ALE_ENT_VID_UNREG_MCAST_IDX,
633
+ NU_VLAN_UNREG_MCAST_IDX);
447634 cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, unreg_mcast);
448635 }
449
- cpsw_ale_set_vlan_member_list(ale_entry, port, ale->vlan_field_bits);
636
+
637
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
638
+ ALE_ENT_VID_MEMBER_LIST, port_mask);
450639
451640 if (idx < 0)
452641 idx = cpsw_ale_match_free(ale);
....@@ -458,7 +647,45 @@
458647 cpsw_ale_write(ale, idx, ale_entry);
459648 return 0;
460649 }
461
-EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan);
650
+
651
+static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry,
652
+ u16 vid, int port_mask)
653
+{
654
+ int reg_mcast, unreg_mcast;
655
+ int members, untag;
656
+
657
+ members = cpsw_ale_vlan_get_fld(ale, ale_entry,
658
+ ALE_ENT_VID_MEMBER_LIST);
659
+ members &= ~port_mask;
660
+ if (!members) {
661
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
662
+ return;
663
+ }
664
+
665
+ untag = cpsw_ale_vlan_get_fld(ale, ale_entry,
666
+ ALE_ENT_VID_FORCE_UNTAGGED_MSK);
667
+ reg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry,
668
+ ALE_ENT_VID_REG_MCAST_MSK);
669
+ unreg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry,
670
+ ALE_ENT_VID_UNREG_MCAST_MSK);
671
+ untag &= members;
672
+ reg_mcast &= members;
673
+ unreg_mcast &= members;
674
+
675
+ cpsw_ale_set_vlan_untag(ale, ale_entry, vid, untag);
676
+
677
+ if (!ale->params.nu_switch_ale) {
678
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
679
+ ALE_ENT_VID_REG_MCAST_MSK, reg_mcast);
680
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
681
+ ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast);
682
+ } else {
683
+ cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast,
684
+ unreg_mcast);
685
+ }
686
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
687
+ ALE_ENT_VID_MEMBER_LIST, members);
688
+}
462689
463690 int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
464691 {
....@@ -471,29 +698,63 @@
471698
472699 cpsw_ale_read(ale, idx, ale_entry);
473700
474
- if (port_mask)
475
- cpsw_ale_set_vlan_member_list(ale_entry, port_mask,
476
- ale->vlan_field_bits);
477
- else
701
+ if (port_mask) {
702
+ cpsw_ale_del_vlan_modify(ale, ale_entry, vid, port_mask);
703
+ } else {
704
+ cpsw_ale_set_vlan_untag(ale, ale_entry, vid, 0);
478705 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
706
+ }
479707
480708 cpsw_ale_write(ale, idx, ale_entry);
709
+
481710 return 0;
482711 }
483
-EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan);
484712
485
-void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
713
+int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask,
714
+ int untag_mask, int reg_mask, int unreg_mask)
715
+{
716
+ u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
717
+ int reg_mcast_members, unreg_mcast_members;
718
+ int vlan_members, untag_members;
719
+ int idx, ret = 0;
720
+
721
+ idx = cpsw_ale_match_vlan(ale, vid);
722
+ if (idx >= 0)
723
+ cpsw_ale_read(ale, idx, ale_entry);
724
+
725
+ vlan_members = cpsw_ale_vlan_get_fld(ale, ale_entry,
726
+ ALE_ENT_VID_MEMBER_LIST);
727
+ reg_mcast_members = cpsw_ale_vlan_get_fld(ale, ale_entry,
728
+ ALE_ENT_VID_REG_MCAST_MSK);
729
+ unreg_mcast_members =
730
+ cpsw_ale_vlan_get_fld(ale, ale_entry,
731
+ ALE_ENT_VID_UNREG_MCAST_MSK);
732
+ untag_members = cpsw_ale_vlan_get_fld(ale, ale_entry,
733
+ ALE_ENT_VID_FORCE_UNTAGGED_MSK);
734
+
735
+ vlan_members |= port_mask;
736
+ untag_members = (untag_members & ~port_mask) | untag_mask;
737
+ reg_mcast_members = (reg_mcast_members & ~port_mask) | reg_mask;
738
+ unreg_mcast_members = (unreg_mcast_members & ~port_mask) | unreg_mask;
739
+
740
+ ret = cpsw_ale_add_vlan(ale, vid, vlan_members, untag_members,
741
+ reg_mcast_members, unreg_mcast_members);
742
+ if (ret) {
743
+ dev_err(ale->params.dev, "Unable to add vlan\n");
744
+ return ret;
745
+ }
746
+ dev_dbg(ale->params.dev, "port mask 0x%x untag 0x%x\n", vlan_members,
747
+ untag_mask);
748
+
749
+ return ret;
750
+}
751
+
752
+void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask,
753
+ bool add)
486754 {
487755 u32 ale_entry[ALE_ENTRY_WORDS];
756
+ int unreg_members = 0;
488757 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;
497758
498759 for (idx = 0; idx < ale->params.ale_entries; idx++) {
499760 cpsw_ale_read(ale, idx, ale_entry);
....@@ -501,19 +762,84 @@
501762 if (type != ALE_TYPE_VLAN)
502763 continue;
503764
504
- unreg_mcast =
505
- cpsw_ale_get_vlan_unreg_mcast(ale_entry,
506
- ale->vlan_field_bits);
507
- if (allmulti)
508
- unreg_mcast |= 1;
765
+ unreg_members =
766
+ cpsw_ale_vlan_get_fld(ale, ale_entry,
767
+ ALE_ENT_VID_UNREG_MCAST_MSK);
768
+ if (add)
769
+ unreg_members |= unreg_mcast_mask;
509770 else
510
- unreg_mcast &= ~1;
511
- cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast,
512
- ale->vlan_field_bits);
771
+ unreg_members &= ~unreg_mcast_mask;
772
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
773
+ ALE_ENT_VID_UNREG_MCAST_MSK,
774
+ unreg_members);
513775 cpsw_ale_write(ale, idx, ale_entry);
514776 }
515777 }
516
-EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti);
778
+
779
+static void cpsw_ale_vlan_set_unreg_mcast(struct cpsw_ale *ale, u32 *ale_entry,
780
+ int allmulti)
781
+{
782
+ int unreg_mcast;
783
+
784
+ unreg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry,
785
+ ALE_ENT_VID_UNREG_MCAST_MSK);
786
+ if (allmulti)
787
+ unreg_mcast |= ALE_PORT_HOST;
788
+ else
789
+ unreg_mcast &= ~ALE_PORT_HOST;
790
+
791
+ cpsw_ale_vlan_set_fld(ale, ale_entry,
792
+ ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast);
793
+}
794
+
795
+static void
796
+cpsw_ale_vlan_set_unreg_mcast_idx(struct cpsw_ale *ale, u32 *ale_entry,
797
+ int allmulti)
798
+{
799
+ int unreg_mcast;
800
+ int idx;
801
+
802
+ idx = cpsw_ale_vlan_get_fld(ale, ale_entry,
803
+ ALE_ENT_VID_UNREG_MCAST_IDX);
804
+
805
+ unreg_mcast = readl(ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
806
+
807
+ if (allmulti)
808
+ unreg_mcast |= ALE_PORT_HOST;
809
+ else
810
+ unreg_mcast &= ~ALE_PORT_HOST;
811
+
812
+ writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
813
+}
814
+
815
+void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port)
816
+{
817
+ u32 ale_entry[ALE_ENTRY_WORDS];
818
+ int type, idx;
819
+
820
+ for (idx = 0; idx < ale->params.ale_entries; idx++) {
821
+ int vlan_members;
822
+
823
+ cpsw_ale_read(ale, idx, ale_entry);
824
+ type = cpsw_ale_get_entry_type(ale_entry);
825
+ if (type != ALE_TYPE_VLAN)
826
+ continue;
827
+
828
+ vlan_members = cpsw_ale_vlan_get_fld(ale, ale_entry,
829
+ ALE_ENT_VID_MEMBER_LIST);
830
+
831
+ if (port != -1 && !(vlan_members & BIT(port)))
832
+ continue;
833
+
834
+ if (!ale->params.nu_switch_ale)
835
+ cpsw_ale_vlan_set_unreg_mcast(ale, ale_entry, allmulti);
836
+ else
837
+ cpsw_ale_vlan_set_unreg_mcast_idx(ale, ale_entry,
838
+ allmulti);
839
+
840
+ cpsw_ale_write(ale, idx, ale_entry);
841
+ }
842
+}
517843
518844 struct ale_control_info {
519845 const char *name;
....@@ -659,6 +985,22 @@
659985 .port_shift = 0,
660986 .bits = 1,
661987 },
988
+ [ALE_PORT_MACONLY] = {
989
+ .name = "mac_only_port_mode",
990
+ .offset = ALE_PORTCTL,
991
+ .port_offset = 4,
992
+ .shift = 11,
993
+ .port_shift = 0,
994
+ .bits = 1,
995
+ },
996
+ [ALE_PORT_MACONLY_CAF] = {
997
+ .name = "mac_only_port_caf",
998
+ .offset = ALE_PORTCTL,
999
+ .port_offset = 4,
1000
+ .shift = 13,
1001
+ .port_shift = 0,
1002
+ .bits = 1,
1003
+ },
6621004 [ALE_PORT_MCAST_LIMIT] = {
6631005 .name = "mcast_limit",
6641006 .offset = ALE_PORTCTL,
....@@ -707,6 +1049,22 @@
7071049 .port_shift = 0,
7081050 .bits = 6,
7091051 },
1052
+ [ALE_DEFAULT_THREAD_ID] = {
1053
+ .name = "default_thread_id",
1054
+ .offset = AM65_CPSW_ALE_THREAD_DEF_REG,
1055
+ .port_offset = 0,
1056
+ .shift = 0,
1057
+ .port_shift = 0,
1058
+ .bits = 6,
1059
+ },
1060
+ [ALE_DEFAULT_THREAD_ENABLE] = {
1061
+ .name = "default_thread_id_enable",
1062
+ .offset = AM65_CPSW_ALE_THREAD_DEF_REG,
1063
+ .port_offset = 0,
1064
+ .shift = 15,
1065
+ .port_shift = 0,
1066
+ .bits = 1,
1067
+ },
7101068 };
7111069
7121070 int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control,
....@@ -739,7 +1097,6 @@
7391097
7401098 return 0;
7411099 }
742
-EXPORT_SYMBOL_GPL(cpsw_ale_control_set);
7431100
7441101 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
7451102 {
....@@ -763,7 +1120,6 @@
7631120 tmp = readl_relaxed(ale->params.ale_regs + offset) >> shift;
7641121 return tmp & BITMASK(info->bits);
7651122 }
766
-EXPORT_SYMBOL_GPL(cpsw_ale_control_get);
7671123
7681124 static void cpsw_ale_timer(struct timer_list *t)
7691125 {
....@@ -777,42 +1133,163 @@
7771133 }
7781134 }
7791135
1136
+static void cpsw_ale_hw_aging_timer_start(struct cpsw_ale *ale)
1137
+{
1138
+ u32 aging_timer;
1139
+
1140
+ aging_timer = ale->params.bus_freq / 1000000;
1141
+ aging_timer *= ale->params.ale_ageout;
1142
+
1143
+ if (aging_timer & ~ALE_AGING_TIMER_MASK) {
1144
+ aging_timer = ALE_AGING_TIMER_MASK;
1145
+ dev_warn(ale->params.dev,
1146
+ "ALE aging timer overflow, set to max\n");
1147
+ }
1148
+
1149
+ writel(aging_timer, ale->params.ale_regs + ALE_AGING_TIMER);
1150
+}
1151
+
1152
+static void cpsw_ale_hw_aging_timer_stop(struct cpsw_ale *ale)
1153
+{
1154
+ writel(0, ale->params.ale_regs + ALE_AGING_TIMER);
1155
+}
1156
+
1157
+static void cpsw_ale_aging_start(struct cpsw_ale *ale)
1158
+{
1159
+ if (!ale->params.ale_ageout)
1160
+ return;
1161
+
1162
+ if (ale->features & CPSW_ALE_F_HW_AUTOAGING) {
1163
+ cpsw_ale_hw_aging_timer_start(ale);
1164
+ return;
1165
+ }
1166
+
1167
+ timer_setup(&ale->timer, cpsw_ale_timer, 0);
1168
+ ale->timer.expires = jiffies + ale->ageout;
1169
+ add_timer(&ale->timer);
1170
+}
1171
+
1172
+static void cpsw_ale_aging_stop(struct cpsw_ale *ale)
1173
+{
1174
+ if (!ale->params.ale_ageout)
1175
+ return;
1176
+
1177
+ if (ale->features & CPSW_ALE_F_HW_AUTOAGING) {
1178
+ cpsw_ale_hw_aging_timer_stop(ale);
1179
+ return;
1180
+ }
1181
+
1182
+ del_timer_sync(&ale->timer);
1183
+}
1184
+
7801185 void cpsw_ale_start(struct cpsw_ale *ale)
7811186 {
7821187 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1);
7831188 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
7841189
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
- }
1190
+ cpsw_ale_aging_start(ale);
7901191 }
791
-EXPORT_SYMBOL_GPL(cpsw_ale_start);
7921192
7931193 void cpsw_ale_stop(struct cpsw_ale *ale)
7941194 {
795
- del_timer_sync(&ale->timer);
1195
+ cpsw_ale_aging_stop(ale);
7961196 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
7971197 cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
7981198 }
799
-EXPORT_SYMBOL_GPL(cpsw_ale_stop);
1199
+
1200
+static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = {
1201
+ {
1202
+ /* am3/4/5, dra7. dm814x, 66ak2hk-gbe */
1203
+ .dev_id = "cpsw",
1204
+ .tbl_entries = 1024,
1205
+ .major_ver_mask = 0xff,
1206
+ .vlan_entry_tbl = vlan_entry_cpsw,
1207
+ },
1208
+ {
1209
+ /* 66ak2h_xgbe */
1210
+ .dev_id = "66ak2h-xgbe",
1211
+ .tbl_entries = 2048,
1212
+ .major_ver_mask = 0xff,
1213
+ .vlan_entry_tbl = vlan_entry_cpsw,
1214
+ },
1215
+ {
1216
+ .dev_id = "66ak2el",
1217
+ .features = CPSW_ALE_F_STATUS_REG,
1218
+ .major_ver_mask = 0x7,
1219
+ .nu_switch_ale = true,
1220
+ .vlan_entry_tbl = vlan_entry_nu,
1221
+ },
1222
+ {
1223
+ .dev_id = "66ak2g",
1224
+ .features = CPSW_ALE_F_STATUS_REG,
1225
+ .tbl_entries = 64,
1226
+ .major_ver_mask = 0x7,
1227
+ .nu_switch_ale = true,
1228
+ .vlan_entry_tbl = vlan_entry_nu,
1229
+ },
1230
+ {
1231
+ .dev_id = "am65x-cpsw2g",
1232
+ .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING,
1233
+ .tbl_entries = 64,
1234
+ .major_ver_mask = 0x7,
1235
+ .nu_switch_ale = true,
1236
+ .vlan_entry_tbl = vlan_entry_nu,
1237
+ },
1238
+ {
1239
+ .dev_id = "j721e-cpswxg",
1240
+ .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING,
1241
+ .major_ver_mask = 0x7,
1242
+ .vlan_entry_tbl = vlan_entry_k3_cpswxg,
1243
+ },
1244
+ { },
1245
+};
1246
+
1247
+static const struct
1248
+cpsw_ale_dev_id *cpsw_ale_match_id(const struct cpsw_ale_dev_id *id,
1249
+ const char *dev_id)
1250
+{
1251
+ if (!dev_id)
1252
+ return NULL;
1253
+
1254
+ while (id->dev_id) {
1255
+ if (strcmp(dev_id, id->dev_id) == 0)
1256
+ return id;
1257
+ id++;
1258
+ }
1259
+ return NULL;
1260
+}
8001261
8011262 struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
8021263 {
1264
+ const struct cpsw_ale_dev_id *ale_dev_id;
8031265 struct cpsw_ale *ale;
8041266 u32 rev, ale_entries;
8051267
1268
+ ale_dev_id = cpsw_ale_match_id(cpsw_ale_id_match, params->dev_id);
1269
+ if (!ale_dev_id)
1270
+ return ERR_PTR(-EINVAL);
1271
+
1272
+ params->ale_entries = ale_dev_id->tbl_entries;
1273
+ params->major_ver_mask = ale_dev_id->major_ver_mask;
1274
+ params->nu_switch_ale = ale_dev_id->nu_switch_ale;
1275
+
8061276 ale = devm_kzalloc(params->dev, sizeof(*ale), GFP_KERNEL);
8071277 if (!ale)
808
- return NULL;
1278
+ return ERR_PTR(-ENOMEM);
1279
+
1280
+ ale->p0_untag_vid_mask =
1281
+ devm_kmalloc_array(params->dev, BITS_TO_LONGS(VLAN_N_VID),
1282
+ sizeof(unsigned long),
1283
+ GFP_KERNEL);
1284
+ if (!ale->p0_untag_vid_mask)
1285
+ return ERR_PTR(-ENOMEM);
8091286
8101287 ale->params = *params;
8111288 ale->ageout = ale->params.ale_ageout * HZ;
1289
+ ale->features = ale_dev_id->features;
1290
+ ale->vlan_entry_tbl = ale_dev_id->vlan_entry_tbl;
8121291
8131292 rev = readl_relaxed(ale->params.ale_regs + ALE_IDVER);
814
- if (!ale->params.major_ver_mask)
815
- ale->params.major_ver_mask = 0xff;
8161293 ale->version =
8171294 (ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask) << 8) |
8181295 ALE_VERSION_MINOR(rev);
....@@ -820,7 +1297,8 @@
8201297 ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask),
8211298 ALE_VERSION_MINOR(rev));
8221299
823
- if (!ale->params.ale_entries) {
1300
+ if (ale->features & CPSW_ALE_F_STATUS_REG &&
1301
+ !ale->params.ale_entries) {
8241302 ale_entries =
8251303 readl_relaxed(ale->params.ale_regs + ALE_STATUS) &
8261304 ALE_STATUS_SIZE_MASK;
....@@ -829,16 +1307,12 @@
8291307 * table which shows the size as a multiple of 1024 entries.
8301308 * For these, params.ale_entries will be set to zero. So
8311309 * 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.
1310
+ * return error if ale_entries is zero in ALE_STATUS.
8371311 */
8381312 if (!ale_entries)
839
- ale_entries = ALE_TABLE_SIZE_DEFAULT;
840
- else
841
- ale_entries *= ALE_TABLE_SIZE_MULTIPLIER;
1313
+ return ERR_PTR(-EINVAL);
1314
+
1315
+ ale_entries *= ALE_TABLE_SIZE_MULTIPLIER;
8421316 ale->params.ale_entries = ale_entries;
8431317 }
8441318 dev_info(ale->params.dev,
....@@ -881,7 +1355,6 @@
8811355 cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
8821356 return ale;
8831357 }
884
-EXPORT_SYMBOL_GPL(cpsw_ale_create);
8851358
8861359 void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data)
8871360 {
....@@ -892,8 +1365,8 @@
8921365 data += ALE_ENTRY_WORDS;
8931366 }
8941367 }
895
-EXPORT_SYMBOL_GPL(cpsw_ale_dump);
8961368
897
-MODULE_LICENSE("GPL v2");
898
-MODULE_DESCRIPTION("TI CPSW ALE driver");
899
-MODULE_AUTHOR("Texas Instruments");
1369
+u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale)
1370
+{
1371
+ return ale ? ale->params.ale_entries : 0;
1372
+}