xref: /freebsd/sys/dev/dpaa/if_dtsec.c (revision 6966ac055c3b7a39266fb982493330df7a097997)
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 #define	DTSEC_MIN_FRAME_SIZE	64
71 #define	DTSEC_MAX_FRAME_SIZE	9600
72 
73 #define	DTSEC_REG_MAXFRM	0x110
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 int
344 dtsec_if_enable_locked(struct dtsec_softc *sc)
345 {
346 	int error;
347 
348 	DTSEC_LOCK_ASSERT(sc);
349 
350 	error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
351 	if (error != E_OK)
352 		return (EIO);
353 
354 	error = FM_PORT_Enable(sc->sc_rxph);
355 	if (error != E_OK)
356 		return (EIO);
357 
358 	error = FM_PORT_Enable(sc->sc_txph);
359 	if (error != E_OK)
360 		return (EIO);
361 
362 	sc->sc_ifnet->if_drv_flags |= IFF_DRV_RUNNING;
363 
364 	/* Refresh link state */
365 	dtsec_miibus_statchg(sc->sc_dev);
366 
367 	return (0);
368 }
369 
370 static int
371 dtsec_if_disable_locked(struct dtsec_softc *sc)
372 {
373 	int error;
374 
375 	DTSEC_LOCK_ASSERT(sc);
376 
377 	error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
378 	if (error != E_OK)
379 		return (EIO);
380 
381 	error = FM_PORT_Disable(sc->sc_rxph);
382 	if (error != E_OK)
383 		return (EIO);
384 
385 	error = FM_PORT_Disable(sc->sc_txph);
386 	if (error != E_OK)
387 		return (EIO);
388 
389 	sc->sc_ifnet->if_drv_flags &= ~IFF_DRV_RUNNING;
390 
391 	return (0);
392 }
393 
394 static int
395 dtsec_if_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
396 {
397 	struct dtsec_softc *sc;
398 	struct ifreq *ifr;
399 	int error;
400 
401 	sc = ifp->if_softc;
402 	ifr = (struct ifreq *)data;
403 	error = 0;
404 
405 	/* Basic functionality to achieve media status reports */
406 	switch (command) {
407 	case SIOCSIFMTU:
408 		DTSEC_LOCK(sc);
409 		if (dtsec_set_mtu(sc, ifr->ifr_mtu))
410 			ifp->if_mtu = ifr->ifr_mtu;
411 		else
412 			error = EINVAL;
413 		DTSEC_UNLOCK(sc);
414 		break;
415 	case SIOCSIFFLAGS:
416 		DTSEC_LOCK(sc);
417 
418 		if (sc->sc_ifnet->if_flags & IFF_UP)
419 			error = dtsec_if_enable_locked(sc);
420 		else
421 			error = dtsec_if_disable_locked(sc);
422 
423 		DTSEC_UNLOCK(sc);
424 		break;
425 
426 	case SIOCGIFMEDIA:
427 	case SIOCSIFMEDIA:
428 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media,
429 		    command);
430 		break;
431 
432 	default:
433 		error = ether_ioctl(ifp, command, data);
434 	}
435 
436 	return (error);
437 }
438 
439 static void
440 dtsec_if_tick(void *arg)
441 {
442 	struct dtsec_softc *sc;
443 
444 	sc = arg;
445 
446 	/* TODO */
447 	DTSEC_LOCK(sc);
448 
449 	mii_tick(sc->sc_mii);
450 	callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
451 
452 	DTSEC_UNLOCK(sc);
453 }
454 
455 static void
456 dtsec_if_deinit_locked(struct dtsec_softc *sc)
457 {
458 
459 	DTSEC_LOCK_ASSERT(sc);
460 
461 	DTSEC_UNLOCK(sc);
462 	callout_drain(&sc->sc_tick_callout);
463 	DTSEC_LOCK(sc);
464 }
465 
466 static void
467 dtsec_if_init_locked(struct dtsec_softc *sc)
468 {
469 	int error;
470 
471 	DTSEC_LOCK_ASSERT(sc);
472 
473 	/* Set MAC address */
474 	error = FM_MAC_ModifyMacAddr(sc->sc_mach,
475 	    (t_EnetAddr *)IF_LLADDR(sc->sc_ifnet));
476 	if (error != E_OK) {
477 		device_printf(sc->sc_dev, "couldn't set MAC address.\n");
478 		goto err;
479 	}
480 
481 	/* Start MII polling */
482 	if (sc->sc_mii)
483 		callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
484 
485 	if (sc->sc_ifnet->if_flags & IFF_UP) {
486 		error = dtsec_if_enable_locked(sc);
487 		if (error != 0)
488 			goto err;
489 	} else {
490 		error = dtsec_if_disable_locked(sc);
491 		if (error != 0)
492 			goto err;
493 	}
494 
495 	return;
496 
497 err:
498 	dtsec_if_deinit_locked(sc);
499 	device_printf(sc->sc_dev, "initialization error.\n");
500 	return;
501 }
502 
503 static void
504 dtsec_if_init(void *data)
505 {
506 	struct dtsec_softc *sc;
507 
508 	sc = data;
509 
510 	DTSEC_LOCK(sc);
511 	dtsec_if_init_locked(sc);
512 	DTSEC_UNLOCK(sc);
513 }
514 
515 static void
516 dtsec_if_start(struct ifnet *ifp)
517 {
518 	struct dtsec_softc *sc;
519 
520 	sc = ifp->if_softc;
521 	DTSEC_LOCK(sc);
522 	sc->sc_start_locked(sc);
523 	DTSEC_UNLOCK(sc);
524 }
525 
526 static void
527 dtsec_if_watchdog(struct ifnet *ifp)
528 {
529 	/* TODO */
530 }
531 /** @} */
532 
533 
534 /**
535  * @group IFmedia routines.
536  * @{
537  */
538 static int
539 dtsec_ifmedia_upd(struct ifnet *ifp)
540 {
541 	struct dtsec_softc *sc = ifp->if_softc;
542 
543 	DTSEC_LOCK(sc);
544 	mii_mediachg(sc->sc_mii);
545 	DTSEC_UNLOCK(sc);
546 
547 	return (0);
548 }
549 
550 static void
551 dtsec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
552 {
553 	struct dtsec_softc *sc = ifp->if_softc;
554 
555 	DTSEC_LOCK(sc);
556 
557 	mii_pollstat(sc->sc_mii);
558 
559 	ifmr->ifm_active = sc->sc_mii->mii_media_active;
560 	ifmr->ifm_status = sc->sc_mii->mii_media_status;
561 
562 	DTSEC_UNLOCK(sc);
563 }
564 /** @} */
565 
566 
567 /**
568  * @group dTSEC bus interface.
569  * @{
570  */
571 static void
572 dtsec_configure_mode(struct dtsec_softc *sc)
573 {
574 	char tunable[64];
575 
576 	snprintf(tunable, sizeof(tunable), "%s.independent_mode",
577 	    device_get_nameunit(sc->sc_dev));
578 
579 	sc->sc_mode = DTSEC_MODE_REGULAR;
580 	TUNABLE_INT_FETCH(tunable, &sc->sc_mode);
581 
582 	if (sc->sc_mode == DTSEC_MODE_REGULAR) {
583 		sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init;
584 		sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init;
585 		sc->sc_start_locked = dtsec_rm_if_start_locked;
586 	} else {
587 		sc->sc_port_rx_init = dtsec_im_fm_port_rx_init;
588 		sc->sc_port_tx_init = dtsec_im_fm_port_tx_init;
589 		sc->sc_start_locked = dtsec_im_if_start_locked;
590 	}
591 
592 	device_printf(sc->sc_dev, "Configured for %s mode.\n",
593 	    (sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent");
594 }
595 
596 int
597 dtsec_attach(device_t dev)
598 {
599 	struct dtsec_softc *sc;
600 	device_t parent;
601 	int error;
602 	struct ifnet *ifp;
603 
604 	sc = device_get_softc(dev);
605 
606 	parent = device_get_parent(dev);
607 	sc->sc_dev = dev;
608 	sc->sc_mac_mdio_irq = NO_IRQ;
609 
610 	/* Check if MallocSmart allocator is ready */
611 	if (XX_MallocSmartInit() != E_OK)
612 		return (ENXIO);
613 
614 	/* Init locks */
615 	mtx_init(&sc->sc_lock, device_get_nameunit(dev),
616 	    "DTSEC Global Lock", MTX_DEF);
617 
618 	mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev),
619 	    "DTSEC MII Lock", MTX_DEF);
620 
621 	/* Init callouts */
622 	callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE);
623 
624 	/* Read configuraton */
625 	if ((error = fman_get_handle(parent, &sc->sc_fmh)) != 0)
626 		return (error);
627 
628 	if ((error = fman_get_muram_handle(parent, &sc->sc_muramh)) != 0)
629 		return (error);
630 
631 	if ((error = fman_get_bushandle(parent, &sc->sc_fm_base)) != 0)
632 		return (error);
633 
634 	/* Configure working mode */
635 	dtsec_configure_mode(sc);
636 
637 	/* If we are working in regular mode configure BMAN and QMAN */
638 	if (sc->sc_mode == DTSEC_MODE_REGULAR) {
639 		/* Create RX buffer pool */
640 		error = dtsec_rm_pool_rx_init(sc);
641 		if (error != 0)
642 			return (EIO);
643 
644 		/* Create RX frame queue range */
645 		error = dtsec_rm_fqr_rx_init(sc);
646 		if (error != 0)
647 			return (EIO);
648 
649 		/* Create frame info pool */
650 		error = dtsec_rm_fi_pool_init(sc);
651 		if (error != 0)
652 			return (EIO);
653 
654 		/* Create TX frame queue range */
655 		error = dtsec_rm_fqr_tx_init(sc);
656 		if (error != 0)
657 			return (EIO);
658 	}
659 
660 	/* Init FMan MAC module. */
661 	error = dtsec_fm_mac_init(sc, sc->sc_mac_addr);
662 	if (error != 0) {
663 		dtsec_detach(dev);
664 		return (ENXIO);
665 	}
666 
667 	/* Init FMan TX port */
668 	error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev));
669 	if (error != 0) {
670 		dtsec_detach(dev);
671 		return (ENXIO);
672 	}
673 
674 	/* Init FMan RX port */
675 	error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev));
676 	if (error != 0) {
677 		dtsec_detach(dev);
678 		return (ENXIO);
679 	}
680 
681 	/* Create network interface for upper layers */
682 	ifp = sc->sc_ifnet = if_alloc(IFT_ETHER);
683 	if (ifp == NULL) {
684 		device_printf(sc->sc_dev, "if_alloc() failed.\n");
685 		dtsec_detach(dev);
686 		return (ENOMEM);
687 	}
688 
689 	ifp->if_softc = sc;
690 	ifp->if_mtu = ETHERMTU;	/* TODO: Configure */
691 	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_NEEDSEPOCH;
692 	ifp->if_init = dtsec_if_init;
693 	ifp->if_start = dtsec_if_start;
694 	ifp->if_ioctl = dtsec_if_ioctl;
695 	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
696 
697 	if (sc->sc_phy_addr >= 0)
698 		if_initname(ifp, device_get_name(sc->sc_dev),
699 		    device_get_unit(sc->sc_dev));
700 	else
701 		if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev));
702 
703 	/* TODO */
704 #if 0
705 	IFQ_SET_MAXLEN(&ifp->if_snd, TSEC_TX_NUM_DESC - 1);
706 	ifp->if_snd.ifq_drv_maxlen = TSEC_TX_NUM_DESC - 1;
707 	IFQ_SET_READY(&ifp->if_snd);
708 #endif
709 	ifp->if_capabilities = IFCAP_JUMBO_MTU; /* TODO: HWCSUM */
710 	ifp->if_capenable = ifp->if_capabilities;
711 
712 	/* Attach PHY(s) */
713 	error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd,
714 	    dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr,
715 	    MII_OFFSET_ANY, 0);
716 	if (error) {
717 		device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error);
718 		dtsec_detach(sc->sc_dev);
719 		return (error);
720 	}
721 	sc->sc_mii = device_get_softc(sc->sc_mii_dev);
722 
723 	/* Attach to stack */
724 	ether_ifattach(ifp, sc->sc_mac_addr);
725 
726 	return (0);
727 }
728 
729 int
730 dtsec_detach(device_t dev)
731 {
732 	struct dtsec_softc *sc;
733 	if_t ifp;
734 
735 	sc = device_get_softc(dev);
736 	ifp = sc->sc_ifnet;
737 
738 	if (device_is_attached(dev)) {
739 		ether_ifdetach(ifp);
740 		/* Shutdown interface */
741 		DTSEC_LOCK(sc);
742 		dtsec_if_deinit_locked(sc);
743 		DTSEC_UNLOCK(sc);
744 	}
745 
746 	if (sc->sc_ifnet) {
747 		if_free(sc->sc_ifnet);
748 		sc->sc_ifnet = NULL;
749 	}
750 
751 	if (sc->sc_mode == DTSEC_MODE_REGULAR) {
752 		/* Free RX/TX FQRs */
753 		dtsec_rm_fqr_rx_free(sc);
754 		dtsec_rm_fqr_tx_free(sc);
755 
756 		/* Free frame info pool */
757 		dtsec_rm_fi_pool_free(sc);
758 
759 		/* Free RX buffer pool */
760 		dtsec_rm_pool_rx_free(sc);
761 	}
762 
763 	dtsec_fm_mac_free(sc);
764 	dtsec_fm_port_free_both(sc);
765 
766 	/* Destroy lock */
767 	mtx_destroy(&sc->sc_lock);
768 
769 	return (0);
770 }
771 
772 int
773 dtsec_suspend(device_t dev)
774 {
775 
776 	return (0);
777 }
778 
779 int
780 dtsec_resume(device_t dev)
781 {
782 
783 	return (0);
784 }
785 
786 int
787 dtsec_shutdown(device_t dev)
788 {
789 
790 	return (0);
791 }
792 /** @} */
793 
794 
795 /**
796  * @group MII bus interface.
797  * @{
798  */
799 int
800 dtsec_miibus_readreg(device_t dev, int phy, int reg)
801 {
802 	struct dtsec_softc *sc;
803 
804 	sc = device_get_softc(dev);
805 
806 	return (MIIBUS_READREG(sc->sc_mdio, phy, reg));
807 }
808 
809 int
810 dtsec_miibus_writereg(device_t dev, int phy, int reg, int value)
811 {
812 
813 	struct dtsec_softc *sc;
814 
815 	sc = device_get_softc(dev);
816 
817 	return (MIIBUS_WRITEREG(sc->sc_mdio, phy, reg, value));
818 }
819 
820 void
821 dtsec_miibus_statchg(device_t dev)
822 {
823 	struct dtsec_softc *sc;
824 	e_EnetSpeed speed;
825 	bool duplex;
826 	int error;
827 
828 	sc = device_get_softc(dev);
829 
830 	DTSEC_LOCK_ASSERT(sc);
831 
832 	duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX);
833 
834 	switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) {
835 	case IFM_1000_T:
836 	case IFM_1000_SX:
837 		speed = e_ENET_SPEED_1000;
838 		break;
839 
840         case IFM_100_TX:
841 		speed = e_ENET_SPEED_100;
842 		break;
843 
844         case IFM_10_T:
845 		speed = e_ENET_SPEED_10;
846 		break;
847 
848 	default:
849 		speed = e_ENET_SPEED_10;
850 	}
851 
852 	error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex);
853 	if (error != E_OK)
854 		device_printf(sc->sc_dev, "error while adjusting MAC speed.\n");
855 }
856 /** @} */
857