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 *
dtsec_fm_mac_ex_to_str(e_FmMacExceptions exception)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
dtsec_fm_mac_mdio_event_callback(t_Handle h_App,e_FmMacExceptions exception)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
dtsec_fm_mac_exception_callback(t_Handle app,e_FmMacExceptions exception)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
dtsec_fm_mac_free(struct dtsec_softc * sc)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
dtsec_fm_mac_init(struct dtsec_softc * sc,uint8_t * mac)190 dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac)
191 {
192 t_FmMacParams params;
193 t_Error error;
194
195 memset(¶ms, 0, sizeof(params));
196 memcpy(¶ms.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(¶ms);
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 *
dtsec_fm_port_ex_to_str(e_FmPortExceptions exception)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
dtsec_fm_port_rx_exception_callback(t_Handle app,e_FmPortExceptions exception)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
dtsec_fm_port_tx_exception_callback(t_Handle app,e_FmPortExceptions exception)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
dtsec_fm_port_rx_type(enum eth_dev_type type)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
dtsec_fm_port_tx_type(enum eth_dev_type type)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
dtsec_fm_port_free_both(struct dtsec_softc * sc)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
dtsec_if_enable_locked(struct dtsec_softc * sc)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
dtsec_if_disable_locked(struct dtsec_softc * sc)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
dtsec_if_ioctl(struct ifnet * ifp,u_long command,caddr_t data)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
dtsec_if_tick(void * arg)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
dtsec_if_deinit_locked(struct dtsec_softc * sc)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
dtsec_if_init_locked(struct dtsec_softc * sc)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
dtsec_if_init(void * data)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
dtsec_if_start(struct ifnet * ifp)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
dtsec_if_watchdog(struct ifnet * ifp)508 dtsec_if_watchdog(struct ifnet *ifp)
509 {
510 /* TODO */
511 }
512 /** @} */
513
514
515 /**
516 * @group IFmedia routines.
517 * @{
518 */
519 static int
dtsec_ifmedia_upd(struct ifnet * ifp)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
dtsec_ifmedia_sts(struct ifnet * ifp,struct ifmediareq * ifmr)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
dtsec_configure_mode(struct dtsec_softc * sc)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
dtsec_attach(device_t dev)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
dtsec_detach(device_t dev)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
dtsec_suspend(device_t dev)770 dtsec_suspend(device_t dev)
771 {
772
773 return (0);
774 }
775
776 int
dtsec_resume(device_t dev)777 dtsec_resume(device_t dev)
778 {
779
780 return (0);
781 }
782
783 int
dtsec_shutdown(device_t dev)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
dtsec_miibus_readreg(device_t dev,int phy,int reg)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
dtsec_miibus_writereg(device_t dev,int phy,int reg,int value)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
dtsec_miibus_statchg(device_t dev)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 /** @} */
880