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