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