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