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