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