]> Pileus Git - ~andy/linux/blob - drivers/net/ethernet/ti/cpsw_ale.c
Merge branch 'slab/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penber...
[~andy/linux] / 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/platform_device.h>
17 #include <linux/seq_file.h>
18 #include <linux/slab.h>
19 #include <linux/err.h>
20 #include <linux/io.h>
21 #include <linux/stat.h>
22 #include <linux/sysfs.h>
23
24 #include "cpsw_ale.h"
25
26 #define BITMASK(bits)           (BIT(bits) - 1)
27 #define ALE_ENTRY_BITS          68
28 #define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32)
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)
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                 cpsw_ale_get_addr(ale_entry, entry_addr);
163                 if (memcmp(entry_addr, addr, 6) == 0)
164                         return idx;
165         }
166         return -ENOENT;
167 }
168
169 static int cpsw_ale_match_free(struct cpsw_ale *ale)
170 {
171         u32 ale_entry[ALE_ENTRY_WORDS];
172         int type, idx;
173
174         for (idx = 0; idx < ale->params.ale_entries; idx++) {
175                 cpsw_ale_read(ale, idx, ale_entry);
176                 type = cpsw_ale_get_entry_type(ale_entry);
177                 if (type == ALE_TYPE_FREE)
178                         return idx;
179         }
180         return -ENOENT;
181 }
182
183 static int cpsw_ale_find_ageable(struct cpsw_ale *ale)
184 {
185         u32 ale_entry[ALE_ENTRY_WORDS];
186         int type, idx;
187
188         for (idx = 0; idx < ale->params.ale_entries; idx++) {
189                 cpsw_ale_read(ale, idx, ale_entry);
190                 type = cpsw_ale_get_entry_type(ale_entry);
191                 if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
192                         continue;
193                 if (cpsw_ale_get_mcast(ale_entry))
194                         continue;
195                 type = cpsw_ale_get_ucast_type(ale_entry);
196                 if (type != ALE_UCAST_PERSISTANT &&
197                     type != ALE_UCAST_OUI)
198                         return idx;
199         }
200         return -ENOENT;
201 }
202
203 static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
204                                  int port_mask)
205 {
206         int mask;
207
208         mask = cpsw_ale_get_port_mask(ale_entry);
209         if ((mask & port_mask) == 0)
210                 return; /* ports dont intersect, not interested */
211         mask &= ~port_mask;
212
213         /* free if only remaining port is host port */
214         if (mask == BIT(ale->params.ale_ports))
215                 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
216         else
217                 cpsw_ale_set_port_mask(ale_entry, mask);
218 }
219
220 static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry,
221                                  int port_mask)
222 {
223         int port;
224
225         port = cpsw_ale_get_port_num(ale_entry);
226         if ((BIT(port) & port_mask) == 0)
227                 return; /* ports dont intersect, not interested */
228         cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
229 }
230
231 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
232 {
233         u32 ale_entry[ALE_ENTRY_WORDS];
234         int ret, idx;
235
236         for (idx = 0; idx < ale->params.ale_entries; idx++) {
237                 cpsw_ale_read(ale, idx, ale_entry);
238                 ret = cpsw_ale_get_entry_type(ale_entry);
239                 if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR)
240                         continue;
241
242                 if (cpsw_ale_get_mcast(ale_entry))
243                         cpsw_ale_flush_mcast(ale, ale_entry, port_mask);
244                 else
245                         cpsw_ale_flush_ucast(ale, ale_entry, port_mask);
246
247                 cpsw_ale_write(ale, idx, ale_entry);
248         }
249         return 0;
250 }
251
252 int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
253 {
254         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
255         int idx;
256
257         cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
258         cpsw_ale_set_addr(ale_entry, addr);
259         cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
260         cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
261         cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
262         cpsw_ale_set_port_num(ale_entry, port);
263
264         idx = cpsw_ale_match_addr(ale, addr);
265         if (idx < 0)
266                 idx = cpsw_ale_match_free(ale);
267         if (idx < 0)
268                 idx = cpsw_ale_find_ageable(ale);
269         if (idx < 0)
270                 return -ENOMEM;
271
272         cpsw_ale_write(ale, idx, ale_entry);
273         return 0;
274 }
275
276 int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
277 {
278         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
279         int idx;
280
281         idx = cpsw_ale_match_addr(ale, addr);
282         if (idx < 0)
283                 return -ENOENT;
284
285         cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
286         cpsw_ale_write(ale, idx, ale_entry);
287         return 0;
288 }
289
290 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
291                         int super, int mcast_state)
292 {
293         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
294         int idx, mask;
295
296         idx = cpsw_ale_match_addr(ale, addr);
297         if (idx >= 0)
298                 cpsw_ale_read(ale, idx, ale_entry);
299
300         cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
301         cpsw_ale_set_addr(ale_entry, addr);
302         cpsw_ale_set_super(ale_entry, super);
303         cpsw_ale_set_mcast_state(ale_entry, mcast_state);
304
305         mask = cpsw_ale_get_port_mask(ale_entry);
306         port_mask |= mask;
307         cpsw_ale_set_port_mask(ale_entry, port_mask);
308
309         if (idx < 0)
310                 idx = cpsw_ale_match_free(ale);
311         if (idx < 0)
312                 idx = cpsw_ale_find_ageable(ale);
313         if (idx < 0)
314                 return -ENOMEM;
315
316         cpsw_ale_write(ale, idx, ale_entry);
317         return 0;
318 }
319
320 int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
321 {
322         u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
323         int idx;
324
325         idx = cpsw_ale_match_addr(ale, addr);
326         if (idx < 0)
327                 return -EINVAL;
328
329         cpsw_ale_read(ale, idx, ale_entry);
330
331         if (port_mask)
332                 cpsw_ale_set_port_mask(ale_entry, port_mask);
333         else
334                 cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
335
336         cpsw_ale_write(ale, idx, ale_entry);
337         return 0;
338 }
339
340 struct ale_control_info {
341         const char      *name;
342         int             offset, port_offset;
343         int             shift, port_shift;
344         int             bits;
345 };
346
347 static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = {
348         [ALE_ENABLE]            = {
349                 .name           = "enable",
350                 .offset         = ALE_CONTROL,
351                 .port_offset    = 0,
352                 .shift          = 31,
353                 .port_shift     = 0,
354                 .bits           = 1,
355         },
356         [ALE_CLEAR]             = {
357                 .name           = "clear",
358                 .offset         = ALE_CONTROL,
359                 .port_offset    = 0,
360                 .shift          = 30,
361                 .port_shift     = 0,
362                 .bits           = 1,
363         },
364         [ALE_AGEOUT]            = {
365                 .name           = "ageout",
366                 .offset         = ALE_CONTROL,
367                 .port_offset    = 0,
368                 .shift          = 29,
369                 .port_shift     = 0,
370                 .bits           = 1,
371         },
372         [ALE_VLAN_NOLEARN]      = {
373                 .name           = "vlan_nolearn",
374                 .offset         = ALE_CONTROL,
375                 .port_offset    = 0,
376                 .shift          = 7,
377                 .port_shift     = 0,
378                 .bits           = 1,
379         },
380         [ALE_NO_PORT_VLAN]      = {
381                 .name           = "no_port_vlan",
382                 .offset         = ALE_CONTROL,
383                 .port_offset    = 0,
384                 .shift          = 6,
385                 .port_shift     = 0,
386                 .bits           = 1,
387         },
388         [ALE_OUI_DENY]          = {
389                 .name           = "oui_deny",
390                 .offset         = ALE_CONTROL,
391                 .port_offset    = 0,
392                 .shift          = 5,
393                 .port_shift     = 0,
394                 .bits           = 1,
395         },
396         [ALE_BYPASS]            = {
397                 .name           = "bypass",
398                 .offset         = ALE_CONTROL,
399                 .port_offset    = 0,
400                 .shift          = 4,
401                 .port_shift     = 0,
402                 .bits           = 1,
403         },
404         [ALE_RATE_LIMIT_TX]     = {
405                 .name           = "rate_limit_tx",
406                 .offset         = ALE_CONTROL,
407                 .port_offset    = 0,
408                 .shift          = 3,
409                 .port_shift     = 0,
410                 .bits           = 1,
411         },
412         [ALE_VLAN_AWARE]        = {
413                 .name           = "vlan_aware",
414                 .offset         = ALE_CONTROL,
415                 .port_offset    = 0,
416                 .shift          = 2,
417                 .port_shift     = 0,
418                 .bits           = 1,
419         },
420         [ALE_AUTH_ENABLE]       = {
421                 .name           = "auth_enable",
422                 .offset         = ALE_CONTROL,
423                 .port_offset    = 0,
424                 .shift          = 1,
425                 .port_shift     = 0,
426                 .bits           = 1,
427         },
428         [ALE_RATE_LIMIT]        = {
429                 .name           = "rate_limit",
430                 .offset         = ALE_CONTROL,
431                 .port_offset    = 0,
432                 .shift          = 0,
433                 .port_shift     = 0,
434                 .bits           = 1,
435         },
436         [ALE_PORT_STATE]        = {
437                 .name           = "port_state",
438                 .offset         = ALE_PORTCTL,
439                 .port_offset    = 4,
440                 .shift          = 0,
441                 .port_shift     = 0,
442                 .bits           = 2,
443         },
444         [ALE_PORT_DROP_UNTAGGED] = {
445                 .name           = "drop_untagged",
446                 .offset         = ALE_PORTCTL,
447                 .port_offset    = 4,
448                 .shift          = 2,
449                 .port_shift     = 0,
450                 .bits           = 1,
451         },
452         [ALE_PORT_DROP_UNKNOWN_VLAN] = {
453                 .name           = "drop_unknown",
454                 .offset         = ALE_PORTCTL,
455                 .port_offset    = 4,
456                 .shift          = 3,
457                 .port_shift     = 0,
458                 .bits           = 1,
459         },
460         [ALE_PORT_NOLEARN]      = {
461                 .name           = "nolearn",
462                 .offset         = ALE_PORTCTL,
463                 .port_offset    = 4,
464                 .shift          = 4,
465                 .port_shift     = 0,
466                 .bits           = 1,
467         },
468         [ALE_PORT_MCAST_LIMIT]  = {
469                 .name           = "mcast_limit",
470                 .offset         = ALE_PORTCTL,
471                 .port_offset    = 4,
472                 .shift          = 16,
473                 .port_shift     = 0,
474                 .bits           = 8,
475         },
476         [ALE_PORT_BCAST_LIMIT]  = {
477                 .name           = "bcast_limit",
478                 .offset         = ALE_PORTCTL,
479                 .port_offset    = 4,
480                 .shift          = 24,
481                 .port_shift     = 0,
482                 .bits           = 8,
483         },
484         [ALE_PORT_UNKNOWN_VLAN_MEMBER] = {
485                 .name           = "unknown_vlan_member",
486                 .offset         = ALE_UNKNOWNVLAN,
487                 .port_offset    = 0,
488                 .shift          = 0,
489                 .port_shift     = 0,
490                 .bits           = 6,
491         },
492         [ALE_PORT_UNKNOWN_MCAST_FLOOD] = {
493                 .name           = "unknown_mcast_flood",
494                 .offset         = ALE_UNKNOWNVLAN,
495                 .port_offset    = 0,
496                 .shift          = 8,
497                 .port_shift     = 0,
498                 .bits           = 6,
499         },
500         [ALE_PORT_UNKNOWN_REG_MCAST_FLOOD] = {
501                 .name           = "unknown_reg_flood",
502                 .offset         = ALE_UNKNOWNVLAN,
503                 .port_offset    = 0,
504                 .shift          = 16,
505                 .port_shift     = 0,
506                 .bits           = 6,
507         },
508         [ALE_PORT_UNTAGGED_EGRESS] = {
509                 .name           = "untagged_egress",
510                 .offset         = ALE_UNKNOWNVLAN,
511                 .port_offset    = 0,
512                 .shift          = 24,
513                 .port_shift     = 0,
514                 .bits           = 6,
515         },
516 };
517
518 int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control,
519                          int value)
520 {
521         const struct ale_control_info *info;
522         int offset, shift;
523         u32 tmp, mask;
524
525         if (control < 0 || control >= ARRAY_SIZE(ale_controls))
526                 return -EINVAL;
527
528         info = &ale_controls[control];
529         if (info->port_offset == 0 && info->port_shift == 0)
530                 port = 0; /* global, port is a dont care */
531
532         if (port < 0 || port > ale->params.ale_ports)
533                 return -EINVAL;
534
535         mask = BITMASK(info->bits);
536         if (value & ~mask)
537                 return -EINVAL;
538
539         offset = info->offset + (port * info->port_offset);
540         shift  = info->shift  + (port * info->port_shift);
541
542         tmp = __raw_readl(ale->params.ale_regs + offset);
543         tmp = (tmp & ~(mask << shift)) | (value << shift);
544         __raw_writel(tmp, ale->params.ale_regs + offset);
545
546         return 0;
547 }
548
549 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
550 {
551         const struct ale_control_info *info;
552         int offset, shift;
553         u32 tmp;
554
555         if (control < 0 || control >= ARRAY_SIZE(ale_controls))
556                 return -EINVAL;
557
558         info = &ale_controls[control];
559         if (info->port_offset == 0 && info->port_shift == 0)
560                 port = 0; /* global, port is a dont care */
561
562         if (port < 0 || port > ale->params.ale_ports)
563                 return -EINVAL;
564
565         offset = info->offset + (port * info->port_offset);
566         shift  = info->shift  + (port * info->port_shift);
567
568         tmp = __raw_readl(ale->params.ale_regs + offset) >> shift;
569         return tmp & BITMASK(info->bits);
570 }
571
572 static void cpsw_ale_timer(unsigned long arg)
573 {
574         struct cpsw_ale *ale = (struct cpsw_ale *)arg;
575
576         cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1);
577
578         if (ale->ageout) {
579                 ale->timer.expires = jiffies + ale->ageout;
580                 add_timer(&ale->timer);
581         }
582 }
583
584 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout)
585 {
586         del_timer_sync(&ale->timer);
587         ale->ageout = ageout * HZ;
588         if (ale->ageout) {
589                 ale->timer.expires = jiffies + ale->ageout;
590                 add_timer(&ale->timer);
591         }
592         return 0;
593 }
594
595 void cpsw_ale_start(struct cpsw_ale *ale)
596 {
597         u32 rev;
598
599         rev = __raw_readl(ale->params.ale_regs + ALE_IDVER);
600         dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n",
601                 ALE_VERSION_MAJOR(rev), ALE_VERSION_MINOR(rev));
602         cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1);
603         cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
604
605         init_timer(&ale->timer);
606         ale->timer.data     = (unsigned long)ale;
607         ale->timer.function = cpsw_ale_timer;
608         if (ale->ageout) {
609                 ale->timer.expires = jiffies + ale->ageout;
610                 add_timer(&ale->timer);
611         }
612 }
613
614 void cpsw_ale_stop(struct cpsw_ale *ale)
615 {
616         del_timer_sync(&ale->timer);
617 }
618
619 struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
620 {
621         struct cpsw_ale *ale;
622
623         ale = kzalloc(sizeof(*ale), GFP_KERNEL);
624         if (!ale)
625                 return NULL;
626
627         ale->params = *params;
628         ale->ageout = ale->params.ale_ageout * HZ;
629
630         return ale;
631 }
632
633 int cpsw_ale_destroy(struct cpsw_ale *ale)
634 {
635         if (!ale)
636                 return -EINVAL;
637         cpsw_ale_stop(ale);
638         cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
639         kfree(ale);
640         return 0;
641 }