xref: /freebsd/sys/dev/dpaa/if_dtsec.c (revision edf8578117e8844e02c0121147f45e4609b30680)
1 /*-
2  * Copyright (c) 2011-2012 Semihalf.
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 #include <sys/cdefs.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/module.h>
32 #include <sys/bus.h>
33 #include <sys/rman.h>
34 #include <sys/malloc.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/sysctl.h>
38 #include <sys/sockio.h>
39 
40 #include <machine/bus.h>
41 #include <machine/resource.h>
42 
43 #include <net/ethernet.h>
44 #include <net/if.h>
45 #include <net/if_dl.h>
46 #include <net/if_media.h>
47 #include <net/if_types.h>
48 #include <net/if_arp.h>
49 
50 #include <dev/mii/mii.h>
51 #include <dev/mii/miivar.h>
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
54 #include <dev/ofw/openfirm.h>
55 
56 #include "miibus_if.h"
57 
58 #include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h>
59 #include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
60 #include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
61 #include <contrib/ncsw/inc/flib/fsl_fman_dtsec.h>
62 #include <contrib/ncsw/inc/xx_ext.h>
63 
64 #include "fman.h"
65 #include "if_dtsec.h"
66 #include "if_dtsec_im.h"
67 #include "if_dtsec_rm.h"
68 
69 #define	DTSEC_MIN_FRAME_SIZE	64
70 #define	DTSEC_MAX_FRAME_SIZE	9600
71 
72 #define	DTSEC_REG_MAXFRM	0x110
73 #define	DTSEC_REG_GADDR(i)	(0x0a0 + 4*(i))
74 
75 /**
76  * @group dTSEC private defines.
77  * @{
78  */
79 /**
80  * dTSEC FMan MAC exceptions info struct.
81  */
82 struct dtsec_fm_mac_ex_str {
83 	const int num;
84 	const char *str;
85 };
86 /** @} */
87 
88 
89 /**
90  * @group FMan MAC routines.
91  * @{
92  */
93 #define	DTSEC_MAC_EXCEPTIONS_END	(-1)
94 
95 /**
96  * FMan MAC exceptions.
97  */
98 static const struct dtsec_fm_mac_ex_str dtsec_fm_mac_exceptions[] = {
99 	{ e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO, "MDIO scan event" },
100 	{ e_FM_MAC_EX_10G_MDIO_CMD_CMPL, "MDIO command completion" },
101 	{ e_FM_MAC_EX_10G_REM_FAULT, "Remote fault" },
102 	{ e_FM_MAC_EX_10G_LOC_FAULT, "Local fault" },
103 	{ e_FM_MAC_EX_10G_1TX_ECC_ER, "Transmit frame ECC error" },
104 	{ e_FM_MAC_EX_10G_TX_FIFO_UNFL, "Transmit FIFO underflow" },
105 	{ e_FM_MAC_EX_10G_TX_FIFO_OVFL, "Receive FIFO overflow" },
106 	{ e_FM_MAC_EX_10G_TX_ER, "Transmit frame error" },
107 	{ e_FM_MAC_EX_10G_RX_FIFO_OVFL, "Receive FIFO overflow" },
108 	{ e_FM_MAC_EX_10G_RX_ECC_ER, "Receive frame ECC error" },
109 	{ e_FM_MAC_EX_10G_RX_JAB_FRM, "Receive jabber frame" },
110 	{ e_FM_MAC_EX_10G_RX_OVRSZ_FRM, "Receive oversized frame" },
111 	{ e_FM_MAC_EX_10G_RX_RUNT_FRM, "Receive runt frame" },
112 	{ e_FM_MAC_EX_10G_RX_FRAG_FRM, "Receive fragment frame" },
113 	{ e_FM_MAC_EX_10G_RX_LEN_ER, "Receive payload length error" },
114 	{ e_FM_MAC_EX_10G_RX_CRC_ER, "Receive CRC error" },
115 	{ e_FM_MAC_EX_10G_RX_ALIGN_ER, "Receive alignment error" },
116 	{ e_FM_MAC_EX_1G_BAB_RX, "Babbling receive error" },
117 	{ e_FM_MAC_EX_1G_RX_CTL, "Receive control (pause frame) interrupt" },
118 	{ e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET, "Graceful transmit stop "
119 	    "complete" },
120 	{ e_FM_MAC_EX_1G_BAB_TX, "Babbling transmit error" },
121 	{ e_FM_MAC_EX_1G_TX_CTL, "Transmit control (pause frame) interrupt" },
122 	{ e_FM_MAC_EX_1G_TX_ERR, "Transmit error" },
123 	{ e_FM_MAC_EX_1G_LATE_COL, "Late collision" },
124 	{ e_FM_MAC_EX_1G_COL_RET_LMT, "Collision retry limit" },
125 	{ e_FM_MAC_EX_1G_TX_FIFO_UNDRN, "Transmit FIFO underrun" },
126 	{ e_FM_MAC_EX_1G_MAG_PCKT, "Magic Packet detected when dTSEC is in "
127 	    "Magic Packet detection mode" },
128 	{ e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET, "MII management read completion" },
129 	{ e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET, "MII management write completion" },
130 	{ e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET, "Graceful receive stop "
131 	    "complete" },
132 	{ e_FM_MAC_EX_1G_TX_DATA_ERR, "Internal data error on transmit" },
133 	{ e_FM_MAC_EX_1G_RX_DATA_ERR, "Internal data error on receive" },
134 	{ e_FM_MAC_EX_1G_1588_TS_RX_ERR, "Time-Stamp Receive Error" },
135 	{ e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, "MIB counter overflow" },
136 	{ DTSEC_MAC_EXCEPTIONS_END, "" }
137 };
138 
139 static const char *
140 dtsec_fm_mac_ex_to_str(e_FmMacExceptions exception)
141 {
142 	int i;
143 
144 	for (i = 0; dtsec_fm_mac_exceptions[i].num != exception &&
145 	    dtsec_fm_mac_exceptions[i].num != DTSEC_MAC_EXCEPTIONS_END; ++i)
146 		;
147 
148 	if (dtsec_fm_mac_exceptions[i].num == DTSEC_MAC_EXCEPTIONS_END)
149 		return ("<Unknown Exception>");
150 
151 	return (dtsec_fm_mac_exceptions[i].str);
152 }
153 
154 static void
155 dtsec_fm_mac_mdio_event_callback(t_Handle h_App,
156     e_FmMacExceptions exception)
157 {
158 	struct dtsec_softc *sc;
159 
160 	sc = h_App;
161 	device_printf(sc->sc_dev, "MDIO event %i: %s.\n", exception,
162 	    dtsec_fm_mac_ex_to_str(exception));
163 }
164 
165 static void
166 dtsec_fm_mac_exception_callback(t_Handle app, e_FmMacExceptions exception)
167 {
168 	struct dtsec_softc *sc;
169 
170 	sc = app;
171 	device_printf(sc->sc_dev, "MAC exception %i: %s.\n", exception,
172 	    dtsec_fm_mac_ex_to_str(exception));
173 }
174 
175 static void
176 dtsec_fm_mac_free(struct dtsec_softc *sc)
177 {
178 	if (sc->sc_mach == NULL)
179 		return;
180 
181 	FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
182 	FM_MAC_Free(sc->sc_mach);
183 	sc->sc_mach = NULL;
184 }
185 
186 static int
187 dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac)
188 {
189 	t_FmMacParams params;
190 	t_Error error;
191 
192 	memset(&params, 0, sizeof(params));
193 	memcpy(&params.addr, mac, sizeof(params.addr));
194 
195 	params.baseAddr = rman_get_bushandle(sc->sc_mem);
196 	params.enetMode = sc->sc_mac_enet_mode;
197 	params.macId = sc->sc_eth_id;
198 	params.mdioIrq = sc->sc_mac_mdio_irq;
199 	params.f_Event = dtsec_fm_mac_mdio_event_callback;
200 	params.f_Exception = dtsec_fm_mac_exception_callback;
201 	params.h_App = sc;
202 	params.h_Fm = sc->sc_fmh;
203 
204 	sc->sc_mach = FM_MAC_Config(&params);
205 	if (sc->sc_mach == NULL) {
206 		device_printf(sc->sc_dev, "couldn't configure FM_MAC module.\n"
207 		    );
208 		return (ENXIO);
209 	}
210 
211 	error = FM_MAC_ConfigResetOnInit(sc->sc_mach, TRUE);
212 	if (error != E_OK) {
213 		device_printf(sc->sc_dev, "couldn't enable reset on init "
214 		    "feature.\n");
215 		dtsec_fm_mac_free(sc);
216 		return (ENXIO);
217 	}
218 
219 	/* Do not inform about pause frames */
220 	error = FM_MAC_ConfigException(sc->sc_mach, e_FM_MAC_EX_1G_RX_CTL,
221 	    FALSE);
222 	if (error != E_OK) {
223 		device_printf(sc->sc_dev, "couldn't disable pause frames "
224 			"exception.\n");
225 		dtsec_fm_mac_free(sc);
226 		return (ENXIO);
227 	}
228 
229 	error = FM_MAC_Init(sc->sc_mach);
230 	if (error != E_OK) {
231 		device_printf(sc->sc_dev, "couldn't initialize FM_MAC module."
232 		    "\n");
233 		dtsec_fm_mac_free(sc);
234 		return (ENXIO);
235 	}
236 
237 	return (0);
238 }
239 /** @} */
240 
241 
242 /**
243  * @group FMan PORT routines.
244  * @{
245  */
246 static const char *
247 dtsec_fm_port_ex_to_str(e_FmPortExceptions exception)
248 {
249 
250 	switch (exception) {
251 	case e_FM_PORT_EXCEPTION_IM_BUSY:
252 		return ("IM: RX busy");
253 	default:
254 		return ("<Unknown Exception>");
255 	}
256 }
257 
258 void
259 dtsec_fm_port_rx_exception_callback(t_Handle app,
260     e_FmPortExceptions exception)
261 {
262 	struct dtsec_softc *sc;
263 
264 	sc = app;
265 	device_printf(sc->sc_dev, "RX exception: %i: %s.\n", exception,
266 	    dtsec_fm_port_ex_to_str(exception));
267 }
268 
269 void
270 dtsec_fm_port_tx_exception_callback(t_Handle app,
271     e_FmPortExceptions exception)
272 {
273 	struct dtsec_softc *sc;
274 
275 	sc = app;
276 	device_printf(sc->sc_dev, "TX exception: %i: %s.\n", exception,
277 	    dtsec_fm_port_ex_to_str(exception));
278 }
279 
280 e_FmPortType
281 dtsec_fm_port_rx_type(enum eth_dev_type type)
282 {
283 	switch (type) {
284 	case ETH_DTSEC:
285 		return (e_FM_PORT_TYPE_RX);
286 	case ETH_10GSEC:
287 		return (e_FM_PORT_TYPE_RX_10G);
288 	default:
289 		return (e_FM_PORT_TYPE_DUMMY);
290 	}
291 }
292 
293 e_FmPortType
294 dtsec_fm_port_tx_type(enum eth_dev_type type)
295 {
296 
297 	switch (type) {
298 	case ETH_DTSEC:
299 		return (e_FM_PORT_TYPE_TX);
300 	case ETH_10GSEC:
301 		return (e_FM_PORT_TYPE_TX_10G);
302 	default:
303 		return (e_FM_PORT_TYPE_DUMMY);
304 	}
305 }
306 
307 static void
308 dtsec_fm_port_free_both(struct dtsec_softc *sc)
309 {
310 	if (sc->sc_rxph) {
311 		FM_PORT_Free(sc->sc_rxph);
312 		sc->sc_rxph = NULL;
313 	}
314 
315 	if (sc->sc_txph) {
316 		FM_PORT_Free(sc->sc_txph);
317 		sc->sc_txph = NULL;
318 	}
319 }
320 /** @} */
321 
322 
323 /**
324  * @group IFnet routines.
325  * @{
326  */
327 static int
328 dtsec_set_mtu(struct dtsec_softc *sc, unsigned int mtu)
329 {
330 
331 	mtu += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
332 
333 	DTSEC_LOCK_ASSERT(sc);
334 
335 	if (mtu >= DTSEC_MIN_FRAME_SIZE && mtu <= DTSEC_MAX_FRAME_SIZE) {
336 		bus_write_4(sc->sc_mem, DTSEC_REG_MAXFRM, mtu);
337 		return (mtu);
338 	}
339 
340 	return (0);
341 }
342 
343 static u_int
344 dtsec_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
345 {
346 	struct dtsec_softc *sc = arg;
347 
348 	FM_MAC_AddHashMacAddr(sc->sc_mach, (t_EnetAddr *)LLADDR(sdl));
349 
350 	return (1);
351 }
352 
353 static void
354 dtsec_setup_multicast(struct dtsec_softc *sc)
355 {
356 	int i;
357 
358 	if (if_getflags(sc->sc_ifnet) & IFF_ALLMULTI) {
359 		for (i = 0; i < 8; i++)
360 			bus_write_4(sc->sc_mem, DTSEC_REG_GADDR(i), 0xFFFFFFFF);
361 
362 		return;
363 	}
364 
365 	fman_dtsec_reset_filter_table(rman_get_virtual(sc->sc_mem),
366 	    true, false);
367 	if_foreach_llmaddr(sc->sc_ifnet, dtsec_hash_maddr, sc);
368 }
369 
370 static int
371 dtsec_if_enable_locked(struct dtsec_softc *sc)
372 {
373 	int error;
374 
375 	DTSEC_LOCK_ASSERT(sc);
376 
377 	error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
378 	if (error != E_OK)
379 		return (EIO);
380 
381 	error = FM_PORT_Enable(sc->sc_rxph);
382 	if (error != E_OK)
383 		return (EIO);
384 
385 	error = FM_PORT_Enable(sc->sc_txph);
386 	if (error != E_OK)
387 		return (EIO);
388 
389 	dtsec_setup_multicast(sc);
390 
391 	if_setdrvflagbits(sc->sc_ifnet, IFF_DRV_RUNNING, 0);
392 
393 	/* Refresh link state */
394 	dtsec_miibus_statchg(sc->sc_dev);
395 
396 	return (0);
397 }
398 
399 static int
400 dtsec_if_disable_locked(struct dtsec_softc *sc)
401 {
402 	int error;
403 
404 	DTSEC_LOCK_ASSERT(sc);
405 
406 	error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
407 	if (error != E_OK)
408 		return (EIO);
409 
410 	error = FM_PORT_Disable(sc->sc_rxph);
411 	if (error != E_OK)
412 		return (EIO);
413 
414 	error = FM_PORT_Disable(sc->sc_txph);
415 	if (error != E_OK)
416 		return (EIO);
417 
418 	if_setdrvflagbits(sc->sc_ifnet, 0, IFF_DRV_RUNNING);
419 
420 	return (0);
421 }
422 
423 static int
424 dtsec_if_ioctl(if_t ifp, u_long command, caddr_t data)
425 {
426 	struct dtsec_softc *sc;
427 	struct ifreq *ifr;
428 	int error;
429 
430 	sc = if_getsoftc(ifp);
431 	ifr = (struct ifreq *)data;
432 	error = 0;
433 
434 	/* Basic functionality to achieve media status reports */
435 	switch (command) {
436 	case SIOCSIFMTU:
437 		DTSEC_LOCK(sc);
438 		if (dtsec_set_mtu(sc, ifr->ifr_mtu))
439 			if_setmtu(ifp, ifr->ifr_mtu);
440 		else
441 			error = EINVAL;
442 		DTSEC_UNLOCK(sc);
443 		break;
444 	case SIOCSIFFLAGS:
445 		DTSEC_LOCK(sc);
446 
447 		if (if_getflags(sc->sc_ifnet) & IFF_UP)
448 			error = dtsec_if_enable_locked(sc);
449 		else
450 			error = dtsec_if_disable_locked(sc);
451 
452 		DTSEC_UNLOCK(sc);
453 		break;
454 
455 	case SIOCGIFMEDIA:
456 	case SIOCSIFMEDIA:
457 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media,
458 		    command);
459 		break;
460 
461 	default:
462 		error = ether_ioctl(ifp, command, data);
463 	}
464 
465 	return (error);
466 }
467 
468 static void
469 dtsec_if_tick(void *arg)
470 {
471 	struct dtsec_softc *sc;
472 
473 	sc = arg;
474 
475 	/* TODO */
476 	DTSEC_LOCK(sc);
477 
478 	mii_tick(sc->sc_mii);
479 	callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
480 
481 	DTSEC_UNLOCK(sc);
482 }
483 
484 static void
485 dtsec_if_deinit_locked(struct dtsec_softc *sc)
486 {
487 
488 	DTSEC_LOCK_ASSERT(sc);
489 
490 	DTSEC_UNLOCK(sc);
491 	callout_drain(&sc->sc_tick_callout);
492 	DTSEC_LOCK(sc);
493 }
494 
495 static void
496 dtsec_if_init_locked(struct dtsec_softc *sc)
497 {
498 	int error;
499 
500 	DTSEC_LOCK_ASSERT(sc);
501 
502 	/* Set MAC address */
503 	error = FM_MAC_ModifyMacAddr(sc->sc_mach,
504 	    (t_EnetAddr *)if_getlladdr(sc->sc_ifnet));
505 	if (error != E_OK) {
506 		device_printf(sc->sc_dev, "couldn't set MAC address.\n");
507 		goto err;
508 	}
509 
510 	/* Start MII polling */
511 	if (sc->sc_mii)
512 		callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
513 
514 	if (if_getflags(sc->sc_ifnet) & IFF_UP) {
515 		error = dtsec_if_enable_locked(sc);
516 		if (error != 0)
517 			goto err;
518 	} else {
519 		error = dtsec_if_disable_locked(sc);
520 		if (error != 0)
521 			goto err;
522 	}
523 
524 	return;
525 
526 err:
527 	dtsec_if_deinit_locked(sc);
528 	device_printf(sc->sc_dev, "initialization error.\n");
529 	return;
530 }
531 
532 static void
533 dtsec_if_init(void *data)
534 {
535 	struct dtsec_softc *sc;
536 
537 	sc = data;
538 
539 	DTSEC_LOCK(sc);
540 	dtsec_if_init_locked(sc);
541 	DTSEC_UNLOCK(sc);
542 }
543 
544 static void
545 dtsec_if_start(if_t ifp)
546 {
547 	struct dtsec_softc *sc;
548 
549 	sc = if_getsoftc(ifp);
550 	DTSEC_LOCK(sc);
551 	sc->sc_start_locked(sc);
552 	DTSEC_UNLOCK(sc);
553 }
554 
555 static void
556 dtsec_if_watchdog(if_t ifp)
557 {
558 	/* TODO */
559 }
560 /** @} */
561 
562 
563 /**
564  * @group IFmedia routines.
565  * @{
566  */
567 static int
568 dtsec_ifmedia_upd(if_t ifp)
569 {
570 	struct dtsec_softc *sc = if_getsoftc(ifp);
571 
572 	DTSEC_LOCK(sc);
573 	mii_mediachg(sc->sc_mii);
574 	DTSEC_UNLOCK(sc);
575 
576 	return (0);
577 }
578 
579 static void
580 dtsec_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
581 {
582 	struct dtsec_softc *sc = if_getsoftc(ifp);
583 
584 	DTSEC_LOCK(sc);
585 
586 	mii_pollstat(sc->sc_mii);
587 
588 	ifmr->ifm_active = sc->sc_mii->mii_media_active;
589 	ifmr->ifm_status = sc->sc_mii->mii_media_status;
590 
591 	DTSEC_UNLOCK(sc);
592 }
593 /** @} */
594 
595 
596 /**
597  * @group dTSEC bus interface.
598  * @{
599  */
600 static void
601 dtsec_configure_mode(struct dtsec_softc *sc)
602 {
603 	char tunable[64];
604 
605 	snprintf(tunable, sizeof(tunable), "%s.independent_mode",
606 	    device_get_nameunit(sc->sc_dev));
607 
608 	sc->sc_mode = DTSEC_MODE_REGULAR;
609 	TUNABLE_INT_FETCH(tunable, &sc->sc_mode);
610 
611 	if (sc->sc_mode == DTSEC_MODE_REGULAR) {
612 		sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init;
613 		sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init;
614 		sc->sc_start_locked = dtsec_rm_if_start_locked;
615 	} else {
616 		sc->sc_port_rx_init = dtsec_im_fm_port_rx_init;
617 		sc->sc_port_tx_init = dtsec_im_fm_port_tx_init;
618 		sc->sc_start_locked = dtsec_im_if_start_locked;
619 	}
620 
621 	device_printf(sc->sc_dev, "Configured for %s mode.\n",
622 	    (sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent");
623 }
624 
625 int
626 dtsec_attach(device_t dev)
627 {
628 	struct dtsec_softc *sc;
629 	device_t parent;
630 	int error;
631 	if_t ifp;
632 
633 	sc = device_get_softc(dev);
634 
635 	parent = device_get_parent(dev);
636 	sc->sc_dev = dev;
637 	sc->sc_mac_mdio_irq = NO_IRQ;
638 
639 	/* Check if MallocSmart allocator is ready */
640 	if (XX_MallocSmartInit() != E_OK)
641 		return (ENXIO);
642 
643 	/* Init locks */
644 	mtx_init(&sc->sc_lock, device_get_nameunit(dev),
645 	    "DTSEC Global Lock", MTX_DEF);
646 
647 	mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev),
648 	    "DTSEC MII Lock", MTX_DEF);
649 
650 	/* Init callouts */
651 	callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE);
652 
653 	/* Read configuraton */
654 	if ((error = fman_get_handle(parent, &sc->sc_fmh)) != 0)
655 		return (error);
656 
657 	if ((error = fman_get_muram_handle(parent, &sc->sc_muramh)) != 0)
658 		return (error);
659 
660 	if ((error = fman_get_bushandle(parent, &sc->sc_fm_base)) != 0)
661 		return (error);
662 
663 	/* Configure working mode */
664 	dtsec_configure_mode(sc);
665 
666 	/* If we are working in regular mode configure BMAN and QMAN */
667 	if (sc->sc_mode == DTSEC_MODE_REGULAR) {
668 		/* Create RX buffer pool */
669 		error = dtsec_rm_pool_rx_init(sc);
670 		if (error != 0)
671 			return (EIO);
672 
673 		/* Create RX frame queue range */
674 		error = dtsec_rm_fqr_rx_init(sc);
675 		if (error != 0)
676 			return (EIO);
677 
678 		/* Create frame info pool */
679 		error = dtsec_rm_fi_pool_init(sc);
680 		if (error != 0)
681 			return (EIO);
682 
683 		/* Create TX frame queue range */
684 		error = dtsec_rm_fqr_tx_init(sc);
685 		if (error != 0)
686 			return (EIO);
687 	}
688 
689 	/* Init FMan MAC module. */
690 	error = dtsec_fm_mac_init(sc, sc->sc_mac_addr);
691 	if (error != 0) {
692 		dtsec_detach(dev);
693 		return (ENXIO);
694 	}
695 
696 	/* Init FMan TX port */
697 	error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev));
698 	if (error != 0) {
699 		dtsec_detach(dev);
700 		return (ENXIO);
701 	}
702 
703 	/* Init FMan RX port */
704 	error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev));
705 	if (error != 0) {
706 		dtsec_detach(dev);
707 		return (ENXIO);
708 	}
709 
710 	/* Create network interface for upper layers */
711 	ifp = sc->sc_ifnet = if_alloc(IFT_ETHER);
712 	if (ifp == NULL) {
713 		device_printf(sc->sc_dev, "if_alloc() failed.\n");
714 		dtsec_detach(dev);
715 		return (ENOMEM);
716 	}
717 
718 	if_setsoftc(ifp, sc);
719 
720 	if_setflags(ifp, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
721 	if_setinitfn(ifp, dtsec_if_init);
722 	if_setstartfn(ifp, dtsec_if_start);
723 	if_setioctlfn(ifp, dtsec_if_ioctl);
724 	if_setsendqlen(ifp, IFQ_MAXLEN);
725 
726 	if (sc->sc_phy_addr >= 0)
727 		if_initname(ifp, device_get_name(sc->sc_dev),
728 		    device_get_unit(sc->sc_dev));
729 	else
730 		if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev));
731 
732 	/* TODO */
733 #if 0
734 	if_setsendqlen(ifp, TSEC_TX_NUM_DESC - 1);
735 	if_setsendqready(ifp);
736 #endif
737 
738 	if_setcapabilities(ifp, IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU);
739 	if_setcapenable(ifp, if_getcapabilities(ifp));
740 
741 	/* Attach PHY(s) */
742 	error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd,
743 	    dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr,
744 	    MII_OFFSET_ANY, 0);
745 	if (error) {
746 		device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error);
747 		dtsec_detach(sc->sc_dev);
748 		return (error);
749 	}
750 	sc->sc_mii = device_get_softc(sc->sc_mii_dev);
751 
752 	/* Attach to stack */
753 	ether_ifattach(ifp, sc->sc_mac_addr);
754 
755 	return (0);
756 }
757 
758 int
759 dtsec_detach(device_t dev)
760 {
761 	struct dtsec_softc *sc;
762 	if_t ifp;
763 
764 	sc = device_get_softc(dev);
765 	ifp = sc->sc_ifnet;
766 
767 	if (device_is_attached(dev)) {
768 		ether_ifdetach(ifp);
769 		/* Shutdown interface */
770 		DTSEC_LOCK(sc);
771 		dtsec_if_deinit_locked(sc);
772 		DTSEC_UNLOCK(sc);
773 	}
774 
775 	if (sc->sc_ifnet) {
776 		if_free(sc->sc_ifnet);
777 		sc->sc_ifnet = NULL;
778 	}
779 
780 	if (sc->sc_mode == DTSEC_MODE_REGULAR) {
781 		/* Free RX/TX FQRs */
782 		dtsec_rm_fqr_rx_free(sc);
783 		dtsec_rm_fqr_tx_free(sc);
784 
785 		/* Free frame info pool */
786 		dtsec_rm_fi_pool_free(sc);
787 
788 		/* Free RX buffer pool */
789 		dtsec_rm_pool_rx_free(sc);
790 	}
791 
792 	dtsec_fm_mac_free(sc);
793 	dtsec_fm_port_free_both(sc);
794 
795 	/* Destroy lock */
796 	mtx_destroy(&sc->sc_lock);
797 
798 	return (0);
799 }
800 
801 int
802 dtsec_suspend(device_t dev)
803 {
804 
805 	return (0);
806 }
807 
808 int
809 dtsec_resume(device_t dev)
810 {
811 
812 	return (0);
813 }
814 
815 int
816 dtsec_shutdown(device_t dev)
817 {
818 
819 	return (0);
820 }
821 /** @} */
822 
823 
824 /**
825  * @group MII bus interface.
826  * @{
827  */
828 int
829 dtsec_miibus_readreg(device_t dev, int phy, int reg)
830 {
831 	struct dtsec_softc *sc;
832 
833 	sc = device_get_softc(dev);
834 
835 	return (MIIBUS_READREG(sc->sc_mdio, phy, reg));
836 }
837 
838 int
839 dtsec_miibus_writereg(device_t dev, int phy, int reg, int value)
840 {
841 
842 	struct dtsec_softc *sc;
843 
844 	sc = device_get_softc(dev);
845 
846 	return (MIIBUS_WRITEREG(sc->sc_mdio, phy, reg, value));
847 }
848 
849 void
850 dtsec_miibus_statchg(device_t dev)
851 {
852 	struct dtsec_softc *sc;
853 	e_EnetSpeed speed;
854 	bool duplex;
855 	int error;
856 
857 	sc = device_get_softc(dev);
858 
859 	DTSEC_LOCK_ASSERT(sc);
860 
861 	duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX);
862 
863 	switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) {
864 	case IFM_1000_T:
865 	case IFM_1000_SX:
866 		speed = e_ENET_SPEED_1000;
867 		break;
868 
869         case IFM_100_TX:
870 		speed = e_ENET_SPEED_100;
871 		break;
872 
873         case IFM_10_T:
874 		speed = e_ENET_SPEED_10;
875 		break;
876 
877 	default:
878 		speed = e_ENET_SPEED_10;
879 	}
880 
881 	error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex);
882 	if (error != E_OK)
883 		device_printf(sc->sc_dev, "error while adjusting MAC speed.\n");
884 }
885 /** @} */
886