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