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