2 * Copyright (c) 2011-2012 Semihalf.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
36 #include <sys/malloc.h>
38 #include <sys/socket.h>
39 #include <sys/sysctl.h>
40 #include <sys/sockio.h>
42 #include <machine/bus.h>
43 #include <machine/resource.h>
45 #include <net/ethernet.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>
52 #include <dev/fdt/fdt_common.h>
53 #include <dev/fdt/simplebus.h>
54 #include <dev/mii/mii.h>
55 #include <dev/mii/miivar.h>
56 #include <dev/ofw/ofw_bus.h>
57 #include <dev/ofw/ofw_bus_subr.h>
58 #include <dev/ofw/openfirm.h>
60 #include "miibus_if.h"
62 #include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
63 #include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
64 #include <contrib/ncsw/inc/xx_ext.h>
68 #include "if_dtsec_im.h"
69 #include "if_dtsec_rm.h"
73 * @group dTSEC private defines.
77 * dTSEC FMan MAC exceptions info struct.
79 struct dtsec_fm_mac_ex_str {
87 * @group FMan MAC routines.
90 #define DTSEC_MAC_EXCEPTIONS_END (-1)
93 * FMan MAC exceptions.
95 static const struct dtsec_fm_mac_ex_str dtsec_fm_mac_exceptions[] = {
96 { e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO, "MDIO scan event" },
97 { e_FM_MAC_EX_10G_MDIO_CMD_CMPL, "MDIO command completion" },
98 { e_FM_MAC_EX_10G_REM_FAULT, "Remote fault" },
99 { e_FM_MAC_EX_10G_LOC_FAULT, "Local fault" },
100 { e_FM_MAC_EX_10G_1TX_ECC_ER, "Transmit frame ECC error" },
101 { e_FM_MAC_EX_10G_TX_FIFO_UNFL, "Transmit FIFO underflow" },
102 { e_FM_MAC_EX_10G_TX_FIFO_OVFL, "Receive FIFO overflow" },
103 { e_FM_MAC_EX_10G_TX_ER, "Transmit frame error" },
104 { e_FM_MAC_EX_10G_RX_FIFO_OVFL, "Receive FIFO overflow" },
105 { e_FM_MAC_EX_10G_RX_ECC_ER, "Receive frame ECC error" },
106 { e_FM_MAC_EX_10G_RX_JAB_FRM, "Receive jabber frame" },
107 { e_FM_MAC_EX_10G_RX_OVRSZ_FRM, "Receive oversized frame" },
108 { e_FM_MAC_EX_10G_RX_RUNT_FRM, "Receive runt frame" },
109 { e_FM_MAC_EX_10G_RX_FRAG_FRM, "Receive fragment frame" },
110 { e_FM_MAC_EX_10G_RX_LEN_ER, "Receive payload length error" },
111 { e_FM_MAC_EX_10G_RX_CRC_ER, "Receive CRC error" },
112 { e_FM_MAC_EX_10G_RX_ALIGN_ER, "Receive alignment error" },
113 { e_FM_MAC_EX_1G_BAB_RX, "Babbling receive error" },
114 { e_FM_MAC_EX_1G_RX_CTL, "Receive control (pause frame) interrupt" },
115 { e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET, "Graceful transmit stop "
117 { e_FM_MAC_EX_1G_BAB_TX, "Babbling transmit error" },
118 { e_FM_MAC_EX_1G_TX_CTL, "Transmit control (pause frame) interrupt" },
119 { e_FM_MAC_EX_1G_TX_ERR, "Transmit error" },
120 { e_FM_MAC_EX_1G_LATE_COL, "Late collision" },
121 { e_FM_MAC_EX_1G_COL_RET_LMT, "Collision retry limit" },
122 { e_FM_MAC_EX_1G_TX_FIFO_UNDRN, "Transmit FIFO underrun" },
123 { e_FM_MAC_EX_1G_MAG_PCKT, "Magic Packet detected when dTSEC is in "
124 "Magic Packet detection mode" },
125 { e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET, "MII management read completion" },
126 { e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET, "MII management write completion" },
127 { e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET, "Graceful receive stop "
129 { e_FM_MAC_EX_1G_TX_DATA_ERR, "Internal data error on transmit" },
130 { e_FM_MAC_EX_1G_RX_DATA_ERR, "Internal data error on receive" },
131 { e_FM_MAC_EX_1G_1588_TS_RX_ERR, "Time-Stamp Receive Error" },
132 { e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, "MIB counter overflow" },
133 { DTSEC_MAC_EXCEPTIONS_END, "" }
137 dtsec_fm_mac_ex_to_str(e_FmMacExceptions exception)
141 for (i = 0; dtsec_fm_mac_exceptions[i].num != exception &&
142 dtsec_fm_mac_exceptions[i].num != DTSEC_MAC_EXCEPTIONS_END; ++i)
145 if (dtsec_fm_mac_exceptions[i].num == DTSEC_MAC_EXCEPTIONS_END)
146 return ("<Unknown Exception>");
148 return (dtsec_fm_mac_exceptions[i].str);
152 dtsec_fm_mac_mdio_event_callback(t_Handle h_App,
153 e_FmMacExceptions exception)
155 struct dtsec_softc *sc;
158 device_printf(sc->sc_dev, "MDIO event %i: %s.\n", exception,
159 dtsec_fm_mac_ex_to_str(exception));
163 dtsec_fm_mac_exception_callback(t_Handle app, e_FmMacExceptions exception)
165 struct dtsec_softc *sc;
168 device_printf(sc->sc_dev, "MAC exception %i: %s.\n", exception,
169 dtsec_fm_mac_ex_to_str(exception));
173 dtsec_fm_mac_free(struct dtsec_softc *sc)
175 if (sc->sc_mach == NULL)
178 FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
179 FM_MAC_Free(sc->sc_mach);
184 dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac)
186 t_FmMacParams params;
189 memset(¶ms, 0, sizeof(params));
190 memcpy(¶ms.addr, mac, sizeof(params.addr));
192 params.baseAddr = sc->sc_fm_base + sc->sc_mac_mem_offset;
193 params.enetMode = sc->sc_mac_enet_mode;
194 params.macId = sc->sc_eth_id;
195 params.mdioIrq = sc->sc_mac_mdio_irq;
196 params.f_Event = dtsec_fm_mac_mdio_event_callback;
197 params.f_Exception = dtsec_fm_mac_exception_callback;
199 params.h_Fm = sc->sc_fmh;
201 sc->sc_mach = FM_MAC_Config(¶ms);
202 if (sc->sc_mach == NULL) {
203 device_printf(sc->sc_dev, "couldn't configure FM_MAC module.\n"
208 error = FM_MAC_ConfigResetOnInit(sc->sc_mach, TRUE);
210 device_printf(sc->sc_dev, "couldn't enable reset on init "
212 dtsec_fm_mac_free(sc);
216 /* Do not inform about pause frames */
217 error = FM_MAC_ConfigException(sc->sc_mach, e_FM_MAC_EX_1G_RX_CTL,
220 device_printf(sc->sc_dev, "couldn't disable pause frames "
222 dtsec_fm_mac_free(sc);
226 error = FM_MAC_Init(sc->sc_mach);
228 device_printf(sc->sc_dev, "couldn't initialize FM_MAC module."
230 dtsec_fm_mac_free(sc);
240 * @group FMan PORT routines.
244 dtsec_fm_port_ex_to_str(e_FmPortExceptions exception)
248 case e_FM_PORT_EXCEPTION_IM_BUSY:
249 return ("IM: RX busy");
251 return ("<Unknown Exception>");
256 dtsec_fm_port_rx_exception_callback(t_Handle app,
257 e_FmPortExceptions exception)
259 struct dtsec_softc *sc;
262 device_printf(sc->sc_dev, "RX exception: %i: %s.\n", exception,
263 dtsec_fm_port_ex_to_str(exception));
267 dtsec_fm_port_tx_exception_callback(t_Handle app,
268 e_FmPortExceptions exception)
270 struct dtsec_softc *sc;
273 device_printf(sc->sc_dev, "TX exception: %i: %s.\n", exception,
274 dtsec_fm_port_ex_to_str(exception));
278 dtsec_fm_port_rx_type(enum eth_dev_type type)
282 return (e_FM_PORT_TYPE_RX);
284 return (e_FM_PORT_TYPE_RX_10G);
286 return (e_FM_PORT_TYPE_DUMMY);
291 dtsec_fm_port_tx_type(enum eth_dev_type type)
296 return (e_FM_PORT_TYPE_TX);
298 return (e_FM_PORT_TYPE_TX_10G);
300 return (e_FM_PORT_TYPE_DUMMY);
305 dtsec_fm_port_free_both(struct dtsec_softc *sc)
308 FM_PORT_Free(sc->sc_rxph);
313 FM_PORT_Free(sc->sc_txph);
321 * @group IFnet routines.
325 dtsec_if_enable_locked(struct dtsec_softc *sc)
329 DTSEC_LOCK_ASSERT(sc);
331 error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
335 error = FM_PORT_Enable(sc->sc_rxph);
339 error = FM_PORT_Enable(sc->sc_txph);
343 sc->sc_ifnet->if_drv_flags |= IFF_DRV_RUNNING;
345 /* Refresh link state */
346 dtsec_miibus_statchg(sc->sc_dev);
352 dtsec_if_disable_locked(struct dtsec_softc *sc)
356 DTSEC_LOCK_ASSERT(sc);
358 error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
362 error = FM_PORT_Disable(sc->sc_rxph);
366 error = FM_PORT_Disable(sc->sc_txph);
370 sc->sc_ifnet->if_drv_flags &= ~IFF_DRV_RUNNING;
376 dtsec_if_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
378 struct dtsec_softc *sc;
383 ifr = (struct ifreq *)data;
386 /* Basic functionality to achieve media status reports */
391 if (sc->sc_ifnet->if_flags & IFF_UP)
392 error = dtsec_if_enable_locked(sc);
394 error = dtsec_if_disable_locked(sc);
401 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media,
406 error = ether_ioctl(ifp, command, data);
413 dtsec_if_tick(void *arg)
415 struct dtsec_softc *sc;
422 mii_tick(sc->sc_mii);
423 callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
429 dtsec_if_deinit_locked(struct dtsec_softc *sc)
432 DTSEC_LOCK_ASSERT(sc);
435 callout_drain(&sc->sc_tick_callout);
440 dtsec_if_init_locked(struct dtsec_softc *sc)
444 DTSEC_LOCK_ASSERT(sc);
446 /* Set MAC address */
447 error = FM_MAC_ModifyMacAddr(sc->sc_mach,
448 (t_EnetAddr *)IF_LLADDR(sc->sc_ifnet));
450 device_printf(sc->sc_dev, "couldn't set MAC address.\n");
454 /* Start MII polling */
456 callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
458 if (sc->sc_ifnet->if_flags & IFF_UP) {
459 error = dtsec_if_enable_locked(sc);
463 error = dtsec_if_disable_locked(sc);
471 dtsec_if_deinit_locked(sc);
472 device_printf(sc->sc_dev, "initialization error.\n");
477 dtsec_if_init(void *data)
479 struct dtsec_softc *sc;
484 dtsec_if_init_locked(sc);
489 dtsec_if_start(struct ifnet *ifp)
491 struct dtsec_softc *sc;
495 sc->sc_start_locked(sc);
500 dtsec_if_watchdog(struct ifnet *ifp)
508 * @group IFmedia routines.
512 dtsec_ifmedia_upd(struct ifnet *ifp)
514 struct dtsec_softc *sc = ifp->if_softc;
517 mii_mediachg(sc->sc_mii);
524 dtsec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
526 struct dtsec_softc *sc = ifp->if_softc;
530 mii_pollstat(sc->sc_mii);
532 ifmr->ifm_active = sc->sc_mii->mii_media_active;
533 ifmr->ifm_status = sc->sc_mii->mii_media_status;
541 * @group dTSEC bus interface.
545 dtsec_configure_mode(struct dtsec_softc *sc)
549 snprintf(tunable, sizeof(tunable), "%s.independent_mode",
550 device_get_nameunit(sc->sc_dev));
552 sc->sc_mode = DTSEC_MODE_REGULAR;
553 TUNABLE_INT_FETCH(tunable, &sc->sc_mode);
555 if (sc->sc_mode == DTSEC_MODE_REGULAR) {
556 sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init;
557 sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init;
558 sc->sc_start_locked = dtsec_rm_if_start_locked;
560 sc->sc_port_rx_init = dtsec_im_fm_port_rx_init;
561 sc->sc_port_tx_init = dtsec_im_fm_port_tx_init;
562 sc->sc_start_locked = dtsec_im_if_start_locked;
565 device_printf(sc->sc_dev, "Configured for %s mode.\n",
566 (sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent");
570 dtsec_attach(device_t dev)
572 struct dtsec_softc *sc;
576 sc = device_get_softc(dev);
579 sc->sc_mac_mdio_irq = NO_IRQ;
580 sc->sc_eth_id = device_get_unit(dev);
583 /* Check if MallocSmart allocator is ready */
584 if (XX_MallocSmartInit() != E_OK)
590 mtx_init(&sc->sc_lock, device_get_nameunit(dev),
591 "DTSEC Global Lock", MTX_DEF);
593 mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev),
594 "DTSEC MII Lock", MTX_DEF);
597 callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE);
599 /* Read configuraton */
600 if ((error = fman_get_handle(&sc->sc_fmh)) != 0)
603 if ((error = fman_get_muram_handle(&sc->sc_muramh)) != 0)
606 if ((error = fman_get_bushandle(&sc->sc_fm_base)) != 0)
609 /* Configure working mode */
610 dtsec_configure_mode(sc);
612 /* If we are working in regular mode configure BMAN and QMAN */
613 if (sc->sc_mode == DTSEC_MODE_REGULAR) {
614 /* Create RX buffer pool */
615 error = dtsec_rm_pool_rx_init(sc);
619 /* Create RX frame queue range */
620 error = dtsec_rm_fqr_rx_init(sc);
624 /* Create frame info pool */
625 error = dtsec_rm_fi_pool_init(sc);
629 /* Create TX frame queue range */
630 error = dtsec_rm_fqr_tx_init(sc);
635 /* Init FMan MAC module. */
636 error = dtsec_fm_mac_init(sc, sc->sc_mac_addr);
642 /* Init FMan TX port */
643 error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev));
649 /* Init FMan RX port */
650 error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev));
656 /* Create network interface for upper layers */
657 ifp = sc->sc_ifnet = if_alloc(IFT_ETHER);
659 device_printf(sc->sc_dev, "if_alloc() failed.\n");
665 ifp->if_mtu = ETHERMTU; /* TODO: Configure */
666 ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST;
667 ifp->if_init = dtsec_if_init;
668 ifp->if_start = dtsec_if_start;
669 ifp->if_ioctl = dtsec_if_ioctl;
670 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
672 if (sc->sc_phy_addr >= 0)
673 if_initname(ifp, device_get_name(sc->sc_dev),
674 device_get_unit(sc->sc_dev));
676 if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev));
680 IFQ_SET_MAXLEN(&ifp->if_snd, TSEC_TX_NUM_DESC - 1);
681 ifp->if_snd.ifq_drv_maxlen = TSEC_TX_NUM_DESC - 1;
682 IFQ_SET_READY(&ifp->if_snd);
684 ifp->if_capabilities = 0; /* TODO: Check */
685 ifp->if_capenable = ifp->if_capabilities;
688 error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd,
689 dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr,
692 device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error);
693 dtsec_detach(sc->sc_dev);
696 sc->sc_mii = device_get_softc(sc->sc_mii_dev);
698 /* Attach to stack */
699 ether_ifattach(ifp, sc->sc_mac_addr);
705 dtsec_detach(device_t dev)
707 struct dtsec_softc *sc;
710 sc = device_get_softc(dev);
713 if (device_is_attached(dev)) {
715 /* Shutdown interface */
717 dtsec_if_deinit_locked(sc);
722 if_free(sc->sc_ifnet);
726 if (sc->sc_mode == DTSEC_MODE_REGULAR) {
727 /* Free RX/TX FQRs */
728 dtsec_rm_fqr_rx_free(sc);
729 dtsec_rm_fqr_tx_free(sc);
731 /* Free frame info pool */
732 dtsec_rm_fi_pool_free(sc);
734 /* Free RX buffer pool */
735 dtsec_rm_pool_rx_free(sc);
738 dtsec_fm_mac_free(sc);
739 dtsec_fm_port_free_both(sc);
742 mtx_destroy(&sc->sc_lock);
748 dtsec_suspend(device_t dev)
755 dtsec_resume(device_t dev)
762 dtsec_shutdown(device_t dev)
771 * @group MII bus interface.
775 dtsec_miibus_readreg(device_t dev, int phy, int reg)
777 struct dtsec_softc *sc;
779 sc = device_get_softc(dev);
781 return (MIIBUS_READREG(sc->sc_mdio, phy, reg));
785 dtsec_miibus_writereg(device_t dev, int phy, int reg, int value)
788 struct dtsec_softc *sc;
790 sc = device_get_softc(dev);
792 return (MIIBUS_WRITEREG(sc->sc_mdio, phy, reg, value));
796 dtsec_miibus_statchg(device_t dev)
798 struct dtsec_softc *sc;
803 sc = device_get_softc(dev);
805 DTSEC_LOCK_ASSERT(sc);
807 duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX);
809 switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) {
812 speed = e_ENET_SPEED_1000;
816 speed = e_ENET_SPEED_100;
820 speed = e_ENET_SPEED_10;
824 speed = e_ENET_SPEED_10;
827 error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex);
829 device_printf(sc->sc_dev, "error while adjusting MAC speed.\n");