Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / net / ethernet / ti / cpsw_ale.c
1 /*
2  * Texas Instruments 3-Port Ethernet Switch Address Lookup Engine
3  *
4  * Copyright (C) 2012 Texas Instruments
5  *
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.
14  */
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/seq_file.h>
19 #include <linux/slab.h>
20 #include <linux/err.h>
21 #include <linux/io.h>
22 #include <linux/stat.h>
23 #include <linux/sysfs.h>
24 #include <linux/etherdevice.h>
25
26 #include "cpsw_ale.h"
27
28 #define BITMASK(bits)           (BIT(bits) - 1)
29
30 #define ALE_VERSION_MAJOR(rev)  ((rev >> 8) & 0xff)
31 #define ALE_VERSION_MINOR(rev)  (rev & 0xff)
32
33 /* ALE Registers */
34 #define ALE_IDVER               0x00
35 #define ALE_CONTROL             0x08
36 #define ALE_PRESCALE            0x10
37 #define ALE_UNKNOWNVLAN         0x18
38 #define ALE_TABLE_CONTROL       0x20
39 #define ALE_TABLE               0x34
40 #define ALE_PORTCTL             0x40
41
42 #define ALE_TABLE_WRITE         BIT(31)
43
44 #define ALE_TYPE_FREE                   0
45 #define ALE_TYPE_ADDR                   1
46 #define ALE_TYPE_VLAN                   2
47 #define ALE_TYPE_VLAN_ADDR              3
48
49 #define ALE_UCAST_PERSISTANT            0
50 #define ALE_UCAST_UNTOUCHED             1
51 #define ALE_UCAST_OUI                   2
52 #define ALE_UCAST_TOUCHED               3
53
54 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
55 {
56         int idx;
57
58         idx    = start / 32;
59         start -= idx * 32;
60         idx    = 2 - idx; /* flip */
61         return (ale_entry[idx] >> start) & BITMASK(bits);
62 }
63
64 static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
65                                       u32 value)
66 {
67         int idx;
68
69         value &= BITMASK(bits);
70         idx    = start / 32;
71         start -= idx * 32;
72         idx    = 2 - idx; /* flip */
73         ale_entry[idx] &= ~(BITMASK(bits) << start);
74         ale_entry[idx] |=  (value << start);
75 }
76
77 #define DEFINE_ALE_FIELD(name, start, bits)                             \
78 static inline int cpsw_ale_get_##name(u32 *ale_entry)                   \
79 {                                                                       \
80         return cpsw_ale_get_field(ale_entry, start, bits);              \
81 }                                                                       \
82 static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value)       \
83 {                                                                       \
84         cpsw_ale_set_field(ale_entry, start, bits, value);              \
85 }
86
87 DEFINE_ALE_FIELD(entry_type,            60,     2)
88 DEFINE_ALE_FIELD(vlan_id,               48,     12)
89 DEFINE_ALE_FIELD(mcast_state,           62,     2)
90 DEFINE_ALE_FIELD(port_mask,             66,     3)
91 DEFINE_ALE_FIELD(super,                 65,     1)
92 DEFINE_ALE_FIELD(ucast_type,            62,     2)
93 DEFINE_ALE_FIELD(port_num,              66,     2)
94 DEFINE_ALE_FIELD(blocked,               65,     1)
95 DEFINE_ALE_FIELD(secure,                64,     1)
96 DEFINE_ALE_FIELD(vlan_untag_force,      24,     3)
97 DEFINE_ALE_FIELD(vlan_reg_mcast,        16,     3)
98 DEFINE_ALE_FIELD(vlan_unreg_mcast,      8,      3)
99 DEFINE_ALE_FIELD(vlan_member_list,      0,      3)
100 DEFINE_ALE_FIELD(mcast,                 40,     1)
101
102 /* The MAC address field in the ALE entry cannot be macroized as above */
103 static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
104 {
105         int i;
106
107         for (i = 0; i < 6; i++)
108                 addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
109 }
110
111 static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr)
112 {
113         int i;
114
115         for (i = 0; i < 6; i++)
116                 cpsw_ale_set_field(ale_entry, 40 - 8*i, 8, addr[i]);
117 }
118
119 static int cpsw_ale_read(struct cpsw_ale *ale, int idx, u32 *ale_entry)
120 {
121         int i;
122
123         WARN_ON(idx > ale->params.ale_entries);
124
125         __raw_writel(idx, ale->params.ale_regs + ALE_TABLE_CONTROL);
126
127         for (i = 0; i < ALE_ENTRY_WORDS; i++)
128                 ale_entry[i] = __raw_readl(ale->params.ale_regs +
129                                            ALE_TABLE + 4 * i);
130
131         return idx;
132 }
133
134 static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry)
135 {
136         int i;
137
138         WARN_ON(idx > ale->params.ale_entries);
139
140         for (i = 0; i < ALE_ENTRY_WORDS; i++)
141                 __raw_writel(ale_entry[i], ale->params.ale_regs +
142                              ALE_TABLE + 4 * i);
143
144         __raw_writel(idx | ALE_TABLE_WRITE, ale->params.ale_regs +
145                      ALE_TABLE_CONTROL);
146
147         return idx;
148 }
149
150 static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
151 {
152         u32 ale_entry[ALE_ENTRY_WORDS];
153         int type, idx;
154
155         for (idx = 0; idx < ale->params.ale_entries; idx++) {
156                 u8 entry_addr[6];
157
158                 cpsw_ale_read(ale, idx, ale_entry);
159                 type = cpsw_ale_get_entry_type(ale_entry);
160                 if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
161                         continue;
162                 if (cpsw_ale_get_vlan_id(ale_entry) != vid)
163                         continue;
164                 cpsw_ale_get_addr(ale_entry, entry_addr);
165                 if (ether_addr_equal(entry_addr, addr))
166                         return idx;
167         }
168         return -ENOENT;
169 }
170
171 static int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid)
172 {
173         u32 ale_entry[ALE_ENTRY_WORDS];
174         int type, idx;
175
176         for (idx = 0; idx < ale->params.ale_entries; idx++) {
177                 cpsw_ale_read(ale, idx, ale_entry);
178                 type = cpsw_ale_get_entry_type(ale_entry);
179                 if (type != ALE_TYPE_VLAN)
180                         continue;
181                 if (cpsw_ale_get_vlan_id(ale_entry) == vid)
182                         return idx;
183         }
184         return -ENOENT;
185 }
186
187 static int cpsw_ale_match_free(struct cpsw_ale *ale)
188 {
189         u32 ale_entry[ALE_ENTRY_WORDS];
190         int type, idx;
191
192         for (idx = 0; idx < ale->params.ale_entries; idx++) {
193                 cpsw_ale_read(ale, idx, ale_entry);
194                 type = cpsw_ale_get_entry_type(ale_entry);
195                 if (type == ALE_TYPE_FREE)
196                         return idx;
197         }
198         return -ENOENT;
199 }
200
201 static int cpsw_ale_find_ageable(struct cpsw_ale *ale)
202 {
203         u32 ale_entry[ALE_ENTRY_WORDS];
204         int type, idx;
205
206         for (idx = 0; idx < ale->params.ale_entries; idx++) {
207                 cpsw_ale_read(ale, idx, ale_entry);
208                 type = cpsw_ale_get_entry_type(ale_entry);
209                 if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
210                         continue;
211                 if (cpsw_ale_get_mcast(ale_entry))
212                         continue;
213                 type = cpsw_ale_get_ucast_type(ale_entry);
214                 if (type != ALE_UCAST_PERSISTANT &&
215                     type != ALE_UCAST_OUI)
216                         return idx;
217         }
218         return -ENOENT;
219 }
220
221 static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
222                                  int port_mask)
223 {
224         int mask;
225
226         mask = cpsw_ale_get_port_mask(ale_entry);
227         if ((mask & port_mask) == 0)
228                 return; /* ports dont intersect, not interested */
229         mask &= ~port_mask;
230
231         /* free if only remaining port is host port */
232         if (mask)
233                 cpsw_ale_set_port_mask(ale_entry, mask);
234         else
235                 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
236 }
237
238 int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
239 {
240         u32 ale_entry[ALE_ENTRY_WORDS];
241         int ret, idx;
242
243         for (idx = 0; idx < ale->params.ale_entries; idx++) {
244                 cpsw_ale_read(ale, idx, ale_entry);
245                 ret = cpsw_ale_get_entry_type(ale_entry);
246                 if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR)
247                         continue;
248
249                 /* if vid passed is -1 then remove all multicast entry from
250                  * the table irrespective of vlan id, if a valid vlan id is
251                  * passed then remove only multicast added to that vlan id.
252                  * if vlan id doesn't match then move on to next entry.
253                  */
254                 if (vid != -1 && cpsw_ale_get_vlan_id(ale_entry) != vid)
255                         continue;
256
257                 if (cpsw_ale_get_mcast(ale_entry)) {
258                         u8 addr[6];
259
260                         cpsw_ale_get_addr(ale_entry, addr);
261                         if (!is_broadcast_ether_addr(addr))
262                                 cpsw_ale_flush_mcast(ale, ale_entry, port_mask);
263                 }
264
265                 cpsw_ale_write(ale, idx, ale_entry);
266         }
267         return 0;
268 }
269 EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast);
270
271 static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry,
272                                  int port_mask)
273 {
274         int port;
275
276         port = cpsw_ale_get_port_num(ale_entry);
277         if ((BIT(port) & port_mask) == 0)
278                 return; /* ports dont intersect, not interested */
279         cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
280 }
281
282 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
283 {
284         u32 ale_entry[ALE_ENTRY_WORDS];
285         int ret, idx;
286
287         for (idx = 0; idx < ale->params.ale_entries; idx++) {
288                 cpsw_ale_read(ale, idx, ale_entry);
289                 ret = cpsw_ale_get_entry_type(ale_entry);
290                 if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR)
291                         continue;
292
293                 if (cpsw_ale_get_mcast(ale_entry))
294                         cpsw_ale_flush_mcast(ale, ale_entry, port_mask);
295                 else
296                         cpsw_ale_flush_ucast(ale, ale_entry, port_mask);
297
298                 cpsw_ale_write(ale, idx, ale_entry);
299         }
300         return 0;
301 }
302 EXPORT_SYMBOL_GPL(cpsw_ale_flush);
303
304 static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
305                                                 int flags, u16 vid)
306 {
307         if (flags & ALE_VLAN) {
308                 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
309                 cpsw_ale_set_vlan_id(ale_entry, vid);
310         } else {
311                 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
312         }
313 }
314
315 int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
316                        int flags, u16 vid)
317 {
318         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
319         int idx;
320
321         cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
322
323         cpsw_ale_set_addr(ale_entry, addr);
324         cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
325         cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
326         cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
327         cpsw_ale_set_port_num(ale_entry, port);
328
329         idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
330         if (idx < 0)
331                 idx = cpsw_ale_match_free(ale);
332         if (idx < 0)
333                 idx = cpsw_ale_find_ageable(ale);
334         if (idx < 0)
335                 return -ENOMEM;
336
337         cpsw_ale_write(ale, idx, ale_entry);
338         return 0;
339 }
340 EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast);
341
342 int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
343                        int flags, u16 vid)
344 {
345         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
346         int idx;
347
348         idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
349         if (idx < 0)
350                 return -ENOENT;
351
352         cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
353         cpsw_ale_write(ale, idx, ale_entry);
354         return 0;
355 }
356 EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast);
357
358 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
359                        int flags, u16 vid, int mcast_state)
360 {
361         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
362         int idx, mask;
363
364         idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
365         if (idx >= 0)
366                 cpsw_ale_read(ale, idx, ale_entry);
367
368         cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
369
370         cpsw_ale_set_addr(ale_entry, addr);
371         cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
372         cpsw_ale_set_mcast_state(ale_entry, mcast_state);
373
374         mask = cpsw_ale_get_port_mask(ale_entry);
375         port_mask |= mask;
376         cpsw_ale_set_port_mask(ale_entry, port_mask);
377
378         if (idx < 0)
379                 idx = cpsw_ale_match_free(ale);
380         if (idx < 0)
381                 idx = cpsw_ale_find_ageable(ale);
382         if (idx < 0)
383                 return -ENOMEM;
384
385         cpsw_ale_write(ale, idx, ale_entry);
386         return 0;
387 }
388 EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast);
389
390 int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
391                        int flags, u16 vid)
392 {
393         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
394         int idx;
395
396         idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
397         if (idx < 0)
398                 return -EINVAL;
399
400         cpsw_ale_read(ale, idx, ale_entry);
401
402         if (port_mask)
403                 cpsw_ale_set_port_mask(ale_entry, port_mask);
404         else
405                 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
406
407         cpsw_ale_write(ale, idx, ale_entry);
408         return 0;
409 }
410 EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast);
411
412 int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
413                       int reg_mcast, int unreg_mcast)
414 {
415         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
416         int idx;
417
418         idx = cpsw_ale_match_vlan(ale, vid);
419         if (idx >= 0)
420                 cpsw_ale_read(ale, idx, ale_entry);
421
422         cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
423         cpsw_ale_set_vlan_id(ale_entry, vid);
424
425         cpsw_ale_set_vlan_untag_force(ale_entry, untag);
426         cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast);
427         cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
428         cpsw_ale_set_vlan_member_list(ale_entry, port);
429
430         if (idx < 0)
431                 idx = cpsw_ale_match_free(ale);
432         if (idx < 0)
433                 idx = cpsw_ale_find_ageable(ale);
434         if (idx < 0)
435                 return -ENOMEM;
436
437         cpsw_ale_write(ale, idx, ale_entry);
438         return 0;
439 }
440 EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan);
441
442 int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
443 {
444         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
445         int idx;
446
447         idx = cpsw_ale_match_vlan(ale, vid);
448         if (idx < 0)
449                 return -ENOENT;
450
451         cpsw_ale_read(ale, idx, ale_entry);
452
453         if (port_mask)
454                 cpsw_ale_set_vlan_member_list(ale_entry, port_mask);
455         else
456                 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
457
458         cpsw_ale_write(ale, idx, ale_entry);
459         return 0;
460 }
461 EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan);
462
463 void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
464 {
465         u32 ale_entry[ALE_ENTRY_WORDS];
466         int type, idx;
467         int unreg_mcast = 0;
468
469         /* Only bother doing the work if the setting is actually changing */
470         if (ale->allmulti == allmulti)
471                 return;
472
473         /* Remember the new setting to check against next time */
474         ale->allmulti = allmulti;
475
476         for (idx = 0; idx < ale->params.ale_entries; idx++) {
477                 cpsw_ale_read(ale, idx, ale_entry);
478                 type = cpsw_ale_get_entry_type(ale_entry);
479                 if (type != ALE_TYPE_VLAN)
480                         continue;
481
482                 unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry);
483                 if (allmulti)
484                         unreg_mcast |= 1;
485                 else
486                         unreg_mcast &= ~1;
487                 cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
488                 cpsw_ale_write(ale, idx, ale_entry);
489         }
490 }
491 EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti);
492
493 struct ale_control_info {
494         const char      *name;
495         int             offset, port_offset;
496         int             shift, port_shift;
497         int             bits;
498 };
499
500 static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = {
501         [ALE_ENABLE]            = {
502                 .name           = "enable",
503                 .offset         = ALE_CONTROL,
504                 .port_offset    = 0,
505                 .shift          = 31,
506                 .port_shift     = 0,
507                 .bits           = 1,
508         },
509         [ALE_CLEAR]             = {
510                 .name           = "clear",
511                 .offset         = ALE_CONTROL,
512                 .port_offset    = 0,
513                 .shift          = 30,
514                 .port_shift     = 0,
515                 .bits           = 1,
516         },
517         [ALE_AGEOUT]            = {
518                 .name           = "ageout",
519                 .offset         = ALE_CONTROL,
520                 .port_offset    = 0,
521                 .shift          = 29,
522                 .port_shift     = 0,
523                 .bits           = 1,
524         },
525         [ALE_P0_UNI_FLOOD]      = {
526                 .name           = "port0_unicast_flood",
527                 .offset         = ALE_CONTROL,
528                 .port_offset    = 0,
529                 .shift          = 8,
530                 .port_shift     = 0,
531                 .bits           = 1,
532         },
533         [ALE_VLAN_NOLEARN]      = {
534                 .name           = "vlan_nolearn",
535                 .offset         = ALE_CONTROL,
536                 .port_offset    = 0,
537                 .shift          = 7,
538                 .port_shift     = 0,
539                 .bits           = 1,
540         },
541         [ALE_NO_PORT_VLAN]      = {
542                 .name           = "no_port_vlan",
543                 .offset         = ALE_CONTROL,
544                 .port_offset    = 0,
545                 .shift          = 6,
546                 .port_shift     = 0,
547                 .bits           = 1,
548         },
549         [ALE_OUI_DENY]          = {
550                 .name           = "oui_deny",
551                 .offset         = ALE_CONTROL,
552                 .port_offset    = 0,
553                 .shift          = 5,
554                 .port_shift     = 0,
555                 .bits           = 1,
556         },
557         [ALE_BYPASS]            = {
558                 .name           = "bypass",
559                 .offset         = ALE_CONTROL,
560                 .port_offset    = 0,
561                 .shift          = 4,
562                 .port_shift     = 0,
563                 .bits           = 1,
564         },
565         [ALE_RATE_LIMIT_TX]     = {
566                 .name           = "rate_limit_tx",
567                 .offset         = ALE_CONTROL,
568                 .port_offset    = 0,
569                 .shift          = 3,
570                 .port_shift     = 0,
571                 .bits           = 1,
572         },
573         [ALE_VLAN_AWARE]        = {
574                 .name           = "vlan_aware",
575                 .offset         = ALE_CONTROL,
576                 .port_offset    = 0,
577                 .shift          = 2,
578                 .port_shift     = 0,
579                 .bits           = 1,
580         },
581         [ALE_AUTH_ENABLE]       = {
582                 .name           = "auth_enable",
583                 .offset         = ALE_CONTROL,
584                 .port_offset    = 0,
585                 .shift          = 1,
586                 .port_shift     = 0,
587                 .bits           = 1,
588         },
589         [ALE_RATE_LIMIT]        = {
590                 .name           = "rate_limit",
591                 .offset         = ALE_CONTROL,
592                 .port_offset    = 0,
593                 .shift          = 0,
594                 .port_shift     = 0,
595                 .bits           = 1,
596         },
597         [ALE_PORT_STATE]        = {
598                 .name           = "port_state",
599                 .offset         = ALE_PORTCTL,
600                 .port_offset    = 4,
601                 .shift          = 0,
602                 .port_shift     = 0,
603                 .bits           = 2,
604         },
605         [ALE_PORT_DROP_UNTAGGED] = {
606                 .name           = "drop_untagged",
607                 .offset         = ALE_PORTCTL,
608                 .port_offset    = 4,
609                 .shift          = 2,
610                 .port_shift     = 0,
611                 .bits           = 1,
612         },
613         [ALE_PORT_DROP_UNKNOWN_VLAN] = {
614                 .name           = "drop_unknown",
615                 .offset         = ALE_PORTCTL,
616                 .port_offset    = 4,
617                 .shift          = 3,
618                 .port_shift     = 0,
619                 .bits           = 1,
620         },
621         [ALE_PORT_NOLEARN]      = {
622                 .name           = "nolearn",
623                 .offset         = ALE_PORTCTL,
624                 .port_offset    = 4,
625                 .shift          = 4,
626                 .port_shift     = 0,
627                 .bits           = 1,
628         },
629         [ALE_PORT_NO_SA_UPDATE] = {
630                 .name           = "no_source_update",
631                 .offset         = ALE_PORTCTL,
632                 .port_offset    = 4,
633                 .shift          = 5,
634                 .port_shift     = 0,
635                 .bits           = 1,
636         },
637         [ALE_PORT_MCAST_LIMIT]  = {
638                 .name           = "mcast_limit",
639                 .offset         = ALE_PORTCTL,
640                 .port_offset    = 4,
641                 .shift          = 16,
642                 .port_shift     = 0,
643                 .bits           = 8,
644         },
645         [ALE_PORT_BCAST_LIMIT]  = {
646                 .name           = "bcast_limit",
647                 .offset         = ALE_PORTCTL,
648                 .port_offset    = 4,
649                 .shift          = 24,
650                 .port_shift     = 0,
651                 .bits           = 8,
652         },
653         [ALE_PORT_UNKNOWN_VLAN_MEMBER] = {
654                 .name           = "unknown_vlan_member",
655                 .offset         = ALE_UNKNOWNVLAN,
656                 .port_offset    = 0,
657                 .shift          = 0,
658                 .port_shift     = 0,
659                 .bits           = 6,
660         },
661         [ALE_PORT_UNKNOWN_MCAST_FLOOD] = {
662                 .name           = "unknown_mcast_flood",
663                 .offset         = ALE_UNKNOWNVLAN,
664                 .port_offset    = 0,
665                 .shift          = 8,
666                 .port_shift     = 0,
667                 .bits           = 6,
668         },
669         [ALE_PORT_UNKNOWN_REG_MCAST_FLOOD] = {
670                 .name           = "unknown_reg_flood",
671                 .offset         = ALE_UNKNOWNVLAN,
672                 .port_offset    = 0,
673                 .shift          = 16,
674                 .port_shift     = 0,
675                 .bits           = 6,
676         },
677         [ALE_PORT_UNTAGGED_EGRESS] = {
678                 .name           = "untagged_egress",
679                 .offset         = ALE_UNKNOWNVLAN,
680                 .port_offset    = 0,
681                 .shift          = 24,
682                 .port_shift     = 0,
683                 .bits           = 6,
684         },
685 };
686
687 int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control,
688                          int value)
689 {
690         const struct ale_control_info *info;
691         int offset, shift;
692         u32 tmp, mask;
693
694         if (control < 0 || control >= ARRAY_SIZE(ale_controls))
695                 return -EINVAL;
696
697         info = &ale_controls[control];
698         if (info->port_offset == 0 && info->port_shift == 0)
699                 port = 0; /* global, port is a dont care */
700
701         if (port < 0 || port > ale->params.ale_ports)
702                 return -EINVAL;
703
704         mask = BITMASK(info->bits);
705         if (value & ~mask)
706                 return -EINVAL;
707
708         offset = info->offset + (port * info->port_offset);
709         shift  = info->shift  + (port * info->port_shift);
710
711         tmp = __raw_readl(ale->params.ale_regs + offset);
712         tmp = (tmp & ~(mask << shift)) | (value << shift);
713         __raw_writel(tmp, ale->params.ale_regs + offset);
714
715         return 0;
716 }
717 EXPORT_SYMBOL_GPL(cpsw_ale_control_set);
718
719 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
720 {
721         const struct ale_control_info *info;
722         int offset, shift;
723         u32 tmp;
724
725         if (control < 0 || control >= ARRAY_SIZE(ale_controls))
726                 return -EINVAL;
727
728         info = &ale_controls[control];
729         if (info->port_offset == 0 && info->port_shift == 0)
730                 port = 0; /* global, port is a dont care */
731
732         if (port < 0 || port > ale->params.ale_ports)
733                 return -EINVAL;
734
735         offset = info->offset + (port * info->port_offset);
736         shift  = info->shift  + (port * info->port_shift);
737
738         tmp = __raw_readl(ale->params.ale_regs + offset) >> shift;
739         return tmp & BITMASK(info->bits);
740 }
741 EXPORT_SYMBOL_GPL(cpsw_ale_control_get);
742
743 static void cpsw_ale_timer(unsigned long arg)
744 {
745         struct cpsw_ale *ale = (struct cpsw_ale *)arg;
746
747         cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1);
748
749         if (ale->ageout) {
750                 ale->timer.expires = jiffies + ale->ageout;
751                 add_timer(&ale->timer);
752         }
753 }
754
755 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout)
756 {
757         del_timer_sync(&ale->timer);
758         ale->ageout = ageout * HZ;
759         if (ale->ageout) {
760                 ale->timer.expires = jiffies + ale->ageout;
761                 add_timer(&ale->timer);
762         }
763         return 0;
764 }
765 EXPORT_SYMBOL_GPL(cpsw_ale_set_ageout);
766
767 void cpsw_ale_start(struct cpsw_ale *ale)
768 {
769         u32 rev;
770
771         rev = __raw_readl(ale->params.ale_regs + ALE_IDVER);
772         dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n",
773                 ALE_VERSION_MAJOR(rev), ALE_VERSION_MINOR(rev));
774         cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1);
775         cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
776
777         init_timer(&ale->timer);
778         ale->timer.data     = (unsigned long)ale;
779         ale->timer.function = cpsw_ale_timer;
780         if (ale->ageout) {
781                 ale->timer.expires = jiffies + ale->ageout;
782                 add_timer(&ale->timer);
783         }
784 }
785 EXPORT_SYMBOL_GPL(cpsw_ale_start);
786
787 void cpsw_ale_stop(struct cpsw_ale *ale)
788 {
789         del_timer_sync(&ale->timer);
790 }
791 EXPORT_SYMBOL_GPL(cpsw_ale_stop);
792
793 struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
794 {
795         struct cpsw_ale *ale;
796
797         ale = kzalloc(sizeof(*ale), GFP_KERNEL);
798         if (!ale)
799                 return NULL;
800
801         ale->params = *params;
802         ale->ageout = ale->params.ale_ageout * HZ;
803
804         return ale;
805 }
806 EXPORT_SYMBOL_GPL(cpsw_ale_create);
807
808 int cpsw_ale_destroy(struct cpsw_ale *ale)
809 {
810         if (!ale)
811                 return -EINVAL;
812         cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
813         kfree(ale);
814         return 0;
815 }
816 EXPORT_SYMBOL_GPL(cpsw_ale_destroy);
817
818 void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data)
819 {
820         int i;
821
822         for (i = 0; i < ale->params.ale_entries; i++) {
823                 cpsw_ale_read(ale, i, data);
824                 data += ALE_ENTRY_WORDS;
825         }
826 }
827 EXPORT_SYMBOL_GPL(cpsw_ale_dump);
828
829 MODULE_LICENSE("GPL v2");
830 MODULE_DESCRIPTION("TI CPSW ALE driver");
831 MODULE_AUTHOR("Texas Instruments");