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