xref: /linux/drivers/net/ethernet/ti/cpsw_ale.c (revision 4413e16d9d21673bb5048a2e542f1aaa00015c2e)
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 }
642