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