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 */
81struct 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 */
97static 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
138static const char *
139dtsec_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
153static void
154dtsec_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
164static void
165dtsec_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
174static void
175dtsec_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
185static int
186dtsec_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 */
245static const char *
246dtsec_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
257void
258dtsec_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
268void
269dtsec_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
279e_FmPortType
280dtsec_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
292e_FmPortType
293dtsec_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
306static void
307dtsec_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 */
326static int
327dtsec_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
342static u_int
343dtsec_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
352static void
353dtsec_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
369static int
370dtsec_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
398static int
399dtsec_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
422static int
423dtsec_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
467static void
468dtsec_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
483static void
484dtsec_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
494static void
495dtsec_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
525err:
526	dtsec_if_deinit_locked(sc);
527	device_printf(sc->sc_dev, "initialization error.\n");
528	return;
529}
530
531static void
532dtsec_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
543static void
544dtsec_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
554static void
555dtsec_if_watchdog(if_t ifp)
556{
557	/* TODO */
558}
559/** @} */
560
561
562/**
563 * @group IFmedia routines.
564 * @{
565 */
566static int
567dtsec_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
578static void
579dtsec_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 */
599static void
600dtsec_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
624int
625dtsec_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
757int
758dtsec_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
800int
801dtsec_suspend(device_t dev)
802{
803
804	return (0);
805}
806
807int
808dtsec_resume(device_t dev)
809{
810
811	return (0);
812}
813
814int
815dtsec_shutdown(device_t dev)
816{
817
818	return (0);
819}
820/** @} */
821
822
823/**
824 * @group MII bus interface.
825 * @{
826 */
827int
828dtsec_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
837int
838dtsec_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
848void
849dtsec_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