xref: /freebsd/sys/arm/ti/cpsw/if_cpsw.c (revision c243e4902be8df1e643c76b5f18b68bb77cc5268)
1 /*-
2  * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * TI 3 Port Switch Ethernet (CPSW) Driver
29  * Found in TI8148, AM335x SoCs
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/endian.h>
38 #include <sys/mbuf.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/socket.h>
44 #include <sys/sysctl.h>
45 
46 #include <net/ethernet.h>
47 #include <net/bpf.h>
48 #include <net/if.h>
49 #include <net/if_arp.h>
50 #include <net/if_dl.h>
51 #include <net/if_media.h>
52 #include <net/if_types.h>
53 #include <net/if_vlan_var.h>
54 
55 #include <netinet/in_systm.h>
56 #include <netinet/in.h>
57 #include <netinet/ip.h>
58 
59 #include <sys/sockio.h>
60 #include <sys/bus.h>
61 #include <machine/bus.h>
62 #include <sys/rman.h>
63 #include <machine/resource.h>
64 
65 #include <dev/mii/mii.h>
66 #include <dev/mii/miivar.h>
67 
68 #include <dev/fdt/fdt_common.h>
69 #include <dev/ofw/ofw_bus.h>
70 #include <dev/ofw/ofw_bus_subr.h>
71 
72 #include <arm/ti/cpsw/if_cpswreg.h>
73 #include <arm/ti/cpsw/if_cpswvar.h>
74 
75 #include <arm/ti/ti_scm.h>
76 
77 #include "miibus_if.h"
78 
79 static int cpsw_probe(device_t dev);
80 static int cpsw_attach(device_t dev);
81 static int cpsw_detach(device_t dev);
82 static int cpsw_shutdown(device_t dev);
83 static int cpsw_suspend(device_t dev);
84 static int cpsw_resume(device_t dev);
85 
86 static int cpsw_miibus_readreg(device_t dev, int phy, int reg);
87 static int cpsw_miibus_writereg(device_t dev, int phy, int reg, int value);
88 
89 static int cpsw_ifmedia_upd(struct ifnet *ifp);
90 static void cpsw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
91 
92 static void cpsw_init(void *arg);
93 static void cpsw_init_locked(void *arg);
94 static void cpsw_start(struct ifnet *ifp);
95 static void cpsw_start_locked(struct ifnet *ifp);
96 static void cpsw_stop(struct cpsw_softc *sc);
97 static int cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
98 static int cpsw_allocate_dma(struct cpsw_softc *sc);
99 static int cpsw_free_dma(struct cpsw_softc *sc);
100 static int cpsw_new_rxbuf(struct cpsw_softc *sc, uint32_t i, uint32_t next);
101 static void cpsw_watchdog(struct cpsw_softc *sc);
102 
103 static void cpsw_intr_rx_thresh(void *arg);
104 static void cpsw_intr_rx(void *arg);
105 static void cpsw_intr_rx_locked(void *arg);
106 static void cpsw_intr_tx(void *arg);
107 static void cpsw_intr_tx_locked(void *arg);
108 static void cpsw_intr_misc(void *arg);
109 
110 static void cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry);
111 static void cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry);
112 static int cpsw_ale_uc_entry_set(struct cpsw_softc *sc, uint8_t port, uint8_t *mac);
113 static int cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac);
114 #ifdef CPSW_DEBUG
115 static void cpsw_ale_dump_table(struct cpsw_softc *sc);
116 #endif
117 
118 static device_method_t cpsw_methods[] = {
119 	/* Device interface */
120 	DEVMETHOD(device_probe,		cpsw_probe),
121 	DEVMETHOD(device_attach,	cpsw_attach),
122 	DEVMETHOD(device_detach,	cpsw_detach),
123 	DEVMETHOD(device_shutdown,	cpsw_shutdown),
124 	DEVMETHOD(device_suspend,	cpsw_suspend),
125 	DEVMETHOD(device_resume,	cpsw_resume),
126 	/* MII interface */
127 	DEVMETHOD(miibus_readreg,	cpsw_miibus_readreg),
128 	DEVMETHOD(miibus_writereg,	cpsw_miibus_writereg),
129 	{ 0, 0 }
130 };
131 
132 static driver_t cpsw_driver = {
133 	"cpsw",
134 	cpsw_methods,
135 	sizeof(struct cpsw_softc),
136 };
137 
138 static devclass_t cpsw_devclass;
139 
140 
141 DRIVER_MODULE(cpsw, simplebus, cpsw_driver, cpsw_devclass, 0, 0);
142 DRIVER_MODULE(miibus, cpsw, miibus_driver, miibus_devclass, 0, 0);
143 MODULE_DEPEND(cpsw, ether, 1, 1, 1);
144 MODULE_DEPEND(cpsw, miibus, 1, 1, 1);
145 
146 static struct resource_spec res_spec[] = {
147 	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
148 	{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
149 	{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
150 	{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
151 	{ SYS_RES_IRQ, 3, RF_ACTIVE | RF_SHAREABLE },
152 	{ -1, 0 }
153 };
154 
155 static struct {
156 	driver_intr_t *handler;
157 	char * description;
158 } cpsw_intrs[CPSW_INTR_COUNT + 1] = {
159 	{ cpsw_intr_rx_thresh,"CPSW RX threshold interrupt" },
160 	{ cpsw_intr_rx,	"CPSW RX interrupt" },
161 	{ cpsw_intr_tx,	"CPSW TX interrupt" },
162 	{ cpsw_intr_misc,"CPSW misc interrupt" },
163 };
164 
165 /* Locking macros */
166 #define CPSW_TX_LOCK(sc) do {					\
167 		mtx_assert(&(sc)->rx_lock, MA_NOTOWNED);		\
168 		mtx_lock(&(sc)->tx_lock);				\
169 } while (0)
170 
171 #define CPSW_TX_UNLOCK(sc)	mtx_unlock(&(sc)->tx_lock)
172 #define CPSW_TX_LOCK_ASSERT(sc)	mtx_assert(&(sc)->tx_lock, MA_OWNED)
173 
174 #define CPSW_RX_LOCK(sc) do {					\
175 		mtx_assert(&(sc)->tx_lock, MA_NOTOWNED);		\
176 		mtx_lock(&(sc)->rx_lock);				\
177 } while (0)
178 
179 #define CPSW_RX_UNLOCK(sc)		mtx_unlock(&(sc)->rx_lock)
180 #define CPSW_RX_LOCK_ASSERT(sc)	mtx_assert(&(sc)->rx_lock, MA_OWNED)
181 
182 #define CPSW_GLOBAL_LOCK(sc) do {					\
183 		if ((mtx_owned(&(sc)->tx_lock) ? 1 : 0) !=	\
184 		    (mtx_owned(&(sc)->rx_lock) ? 1 : 0)) {		\
185 			panic("cpsw deadlock possibility detection!");	\
186 		}							\
187 		mtx_lock(&(sc)->tx_lock);				\
188 		mtx_lock(&(sc)->rx_lock);				\
189 } while (0)
190 
191 #define CPSW_GLOBAL_UNLOCK(sc) do {					\
192 		CPSW_RX_UNLOCK(sc);				\
193 		CPSW_TX_UNLOCK(sc);				\
194 } while (0)
195 
196 #define CPSW_GLOBAL_LOCK_ASSERT(sc) do {				\
197 		CPSW_TX_LOCK_ASSERT(sc);				\
198 		CPSW_RX_LOCK_ASSERT(sc);				\
199 } while (0)
200 
201 
202 static int
203 cpsw_probe(device_t dev)
204 {
205 
206 	if (!ofw_bus_is_compatible(dev, "ti,cpsw"))
207 		return (ENXIO);
208 
209 	device_set_desc(dev, "3-port Switch Ethernet Subsystem");
210 	return (BUS_PROBE_DEFAULT);
211 }
212 
213 static int
214 cpsw_attach(device_t dev)
215 {
216 	struct cpsw_softc *sc;
217 	struct mii_softc *miisc;
218 	struct ifnet *ifp;
219 	int i, error, phy;
220 	uint32_t reg;
221 
222 	sc = device_get_softc(dev);
223 	sc->dev = dev;
224 	sc->node = ofw_bus_get_node(dev);
225 
226 	/* Get phy address from fdt */
227 	if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) != 0) {
228 		device_printf(dev, "failed to get PHY address from FDT\n");
229 		return (ENXIO);
230 	}
231 	/* Initialize mutexes */
232 	mtx_init(&sc->tx_lock, device_get_nameunit(dev),
233 		"cpsw TX lock", MTX_DEF);
234 	mtx_init(&sc->rx_lock, device_get_nameunit(dev),
235 		"cpsw RX lock", MTX_DEF);
236 
237 	/* Allocate IO and IRQ resources */
238 	error = bus_alloc_resources(dev, res_spec, sc->res);
239 	if (error) {
240 		device_printf(dev, "could not allocate resources\n");
241 		cpsw_detach(dev);
242 		return (ENXIO);
243 	}
244 
245 	reg = cpsw_read_4(CPSW_SS_IDVER);
246 	device_printf(dev, "Version %d.%d (%d)\n", (reg >> 8 & 0x7),
247 		reg & 0xFF, (reg >> 11) & 0x1F);
248 
249 	/* Allocate DMA, buffers, buffer descriptors */
250 	error = cpsw_allocate_dma(sc);
251 	if (error) {
252 		cpsw_detach(dev);
253 		return (ENXIO);
254 	}
255 
256 	//cpsw_add_sysctls(sc); TODO
257 
258 	/* Allocate network interface */
259 	ifp = sc->ifp = if_alloc(IFT_ETHER);
260 	if (ifp == NULL) {
261 		device_printf(dev, "if_alloc() failed\n");
262 		cpsw_detach(dev);
263 		return (ENOMEM);
264 	}
265 
266 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
267 	ifp->if_softc = sc;
268 	ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
269 	ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; //FIXME VLAN?
270 	ifp->if_capenable = ifp->if_capabilities;
271 
272 	ifp->if_init = cpsw_init;
273 	ifp->if_start = cpsw_start;
274 	ifp->if_ioctl = cpsw_ioctl;
275 
276 	ifp->if_snd.ifq_drv_maxlen = CPSW_MAX_TX_BUFFERS - 1;
277 	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
278 	IFQ_SET_READY(&ifp->if_snd);
279 
280 	/* Get high part of MAC address from control module (mac_id0_hi) */
281 	ti_scm_reg_read_4(0x634, &reg);
282 	sc->mac_addr[0] = reg & 0xFF;
283 	sc->mac_addr[1] = (reg >>  8) & 0xFF;
284 	sc->mac_addr[2] = (reg >> 16) & 0xFF;
285 	sc->mac_addr[3] = (reg >> 24) & 0xFF;
286 
287 	/* Get low part of MAC address from control module (mac_id0_lo) */
288 	ti_scm_reg_read_4(0x630, &reg);
289 	sc->mac_addr[4] = reg & 0xFF;
290 	sc->mac_addr[5] = (reg >>  8) & 0xFF;
291 
292 	ether_ifattach(ifp, sc->mac_addr);
293 	callout_init(&sc->wd_callout, 0);
294 
295 	/* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
296 	/* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
297 	cpsw_write_4(MDIOCONTROL, (1<<30) | (1<<18) | 0xFF);
298 
299 	/* Attach PHY(s) */
300 	error = mii_attach(dev, &sc->miibus, ifp, cpsw_ifmedia_upd,
301 	    cpsw_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
302 	if (error) {
303 		device_printf(dev, "attaching PHYs failed\n");
304 		cpsw_detach(dev);
305 		return (error);
306 	}
307 	sc->mii = device_get_softc(sc->miibus);
308 
309 	/* Tell the MAC where to find the PHY so autoneg works */
310 	miisc = LIST_FIRST(&sc->mii->mii_phys);
311 
312 	/* Select PHY and enable interrupts */
313 	cpsw_write_4(MDIOUSERPHYSEL0, (1 << 6) | (miisc->mii_phy & 0x1F));
314 
315 	/* Attach interrupt handlers */
316 	for (i = 1; i <= CPSW_INTR_COUNT; ++i) {
317 		error = bus_setup_intr(dev, sc->res[i],
318 		    INTR_TYPE_NET | INTR_MPSAFE,
319 		    NULL, *cpsw_intrs[i - 1].handler,
320 		    sc, &sc->ih_cookie[i - 1]);
321 		if (error) {
322 			device_printf(dev, "could not setup %s\n",
323 			    cpsw_intrs[i].description);
324 			cpsw_detach(dev);
325 			return (error);
326 		}
327 	}
328 
329 	return (0);
330 }
331 
332 static int
333 cpsw_detach(device_t dev)
334 {
335 	struct cpsw_softc *sc;
336 	int error,i;
337 
338 	sc = device_get_softc(dev);
339 
340 	/* Stop controller and free TX queue */
341 	if (sc->ifp)
342 		cpsw_shutdown(dev);
343 
344 	/* Wait for stopping ticks */
345         callout_drain(&sc->wd_callout);
346 
347 	/* Stop and release all interrupts */
348 	for (i = 0; i < CPSW_INTR_COUNT; ++i) {
349 		if (!sc->ih_cookie[i])
350 			continue;
351 
352 		error = bus_teardown_intr(dev, sc->res[1 + i], sc->ih_cookie[i]);
353 		if (error)
354 			device_printf(dev, "could not release %s\n",
355 			    cpsw_intrs[i + 1].description);
356 	}
357 
358 	/* Detach network interface */
359 	if (sc->ifp) {
360 		ether_ifdetach(sc->ifp);
361 		if_free(sc->ifp);
362 	}
363 
364 	/* Free DMA resources */
365 	cpsw_free_dma(sc);
366 
367 	/* Free IO memory handler */
368 	bus_release_resources(dev, res_spec, sc->res);
369 
370 	/* Destroy mutexes */
371 	mtx_destroy(&sc->rx_lock);
372 	mtx_destroy(&sc->tx_lock);
373 
374 	return (0);
375 }
376 
377 static int
378 cpsw_suspend(device_t dev)
379 {
380 
381 	device_printf(dev, "%s\n", __FUNCTION__);
382 	return (0);
383 }
384 
385 static int
386 cpsw_resume(device_t dev)
387 {
388 
389 	device_printf(dev, "%s\n", __FUNCTION__);
390 	return (0);
391 }
392 
393 static int
394 cpsw_shutdown(device_t dev)
395 {
396 	struct cpsw_softc *sc = device_get_softc(dev);
397 
398 	CPSW_GLOBAL_LOCK(sc);
399 
400 	cpsw_stop(sc);
401 
402 	CPSW_GLOBAL_UNLOCK(sc);
403 
404 	return (0);
405 }
406 
407 static int
408 cpsw_miibus_readreg(device_t dev, int phy, int reg)
409 {
410 	struct cpsw_softc *sc;
411 	uint32_t r;
412 	uint32_t retries = CPSW_MIIBUS_RETRIES;
413 
414 	sc = device_get_softc(dev);
415 
416 	/* Wait until interface is ready by watching GO bit */
417 	while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
418 		DELAY(CPSW_MIIBUS_DELAY);
419 	if (!retries)
420 		device_printf(dev, "Timeout while waiting for MDIO.\n");
421 
422 	/* Set GO, phy and reg */
423 	cpsw_write_4(MDIOUSERACCESS0, (1 << 31) |
424 		((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
425 
426 	while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
427 		DELAY(CPSW_MIIBUS_DELAY);
428 	if (!retries)
429 		device_printf(dev, "Timeout while waiting for MDIO.\n");
430 
431 	r = cpsw_read_4(MDIOUSERACCESS0);
432 	/* Check for ACK */
433 	if(r & (1<<29)) {
434 		return (r & 0xFFFF);
435 	}
436 	device_printf(dev, "Failed to read from PHY.\n");
437 	return 0;
438 }
439 
440 static int
441 cpsw_miibus_writereg(device_t dev, int phy, int reg, int value)
442 {
443 	struct cpsw_softc *sc;
444 	uint32_t retries = CPSW_MIIBUS_RETRIES;
445 
446 	sc = device_get_softc(dev);
447 
448 	/* Wait until interface is ready by watching GO bit */
449 	while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
450 		DELAY(CPSW_MIIBUS_DELAY);
451 	if (!retries)
452 		device_printf(dev, "Timeout while waiting for MDIO.\n");
453 
454 	/* Set GO, WRITE, phy, reg and value */
455 	cpsw_write_4(MDIOUSERACCESS0, (value & 0xFFFF) | (3 << 30) |
456 		((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
457 
458 	while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
459 		DELAY(CPSW_MIIBUS_DELAY);
460 	if (!retries)
461 		device_printf(dev, "Timeout while waiting for MDIO.\n");
462 
463 	/* Check for ACK */
464 	if(cpsw_read_4(MDIOUSERACCESS0) & (1<<29)) {
465 		return 0;
466 	}
467 	device_printf(dev, "Failed to write to PHY.\n");
468 
469 	return 0;
470 }
471 
472 static int
473 cpsw_allocate_dma(struct cpsw_softc *sc)
474 {
475 	int err;
476 	int i;
477 
478 	/* Allocate a busdma tag and DMA safe memory for tx mbufs. */
479 	err = bus_dma_tag_create(
480 		bus_get_dma_tag(sc->dev),	/* parent */
481 		1, 0,				/* alignment, boundary */
482 		BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
483 		BUS_SPACE_MAXADDR,		/* highaddr */
484 		NULL, NULL,			/* filtfunc, filtfuncarg */
485 		MCLBYTES, 1,			/* maxsize, nsegments */
486 		MCLBYTES, 0,			/* maxsegsz, flags */
487 		NULL, NULL,			/* lockfunc, lockfuncarg */
488 		&sc->mbuf_dtag);		/* dmatag */
489 
490 	if (err)
491 		return (ENOMEM);
492 	for (i = 0; i < CPSW_MAX_TX_BUFFERS; i++) {
493 		if ( bus_dmamap_create(sc->mbuf_dtag, 0, &sc->tx_dmamap[i])) {
494 			if_printf(sc->ifp, "failed to create dmamap for rx mbuf\n");
495 			return (ENOMEM);
496 		}
497 	}
498 
499 	for (i = 0; i < CPSW_MAX_RX_BUFFERS; i++) {
500 		if ( bus_dmamap_create(sc->mbuf_dtag, 0, &sc->rx_dmamap[i])) {
501 			if_printf(sc->ifp, "failed to create dmamap for rx mbuf\n");
502 			return (ENOMEM);
503 		}
504 	}
505 
506 	return (0);
507 }
508 
509 static int
510 cpsw_free_dma(struct cpsw_softc *sc)
511 {
512 	(void)sc; /* UNUSED */
513 	// TODO
514 	return 0;
515 }
516 
517 static int
518 cpsw_new_rxbuf(struct cpsw_softc *sc, uint32_t i, uint32_t next)
519 {
520 	bus_dma_segment_t seg[1];
521 	struct cpsw_cpdma_bd bd;
522 	int error;
523 	int nsegs;
524 
525 	if (sc->rx_mbuf[i]) {
526 		bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_POSTREAD);
527 		bus_dmamap_unload(sc->mbuf_dtag, sc->rx_dmamap[i]);
528 	}
529 
530 	sc->rx_mbuf[i] = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
531 	if (sc->rx_mbuf[i] == NULL)
532 		return (ENOBUFS);
533 
534 	sc->rx_mbuf[i]->m_len = sc->rx_mbuf[i]->m_pkthdr.len = sc->rx_mbuf[i]->m_ext.ext_size;
535 
536 	error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, sc->rx_dmamap[i],
537 		sc->rx_mbuf[i], seg, &nsegs, BUS_DMA_NOWAIT);
538 
539 	KASSERT(nsegs == 1, ("Too many segments returned!"));
540 	if (nsegs != 1 || error)
541 		panic("%s: nsegs(%d), error(%d)",__func__, nsegs, error);
542 
543 	bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_PREREAD);
544 
545 	/* Create and submit new rx descriptor*/
546 	bd.next = next;
547 	bd.bufptr = seg->ds_addr;
548 	bd.buflen = MCLBYTES-1;
549 	bd.bufoff = 2; /* make IP hdr aligned with 4 */
550 	bd.pktlen = 0;
551 	bd.flags = CPDMA_BD_OWNER;
552 	cpsw_cpdma_write_rxbd(i, &bd);
553 
554 	return (0);
555 }
556 
557 
558 static int
559 cpsw_encap(struct cpsw_softc *sc, struct mbuf *m0)
560 {
561 	bus_dma_segment_t seg[1];
562 	struct cpsw_cpdma_bd bd;
563 	int error;
564 	int nsegs;
565 	int idx;
566 
567 	if (sc->txbd_queue_size == CPSW_MAX_TX_BUFFERS)
568 		return (ENOBUFS);
569 
570 	idx = sc->txbd_head + sc->txbd_queue_size;
571 
572 	if (idx >= (CPSW_MAX_TX_BUFFERS) )
573 		idx -= CPSW_MAX_TX_BUFFERS;
574 
575 	/* Create mapping in DMA memory */
576 	error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, sc->tx_dmamap[idx], m0, seg, &nsegs,
577 	    BUS_DMA_NOWAIT);
578 	sc->tc[idx]++;
579 	if (error != 0 || nsegs != 1 ) {
580 		bus_dmamap_unload(sc->mbuf_dtag, sc->tx_dmamap[idx]);
581 		return ((error != 0) ? error : -1);
582 	}
583 	bus_dmamap_sync(sc->mbuf_dtag, sc->tx_dmamap[idx], BUS_DMASYNC_PREWRITE);
584 
585 	/* Fill descriptor data */
586 	bd.next = 0;
587 	bd.bufptr = seg->ds_addr;
588 	bd.bufoff = 0;
589 	bd.buflen = (seg->ds_len < 64 ? 64 : seg->ds_len);
590 	bd.pktlen = (seg->ds_len < 64 ? 64 : seg->ds_len);
591 	/* Set OWNERSHIP, SOP, EOP */
592 	bd.flags = (7<<13);
593 
594 	/* Write descriptor */
595 	cpsw_cpdma_write_txbd(idx, &bd);
596 
597 	/* Previous descriptor should point to us */
598 	cpsw_cpdma_write_txbd_next(((idx-1<0)?(CPSW_MAX_TX_BUFFERS-1):(idx-1)),
599 		cpsw_cpdma_txbd_paddr(idx));
600 
601 	sc->txbd_queue_size++;
602 
603 	return (0);
604 }
605 
606 static void
607 cpsw_start(struct ifnet *ifp)
608 {
609 	struct cpsw_softc *sc = ifp->if_softc;
610 
611 	CPSW_TX_LOCK(sc);
612 	cpsw_start_locked(ifp);
613 	CPSW_TX_UNLOCK(sc);
614 }
615 
616 static void
617 cpsw_start_locked(struct ifnet *ifp)
618 {
619 	struct cpsw_softc *sc = ifp->if_softc;
620 	struct mbuf *m0, *mtmp;
621 	uint32_t queued = 0;
622 
623 	CPSW_TX_LOCK_ASSERT(sc);
624 
625 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
626 	    IFF_DRV_RUNNING)
627 		return;
628 
629 	for (;;) {
630 		/* Get packet from the queue */
631 		IF_DEQUEUE(&ifp->if_snd, m0);
632 		if (m0 == NULL)
633 			break;
634 
635 		mtmp = m_defrag(m0, M_DONTWAIT);
636 		if (mtmp)
637 			m0 = mtmp;
638 
639 		if (cpsw_encap(sc, m0)) {
640 			IF_PREPEND(&ifp->if_snd, m0);
641 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
642 			break;
643 		}
644 		queued++;
645 		BPF_MTAP(ifp, m0);
646 	}
647 
648 	if (!queued)
649 		return;
650 
651 	if (sc->eoq) {
652 		cpsw_write_4(CPSW_CPDMA_TX_HDP(0), cpsw_cpdma_txbd_paddr(sc->txbd_head));
653 		sc->eoq = 0;
654 	}
655 	sc->wd_timer = 5;
656 }
657 
658 static void
659 cpsw_stop(struct cpsw_softc *sc)
660 {
661 	struct ifnet *ifp;
662 
663 	ifp = sc->ifp;
664 
665 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
666 		return;
667 
668 	/* Stop tick engine */
669 	callout_stop(&sc->wd_callout);
670 
671 	/* Disable interface */
672 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
673 	sc->wd_timer = 0;
674 
675 	/* Disable interrupts  TODO */
676 
677 }
678 
679 static int
680 cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
681 {
682 	struct cpsw_softc *sc = ifp->if_softc;
683 	struct ifreq *ifr = (struct ifreq *)data;
684 	int error;
685 	uint32_t flags;
686 
687 	error = 0;
688 
689 	// FIXME
690 	switch (command) {
691 	case SIOCSIFFLAGS:
692 		CPSW_GLOBAL_LOCK(sc);
693 		if (ifp->if_flags & IFF_UP) {
694 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
695 				flags = ifp->if_flags ^ sc->cpsw_if_flags;
696 				if (flags & IFF_PROMISC)
697 					printf("%s: SIOCSIFFLAGS "
698 						"IFF_PROMISC unimplemented\n",
699 						__func__);
700 
701 				if (flags & IFF_ALLMULTI)
702 					printf("%s: SIOCSIFFLAGS "
703 						"IFF_ALLMULTI unimplemented\n",
704 						__func__);
705 			} else {
706 				printf("%s: SIOCSIFFLAGS cpsw_init_locked\n", __func__);
707 				//cpsw_init_locked(sc);
708 			}
709 		}
710 		else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
711 			cpsw_stop(sc);
712 
713 		sc->cpsw_if_flags = ifp->if_flags;
714 		CPSW_GLOBAL_UNLOCK(sc);
715 		break;
716 		printf("%s: SIOCSIFFLAGS\n",__func__);
717 		break;
718 	case SIOCADDMULTI:
719 		printf("%s: SIOCADDMULTI\n",__func__);
720 		break;
721 	case SIOCDELMULTI:
722 		printf("%s: SIOCDELMULTI\n",__func__);
723 		break;
724 	case SIOCSIFCAP:
725 		printf("%s: SIOCSIFCAP\n",__func__);
726 		break;
727 	case SIOCGIFMEDIA: /* fall through */
728 		printf("%s: SIOCGIFMEDIA\n",__func__);
729 		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
730 		break;
731 	case SIOCSIFMEDIA:
732 		printf("%s: SIOCSIFMEDIA\n",__func__);
733 		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
734 		break;
735 	default:
736 		error = ether_ioctl(ifp, command, data);
737 	}
738 	return (error);
739 }
740 
741 static void
742 cpsw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
743 {
744 	struct cpsw_softc *sc = ifp->if_softc;
745 	struct mii_data *mii;
746 
747 	CPSW_TX_LOCK(sc);
748 
749 	mii = sc->mii;
750 	mii_pollstat(mii);
751 
752 	ifmr->ifm_active = mii->mii_media_active;
753 	ifmr->ifm_status = mii->mii_media_status;
754 
755 	CPSW_TX_UNLOCK(sc);
756 }
757 
758 
759 static int
760 cpsw_ifmedia_upd(struct ifnet *ifp)
761 {
762 	struct cpsw_softc *sc = ifp->if_softc;
763 
764 	if (ifp->if_flags & IFF_UP) {
765 		CPSW_GLOBAL_LOCK(sc);
766 
767 		sc->cpsw_media_status = sc->mii->mii_media.ifm_media;
768 		mii_mediachg(sc->mii);
769 		cpsw_init_locked(sc);
770 
771 		CPSW_GLOBAL_UNLOCK(sc);
772 	}
773 
774 	return (0);
775 }
776 
777 static void
778 cpsw_intr_rx_thresh(void *arg)
779 {
780 	(void)arg; /* UNUSED */
781 }
782 
783 static void
784 cpsw_intr_rx(void *arg)
785 {
786 	struct cpsw_softc *sc = arg;
787 	CPSW_RX_LOCK(sc);
788 	cpsw_intr_rx_locked(arg);
789 	CPSW_RX_UNLOCK(sc);
790 }
791 
792 static void
793 cpsw_intr_rx_locked(void *arg)
794 {
795 	struct cpsw_softc *sc = arg;
796 	struct cpsw_cpdma_bd bd;
797 	struct ifnet *ifp;
798 	int i;
799 
800 	ifp = sc->ifp;
801 
802 	i = sc->rxbd_head;
803 	cpsw_cpdma_read_rxbd(i, &bd);
804 
805 	while (bd.flags & CPDMA_BD_SOP) {
806 		cpsw_write_4(CPSW_CPDMA_RX_CP(0), cpsw_cpdma_rxbd_paddr(i));
807 
808 		bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_POSTREAD);
809 
810 		/* Fill mbuf */
811 		sc->rx_mbuf[i]->m_hdr.mh_data +=2;
812 		sc->rx_mbuf[i]->m_len = bd.pktlen-2;
813 		sc->rx_mbuf[i]->m_pkthdr.len = bd.pktlen-2;
814 		sc->rx_mbuf[i]->m_flags |= M_PKTHDR;
815 		sc->rx_mbuf[i]->m_pkthdr.rcvif = ifp;
816 
817 		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
818 			/* check for valid CRC by looking into pkt_err[5:4] */
819 			if ( (bd.flags & CPDMA_BD_PKT_ERR_MASK) == 0  ) {
820 				sc->rx_mbuf[i]->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
821 				sc->rx_mbuf[i]->m_pkthdr.csum_flags |= CSUM_IP_VALID;
822 				sc->rx_mbuf[i]->m_pkthdr.csum_data = 0xffff;
823 			}
824 		}
825 
826 		/* Handover packet */
827 		CPSW_RX_UNLOCK(sc);
828 		(*ifp->if_input)(ifp, sc->rx_mbuf[i]);
829 		CPSW_RX_LOCK(sc);
830 
831 		/* Allocate new buffer for current descriptor */
832 		cpsw_new_rxbuf(sc, i, 0);
833 
834 		/* we are not at tail so old tail BD should point to new one */
835 		cpsw_cpdma_write_rxbd_next(sc->rxbd_tail,
836 			cpsw_cpdma_rxbd_paddr(i));
837 
838 		/* Check if EOQ is reached */
839 		if (cpsw_cpdma_read_rxbd_flags(sc->rxbd_tail) & CPDMA_BD_EOQ) {
840 			cpsw_write_4(CPSW_CPDMA_RX_HDP(0), cpsw_cpdma_rxbd_paddr(i));
841 		}
842 		sc->rxbd_tail = i;
843 
844 		/* read next descriptor */
845 		if (++i == CPSW_MAX_RX_BUFFERS)
846 			i = 0;
847 		cpsw_cpdma_read_rxbd(i, &bd);
848 		sc->rxbd_head = i;
849 	}
850 
851 	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
852 }
853 
854 static void
855 cpsw_intr_tx(void *arg)
856 {
857 	struct cpsw_softc *sc = arg;
858 	CPSW_TX_LOCK(sc);
859 	cpsw_intr_tx_locked(arg);
860 	CPSW_TX_UNLOCK(sc);
861 }
862 
863 static void
864 cpsw_intr_tx_locked(void *arg)
865 {
866 	struct cpsw_softc *sc = arg;
867 	uint32_t flags;
868 
869 	if(sc->txbd_head == -1)
870 		return;
871 
872 	if(sc->txbd_queue_size<1) {
873 		/* in some casses interrupt happens even when there is no
874 		   data in transmit queue */
875 		return;
876 	}
877 
878 	/* Disable watchdog */
879 	sc->wd_timer = 0;
880 
881 	flags = cpsw_cpdma_read_txbd_flags(sc->txbd_head);
882 
883 	/* After BD is transmitted CPDMA will set OWNER to 0 */
884 	if (flags & CPDMA_BD_OWNER)
885 		return;
886 
887 	if(flags & CPDMA_BD_EOQ)
888 		sc->eoq=1;
889 
890 	/* release dmamap and mbuf */
891 	bus_dmamap_sync(sc->mbuf_dtag, sc->tx_dmamap[sc->txbd_head],
892 	    BUS_DMASYNC_POSTWRITE);
893 	bus_dmamap_unload(sc->mbuf_dtag, sc->tx_dmamap[sc->txbd_head]);
894 	m_freem(sc->tx_mbuf[sc->txbd_head]);
895 
896 	cpsw_write_4(CPSW_CPDMA_TX_CP(0), cpsw_cpdma_txbd_paddr(sc->txbd_head));
897 
898 	if (++sc->txbd_head == CPSW_MAX_TX_BUFFERS)
899 		sc->txbd_head = 0;
900 
901 	--sc->txbd_queue_size;
902 
903 	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 2);
904 	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
905 }
906 
907 static void
908 cpsw_intr_misc(void *arg)
909 {
910 	struct cpsw_softc *sc = arg;
911 	uint32_t stat = cpsw_read_4(CPSW_WR_C_MISC_STAT(0));
912 	printf("%s: stat=%x\n",__func__,stat);
913 	/* EOI_RX_PULSE */
914 	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 3);
915 }
916 
917 static void
918 cpsw_tick(void *msc)
919 {
920 	struct cpsw_softc *sc = msc;
921 
922 	/* Check for TX timeout */
923 	cpsw_watchdog(sc);
924 
925 	mii_tick(sc->mii);
926 
927 	/* Check for media type change */
928 	if(sc->cpsw_media_status != sc->mii->mii_media.ifm_media) {
929 		printf("%s: media type changed (ifm_media=%x)\n",__func__,
930 			sc->mii->mii_media.ifm_media);
931 		cpsw_ifmedia_upd(sc->ifp);
932 	}
933 
934 	/* Schedule another timeout one second from now */
935 	callout_reset(&sc->wd_callout, hz, cpsw_tick, sc);
936 }
937 
938 static void
939 cpsw_watchdog(struct cpsw_softc *sc)
940 {
941 	struct ifnet *ifp;
942 
943 	ifp = sc->ifp;
944 
945 	CPSW_GLOBAL_LOCK(sc);
946 
947 	if (sc->wd_timer == 0 || --sc->wd_timer) {
948 		CPSW_GLOBAL_UNLOCK(sc);
949 		return;
950 	}
951 
952 	ifp->if_oerrors++;
953 	if_printf(ifp, "watchdog timeout\n");
954 
955 	cpsw_stop(sc);
956 	cpsw_init_locked(sc);
957 
958 	CPSW_GLOBAL_UNLOCK(sc);
959 }
960 
961 static void
962 cpsw_init(void *arg)
963 {
964 	struct cpsw_softc *sc = arg;
965 	CPSW_GLOBAL_LOCK(sc);
966 	cpsw_init_locked(arg);
967 	CPSW_GLOBAL_UNLOCK(sc);
968 }
969 
970 int once = 1;
971 
972 static void
973 cpsw_init_locked(void *arg)
974 {
975 	struct ifnet *ifp;
976 	struct cpsw_softc *sc = arg;
977 	uint8_t  broadcast_address[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
978 	uint32_t next_bdp;
979 	uint32_t i;
980 
981 	ifp = sc->ifp;
982 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
983 		return;
984 
985 	printf("%s: start\n",__func__);
986 
987 	/* Reset writer */
988 	cpsw_write_4(CPSW_WR_SOFT_RESET, 1);
989 	while(cpsw_read_4(CPSW_WR_SOFT_RESET) & 1);
990 
991 	/* Reset SS */
992 	cpsw_write_4(CPSW_SS_SOFT_RESET, 1);
993 	while(cpsw_read_4(CPSW_SS_SOFT_RESET) & 1);
994 
995 	/* Clear table (30) and enable ALE(31) */
996 	if (once)
997 		cpsw_write_4(CPSW_ALE_CONTROL, (3 << 30));
998 	else
999 		cpsw_write_4(CPSW_ALE_CONTROL, (1 << 31));
1000 	once = 0; // FIXME
1001 
1002 	/* Reset and init Sliver port 1 and 2 */
1003 	for(i=0;i<2;i++) {
1004 		/* Reset */
1005 		cpsw_write_4(CPSW_SL_SOFT_RESET(i), 1);
1006 		while(cpsw_read_4(CPSW_SL_SOFT_RESET(i)) & 1);
1007 		/* Set Slave Mapping */
1008 		cpsw_write_4(CPSW_SL_RX_PRI_MAP(i),0x76543210);
1009 		cpsw_write_4(CPSW_PORT_P_TX_PRI_MAP(i+1),0x33221100);
1010 		cpsw_write_4(CPSW_SL_RX_MAXLEN(i),0x5f2);
1011 		/* Set MAC Address */
1012 		cpsw_write_4(CPSW_PORT_P_SA_HI(i+1), sc->mac_addr[0] |
1013 			(sc->mac_addr[1] <<  8) |
1014 			(sc->mac_addr[2] << 16) |
1015 			(sc->mac_addr[3] << 24));
1016 		cpsw_write_4(CPSW_PORT_P_SA_LO(i+1), sc->mac_addr[4] |
1017 			(sc->mac_addr[5] <<  8));
1018 
1019 		/* Set MACCONTROL for ports 0,1: FULLDUPLEX(1), GMII_EN(5),
1020 		   IFCTL_A(15), IFCTL_B(16) FIXME */
1021 		cpsw_write_4(CPSW_SL_MACCONTROL(i), 1 | (1<<5) | (1<<15));
1022 
1023 		/* Set ALE port to forwarding(3) */
1024 		cpsw_write_4(CPSW_ALE_PORTCTL(i+1), 3);
1025 	}
1026 
1027 	/* Set Host Port Mapping */
1028 	cpsw_write_4(CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210);
1029 	cpsw_write_4(CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0);
1030 
1031 	/* Set ALE port to forwarding(3)*/
1032 	cpsw_write_4(CPSW_ALE_PORTCTL(0), 3);
1033 
1034 	/* Add own MAC address and broadcast to ALE */
1035 	cpsw_ale_uc_entry_set(sc, 0, sc->mac_addr);
1036 	cpsw_ale_mc_entry_set(sc, 7, broadcast_address);
1037 
1038 	cpsw_write_4(CPSW_SS_PTYPE, 0);
1039 	/* Enable statistics for ports 0, 1 and 2 */
1040 	cpsw_write_4(CPSW_SS_STAT_PORT_EN, 7);
1041 
1042 	/* Reset CPDMA */
1043 	cpsw_write_4(CPSW_CPDMA_SOFT_RESET, 1);
1044 	while(cpsw_read_4(CPSW_CPDMA_SOFT_RESET) & 1);
1045 
1046         for(i = 0; i < 8; i++) {
1047 		cpsw_write_4(CPSW_CPDMA_TX_HDP(i), 0);
1048 		cpsw_write_4(CPSW_CPDMA_RX_HDP(i), 0);
1049 		cpsw_write_4(CPSW_CPDMA_TX_CP(i), 0);
1050 		cpsw_write_4(CPSW_CPDMA_RX_CP(i), 0);
1051         }
1052 
1053 	cpsw_write_4(CPSW_CPDMA_RX_FREEBUFFER(0), 0);
1054 
1055 	/* Initialize RX Buffer Descriptors */
1056 	i = CPSW_MAX_RX_BUFFERS;
1057 	next_bdp = 0;
1058 	while (i--) {
1059 		cpsw_new_rxbuf(sc, i, next_bdp);
1060 		/* Increment number of free RX buffers */
1061 		//cpsw_write_4(CPSW_CPDMA_RX_FREEBUFFER(0), 1);
1062 		next_bdp = cpsw_cpdma_rxbd_paddr(i);
1063 	}
1064 
1065 	sc->rxbd_head = 0;
1066 	sc->rxbd_tail = CPSW_MAX_RX_BUFFERS-1;
1067 	sc->txbd_head = 0;
1068 	sc->eoq = 1;
1069 	sc->txbd_queue_size = 0;
1070 
1071 	/* Make IP hdr aligned with 4 */
1072 	cpsw_write_4(CPSW_CPDMA_RX_BUFFER_OFFSET, 2);
1073 	/* Write channel 0 RX HDP */
1074 	cpsw_write_4(CPSW_CPDMA_RX_HDP(0), cpsw_cpdma_rxbd_paddr(0));
1075 
1076 	/* Clear all interrupt Masks */
1077 	cpsw_write_4(CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
1078 	cpsw_write_4(CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
1079 
1080 	/* Enable TX & RX DMA */
1081 	cpsw_write_4(CPSW_CPDMA_TX_CONTROL, 1);
1082 	cpsw_write_4(CPSW_CPDMA_RX_CONTROL, 1);
1083 
1084 	/* Enable TX and RX interrupt receive for core 0 */
1085 	cpsw_write_4(CPSW_WR_C_TX_EN(0), 0xFF);
1086 	cpsw_write_4(CPSW_WR_C_RX_EN(0), 0xFF);
1087 	//cpsw_write_4(CPSW_WR_C_MISC_EN(0), 0x3F);
1088 
1089 	/* Enable host Error Interrupt */
1090 	cpsw_write_4(CPSW_CPDMA_DMA_INTMASK_SET, 1);
1091 
1092 	/* Enable interrupts for TX and RX Channel 0 */
1093 	cpsw_write_4(CPSW_CPDMA_TX_INTMASK_SET, 1);
1094 	cpsw_write_4(CPSW_CPDMA_RX_INTMASK_SET, 1);
1095 
1096 	/* Ack stalled irqs */
1097 	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 0);
1098 	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
1099 	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 2);
1100 	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 3);
1101 
1102 	/* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
1103 	/* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
1104 	cpsw_write_4(MDIOCONTROL, (1<<30) | (1<<18) | 0xFF);
1105 
1106 	/* Select MII in GMII_SEL, Internal Delay mode */
1107 	//ti_scm_reg_write_4(0x650, 0);
1108 
1109 	/* Activate network interface */
1110 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
1111 	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1112 	sc->wd_timer = 0;
1113 	callout_reset(&sc->wd_callout, hz, cpsw_tick, sc);
1114 }
1115 
1116 static void
1117 cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
1118 {
1119 	cpsw_write_4(CPSW_ALE_TBLCTL, idx & 1023);
1120 	ale_entry[0] = cpsw_read_4(CPSW_ALE_TBLW0);
1121 	ale_entry[1] = cpsw_read_4(CPSW_ALE_TBLW1);
1122 	ale_entry[2] = cpsw_read_4(CPSW_ALE_TBLW2);
1123 }
1124 
1125 static void
1126 cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
1127 {
1128 	cpsw_write_4(CPSW_ALE_TBLW0, ale_entry[0]);
1129 	cpsw_write_4(CPSW_ALE_TBLW1, ale_entry[1]);
1130 	cpsw_write_4(CPSW_ALE_TBLW2, ale_entry[2]);
1131 	cpsw_write_4(CPSW_ALE_TBLCTL, (idx & 1023) | (1 << 31));
1132 }
1133 
1134 static int
1135 cpsw_ale_find_entry_by_mac(struct cpsw_softc *sc, uint8_t *mac)
1136 {
1137 	int i;
1138 	uint32_t ale_entry[3];
1139 	for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
1140 		cpsw_ale_read_entry(sc, i, ale_entry);
1141 		if ((((ale_entry[1] >> 8) & 0xFF) == mac[0]) &&
1142 		    (((ale_entry[1] >> 0) & 0xFF) == mac[1]) &&
1143 		    (((ale_entry[0] >>24) & 0xFF) == mac[2]) &&
1144 		    (((ale_entry[0] >>16) & 0xFF) == mac[3]) &&
1145 		    (((ale_entry[0] >> 8) & 0xFF) == mac[4]) &&
1146 		    (((ale_entry[0] >> 0) & 0xFF) == mac[5])) {
1147 			return (i);
1148 		}
1149 	}
1150 	return CPSW_MAX_ALE_ENTRIES;
1151 }
1152 
1153 static int
1154 cpsw_ale_find_free_entry(struct cpsw_softc *sc)
1155 {
1156 	int i;
1157 	uint32_t ale_entry[3];
1158 	for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
1159 		cpsw_ale_read_entry(sc, i, ale_entry);
1160 		/* Entry Type[61:60] is 0 for free entry */
1161 		if (((ale_entry[1] >> 28) & 3) == 0) {
1162 			return i;
1163 		}
1164 	}
1165 	return CPSW_MAX_ALE_ENTRIES;
1166 }
1167 
1168 
1169 static int
1170 cpsw_ale_uc_entry_set(struct cpsw_softc *sc, uint8_t port, uint8_t *mac)
1171 {
1172 	int i;
1173 	uint32_t ale_entry[3];
1174 
1175 	if ((i = cpsw_ale_find_entry_by_mac(sc, mac)) == CPSW_MAX_ALE_ENTRIES) {
1176 		i = cpsw_ale_find_free_entry(sc);
1177 	}
1178 
1179 	if (i == CPSW_MAX_ALE_ENTRIES)
1180 		return (ENOMEM);
1181 
1182 	/* Set MAC address */
1183 	ale_entry[0] = mac[2]<<24 | mac[3]<<16 | mac[4]<<8 | mac[5];
1184 	ale_entry[1] = mac[0]<<8 | mac[1];
1185 
1186 	/* Entry type[61:60] is addr entry(1) */
1187 	ale_entry[1] |= 0x10<<24;
1188 
1189 	/* Set portmask [67:66] */
1190 	ale_entry[2] = (port & 3) << 2;
1191 
1192 	cpsw_ale_write_entry(sc, i, ale_entry);
1193 
1194 	return 0;
1195 }
1196 
1197 static int
1198 cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac)
1199 {
1200 	int i;
1201 	uint32_t ale_entry[3];
1202 
1203 	if ((i = cpsw_ale_find_entry_by_mac(sc, mac)) == CPSW_MAX_ALE_ENTRIES) {
1204 		i = cpsw_ale_find_free_entry(sc);
1205 	}
1206 
1207 	if (i == CPSW_MAX_ALE_ENTRIES)
1208 		return (ENOMEM);
1209 
1210 	/* Set MAC address */
1211 	ale_entry[0] = mac[2]<<24 | mac[3]<<16 | mac[4]<<8 | mac[5];
1212 	ale_entry[1] = mac[0]<<8 | mac[1];
1213 
1214 	/* Entry type[61:60] is addr entry(1), Mcast fwd state[63:62] is fw(3)*/
1215 	ale_entry[1] |= 0xd0<<24;
1216 
1217 	/* Set portmask [68:66] */
1218 	ale_entry[2] = (portmap & 7) << 2;
1219 
1220 	cpsw_ale_write_entry(sc, i, ale_entry);
1221 
1222 	return 0;
1223 }
1224 
1225 #ifdef CPSW_DEBUG
1226 static void
1227 cpsw_ale_dump_table(struct cpsw_softc *sc) {
1228 	int i;
1229 	uint32_t ale_entry[3];
1230 	for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
1231 		cpsw_ale_read_entry(sc, i, ale_entry);
1232 		if (ale_entry[0] || ale_entry[1] || ale_entry[2]) {
1233 			printf("ALE[%4u] %08x %08x %08x ", i, ale_entry[0],
1234 				ale_entry[1],ale_entry[2]);
1235 			printf("mac: %02x:%02x:%02x:%02x:%02x:%02x ",
1236 				(ale_entry[1] >> 8) & 0xFF,
1237 				(ale_entry[1] >> 0) & 0xFF,
1238 				(ale_entry[0] >>24) & 0xFF,
1239 				(ale_entry[0] >>16) & 0xFF,
1240 				(ale_entry[0] >> 8) & 0xFF,
1241 				(ale_entry[0] >> 0) & 0xFF);
1242 			printf( ((ale_entry[1]>>8)&1) ? "mcast " : "ucast ");
1243 			printf("type: %u ", (ale_entry[1]>>28)&3);
1244 			printf("port: %u ", (ale_entry[2]>>2)&7);
1245 			printf("\n");
1246 		}
1247 	}
1248 }
1249 #endif
1250