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