Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cpsw_ale.c
Go to the documentation of this file.
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)
90 DEFINE_ALE_FIELD(port_mask, 66, 3)
91 DEFINE_ALE_FIELD(super, 65, 1)
92 DEFINE_ALE_FIELD(ucast_type, 62, 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 +
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 
341  const char *name;
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  },
445  .name = "drop_untagged",
446  .offset = ALE_PORTCTL,
447  .port_offset = 4,
448  .shift = 2,
449  .port_shift = 0,
450  .bits = 1,
451  },
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  },
469  .name = "mcast_limit",
470  .offset = ALE_PORTCTL,
471  .port_offset = 4,
472  .shift = 16,
473  .port_shift = 0,
474  .bits = 8,
475  },
477  .name = "bcast_limit",
478  .offset = ALE_PORTCTL,
479  .port_offset = 4,
480  .shift = 24,
481  .port_shift = 0,
482  .bits = 8,
483  },
485  .name = "unknown_vlan_member",
486  .offset = ALE_UNKNOWNVLAN,
487  .port_offset = 0,
488  .shift = 0,
489  .port_shift = 0,
490  .bits = 6,
491  },
493  .name = "unknown_mcast_flood",
494  .offset = ALE_UNKNOWNVLAN,
495  .port_offset = 0,
496  .shift = 8,
497  .port_shift = 0,
498  .bits = 6,
499  },
501  .name = "unknown_reg_flood",
502  .offset = ALE_UNKNOWNVLAN,
503  .port_offset = 0,
504  .shift = 16,
505  .port_shift = 0,
506  .bits = 6,
507  },
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",
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 
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 }