]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/dpaa/if_dtsec.c
More cleanup in response queue and reset code.
[FreeBSD/FreeBSD.git] / sys / dev / dpaa / if_dtsec.c
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;
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 /** @} */