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