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