19f55f5f5SRafal Jaworowski /*-
27282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni *
49f55f5f5SRafal Jaworowski * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
53c71b84fSZbigniew Bodek * Copyright (C) 2009-2015 Semihalf
63c71b84fSZbigniew Bodek * Copyright (C) 2015 Stormshield
79f55f5f5SRafal Jaworowski * All rights reserved.
89f55f5f5SRafal Jaworowski *
99f55f5f5SRafal Jaworowski * Developed by Semihalf.
109f55f5f5SRafal Jaworowski *
119f55f5f5SRafal Jaworowski * Redistribution and use in source and binary forms, with or without
129f55f5f5SRafal Jaworowski * modification, are permitted provided that the following conditions
139f55f5f5SRafal Jaworowski * are met:
149f55f5f5SRafal Jaworowski * 1. Redistributions of source code must retain the above copyright
159f55f5f5SRafal Jaworowski * notice, this list of conditions and the following disclaimer.
169f55f5f5SRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright
179f55f5f5SRafal Jaworowski * notice, this list of conditions and the following disclaimer in the
189f55f5f5SRafal Jaworowski * documentation and/or other materials provided with the distribution.
199f55f5f5SRafal Jaworowski * 3. Neither the name of MARVELL nor the names of contributors
209f55f5f5SRafal Jaworowski * may be used to endorse or promote products derived from this software
219f55f5f5SRafal Jaworowski * without specific prior written permission.
229f55f5f5SRafal Jaworowski *
239f55f5f5SRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
249f55f5f5SRafal Jaworowski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
259f55f5f5SRafal Jaworowski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
269f55f5f5SRafal Jaworowski * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
279f55f5f5SRafal Jaworowski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
289f55f5f5SRafal Jaworowski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
299f55f5f5SRafal Jaworowski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
309f55f5f5SRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
319f55f5f5SRafal Jaworowski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
329f55f5f5SRafal Jaworowski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
339f55f5f5SRafal Jaworowski * SUCH DAMAGE.
349f55f5f5SRafal Jaworowski */
359f55f5f5SRafal Jaworowski
369f55f5f5SRafal Jaworowski #ifdef HAVE_KERNEL_OPTION_HEADERS
379f55f5f5SRafal Jaworowski #include "opt_device_polling.h"
389f55f5f5SRafal Jaworowski #endif
399f55f5f5SRafal Jaworowski
409f55f5f5SRafal Jaworowski #include <sys/param.h>
419f55f5f5SRafal Jaworowski #include <sys/systm.h>
429f55f5f5SRafal Jaworowski #include <sys/endian.h>
439f55f5f5SRafal Jaworowski #include <sys/mbuf.h>
449f55f5f5SRafal Jaworowski #include <sys/lock.h>
459f55f5f5SRafal Jaworowski #include <sys/mutex.h>
469f55f5f5SRafal Jaworowski #include <sys/kernel.h>
479f55f5f5SRafal Jaworowski #include <sys/module.h>
489f55f5f5SRafal Jaworowski #include <sys/socket.h>
499f55f5f5SRafal Jaworowski #include <sys/sysctl.h>
509f55f5f5SRafal Jaworowski
519f55f5f5SRafal Jaworowski #include <net/ethernet.h>
529f55f5f5SRafal Jaworowski #include <net/bpf.h>
539f55f5f5SRafal Jaworowski #include <net/if.h>
549f55f5f5SRafal Jaworowski #include <net/if_arp.h>
559f55f5f5SRafal Jaworowski #include <net/if_dl.h>
569f55f5f5SRafal Jaworowski #include <net/if_media.h>
579f55f5f5SRafal Jaworowski #include <net/if_types.h>
589f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h>
599f55f5f5SRafal Jaworowski
609f55f5f5SRafal Jaworowski #include <netinet/in_systm.h>
619f55f5f5SRafal Jaworowski #include <netinet/in.h>
629f55f5f5SRafal Jaworowski #include <netinet/ip.h>
639f55f5f5SRafal Jaworowski
649f55f5f5SRafal Jaworowski #include <sys/sockio.h>
659f55f5f5SRafal Jaworowski #include <sys/bus.h>
669f55f5f5SRafal Jaworowski #include <machine/bus.h>
679f55f5f5SRafal Jaworowski #include <sys/rman.h>
689f55f5f5SRafal Jaworowski #include <machine/resource.h>
699f55f5f5SRafal Jaworowski
709f55f5f5SRafal Jaworowski #include <dev/mii/mii.h>
719f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h>
729f55f5f5SRafal Jaworowski
73db5ef4fcSRafal Jaworowski #include <dev/fdt/fdt_common.h>
74db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h>
75db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
7671e8eac4SAdrian Chadd #include <dev/mdio/mdio.h>
779f55f5f5SRafal Jaworowski
789f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h>
799f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h>
808e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h>
819f55f5f5SRafal Jaworowski
829f55f5f5SRafal Jaworowski #include "miibus_if.h"
833c71b84fSZbigniew Bodek #include "mdio_if.h"
843c71b84fSZbigniew Bodek
853c71b84fSZbigniew Bodek #define MGE_DELAY(x) pause("SMI access sleep", (x) / tick_sbt)
869f55f5f5SRafal Jaworowski
879f55f5f5SRafal Jaworowski static int mge_probe(device_t dev);
889f55f5f5SRafal Jaworowski static int mge_attach(device_t dev);
899f55f5f5SRafal Jaworowski static int mge_detach(device_t dev);
909f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev);
919f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev);
929f55f5f5SRafal Jaworowski static int mge_resume(device_t dev);
939f55f5f5SRafal Jaworowski
949f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg);
958e45f0b7SAndriy Gapon static int mge_miibus_writereg(device_t dev, int phy, int reg, int value);
969f55f5f5SRafal Jaworowski
973c71b84fSZbigniew Bodek static int mge_mdio_readreg(device_t dev, int phy, int reg);
983c71b84fSZbigniew Bodek static int mge_mdio_writereg(device_t dev, int phy, int reg, int value);
993c71b84fSZbigniew Bodek
10098fe10c8SJustin Hibbits static int mge_ifmedia_upd(if_t ifp);
10198fe10c8SJustin Hibbits static void mge_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr);
1029f55f5f5SRafal Jaworowski
1039f55f5f5SRafal Jaworowski static void mge_init(void *arg);
1049f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg);
10598fe10c8SJustin Hibbits static void mge_start(if_t ifp);
10698fe10c8SJustin Hibbits static void mge_start_locked(if_t ifp);
1079f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc);
10898fe10c8SJustin Hibbits static int mge_ioctl(if_t ifp, u_long command, caddr_t data);
1099f55f5f5SRafal Jaworowski
1108e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver);
1118e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver);
1128e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc);
1138e1dc58eSRafal Jaworowski
1149f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable);
11575f1438bSOleksandr Tymoshenko static void mge_intr_rxtx(void *arg);
1169f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg);
11775f1438bSOleksandr Tymoshenko static void mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
11875f1438bSOleksandr Tymoshenko uint32_t int_cause_ext);
1191abcdbd1SAttilio Rao static int mge_intr_rx_locked(struct mge_softc *sc, int count);
1209f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg);
1219f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc);
1229f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg);
1239f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg);
1249f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg);
1259f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc);
1269f55f5f5SRafal Jaworowski static void mge_tick(void *msc);
1279f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media);
1289f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr);
1299f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc);
1309f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte,
1319f55f5f5SRafal Jaworowski uint8_t queue);
1329f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue);
1339f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc);
1349f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc,
1354ac30cc1SZbigniew Bodek struct mge_desc_wrapper* desc_tab, uint32_t size,
1364ac30cc1SZbigniew Bodek bus_dma_tag_t *buffer_tag);
1379f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map,
1389f55f5f5SRafal Jaworowski struct mbuf **mbufp, bus_addr_t *paddr);
1394ac30cc1SZbigniew Bodek static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg,
1404ac30cc1SZbigniew Bodek int error);
1419f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc);
1424ac30cc1SZbigniew Bodek static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
1434ac30cc1SZbigniew Bodek uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs);
14498fe10c8SJustin Hibbits static void mge_offload_process_frame(if_t ifp, struct mbuf *frame,
1459f55f5f5SRafal Jaworowski uint32_t status, uint16_t bufsize);
1469f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc,
1479f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw);
1489f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size);
1499f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc);
1509f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc);
1519f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc);
1529f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc);
1539f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS);
1549f55f5f5SRafal Jaworowski
1559f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = {
1569f55f5f5SRafal Jaworowski /* Device interface */
1579f55f5f5SRafal Jaworowski DEVMETHOD(device_probe, mge_probe),
1589f55f5f5SRafal Jaworowski DEVMETHOD(device_attach, mge_attach),
1599f55f5f5SRafal Jaworowski DEVMETHOD(device_detach, mge_detach),
1609f55f5f5SRafal Jaworowski DEVMETHOD(device_shutdown, mge_shutdown),
1619f55f5f5SRafal Jaworowski DEVMETHOD(device_suspend, mge_suspend),
1629f55f5f5SRafal Jaworowski DEVMETHOD(device_resume, mge_resume),
1639f55f5f5SRafal Jaworowski /* MII interface */
1649f55f5f5SRafal Jaworowski DEVMETHOD(miibus_readreg, mge_miibus_readreg),
1659f55f5f5SRafal Jaworowski DEVMETHOD(miibus_writereg, mge_miibus_writereg),
1663c71b84fSZbigniew Bodek /* MDIO interface */
1673c71b84fSZbigniew Bodek DEVMETHOD(mdio_readreg, mge_mdio_readreg),
1683c71b84fSZbigniew Bodek DEVMETHOD(mdio_writereg, mge_mdio_writereg),
1699f55f5f5SRafal Jaworowski { 0, 0 }
1709f55f5f5SRafal Jaworowski };
1719f55f5f5SRafal Jaworowski
1723c71b84fSZbigniew Bodek DEFINE_CLASS_0(mge, mge_driver, mge_methods, sizeof(struct mge_softc));
1739f55f5f5SRafal Jaworowski
1743c71b84fSZbigniew Bodek static int switch_attached = 0;
1759f55f5f5SRafal Jaworowski
1768059bf7bSJohn Baldwin DRIVER_MODULE(mge, simplebus, mge_driver, 0, 0);
1773e38757dSJohn Baldwin DRIVER_MODULE(miibus, mge, miibus_driver, 0, 0);
1788933f7d6SJohn Baldwin DRIVER_MODULE(mdio, mge, mdio_driver, 0, 0);
1799f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1);
1809f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1);
1813c71b84fSZbigniew Bodek MODULE_DEPEND(mge, mdio, 1, 1, 1);
1829f55f5f5SRafal Jaworowski
1839f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = {
1849f55f5f5SRafal Jaworowski { SYS_RES_MEMORY, 0, RF_ACTIVE },
1859f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
1869f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
1879f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
1889f55f5f5SRafal Jaworowski { -1, 0 }
1899f55f5f5SRafal Jaworowski };
1909f55f5f5SRafal Jaworowski
1919f55f5f5SRafal Jaworowski static struct {
1929f55f5f5SRafal Jaworowski driver_intr_t *handler;
1939f55f5f5SRafal Jaworowski char * description;
19475f1438bSOleksandr Tymoshenko } mge_intrs[MGE_INTR_COUNT + 1] = {
19575f1438bSOleksandr Tymoshenko { mge_intr_rxtx,"GbE aggregated interrupt" },
1969f55f5f5SRafal Jaworowski { mge_intr_rx, "GbE receive interrupt" },
1979f55f5f5SRafal Jaworowski { mge_intr_tx, "GbE transmit interrupt" },
1989f55f5f5SRafal Jaworowski { mge_intr_misc,"GbE misc interrupt" },
1999f55f5f5SRafal Jaworowski { mge_intr_sum, "GbE summary interrupt" },
2009f55f5f5SRafal Jaworowski { mge_intr_err, "GbE error interrupt" },
2019f55f5f5SRafal Jaworowski };
2029f55f5f5SRafal Jaworowski
2033c71b84fSZbigniew Bodek /* SMI access interlock */
2043c71b84fSZbigniew Bodek static struct sx sx_smi;
2053c71b84fSZbigniew Bodek
2063c71b84fSZbigniew Bodek static uint32_t
mv_read_ge_smi(device_t dev,int phy,int reg)2073c71b84fSZbigniew Bodek mv_read_ge_smi(device_t dev, int phy, int reg)
2083c71b84fSZbigniew Bodek {
2093c71b84fSZbigniew Bodek uint32_t timeout;
2103c71b84fSZbigniew Bodek uint32_t ret;
2113c71b84fSZbigniew Bodek struct mge_softc *sc;
2123c71b84fSZbigniew Bodek
2133c71b84fSZbigniew Bodek sc = device_get_softc(dev);
2143c71b84fSZbigniew Bodek KASSERT(sc != NULL, ("NULL softc ptr!"));
2153c71b84fSZbigniew Bodek timeout = MGE_SMI_WRITE_RETRIES;
2163c71b84fSZbigniew Bodek
2173c71b84fSZbigniew Bodek MGE_SMI_LOCK();
2183c71b84fSZbigniew Bodek while (--timeout &&
2193c71b84fSZbigniew Bodek (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
2203c71b84fSZbigniew Bodek MGE_DELAY(MGE_SMI_WRITE_DELAY);
2213c71b84fSZbigniew Bodek
2223c71b84fSZbigniew Bodek if (timeout == 0) {
2233c71b84fSZbigniew Bodek device_printf(dev, "SMI write timeout.\n");
2243c71b84fSZbigniew Bodek ret = ~0U;
2253c71b84fSZbigniew Bodek goto out;
2263c71b84fSZbigniew Bodek }
2273c71b84fSZbigniew Bodek
2283c71b84fSZbigniew Bodek MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
2293c71b84fSZbigniew Bodek (MGE_SMI_READ | (reg << 21) | (phy << 16)));
2303c71b84fSZbigniew Bodek
2313c71b84fSZbigniew Bodek /* Wait till finished. */
2323c71b84fSZbigniew Bodek timeout = MGE_SMI_WRITE_RETRIES;
2333c71b84fSZbigniew Bodek while (--timeout &&
2343c71b84fSZbigniew Bodek !((MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_READVALID)))
2353c71b84fSZbigniew Bodek MGE_DELAY(MGE_SMI_WRITE_DELAY);
2363c71b84fSZbigniew Bodek
2373c71b84fSZbigniew Bodek if (timeout == 0) {
2383c71b84fSZbigniew Bodek device_printf(dev, "SMI write validation timeout.\n");
2393c71b84fSZbigniew Bodek ret = ~0U;
2403c71b84fSZbigniew Bodek goto out;
2413c71b84fSZbigniew Bodek }
2423c71b84fSZbigniew Bodek
2433c71b84fSZbigniew Bodek /* Wait for the data to update in the SMI register */
2443c71b84fSZbigniew Bodek MGE_DELAY(MGE_SMI_DELAY);
2453c71b84fSZbigniew Bodek ret = MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
2463c71b84fSZbigniew Bodek
2473c71b84fSZbigniew Bodek out:
2483c71b84fSZbigniew Bodek MGE_SMI_UNLOCK();
2493c71b84fSZbigniew Bodek return (ret);
2503c71b84fSZbigniew Bodek
2513c71b84fSZbigniew Bodek }
2523c71b84fSZbigniew Bodek
2533c71b84fSZbigniew Bodek static void
mv_write_ge_smi(device_t dev,int phy,int reg,uint32_t value)2543c71b84fSZbigniew Bodek mv_write_ge_smi(device_t dev, int phy, int reg, uint32_t value)
2553c71b84fSZbigniew Bodek {
2563c71b84fSZbigniew Bodek uint32_t timeout;
2573c71b84fSZbigniew Bodek struct mge_softc *sc;
2583c71b84fSZbigniew Bodek
2593c71b84fSZbigniew Bodek sc = device_get_softc(dev);
2603c71b84fSZbigniew Bodek KASSERT(sc != NULL, ("NULL softc ptr!"));
2613c71b84fSZbigniew Bodek
2623c71b84fSZbigniew Bodek MGE_SMI_LOCK();
2633c71b84fSZbigniew Bodek timeout = MGE_SMI_READ_RETRIES;
2643c71b84fSZbigniew Bodek while (--timeout &&
2653c71b84fSZbigniew Bodek (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
2663c71b84fSZbigniew Bodek MGE_DELAY(MGE_SMI_READ_DELAY);
2673c71b84fSZbigniew Bodek
2683c71b84fSZbigniew Bodek if (timeout == 0) {
2693c71b84fSZbigniew Bodek device_printf(dev, "SMI read timeout.\n");
2703c71b84fSZbigniew Bodek goto out;
2713c71b84fSZbigniew Bodek }
2723c71b84fSZbigniew Bodek
2733c71b84fSZbigniew Bodek MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
2743c71b84fSZbigniew Bodek (MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
2753c71b84fSZbigniew Bodek (value & MGE_SMI_DATA_MASK)));
2763c71b84fSZbigniew Bodek
2773c71b84fSZbigniew Bodek out:
2783c71b84fSZbigniew Bodek MGE_SMI_UNLOCK();
2793c71b84fSZbigniew Bodek }
2803c71b84fSZbigniew Bodek
2813c71b84fSZbigniew Bodek static int
mv_read_ext_phy(device_t dev,int phy,int reg)2823c71b84fSZbigniew Bodek mv_read_ext_phy(device_t dev, int phy, int reg)
2833c71b84fSZbigniew Bodek {
2843c71b84fSZbigniew Bodek uint32_t retries;
2853c71b84fSZbigniew Bodek struct mge_softc *sc;
2863c71b84fSZbigniew Bodek uint32_t ret;
2873c71b84fSZbigniew Bodek
2883c71b84fSZbigniew Bodek sc = device_get_softc(dev);
2893c71b84fSZbigniew Bodek
2903c71b84fSZbigniew Bodek MGE_SMI_LOCK();
2913c71b84fSZbigniew Bodek MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
2923c71b84fSZbigniew Bodek (MGE_SMI_READ | (reg << 21) | (phy << 16)));
2933c71b84fSZbigniew Bodek
2943c71b84fSZbigniew Bodek retries = MGE_SMI_READ_RETRIES;
2953c71b84fSZbigniew Bodek while (--retries &&
2963c71b84fSZbigniew Bodek !(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID))
2973c71b84fSZbigniew Bodek DELAY(MGE_SMI_READ_DELAY);
2983c71b84fSZbigniew Bodek
2993c71b84fSZbigniew Bodek if (retries == 0)
3003c71b84fSZbigniew Bodek device_printf(dev, "Timeout while reading from PHY\n");
3013c71b84fSZbigniew Bodek
3023c71b84fSZbigniew Bodek ret = MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
3033c71b84fSZbigniew Bodek MGE_SMI_UNLOCK();
3043c71b84fSZbigniew Bodek
3053c71b84fSZbigniew Bodek return (ret);
3063c71b84fSZbigniew Bodek }
3073c71b84fSZbigniew Bodek
3083c71b84fSZbigniew Bodek static void
mv_write_ext_phy(device_t dev,int phy,int reg,int value)3093c71b84fSZbigniew Bodek mv_write_ext_phy(device_t dev, int phy, int reg, int value)
3103c71b84fSZbigniew Bodek {
3113c71b84fSZbigniew Bodek uint32_t retries;
3123c71b84fSZbigniew Bodek struct mge_softc *sc;
3133c71b84fSZbigniew Bodek
3143c71b84fSZbigniew Bodek sc = device_get_softc(dev);
3153c71b84fSZbigniew Bodek
3163c71b84fSZbigniew Bodek MGE_SMI_LOCK();
3173c71b84fSZbigniew Bodek MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
3183c71b84fSZbigniew Bodek (MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
3193c71b84fSZbigniew Bodek (value & MGE_SMI_DATA_MASK)));
3203c71b84fSZbigniew Bodek
3213c71b84fSZbigniew Bodek retries = MGE_SMI_WRITE_RETRIES;
3223c71b84fSZbigniew Bodek while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY)
3233c71b84fSZbigniew Bodek DELAY(MGE_SMI_WRITE_DELAY);
3243c71b84fSZbigniew Bodek
3253c71b84fSZbigniew Bodek if (retries == 0)
3263c71b84fSZbigniew Bodek device_printf(dev, "Timeout while writing to PHY\n");
3273c71b84fSZbigniew Bodek MGE_SMI_UNLOCK();
3283c71b84fSZbigniew Bodek }
3293c71b84fSZbigniew Bodek
3309f55f5f5SRafal Jaworowski static void
mge_get_mac_address(struct mge_softc * sc,uint8_t * addr)3319f55f5f5SRafal Jaworowski mge_get_mac_address(struct mge_softc *sc, uint8_t *addr)
3329f55f5f5SRafal Jaworowski {
3339f55f5f5SRafal Jaworowski uint32_t mac_l, mac_h;
334db5ef4fcSRafal Jaworowski uint8_t lmac[6];
335db5ef4fcSRafal Jaworowski int i, valid;
3369f55f5f5SRafal Jaworowski
337db5ef4fcSRafal Jaworowski /*
338db5ef4fcSRafal Jaworowski * Retrieve hw address from the device tree.
339db5ef4fcSRafal Jaworowski */
340db5ef4fcSRafal Jaworowski i = OF_getprop(sc->node, "local-mac-address", (void *)lmac, 6);
341db5ef4fcSRafal Jaworowski if (i == 6) {
342db5ef4fcSRafal Jaworowski valid = 0;
343db5ef4fcSRafal Jaworowski for (i = 0; i < 6; i++)
344db5ef4fcSRafal Jaworowski if (lmac[i] != 0) {
345db5ef4fcSRafal Jaworowski valid = 1;
346db5ef4fcSRafal Jaworowski break;
347db5ef4fcSRafal Jaworowski }
3489f55f5f5SRafal Jaworowski
349db5ef4fcSRafal Jaworowski if (valid) {
350db5ef4fcSRafal Jaworowski bcopy(lmac, addr, 6);
351db5ef4fcSRafal Jaworowski return;
352db5ef4fcSRafal Jaworowski }
353db5ef4fcSRafal Jaworowski }
354db5ef4fcSRafal Jaworowski
355db5ef4fcSRafal Jaworowski /*
356db5ef4fcSRafal Jaworowski * Fall back -- use the currently programmed address.
357db5ef4fcSRafal Jaworowski */
3589f55f5f5SRafal Jaworowski mac_l = MGE_READ(sc, MGE_MAC_ADDR_L);
3599f55f5f5SRafal Jaworowski mac_h = MGE_READ(sc, MGE_MAC_ADDR_H);
3609f55f5f5SRafal Jaworowski
3619f55f5f5SRafal Jaworowski addr[0] = (mac_h & 0xff000000) >> 24;
3629f55f5f5SRafal Jaworowski addr[1] = (mac_h & 0x00ff0000) >> 16;
3639f55f5f5SRafal Jaworowski addr[2] = (mac_h & 0x0000ff00) >> 8;
3649f55f5f5SRafal Jaworowski addr[3] = (mac_h & 0x000000ff);
3659f55f5f5SRafal Jaworowski addr[4] = (mac_l & 0x0000ff00) >> 8;
3669f55f5f5SRafal Jaworowski addr[5] = (mac_l & 0x000000ff);
3679f55f5f5SRafal Jaworowski }
3689f55f5f5SRafal Jaworowski
3698e1dc58eSRafal Jaworowski static uint32_t
mge_tfut_ipg(uint32_t val,int ver)3708e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver)
3718e1dc58eSRafal Jaworowski {
3728e1dc58eSRafal Jaworowski
3738e1dc58eSRafal Jaworowski switch (ver) {
3748e1dc58eSRafal Jaworowski case 1:
3758e1dc58eSRafal Jaworowski return ((val & 0x3fff) << 4);
3768e1dc58eSRafal Jaworowski case 2:
3778e1dc58eSRafal Jaworowski default:
3788e1dc58eSRafal Jaworowski return ((val & 0xffff) << 4);
3798e1dc58eSRafal Jaworowski }
3808e1dc58eSRafal Jaworowski }
3818e1dc58eSRafal Jaworowski
3828e1dc58eSRafal Jaworowski static uint32_t
mge_rx_ipg(uint32_t val,int ver)3838e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver)
3848e1dc58eSRafal Jaworowski {
3858e1dc58eSRafal Jaworowski
3868e1dc58eSRafal Jaworowski switch (ver) {
3878e1dc58eSRafal Jaworowski case 1:
3888e1dc58eSRafal Jaworowski return ((val & 0x3fff) << 8);
3898e1dc58eSRafal Jaworowski case 2:
3908e1dc58eSRafal Jaworowski default:
3918e1dc58eSRafal Jaworowski return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7));
3928e1dc58eSRafal Jaworowski }
3938e1dc58eSRafal Jaworowski }
3948e1dc58eSRafal Jaworowski
3958e1dc58eSRafal Jaworowski static void
mge_ver_params(struct mge_softc * sc)3968e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc)
3978e1dc58eSRafal Jaworowski {
3988e1dc58eSRafal Jaworowski uint32_t d, r;
3998e1dc58eSRafal Jaworowski
4008e1dc58eSRafal Jaworowski soc_id(&d, &r);
4018e1dc58eSRafal Jaworowski sc->mge_ver = 1;
4028e1dc58eSRafal Jaworowski sc->mge_mtu = 0x458;
4038e1dc58eSRafal Jaworowski sc->mge_tfut_ipg_max = 0x3FFF;
4048e1dc58eSRafal Jaworowski sc->mge_rx_ipg_max = 0x3FFF;
4058e1dc58eSRafal Jaworowski sc->mge_tx_arb_cfg = 0x000000FF;
4068e1dc58eSRafal Jaworowski sc->mge_tx_tok_cfg = 0x3FFFFFFF;
4078e1dc58eSRafal Jaworowski sc->mge_tx_tok_cnt = 0x3FFFFFFF;
40875f1438bSOleksandr Tymoshenko sc->mge_intr_cnt = 2;
40975f1438bSOleksandr Tymoshenko
410*d25a708bSAndrew Turner if (d == MV_DEV_MV78260 || d == MV_DEV_MV78460)
41175f1438bSOleksandr Tymoshenko sc->mge_hw_csum = 0;
41275f1438bSOleksandr Tymoshenko else
41375f1438bSOleksandr Tymoshenko sc->mge_hw_csum = 1;
4148e1dc58eSRafal Jaworowski }
4158e1dc58eSRafal Jaworowski
4169f55f5f5SRafal Jaworowski static void
mge_set_mac_address(struct mge_softc * sc)4179f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc)
4189f55f5f5SRafal Jaworowski {
4199f55f5f5SRafal Jaworowski char *if_mac;
4209f55f5f5SRafal Jaworowski uint32_t mac_l, mac_h;
4219f55f5f5SRafal Jaworowski
4229f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK_ASSERT(sc);
4239f55f5f5SRafal Jaworowski
42498fe10c8SJustin Hibbits if_mac = (char *)if_getlladdr(sc->ifp);
4259f55f5f5SRafal Jaworowski
4269f55f5f5SRafal Jaworowski mac_l = (if_mac[4] << 8) | (if_mac[5]);
4279f55f5f5SRafal Jaworowski mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) |
4289f55f5f5SRafal Jaworowski (if_mac[2] << 8) | (if_mac[3] << 0);
4299f55f5f5SRafal Jaworowski
4309f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l);
4319f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h);
4329f55f5f5SRafal Jaworowski
4339f55f5f5SRafal Jaworowski mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE);
4349f55f5f5SRafal Jaworowski }
4359f55f5f5SRafal Jaworowski
4369f55f5f5SRafal Jaworowski static void
mge_set_ucast_address(struct mge_softc * sc,uint8_t last_byte,uint8_t queue)4379f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue)
4389f55f5f5SRafal Jaworowski {
4399f55f5f5SRafal Jaworowski uint32_t reg_idx, reg_off, reg_val, i;
4409f55f5f5SRafal Jaworowski
4419f55f5f5SRafal Jaworowski last_byte &= 0xf;
4429f55f5f5SRafal Jaworowski reg_idx = last_byte / MGE_UCAST_REG_NUMBER;
4439f55f5f5SRafal Jaworowski reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8;
4449f55f5f5SRafal Jaworowski reg_val = (1 | (queue << 1)) << reg_off;
4459f55f5f5SRafal Jaworowski
4469f55f5f5SRafal Jaworowski for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) {
4479f55f5f5SRafal Jaworowski if ( i == reg_idx)
4489f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
4499f55f5f5SRafal Jaworowski else
4509f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0);
4519f55f5f5SRafal Jaworowski }
4529f55f5f5SRafal Jaworowski }
4539f55f5f5SRafal Jaworowski
4549f55f5f5SRafal Jaworowski static void
mge_set_prom_mode(struct mge_softc * sc,uint8_t queue)4559f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue)
4569f55f5f5SRafal Jaworowski {
4579f55f5f5SRafal Jaworowski uint32_t port_config;
4589f55f5f5SRafal Jaworowski uint32_t reg_val, i;
4599f55f5f5SRafal Jaworowski
4609f55f5f5SRafal Jaworowski /* Enable or disable promiscuous mode as needed */
46196ab5e71SJustin Hibbits if (if_getflags(sc->ifp) & IFF_PROMISC) {
4629f55f5f5SRafal Jaworowski port_config = MGE_READ(sc, MGE_PORT_CONFIG);
4639f55f5f5SRafal Jaworowski port_config |= PORT_CONFIG_UPM;
4649f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
4659f55f5f5SRafal Jaworowski
4669f55f5f5SRafal Jaworowski reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 |
4679f55f5f5SRafal Jaworowski (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24);
4689f55f5f5SRafal Jaworowski
4699f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
4709f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val);
4719f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val);
4729f55f5f5SRafal Jaworowski }
4739f55f5f5SRafal Jaworowski
4749f55f5f5SRafal Jaworowski for (i = 0; i < MGE_UCAST_REG_NUMBER; i++)
4759f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val);
4769f55f5f5SRafal Jaworowski
4779f55f5f5SRafal Jaworowski } else {
4789f55f5f5SRafal Jaworowski port_config = MGE_READ(sc, MGE_PORT_CONFIG);
4799f55f5f5SRafal Jaworowski port_config &= ~PORT_CONFIG_UPM;
4809f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, port_config);
4819f55f5f5SRafal Jaworowski
4829f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
4839f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0);
4849f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0);
4859f55f5f5SRafal Jaworowski }
4869f55f5f5SRafal Jaworowski
4879f55f5f5SRafal Jaworowski mge_set_mac_address(sc);
4889f55f5f5SRafal Jaworowski }
4899f55f5f5SRafal Jaworowski }
4909f55f5f5SRafal Jaworowski
4919f55f5f5SRafal Jaworowski static void
mge_get_dma_addr(void * arg,bus_dma_segment_t * segs,int nseg,int error)4929f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
4939f55f5f5SRafal Jaworowski {
4949f55f5f5SRafal Jaworowski u_int32_t *paddr;
4959f55f5f5SRafal Jaworowski
4969f55f5f5SRafal Jaworowski KASSERT(nseg == 1, ("wrong number of segments, should be 1"));
4979f55f5f5SRafal Jaworowski paddr = arg;
4989f55f5f5SRafal Jaworowski
4999f55f5f5SRafal Jaworowski *paddr = segs->ds_addr;
5009f55f5f5SRafal Jaworowski }
5019f55f5f5SRafal Jaworowski
5029f55f5f5SRafal Jaworowski static int
mge_new_rxbuf(bus_dma_tag_t tag,bus_dmamap_t map,struct mbuf ** mbufp,bus_addr_t * paddr)5039f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp,
5049f55f5f5SRafal Jaworowski bus_addr_t *paddr)
5059f55f5f5SRafal Jaworowski {
5069f55f5f5SRafal Jaworowski struct mbuf *new_mbuf;
5079f55f5f5SRafal Jaworowski bus_dma_segment_t seg[1];
5089f55f5f5SRafal Jaworowski int error;
5099f55f5f5SRafal Jaworowski int nsegs;
5109f55f5f5SRafal Jaworowski
5119f55f5f5SRafal Jaworowski KASSERT(mbufp != NULL, ("NULL mbuf pointer!"));
5129f55f5f5SRafal Jaworowski
513c6499eccSGleb Smirnoff new_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5149f55f5f5SRafal Jaworowski if (new_mbuf == NULL)
5159f55f5f5SRafal Jaworowski return (ENOBUFS);
5169f55f5f5SRafal Jaworowski new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size;
5179f55f5f5SRafal Jaworowski
5189f55f5f5SRafal Jaworowski if (*mbufp) {
5199f55f5f5SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD);
5209f55f5f5SRafal Jaworowski bus_dmamap_unload(tag, map);
5219f55f5f5SRafal Jaworowski }
5229f55f5f5SRafal Jaworowski
5239f55f5f5SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs,
5249f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT);
5259f55f5f5SRafal Jaworowski KASSERT(nsegs == 1, ("Too many segments returned!"));
5269f55f5f5SRafal Jaworowski if (nsegs != 1 || error)
5279f55f5f5SRafal Jaworowski panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error);
5289f55f5f5SRafal Jaworowski
5299f55f5f5SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD);
5309f55f5f5SRafal Jaworowski
5319f55f5f5SRafal Jaworowski (*mbufp) = new_mbuf;
5329f55f5f5SRafal Jaworowski (*paddr) = seg->ds_addr;
5339f55f5f5SRafal Jaworowski return (0);
5349f55f5f5SRafal Jaworowski }
5359f55f5f5SRafal Jaworowski
5369f55f5f5SRafal Jaworowski static int
mge_alloc_desc_dma(struct mge_softc * sc,struct mge_desc_wrapper * tab,uint32_t size,bus_dma_tag_t * buffer_tag)5379f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab,
5389f55f5f5SRafal Jaworowski uint32_t size, bus_dma_tag_t *buffer_tag)
5399f55f5f5SRafal Jaworowski {
5409f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw;
5419f55f5f5SRafal Jaworowski bus_addr_t desc_paddr;
5429f55f5f5SRafal Jaworowski int i, error;
5439f55f5f5SRafal Jaworowski
5449f55f5f5SRafal Jaworowski desc_paddr = 0;
5459f55f5f5SRafal Jaworowski for (i = size - 1; i >= 0; i--) {
5469f55f5f5SRafal Jaworowski dw = &(tab[i]);
5479f55f5f5SRafal Jaworowski error = bus_dmamem_alloc(sc->mge_desc_dtag,
5489f55f5f5SRafal Jaworowski (void**)&(dw->mge_desc),
5499f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
5509f55f5f5SRafal Jaworowski &(dw->desc_dmap));
5519f55f5f5SRafal Jaworowski
5529f55f5f5SRafal Jaworowski if (error) {
5539f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to allocate DMA memory\n");
5549f55f5f5SRafal Jaworowski dw->mge_desc = NULL;
5559f55f5f5SRafal Jaworowski return (ENXIO);
5569f55f5f5SRafal Jaworowski }
5579f55f5f5SRafal Jaworowski
5589f55f5f5SRafal Jaworowski error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap,
5599f55f5f5SRafal Jaworowski dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr,
5609f55f5f5SRafal Jaworowski &(dw->mge_desc_paddr), BUS_DMA_NOWAIT);
5619f55f5f5SRafal Jaworowski
5629f55f5f5SRafal Jaworowski if (error) {
5639f55f5f5SRafal Jaworowski if_printf(sc->ifp, "can't load descriptor\n");
5649f55f5f5SRafal Jaworowski bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
5659f55f5f5SRafal Jaworowski dw->desc_dmap);
5669f55f5f5SRafal Jaworowski dw->mge_desc = NULL;
5679f55f5f5SRafal Jaworowski return (ENXIO);
5689f55f5f5SRafal Jaworowski }
5699f55f5f5SRafal Jaworowski
5709f55f5f5SRafal Jaworowski /* Chain descriptors */
5719f55f5f5SRafal Jaworowski dw->mge_desc->next_desc = desc_paddr;
5729f55f5f5SRafal Jaworowski desc_paddr = dw->mge_desc_paddr;
5739f55f5f5SRafal Jaworowski }
5749f55f5f5SRafal Jaworowski tab[size - 1].mge_desc->next_desc = desc_paddr;
5759f55f5f5SRafal Jaworowski
5769f55f5f5SRafal Jaworowski /* Allocate a busdma tag for mbufs. */
57762ce43ccSScott Long error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), /* parent */
57875f1438bSOleksandr Tymoshenko 1, 0, /* alignment, boundary */
5799f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
5809f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */
5819f55f5f5SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */
5829f55f5f5SRafal Jaworowski MCLBYTES, 1, /* maxsize, nsegments */
5839f55f5f5SRafal Jaworowski MCLBYTES, 0, /* maxsegsz, flags */
5849f55f5f5SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */
5859f55f5f5SRafal Jaworowski buffer_tag); /* dmat */
5869f55f5f5SRafal Jaworowski if (error) {
5879f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to create busdma tag for mbufs\n");
5889f55f5f5SRafal Jaworowski return (ENXIO);
5899f55f5f5SRafal Jaworowski }
5909f55f5f5SRafal Jaworowski
5919f55f5f5SRafal Jaworowski /* Create TX busdma maps */
5929f55f5f5SRafal Jaworowski for (i = 0; i < size; i++) {
5939f55f5f5SRafal Jaworowski dw = &(tab[i]);
5949f55f5f5SRafal Jaworowski error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap);
5959f55f5f5SRafal Jaworowski if (error) {
5969f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to create map for mbuf\n");
5979f55f5f5SRafal Jaworowski return (ENXIO);
5989f55f5f5SRafal Jaworowski }
5999f55f5f5SRafal Jaworowski
6009f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL;
6019f55f5f5SRafal Jaworowski dw->mge_desc->buffer = (bus_addr_t)NULL;
6029f55f5f5SRafal Jaworowski }
6039f55f5f5SRafal Jaworowski
6049f55f5f5SRafal Jaworowski return (0);
6059f55f5f5SRafal Jaworowski }
6069f55f5f5SRafal Jaworowski
6079f55f5f5SRafal Jaworowski static int
mge_allocate_dma(struct mge_softc * sc)6089f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc)
6099f55f5f5SRafal Jaworowski {
6109f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw;
611d6bdd318SRafal Jaworowski int i;
6129f55f5f5SRafal Jaworowski
6139f55f5f5SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
614f8967810SWarner Losh bus_dma_tag_create(bus_get_dma_tag(sc->dev), /* parent */
6159f55f5f5SRafal Jaworowski 16, 0, /* alignment, boundary */
6169f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
6179f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */
6189f55f5f5SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */
6199f55f5f5SRafal Jaworowski sizeof(struct mge_desc), 1, /* maxsize, nsegments */
6209f55f5f5SRafal Jaworowski sizeof(struct mge_desc), 0, /* maxsegsz, flags */
6219f55f5f5SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */
6229f55f5f5SRafal Jaworowski &sc->mge_desc_dtag); /* dmat */
6239f55f5f5SRafal Jaworowski
6249f55f5f5SRafal Jaworowski
6259f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM,
6269f55f5f5SRafal Jaworowski &sc->mge_tx_dtag);
6279f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
6289f55f5f5SRafal Jaworowski &sc->mge_rx_dtag);
6299f55f5f5SRafal Jaworowski
6309f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) {
6319f55f5f5SRafal Jaworowski dw = &(sc->mge_rx_desc[i]);
6329f55f5f5SRafal Jaworowski mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
6339f55f5f5SRafal Jaworowski &dw->mge_desc->buffer);
6349f55f5f5SRafal Jaworowski }
6359f55f5f5SRafal Jaworowski
6369f55f5f5SRafal Jaworowski sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr;
6379f55f5f5SRafal Jaworowski sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
6389f55f5f5SRafal Jaworowski
6399f55f5f5SRafal Jaworowski return (0);
6409f55f5f5SRafal Jaworowski }
6419f55f5f5SRafal Jaworowski
6429f55f5f5SRafal Jaworowski static void
mge_free_desc(struct mge_softc * sc,struct mge_desc_wrapper * tab,uint32_t size,bus_dma_tag_t buffer_tag,uint8_t free_mbufs)6439f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab,
6449f55f5f5SRafal Jaworowski uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs)
6459f55f5f5SRafal Jaworowski {
6469f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw;
6479f55f5f5SRafal Jaworowski int i;
6489f55f5f5SRafal Jaworowski
6499f55f5f5SRafal Jaworowski for (i = 0; i < size; i++) {
6509f55f5f5SRafal Jaworowski /* Free RX mbuf */
6519f55f5f5SRafal Jaworowski dw = &(tab[i]);
6529f55f5f5SRafal Jaworowski
6539f55f5f5SRafal Jaworowski if (dw->buffer_dmap) {
6549f55f5f5SRafal Jaworowski if (free_mbufs) {
6559f55f5f5SRafal Jaworowski bus_dmamap_sync(buffer_tag, dw->buffer_dmap,
6569f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD);
6579f55f5f5SRafal Jaworowski bus_dmamap_unload(buffer_tag, dw->buffer_dmap);
6589f55f5f5SRafal Jaworowski }
6599f55f5f5SRafal Jaworowski bus_dmamap_destroy(buffer_tag, dw->buffer_dmap);
6609f55f5f5SRafal Jaworowski if (free_mbufs)
6619f55f5f5SRafal Jaworowski m_freem(dw->buffer);
6629f55f5f5SRafal Jaworowski }
6639f55f5f5SRafal Jaworowski /* Free RX descriptors */
6649f55f5f5SRafal Jaworowski if (dw->desc_dmap) {
6659f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
6669f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD);
6679f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap);
6689f55f5f5SRafal Jaworowski bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc,
6699f55f5f5SRafal Jaworowski dw->desc_dmap);
6709f55f5f5SRafal Jaworowski }
6719f55f5f5SRafal Jaworowski }
6729f55f5f5SRafal Jaworowski }
6739f55f5f5SRafal Jaworowski
6749f55f5f5SRafal Jaworowski static void
mge_free_dma(struct mge_softc * sc)6759f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc)
6769f55f5f5SRafal Jaworowski {
6774ac30cc1SZbigniew Bodek
678b1603638SGordon Bergling /* Free descriptors and mbufs */
6799f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
6809f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0);
6819f55f5f5SRafal Jaworowski
6829f55f5f5SRafal Jaworowski /* Destroy mbuf dma tag */
6839f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_tx_dtag);
6849f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_rx_dtag);
6859f55f5f5SRafal Jaworowski /* Destroy descriptors tag */
6869f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_desc_dtag);
6879f55f5f5SRafal Jaworowski }
6889f55f5f5SRafal Jaworowski
6899f55f5f5SRafal Jaworowski static void
mge_reinit_rx(struct mge_softc * sc)6909f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc)
6919f55f5f5SRafal Jaworowski {
6929f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw;
6939f55f5f5SRafal Jaworowski int i;
6949f55f5f5SRafal Jaworowski
695d6bdd318SRafal Jaworowski MGE_RECEIVE_LOCK_ASSERT(sc);
6969f55f5f5SRafal Jaworowski
6979f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1);
6989f55f5f5SRafal Jaworowski
6999f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM,
7009f55f5f5SRafal Jaworowski &sc->mge_rx_dtag);
7019f55f5f5SRafal Jaworowski
7029f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) {
7039f55f5f5SRafal Jaworowski dw = &(sc->mge_rx_desc[i]);
7049f55f5f5SRafal Jaworowski mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer,
7059f55f5f5SRafal Jaworowski &dw->mge_desc->buffer);
7069f55f5f5SRafal Jaworowski }
7079f55f5f5SRafal Jaworowski
7089f55f5f5SRafal Jaworowski sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr;
7099f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0;
7109f55f5f5SRafal Jaworowski
7119f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
7129f55f5f5SRafal Jaworowski sc->rx_desc_start);
7139f55f5f5SRafal Jaworowski
7149f55f5f5SRafal Jaworowski /* Enable RX queue */
7159f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
7169f55f5f5SRafal Jaworowski }
7179f55f5f5SRafal Jaworowski
7189f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
7199f55f5f5SRafal Jaworowski static poll_handler_t mge_poll;
7209f55f5f5SRafal Jaworowski
7211abcdbd1SAttilio Rao static int
mge_poll(if_t ifp,enum poll_cmd cmd,int count)72298fe10c8SJustin Hibbits mge_poll(if_t ifp, enum poll_cmd cmd, int count)
7239f55f5f5SRafal Jaworowski {
72498fe10c8SJustin Hibbits struct mge_softc *sc = if_getsoftc(ifp);
7259f55f5f5SRafal Jaworowski uint32_t int_cause, int_cause_ext;
7261abcdbd1SAttilio Rao int rx_npkts = 0;
7279f55f5f5SRafal Jaworowski
7283c71b84fSZbigniew Bodek MGE_RECEIVE_LOCK(sc);
7299f55f5f5SRafal Jaworowski
73098fe10c8SJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
7313c71b84fSZbigniew Bodek MGE_RECEIVE_UNLOCK(sc);
7321abcdbd1SAttilio Rao return (rx_npkts);
7339f55f5f5SRafal Jaworowski }
7349f55f5f5SRafal Jaworowski
7359f55f5f5SRafal Jaworowski if (cmd == POLL_AND_CHECK_STATUS) {
7369f55f5f5SRafal Jaworowski int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
7379f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
7389f55f5f5SRafal Jaworowski
7399f55f5f5SRafal Jaworowski /* Check for resource error */
7409f55f5f5SRafal Jaworowski if (int_cause & MGE_PORT_INT_RXERRQ0)
7419f55f5f5SRafal Jaworowski mge_reinit_rx(sc);
7429f55f5f5SRafal Jaworowski
7439f55f5f5SRafal Jaworowski if (int_cause || int_cause_ext) {
7449f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
7459f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
7469f55f5f5SRafal Jaworowski }
7479f55f5f5SRafal Jaworowski }
7489f55f5f5SRafal Jaworowski
7493c71b84fSZbigniew Bodek
7501abcdbd1SAttilio Rao rx_npkts = mge_intr_rx_locked(sc, count);
7519f55f5f5SRafal Jaworowski
7523c71b84fSZbigniew Bodek MGE_RECEIVE_UNLOCK(sc);
7533c71b84fSZbigniew Bodek MGE_TRANSMIT_LOCK(sc);
7543c71b84fSZbigniew Bodek mge_intr_tx_locked(sc);
7553c71b84fSZbigniew Bodek MGE_TRANSMIT_UNLOCK(sc);
7561abcdbd1SAttilio Rao return (rx_npkts);
7579f55f5f5SRafal Jaworowski }
7589f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
7599f55f5f5SRafal Jaworowski
7609f55f5f5SRafal Jaworowski static int
mge_attach(device_t dev)7619f55f5f5SRafal Jaworowski mge_attach(device_t dev)
7629f55f5f5SRafal Jaworowski {
7639f55f5f5SRafal Jaworowski struct mge_softc *sc;
764a6eb469dSPhilip Paeps struct mii_softc *miisc;
76598fe10c8SJustin Hibbits if_t ifp;
7669f55f5f5SRafal Jaworowski uint8_t hwaddr[ETHER_ADDR_LEN];
7678e5d93dbSMarius Strobl int i, error, phy;
7689f55f5f5SRafal Jaworowski
7699f55f5f5SRafal Jaworowski sc = device_get_softc(dev);
7709f55f5f5SRafal Jaworowski sc->dev = dev;
771db5ef4fcSRafal Jaworowski sc->node = ofw_bus_get_node(dev);
7723c71b84fSZbigniew Bodek phy = 0;
7733c71b84fSZbigniew Bodek
7743c71b84fSZbigniew Bodek if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) == 0) {
7753c71b84fSZbigniew Bodek device_printf(dev, "PHY%i attached, phy_sc points to %s\n", phy,
7763c71b84fSZbigniew Bodek device_get_nameunit(sc->phy_sc->dev));
7773c71b84fSZbigniew Bodek sc->phy_attached = 1;
7783c71b84fSZbigniew Bodek } else {
7793c71b84fSZbigniew Bodek device_printf(dev, "PHY not attached.\n");
7803c71b84fSZbigniew Bodek sc->phy_attached = 0;
7813c71b84fSZbigniew Bodek sc->phy_sc = sc;
7823c71b84fSZbigniew Bodek }
7833c71b84fSZbigniew Bodek
7843c71b84fSZbigniew Bodek if (fdt_find_compatible(sc->node, "mrvl,sw", 1) != 0) {
7853c71b84fSZbigniew Bodek device_printf(dev, "Switch attached.\n");
7863c71b84fSZbigniew Bodek sc->switch_attached = 1;
7873c71b84fSZbigniew Bodek /* additional variable available across instances */
7883c71b84fSZbigniew Bodek switch_attached = 1;
7893c71b84fSZbigniew Bodek } else {
7903c71b84fSZbigniew Bodek sc->switch_attached = 0;
7913c71b84fSZbigniew Bodek }
7923c71b84fSZbigniew Bodek
7933c71b84fSZbigniew Bodek if (device_get_unit(dev) == 0) {
7943c71b84fSZbigniew Bodek sx_init(&sx_smi, "mge_tick() SMI access threads interlock");
7953c71b84fSZbigniew Bodek }
7969f55f5f5SRafal Jaworowski
7978e1dc58eSRafal Jaworowski /* Set chip version-dependent parameters */
7988e1dc58eSRafal Jaworowski mge_ver_params(sc);
7998e1dc58eSRafal Jaworowski
8009f55f5f5SRafal Jaworowski /* Initialize mutexes */
8014ac30cc1SZbigniew Bodek mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock",
8024ac30cc1SZbigniew Bodek MTX_DEF);
8034ac30cc1SZbigniew Bodek mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock",
8044ac30cc1SZbigniew Bodek MTX_DEF);
8059f55f5f5SRafal Jaworowski
8069f55f5f5SRafal Jaworowski /* Allocate IO and IRQ resources */
8079f55f5f5SRafal Jaworowski error = bus_alloc_resources(dev, res_spec, sc->res);
8089f55f5f5SRafal Jaworowski if (error) {
8099f55f5f5SRafal Jaworowski device_printf(dev, "could not allocate resources\n");
8109f55f5f5SRafal Jaworowski mge_detach(dev);
8119f55f5f5SRafal Jaworowski return (ENXIO);
8129f55f5f5SRafal Jaworowski }
8139f55f5f5SRafal Jaworowski
8149f55f5f5SRafal Jaworowski /* Allocate DMA, buffers, buffer descriptors */
8159f55f5f5SRafal Jaworowski error = mge_allocate_dma(sc);
8169f55f5f5SRafal Jaworowski if (error) {
8179f55f5f5SRafal Jaworowski mge_detach(dev);
8189f55f5f5SRafal Jaworowski return (ENXIO);
8199f55f5f5SRafal Jaworowski }
8209f55f5f5SRafal Jaworowski
8219f55f5f5SRafal Jaworowski sc->tx_desc_curr = 0;
8229f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0;
8239f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 0;
8245817716fSRafal Jaworowski sc->tx_desc_used_count = 0;
8259f55f5f5SRafal Jaworowski
8269f55f5f5SRafal Jaworowski /* Configure defaults for interrupts coalescing */
8279f55f5f5SRafal Jaworowski sc->rx_ic_time = 768;
8289f55f5f5SRafal Jaworowski sc->tx_ic_time = 768;
8299f55f5f5SRafal Jaworowski mge_add_sysctls(sc);
8309f55f5f5SRafal Jaworowski
8319f55f5f5SRafal Jaworowski /* Allocate network interface */
8329f55f5f5SRafal Jaworowski ifp = sc->ifp = if_alloc(IFT_ETHER);
8339f55f5f5SRafal Jaworowski if_initname(ifp, device_get_name(dev), device_get_unit(dev));
83498fe10c8SJustin Hibbits if_setsoftc(ifp, sc);
83598fe10c8SJustin Hibbits if_setflags(ifp, IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST);
83698fe10c8SJustin Hibbits if_setcapabilities(ifp, IFCAP_VLAN_MTU);
83775f1438bSOleksandr Tymoshenko if (sc->mge_hw_csum) {
83898fe10c8SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_HWCSUM, 0);
83998fe10c8SJustin Hibbits if_sethwassist(ifp, MGE_CHECKSUM_FEATURES);
84075f1438bSOleksandr Tymoshenko }
84198fe10c8SJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp));
8429f55f5f5SRafal Jaworowski
8439f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
8449f55f5f5SRafal Jaworowski /* Advertise that polling is supported */
84598fe10c8SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0);
8469f55f5f5SRafal Jaworowski #endif
8479f55f5f5SRafal Jaworowski
84898fe10c8SJustin Hibbits if_setinitfn(ifp, mge_init);
84998fe10c8SJustin Hibbits if_setstartfn(ifp, mge_start);
85098fe10c8SJustin Hibbits if_setioctlfn(ifp, mge_ioctl);
8519f55f5f5SRafal Jaworowski
85298fe10c8SJustin Hibbits if_setsendqlen(ifp, MGE_TX_DESC_NUM - 1);
85398fe10c8SJustin Hibbits if_setsendqready(ifp);
8549f55f5f5SRafal Jaworowski
8559f55f5f5SRafal Jaworowski mge_get_mac_address(sc, hwaddr);
8569f55f5f5SRafal Jaworowski ether_ifattach(ifp, hwaddr);
8576b2ff27cSAlexander Motin callout_init(&sc->wd_callout, 1);
8589f55f5f5SRafal Jaworowski
8598e5d93dbSMarius Strobl /* Attach PHY(s) */
8603c71b84fSZbigniew Bodek if (sc->phy_attached) {
8618e5d93dbSMarius Strobl error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd,
8628e5d93dbSMarius Strobl mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
8639f55f5f5SRafal Jaworowski if (error) {
8643c71b84fSZbigniew Bodek device_printf(dev, "MII failed to find PHY\n");
8653c71b84fSZbigniew Bodek if_free(ifp);
8663c71b84fSZbigniew Bodek sc->ifp = NULL;
8679f55f5f5SRafal Jaworowski mge_detach(dev);
8689f55f5f5SRafal Jaworowski return (error);
8699f55f5f5SRafal Jaworowski }
8709f55f5f5SRafal Jaworowski sc->mii = device_get_softc(sc->miibus);
8719f55f5f5SRafal Jaworowski
872a6eb469dSPhilip Paeps /* Tell the MAC where to find the PHY so autoneg works */
873a6eb469dSPhilip Paeps miisc = LIST_FIRST(&sc->mii->mii_phys);
874a6eb469dSPhilip Paeps MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy);
8753c71b84fSZbigniew Bodek } else {
8763c71b84fSZbigniew Bodek /* no PHY, so use hard-coded values */
8773c71b84fSZbigniew Bodek ifmedia_init(&sc->mge_ifmedia, 0,
8783c71b84fSZbigniew Bodek mge_ifmedia_upd,
8793c71b84fSZbigniew Bodek mge_ifmedia_sts);
8803c71b84fSZbigniew Bodek ifmedia_add(&sc->mge_ifmedia,
8813c71b84fSZbigniew Bodek IFM_ETHER | IFM_1000_T | IFM_FDX,
8823c71b84fSZbigniew Bodek 0, NULL);
8833c71b84fSZbigniew Bodek ifmedia_set(&sc->mge_ifmedia,
8843c71b84fSZbigniew Bodek IFM_ETHER | IFM_1000_T | IFM_FDX);
8853c71b84fSZbigniew Bodek }
886a6eb469dSPhilip Paeps
8879f55f5f5SRafal Jaworowski /* Attach interrupt handlers */
88875f1438bSOleksandr Tymoshenko /* TODO: review flags, in part. mark RX as INTR_ENTROPY ? */
88975f1438bSOleksandr Tymoshenko for (i = 1; i <= sc->mge_intr_cnt; ++i) {
89075f1438bSOleksandr Tymoshenko error = bus_setup_intr(dev, sc->res[i],
89175f1438bSOleksandr Tymoshenko INTR_TYPE_NET | INTR_MPSAFE,
89275f1438bSOleksandr Tymoshenko NULL, *mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].handler,
89375f1438bSOleksandr Tymoshenko sc, &sc->ih_cookie[i - 1]);
8949f55f5f5SRafal Jaworowski if (error) {
8959f55f5f5SRafal Jaworowski device_printf(dev, "could not setup %s\n",
89675f1438bSOleksandr Tymoshenko mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].description);
897a6eb469dSPhilip Paeps mge_detach(dev);
8989f55f5f5SRafal Jaworowski return (error);
8999f55f5f5SRafal Jaworowski }
9009f55f5f5SRafal Jaworowski }
9019f55f5f5SRafal Jaworowski
9023c71b84fSZbigniew Bodek if (sc->switch_attached) {
9033c71b84fSZbigniew Bodek MGE_WRITE(sc, MGE_REG_PHYDEV, MGE_SWITCH_PHYDEV);
9045b56413dSWarner Losh device_add_child(dev, "mdio", DEVICE_UNIT_ANY);
90518250ec6SJohn Baldwin bus_attach_children(dev);
9063c71b84fSZbigniew Bodek }
9073c71b84fSZbigniew Bodek
9089f55f5f5SRafal Jaworowski return (0);
9099f55f5f5SRafal Jaworowski }
9109f55f5f5SRafal Jaworowski
9119f55f5f5SRafal Jaworowski static int
mge_detach(device_t dev)9129f55f5f5SRafal Jaworowski mge_detach(device_t dev)
9139f55f5f5SRafal Jaworowski {
9149f55f5f5SRafal Jaworowski struct mge_softc *sc;
9159f55f5f5SRafal Jaworowski int error,i;
9169f55f5f5SRafal Jaworowski
9179f55f5f5SRafal Jaworowski sc = device_get_softc(dev);
9189f55f5f5SRafal Jaworowski
9199f55f5f5SRafal Jaworowski /* Stop controller and free TX queue */
9209f55f5f5SRafal Jaworowski if (sc->ifp)
9219f55f5f5SRafal Jaworowski mge_shutdown(dev);
9229f55f5f5SRafal Jaworowski
9239f55f5f5SRafal Jaworowski /* Wait for stopping ticks */
9249f55f5f5SRafal Jaworowski callout_drain(&sc->wd_callout);
9259f55f5f5SRafal Jaworowski
9269f55f5f5SRafal Jaworowski /* Stop and release all interrupts */
92775f1438bSOleksandr Tymoshenko for (i = 0; i < sc->mge_intr_cnt; ++i) {
928a6eb469dSPhilip Paeps if (!sc->ih_cookie[i])
929a6eb469dSPhilip Paeps continue;
930a6eb469dSPhilip Paeps
9314ac30cc1SZbigniew Bodek error = bus_teardown_intr(dev, sc->res[1 + i],
9324ac30cc1SZbigniew Bodek sc->ih_cookie[i]);
9339f55f5f5SRafal Jaworowski if (error)
9349f55f5f5SRafal Jaworowski device_printf(dev, "could not release %s\n",
93575f1438bSOleksandr Tymoshenko mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i + 1)].description);
9369f55f5f5SRafal Jaworowski }
9379f55f5f5SRafal Jaworowski
9389f55f5f5SRafal Jaworowski /* Detach network interface */
9399f55f5f5SRafal Jaworowski if (sc->ifp) {
9409f55f5f5SRafal Jaworowski ether_ifdetach(sc->ifp);
9419f55f5f5SRafal Jaworowski if_free(sc->ifp);
9429f55f5f5SRafal Jaworowski }
9439f55f5f5SRafal Jaworowski
9449f55f5f5SRafal Jaworowski /* Free DMA resources */
9459f55f5f5SRafal Jaworowski mge_free_dma(sc);
9469f55f5f5SRafal Jaworowski
9479f55f5f5SRafal Jaworowski /* Free IO memory handler */
9489f55f5f5SRafal Jaworowski bus_release_resources(dev, res_spec, sc->res);
9499f55f5f5SRafal Jaworowski
9509f55f5f5SRafal Jaworowski /* Destroy mutexes */
9519f55f5f5SRafal Jaworowski mtx_destroy(&sc->receive_lock);
9529f55f5f5SRafal Jaworowski mtx_destroy(&sc->transmit_lock);
9539f55f5f5SRafal Jaworowski
9543c71b84fSZbigniew Bodek if (device_get_unit(dev) == 0)
9553c71b84fSZbigniew Bodek sx_destroy(&sx_smi);
9563c71b84fSZbigniew Bodek
9579f55f5f5SRafal Jaworowski return (0);
9589f55f5f5SRafal Jaworowski }
9599f55f5f5SRafal Jaworowski
9609f55f5f5SRafal Jaworowski static void
mge_ifmedia_sts(if_t ifp,struct ifmediareq * ifmr)96198fe10c8SJustin Hibbits mge_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
9629f55f5f5SRafal Jaworowski {
9634ac30cc1SZbigniew Bodek struct mge_softc *sc;
9649f55f5f5SRafal Jaworowski struct mii_data *mii;
9659f55f5f5SRafal Jaworowski
96698fe10c8SJustin Hibbits sc = if_getsoftc(ifp);
9673c71b84fSZbigniew Bodek MGE_GLOBAL_LOCK(sc);
9683c71b84fSZbigniew Bodek
9693c71b84fSZbigniew Bodek if (!sc->phy_attached) {
9703c71b84fSZbigniew Bodek ifmr->ifm_active = IFM_1000_T | IFM_FDX | IFM_ETHER;
9713c71b84fSZbigniew Bodek ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
9723c71b84fSZbigniew Bodek goto out_unlock;
9733c71b84fSZbigniew Bodek }
9749f55f5f5SRafal Jaworowski
9759f55f5f5SRafal Jaworowski mii = sc->mii;
9769f55f5f5SRafal Jaworowski mii_pollstat(mii);
9779f55f5f5SRafal Jaworowski
9789f55f5f5SRafal Jaworowski ifmr->ifm_active = mii->mii_media_active;
9799f55f5f5SRafal Jaworowski ifmr->ifm_status = mii->mii_media_status;
9809f55f5f5SRafal Jaworowski
9813c71b84fSZbigniew Bodek out_unlock:
9823c71b84fSZbigniew Bodek MGE_GLOBAL_UNLOCK(sc);
9839f55f5f5SRafal Jaworowski }
9849f55f5f5SRafal Jaworowski
9859f55f5f5SRafal Jaworowski static uint32_t
mge_set_port_serial_control(uint32_t media)9869f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media)
9879f55f5f5SRafal Jaworowski {
9889f55f5f5SRafal Jaworowski uint32_t port_config;
9899f55f5f5SRafal Jaworowski
9909f55f5f5SRafal Jaworowski port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL |
9919f55f5f5SRafal Jaworowski PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552);
9929f55f5f5SRafal Jaworowski
9939f55f5f5SRafal Jaworowski if (IFM_TYPE(media) == IFM_ETHER) {
9949f55f5f5SRafal Jaworowski switch(IFM_SUBTYPE(media)) {
9959f55f5f5SRafal Jaworowski case IFM_AUTO:
9969f55f5f5SRafal Jaworowski break;
9979f55f5f5SRafal Jaworowski case IFM_1000_T:
9989f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_GMII_SPEED_1000 |
9993c71b84fSZbigniew Bodek PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
10003c71b84fSZbigniew Bodek | PORT_SERIAL_SPEED_AUTONEG);
10019f55f5f5SRafal Jaworowski break;
10029f55f5f5SRafal Jaworowski case IFM_100_TX:
10039f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_MII_SPEED_100 |
10043c71b84fSZbigniew Bodek PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
10053c71b84fSZbigniew Bodek | PORT_SERIAL_SPEED_AUTONEG);
10069f55f5f5SRafal Jaworowski break;
10079f55f5f5SRafal Jaworowski case IFM_10_T:
10089f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_AUTONEG |
10099f55f5f5SRafal Jaworowski PORT_SERIAL_AUTONEG_FC |
10109f55f5f5SRafal Jaworowski PORT_SERIAL_SPEED_AUTONEG);
10119f55f5f5SRafal Jaworowski break;
10129f55f5f5SRafal Jaworowski }
10139f55f5f5SRafal Jaworowski if (media & IFM_FDX)
10149f55f5f5SRafal Jaworowski port_config |= PORT_SERIAL_FULL_DUPLEX;
10159f55f5f5SRafal Jaworowski }
10169f55f5f5SRafal Jaworowski return (port_config);
10179f55f5f5SRafal Jaworowski }
10189f55f5f5SRafal Jaworowski
10199f55f5f5SRafal Jaworowski static int
mge_ifmedia_upd(if_t ifp)102098fe10c8SJustin Hibbits mge_ifmedia_upd(if_t ifp)
10219f55f5f5SRafal Jaworowski {
102298fe10c8SJustin Hibbits struct mge_softc *sc = if_getsoftc(ifp);
10239f55f5f5SRafal Jaworowski
10243c71b84fSZbigniew Bodek /*
10253c71b84fSZbigniew Bodek * Do not do anything for switch here, as updating media between
10263c71b84fSZbigniew Bodek * MGE MAC and switch MAC is hardcoded in PCB. Changing it here would
10273c71b84fSZbigniew Bodek * break the link.
10283c71b84fSZbigniew Bodek */
10293c71b84fSZbigniew Bodek if (sc->phy_attached) {
10309f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc);
103198fe10c8SJustin Hibbits if (if_getflags(ifp) & IFF_UP) {
10329f55f5f5SRafal Jaworowski sc->mge_media_status = sc->mii->mii_media.ifm_media;
10339f55f5f5SRafal Jaworowski mii_mediachg(sc->mii);
10343c71b84fSZbigniew Bodek
10353c71b84fSZbigniew Bodek /* MGE MAC needs to be reinitialized. */
10369f55f5f5SRafal Jaworowski mge_init_locked(sc);
10379f55f5f5SRafal Jaworowski
10383c71b84fSZbigniew Bodek }
10399f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc);
10409f55f5f5SRafal Jaworowski }
10419f55f5f5SRafal Jaworowski
10429f55f5f5SRafal Jaworowski return (0);
10439f55f5f5SRafal Jaworowski }
10449f55f5f5SRafal Jaworowski
10459f55f5f5SRafal Jaworowski static void
mge_init(void * arg)10469f55f5f5SRafal Jaworowski mge_init(void *arg)
10479f55f5f5SRafal Jaworowski {
10484ac30cc1SZbigniew Bodek struct mge_softc *sc;
10499f55f5f5SRafal Jaworowski
10504ac30cc1SZbigniew Bodek sc = arg;
10519f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc);
10529f55f5f5SRafal Jaworowski
10539f55f5f5SRafal Jaworowski mge_init_locked(arg);
10549f55f5f5SRafal Jaworowski
10559f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc);
10569f55f5f5SRafal Jaworowski }
10579f55f5f5SRafal Jaworowski
10589f55f5f5SRafal Jaworowski static void
mge_init_locked(void * arg)10599f55f5f5SRafal Jaworowski mge_init_locked(void *arg)
10609f55f5f5SRafal Jaworowski {
10619f55f5f5SRafal Jaworowski struct mge_softc *sc = arg;
10629f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw;
10639f55f5f5SRafal Jaworowski volatile uint32_t reg_val;
10649f55f5f5SRafal Jaworowski int i, count;
10653c71b84fSZbigniew Bodek uint32_t media_status;
10669f55f5f5SRafal Jaworowski
10679f55f5f5SRafal Jaworowski
10689f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK_ASSERT(sc);
10699f55f5f5SRafal Jaworowski
10709f55f5f5SRafal Jaworowski /* Stop interface */
10719f55f5f5SRafal Jaworowski mge_stop(sc);
10729f55f5f5SRafal Jaworowski
10739f55f5f5SRafal Jaworowski /* Disable interrupts */
10749f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0);
10759f55f5f5SRafal Jaworowski
10769f55f5f5SRafal Jaworowski /* Set MAC address */
10779f55f5f5SRafal Jaworowski mge_set_mac_address(sc);
10789f55f5f5SRafal Jaworowski
10799f55f5f5SRafal Jaworowski /* Setup multicast filters */
10809f55f5f5SRafal Jaworowski mge_setup_multicast(sc);
10819f55f5f5SRafal Jaworowski
10828e1dc58eSRafal Jaworowski if (sc->mge_ver == 2) {
10839f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN);
10849f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0));
10858e1dc58eSRafal Jaworowski }
10869f55f5f5SRafal Jaworowski
10878e1dc58eSRafal Jaworowski /* Initialize TX queue configuration registers */
10888e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt);
10898e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg);
10908e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg);
10918e1dc58eSRafal Jaworowski
10928e1dc58eSRafal Jaworowski /* Clear TX queue configuration registers for unused queues */
10939f55f5f5SRafal Jaworowski for (i = 1; i < 7; i++) {
10948e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0);
10958e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0);
10968e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0);
10979f55f5f5SRafal Jaworowski }
10989f55f5f5SRafal Jaworowski
10999f55f5f5SRafal Jaworowski /* Set default MTU */
11008e1dc58eSRafal Jaworowski MGE_WRITE(sc, sc->mge_mtu, 0);
11019f55f5f5SRafal Jaworowski
11029f55f5f5SRafal Jaworowski /* Port configuration */
11039f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG,
11049f55f5f5SRafal Jaworowski PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) |
11059f55f5f5SRafal Jaworowski PORT_CONFIG_ARO_RXQ(0));
11069f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0);
11079f55f5f5SRafal Jaworowski
11083c71b84fSZbigniew Bodek /* Configure promisc mode */
11093c71b84fSZbigniew Bodek mge_set_prom_mode(sc, MGE_RX_DEFAULT_QUEUE);
11103c71b84fSZbigniew Bodek
11113c71b84fSZbigniew Bodek media_status = sc->mge_media_status;
11123c71b84fSZbigniew Bodek if (sc->switch_attached) {
11133c71b84fSZbigniew Bodek media_status &= ~IFM_TMASK;
11143c71b84fSZbigniew Bodek media_status |= IFM_1000_T;
11153c71b84fSZbigniew Bodek }
11163c71b84fSZbigniew Bodek
11179f55f5f5SRafal Jaworowski /* Setup port configuration */
11183c71b84fSZbigniew Bodek reg_val = mge_set_port_serial_control(media_status);
11199f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
11209f55f5f5SRafal Jaworowski
11219f55f5f5SRafal Jaworowski /* Setup SDMA configuration */
11229f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP |
11239f55f5f5SRafal Jaworowski MGE_SDMA_TX_BYTE_SWAP |
11249f55f5f5SRafal Jaworowski MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) |
11259f55f5f5SRafal Jaworowski MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD));
11269f55f5f5SRafal Jaworowski
11279f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0);
11289f55f5f5SRafal Jaworowski
11299f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start);
11309f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE),
11319f55f5f5SRafal Jaworowski sc->rx_desc_start);
11329f55f5f5SRafal Jaworowski
11339f55f5f5SRafal Jaworowski /* Reset descriptor indexes */
11349f55f5f5SRafal Jaworowski sc->tx_desc_curr = 0;
11359f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0;
11369f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 0;
11375817716fSRafal Jaworowski sc->tx_desc_used_count = 0;
11389f55f5f5SRafal Jaworowski
11399f55f5f5SRafal Jaworowski /* Enable RX descriptors */
11409f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) {
11419f55f5f5SRafal Jaworowski dw = &sc->mge_rx_desc[i];
11429f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
11439f55f5f5SRafal Jaworowski dw->mge_desc->buff_size = MCLBYTES;
11449f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
11459f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11469f55f5f5SRafal Jaworowski }
11479f55f5f5SRafal Jaworowski
11489f55f5f5SRafal Jaworowski /* Enable RX queue */
11499f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE));
11509f55f5f5SRafal Jaworowski
11519f55f5f5SRafal Jaworowski /* Enable port */
11529f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
11539f55f5f5SRafal Jaworowski reg_val |= PORT_SERIAL_ENABLE;
11549f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
11559f55f5f5SRafal Jaworowski count = 0x100000;
11569f55f5f5SRafal Jaworowski for (;;) {
11579f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_STATUS);
11589f55f5f5SRafal Jaworowski if (reg_val & MGE_STATUS_LINKUP)
11599f55f5f5SRafal Jaworowski break;
11609f55f5f5SRafal Jaworowski DELAY(100);
11619f55f5f5SRafal Jaworowski if (--count == 0) {
11629f55f5f5SRafal Jaworowski if_printf(sc->ifp, "Timeout on link-up\n");
11639f55f5f5SRafal Jaworowski break;
11649f55f5f5SRafal Jaworowski }
11659f55f5f5SRafal Jaworowski }
11669f55f5f5SRafal Jaworowski
11679f55f5f5SRafal Jaworowski /* Setup interrupts coalescing */
11689f55f5f5SRafal Jaworowski mge_set_rxic(sc);
11699f55f5f5SRafal Jaworowski mge_set_txic(sc);
11709f55f5f5SRafal Jaworowski
11719f55f5f5SRafal Jaworowski /* Enable interrupts */
11729f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
11739f55f5f5SRafal Jaworowski /*
11749f55f5f5SRafal Jaworowski * * ...only if polling is not turned on. Disable interrupts explicitly
11759f55f5f5SRafal Jaworowski * if polling is enabled.
11769f55f5f5SRafal Jaworowski */
117796ab5e71SJustin Hibbits if (if_getcapenable(sc->ifp) & IFCAP_POLLING)
11789f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0);
11799f55f5f5SRafal Jaworowski else
11809f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */
11819f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 1);
11829f55f5f5SRafal Jaworowski
11839f55f5f5SRafal Jaworowski /* Activate network interface */
118496ab5e71SJustin Hibbits if_setdrvflagbits(sc->ifp, IFF_DRV_RUNNING, 0);
118596ab5e71SJustin Hibbits if_setdrvflagbits(sc->ifp, 0, IFF_DRV_OACTIVE);
11869f55f5f5SRafal Jaworowski sc->wd_timer = 0;
11879f55f5f5SRafal Jaworowski
11889f55f5f5SRafal Jaworowski /* Schedule watchdog timeout */
11893c71b84fSZbigniew Bodek if (sc->phy_attached)
11909f55f5f5SRafal Jaworowski callout_reset(&sc->wd_callout, hz, mge_tick, sc);
11919f55f5f5SRafal Jaworowski }
11929f55f5f5SRafal Jaworowski
11939f55f5f5SRafal Jaworowski static void
mge_intr_rxtx(void * arg)119475f1438bSOleksandr Tymoshenko mge_intr_rxtx(void *arg)
119575f1438bSOleksandr Tymoshenko {
11964ac30cc1SZbigniew Bodek struct mge_softc *sc;
119775f1438bSOleksandr Tymoshenko uint32_t int_cause, int_cause_ext;
119875f1438bSOleksandr Tymoshenko
11994ac30cc1SZbigniew Bodek sc = arg;
120075f1438bSOleksandr Tymoshenko MGE_GLOBAL_LOCK(sc);
120175f1438bSOleksandr Tymoshenko
120275f1438bSOleksandr Tymoshenko #ifdef DEVICE_POLLING
120396ab5e71SJustin Hibbits if (if_getcapenable(sc->ifp) & IFCAP_POLLING) {
120475f1438bSOleksandr Tymoshenko MGE_GLOBAL_UNLOCK(sc);
120575f1438bSOleksandr Tymoshenko return;
120675f1438bSOleksandr Tymoshenko }
120775f1438bSOleksandr Tymoshenko #endif
120875f1438bSOleksandr Tymoshenko
120975f1438bSOleksandr Tymoshenko /* Get interrupt cause */
121075f1438bSOleksandr Tymoshenko int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
121175f1438bSOleksandr Tymoshenko int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
121275f1438bSOleksandr Tymoshenko
121375f1438bSOleksandr Tymoshenko /* Check for Transmit interrupt */
121475f1438bSOleksandr Tymoshenko if (int_cause_ext & (MGE_PORT_INT_EXT_TXBUF0 |
121575f1438bSOleksandr Tymoshenko MGE_PORT_INT_EXT_TXUR)) {
121675f1438bSOleksandr Tymoshenko MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
121775f1438bSOleksandr Tymoshenko (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
121875f1438bSOleksandr Tymoshenko mge_intr_tx_locked(sc);
121975f1438bSOleksandr Tymoshenko }
122075f1438bSOleksandr Tymoshenko
122175f1438bSOleksandr Tymoshenko MGE_TRANSMIT_UNLOCK(sc);
122275f1438bSOleksandr Tymoshenko
122375f1438bSOleksandr Tymoshenko /* Check for Receive interrupt */
122475f1438bSOleksandr Tymoshenko mge_intr_rx_check(sc, int_cause, int_cause_ext);
122575f1438bSOleksandr Tymoshenko
122675f1438bSOleksandr Tymoshenko MGE_RECEIVE_UNLOCK(sc);
122775f1438bSOleksandr Tymoshenko }
122875f1438bSOleksandr Tymoshenko
122975f1438bSOleksandr Tymoshenko static void
mge_intr_err(void * arg)12309f55f5f5SRafal Jaworowski mge_intr_err(void *arg)
12319f55f5f5SRafal Jaworowski {
12324ac30cc1SZbigniew Bodek struct mge_softc *sc;
123398fe10c8SJustin Hibbits if_t ifp;
12349f55f5f5SRafal Jaworowski
12354ac30cc1SZbigniew Bodek sc = arg;
12369f55f5f5SRafal Jaworowski ifp = sc->ifp;
12379f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__);
12389f55f5f5SRafal Jaworowski }
12399f55f5f5SRafal Jaworowski
12409f55f5f5SRafal Jaworowski static void
mge_intr_misc(void * arg)12419f55f5f5SRafal Jaworowski mge_intr_misc(void *arg)
12429f55f5f5SRafal Jaworowski {
12434ac30cc1SZbigniew Bodek struct mge_softc *sc;
124498fe10c8SJustin Hibbits if_t ifp;
12459f55f5f5SRafal Jaworowski
12464ac30cc1SZbigniew Bodek sc = arg;
12479f55f5f5SRafal Jaworowski ifp = sc->ifp;
12489f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__);
12499f55f5f5SRafal Jaworowski }
12509f55f5f5SRafal Jaworowski
12519f55f5f5SRafal Jaworowski static void
mge_intr_rx(void * arg)12529f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) {
12534ac30cc1SZbigniew Bodek struct mge_softc *sc;
12549f55f5f5SRafal Jaworowski uint32_t int_cause, int_cause_ext;
12559f55f5f5SRafal Jaworowski
12564ac30cc1SZbigniew Bodek sc = arg;
12579f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc);
12589f55f5f5SRafal Jaworowski
12599f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
126096ab5e71SJustin Hibbits if (if_getcapenable(sc->ifp) & IFCAP_POLLING) {
12619f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc);
12629f55f5f5SRafal Jaworowski return;
12639f55f5f5SRafal Jaworowski }
12649f55f5f5SRafal Jaworowski #endif
12659f55f5f5SRafal Jaworowski
12669f55f5f5SRafal Jaworowski /* Get interrupt cause */
12679f55f5f5SRafal Jaworowski int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE);
12689f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
12699f55f5f5SRafal Jaworowski
127075f1438bSOleksandr Tymoshenko mge_intr_rx_check(sc, int_cause, int_cause_ext);
127175f1438bSOleksandr Tymoshenko
127275f1438bSOleksandr Tymoshenko MGE_RECEIVE_UNLOCK(sc);
127375f1438bSOleksandr Tymoshenko }
127475f1438bSOleksandr Tymoshenko
127575f1438bSOleksandr Tymoshenko static void
mge_intr_rx_check(struct mge_softc * sc,uint32_t int_cause,uint32_t int_cause_ext)127675f1438bSOleksandr Tymoshenko mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause,
127775f1438bSOleksandr Tymoshenko uint32_t int_cause_ext)
127875f1438bSOleksandr Tymoshenko {
12799f55f5f5SRafal Jaworowski /* Check for resource error */
12809f55f5f5SRafal Jaworowski if (int_cause & MGE_PORT_INT_RXERRQ0) {
12819f55f5f5SRafal Jaworowski mge_reinit_rx(sc);
12829f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE,
128375f1438bSOleksandr Tymoshenko ~(int_cause & MGE_PORT_INT_RXERRQ0));
12849f55f5f5SRafal Jaworowski }
12859f55f5f5SRafal Jaworowski
12869f55f5f5SRafal Jaworowski int_cause &= MGE_PORT_INT_RXQ0;
12879f55f5f5SRafal Jaworowski int_cause_ext &= MGE_PORT_INT_EXT_RXOR;
12889f55f5f5SRafal Jaworowski
12899f55f5f5SRafal Jaworowski if (int_cause || int_cause_ext) {
12909f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause);
12919f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext);
12929f55f5f5SRafal Jaworowski mge_intr_rx_locked(sc, -1);
12939f55f5f5SRafal Jaworowski }
12949f55f5f5SRafal Jaworowski }
12959f55f5f5SRafal Jaworowski
12961abcdbd1SAttilio Rao static int
mge_intr_rx_locked(struct mge_softc * sc,int count)12979f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count)
12989f55f5f5SRafal Jaworowski {
129998fe10c8SJustin Hibbits if_t ifp = sc->ifp;
13009f55f5f5SRafal Jaworowski uint32_t status;
13019f55f5f5SRafal Jaworowski uint16_t bufsize;
13029f55f5f5SRafal Jaworowski struct mge_desc_wrapper* dw;
13039f55f5f5SRafal Jaworowski struct mbuf *mb;
13041abcdbd1SAttilio Rao int rx_npkts = 0;
13059f55f5f5SRafal Jaworowski
13069f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK_ASSERT(sc);
13079f55f5f5SRafal Jaworowski
13089f55f5f5SRafal Jaworowski while (count != 0) {
13099f55f5f5SRafal Jaworowski dw = &sc->mge_rx_desc[sc->rx_desc_curr];
13109f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
13119f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD);
13129f55f5f5SRafal Jaworowski
13139f55f5f5SRafal Jaworowski /* Get status */
13149f55f5f5SRafal Jaworowski status = dw->mge_desc->cmd_status;
13159f55f5f5SRafal Jaworowski bufsize = dw->mge_desc->buff_size;
13169f55f5f5SRafal Jaworowski if ((status & MGE_DMA_OWNED) != 0)
13179f55f5f5SRafal Jaworowski break;
13189f55f5f5SRafal Jaworowski
13199f55f5f5SRafal Jaworowski if (dw->mge_desc->byte_count &&
13209f55f5f5SRafal Jaworowski ~(status & MGE_ERR_SUMMARY)) {
13219f55f5f5SRafal Jaworowski
13229f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap,
13239f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD);
13249f55f5f5SRafal Jaworowski
13259f55f5f5SRafal Jaworowski mb = m_devget(dw->buffer->m_data,
13269f55f5f5SRafal Jaworowski dw->mge_desc->byte_count - ETHER_CRC_LEN,
13279f55f5f5SRafal Jaworowski 0, ifp, NULL);
13289f55f5f5SRafal Jaworowski
13295817716fSRafal Jaworowski if (mb == NULL)
13305817716fSRafal Jaworowski /* Give up if no mbufs */
13315817716fSRafal Jaworowski break;
13325817716fSRafal Jaworowski
13339f55f5f5SRafal Jaworowski mb->m_len -= 2;
13349f55f5f5SRafal Jaworowski mb->m_pkthdr.len -= 2;
13359f55f5f5SRafal Jaworowski mb->m_data += 2;
13369f55f5f5SRafal Jaworowski
1337b8fad6c0SFabien Thomas mb->m_pkthdr.rcvif = ifp;
1338b8fad6c0SFabien Thomas
13399f55f5f5SRafal Jaworowski mge_offload_process_frame(ifp, mb, status,
13409f55f5f5SRafal Jaworowski bufsize);
13419f55f5f5SRafal Jaworowski
13429f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc);
134398fe10c8SJustin Hibbits if_input(ifp, mb);
13449f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc);
13451abcdbd1SAttilio Rao rx_npkts++;
13469f55f5f5SRafal Jaworowski }
13479f55f5f5SRafal Jaworowski
13489f55f5f5SRafal Jaworowski dw->mge_desc->byte_count = 0;
13499f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
13505817716fSRafal Jaworowski sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM);
13519f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
13529f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
13539f55f5f5SRafal Jaworowski
13549f55f5f5SRafal Jaworowski if (count > 0)
13559f55f5f5SRafal Jaworowski count -= 1;
13569f55f5f5SRafal Jaworowski }
13579f55f5f5SRafal Jaworowski
1358c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_npkts);
1359b8fad6c0SFabien Thomas
13601abcdbd1SAttilio Rao return (rx_npkts);
13619f55f5f5SRafal Jaworowski }
13629f55f5f5SRafal Jaworowski
13639f55f5f5SRafal Jaworowski static void
mge_intr_sum(void * arg)13649f55f5f5SRafal Jaworowski mge_intr_sum(void *arg)
13659f55f5f5SRafal Jaworowski {
13669f55f5f5SRafal Jaworowski struct mge_softc *sc = arg;
136798fe10c8SJustin Hibbits if_t ifp;
13689f55f5f5SRafal Jaworowski
13699f55f5f5SRafal Jaworowski ifp = sc->ifp;
13709f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__);
13719f55f5f5SRafal Jaworowski }
13729f55f5f5SRafal Jaworowski
13739f55f5f5SRafal Jaworowski static void
mge_intr_tx(void * arg)13749f55f5f5SRafal Jaworowski mge_intr_tx(void *arg)
13759f55f5f5SRafal Jaworowski {
13769f55f5f5SRafal Jaworowski struct mge_softc *sc = arg;
13779f55f5f5SRafal Jaworowski uint32_t int_cause_ext;
13789f55f5f5SRafal Jaworowski
13799f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc);
13809f55f5f5SRafal Jaworowski
13819f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
138296ab5e71SJustin Hibbits if (if_getcapenable(sc->ifp) & IFCAP_POLLING) {
13839f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc);
13849f55f5f5SRafal Jaworowski return;
13859f55f5f5SRafal Jaworowski }
13869f55f5f5SRafal Jaworowski #endif
13879f55f5f5SRafal Jaworowski
13889f55f5f5SRafal Jaworowski /* Ack the interrupt */
13899f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT);
139075f1438bSOleksandr Tymoshenko MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext &
139175f1438bSOleksandr Tymoshenko (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR)));
13929f55f5f5SRafal Jaworowski
13939f55f5f5SRafal Jaworowski mge_intr_tx_locked(sc);
13949f55f5f5SRafal Jaworowski
13959f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc);
13969f55f5f5SRafal Jaworowski }
13979f55f5f5SRafal Jaworowski
13989f55f5f5SRafal Jaworowski static void
mge_intr_tx_locked(struct mge_softc * sc)13999f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc)
14009f55f5f5SRafal Jaworowski {
140198fe10c8SJustin Hibbits if_t ifp = sc->ifp;
14029f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw;
14039f55f5f5SRafal Jaworowski struct mge_desc *desc;
14049f55f5f5SRafal Jaworowski uint32_t status;
14059f55f5f5SRafal Jaworowski int send = 0;
14069f55f5f5SRafal Jaworowski
14079f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK_ASSERT(sc);
14089f55f5f5SRafal Jaworowski
14099f55f5f5SRafal Jaworowski /* Disable watchdog */
14109f55f5f5SRafal Jaworowski sc->wd_timer = 0;
14119f55f5f5SRafal Jaworowski
14129f55f5f5SRafal Jaworowski while (sc->tx_desc_used_count) {
14139f55f5f5SRafal Jaworowski /* Get the descriptor */
14149f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
14159f55f5f5SRafal Jaworowski desc = dw->mge_desc;
14169f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
14179f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD);
14189f55f5f5SRafal Jaworowski
14199f55f5f5SRafal Jaworowski /* Get descriptor status */
14209f55f5f5SRafal Jaworowski status = desc->cmd_status;
14219f55f5f5SRafal Jaworowski
14229f55f5f5SRafal Jaworowski if (status & MGE_DMA_OWNED)
14239f55f5f5SRafal Jaworowski break;
14249f55f5f5SRafal Jaworowski
14259f55f5f5SRafal Jaworowski sc->tx_desc_used_idx =
1426c2ede4b3SMartin Blapp (++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM;
14279f55f5f5SRafal Jaworowski sc->tx_desc_used_count--;
14289f55f5f5SRafal Jaworowski
14299f55f5f5SRafal Jaworowski /* Update collision statistics */
14309f55f5f5SRafal Jaworowski if (status & MGE_ERR_SUMMARY) {
14319f55f5f5SRafal Jaworowski if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC)
1432c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1);
14339f55f5f5SRafal Jaworowski if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL)
1434c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 16);
14359f55f5f5SRafal Jaworowski }
14369f55f5f5SRafal Jaworowski
14379f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
14389f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTWRITE);
14399f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
14409f55f5f5SRafal Jaworowski m_freem(dw->buffer);
14419f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL;
14429f55f5f5SRafal Jaworowski send++;
14439f55f5f5SRafal Jaworowski
1444c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
14459f55f5f5SRafal Jaworowski }
14469f55f5f5SRafal Jaworowski
14479f55f5f5SRafal Jaworowski if (send) {
14489f55f5f5SRafal Jaworowski /* Now send anything that was pending */
144998fe10c8SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
14509f55f5f5SRafal Jaworowski mge_start_locked(ifp);
14519f55f5f5SRafal Jaworowski }
14529f55f5f5SRafal Jaworowski }
14539f55f5f5SRafal Jaworowski static int
mge_ioctl(if_t ifp,u_long command,caddr_t data)145498fe10c8SJustin Hibbits mge_ioctl(if_t ifp, u_long command, caddr_t data)
14559f55f5f5SRafal Jaworowski {
145698fe10c8SJustin Hibbits struct mge_softc *sc = if_getsoftc(ifp);
14579f55f5f5SRafal Jaworowski struct ifreq *ifr = (struct ifreq *)data;
14589f55f5f5SRafal Jaworowski int mask, error;
14599f55f5f5SRafal Jaworowski uint32_t flags;
14609f55f5f5SRafal Jaworowski
14619f55f5f5SRafal Jaworowski error = 0;
14629f55f5f5SRafal Jaworowski
14639f55f5f5SRafal Jaworowski switch (command) {
14649f55f5f5SRafal Jaworowski case SIOCSIFFLAGS:
14659f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc);
14669f55f5f5SRafal Jaworowski
146798fe10c8SJustin Hibbits if (if_getflags(ifp) & IFF_UP) {
146898fe10c8SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
146998fe10c8SJustin Hibbits flags = if_getflags(ifp) ^ sc->mge_if_flags;
14709f55f5f5SRafal Jaworowski if (flags & IFF_PROMISC)
14719f55f5f5SRafal Jaworowski mge_set_prom_mode(sc,
14729f55f5f5SRafal Jaworowski MGE_RX_DEFAULT_QUEUE);
14739f55f5f5SRafal Jaworowski
14749f55f5f5SRafal Jaworowski if (flags & IFF_ALLMULTI)
14759f55f5f5SRafal Jaworowski mge_setup_multicast(sc);
14769f55f5f5SRafal Jaworowski } else
14779f55f5f5SRafal Jaworowski mge_init_locked(sc);
14789f55f5f5SRafal Jaworowski }
147998fe10c8SJustin Hibbits else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
14809f55f5f5SRafal Jaworowski mge_stop(sc);
14819f55f5f5SRafal Jaworowski
148298fe10c8SJustin Hibbits sc->mge_if_flags = if_getflags(ifp);
14839f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc);
14849f55f5f5SRafal Jaworowski break;
14859f55f5f5SRafal Jaworowski case SIOCADDMULTI:
14869f55f5f5SRafal Jaworowski case SIOCDELMULTI:
148798fe10c8SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
14889f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc);
14899f55f5f5SRafal Jaworowski mge_setup_multicast(sc);
14909f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc);
14919f55f5f5SRafal Jaworowski }
14929f55f5f5SRafal Jaworowski break;
14939f55f5f5SRafal Jaworowski case SIOCSIFCAP:
149498fe10c8SJustin Hibbits mask = if_getcapenable(ifp) ^ ifr->ifr_reqcap;
14959f55f5f5SRafal Jaworowski if (mask & IFCAP_HWCSUM) {
149698fe10c8SJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_HWCSUM);
149798fe10c8SJustin Hibbits if_setcapenablebit(ifp, IFCAP_HWCSUM & ifr->ifr_reqcap, 0);
149898fe10c8SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_TXCSUM)
149998fe10c8SJustin Hibbits if_sethwassist(ifp, MGE_CHECKSUM_FEATURES);
15009f55f5f5SRafal Jaworowski else
150198fe10c8SJustin Hibbits if_sethwassist(ifp, 0);
15029f55f5f5SRafal Jaworowski }
15039f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
15049f55f5f5SRafal Jaworowski if (mask & IFCAP_POLLING) {
15059f55f5f5SRafal Jaworowski if (ifr->ifr_reqcap & IFCAP_POLLING) {
15069f55f5f5SRafal Jaworowski error = ether_poll_register(mge_poll, ifp);
15079f55f5f5SRafal Jaworowski if (error)
15089f55f5f5SRafal Jaworowski return(error);
15099f55f5f5SRafal Jaworowski
15109f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc);
15119f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0);
151298fe10c8SJustin Hibbits if_setcapenablebit(ifp, IFCAP_POLLING, 0);
15139f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc);
15149f55f5f5SRafal Jaworowski } else {
15159f55f5f5SRafal Jaworowski error = ether_poll_deregister(ifp);
15169f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc);
15179f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 1);
151898fe10c8SJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_POLLING);
15199f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc);
15209f55f5f5SRafal Jaworowski }
15219f55f5f5SRafal Jaworowski }
15229f55f5f5SRafal Jaworowski #endif
15239f55f5f5SRafal Jaworowski break;
15249f55f5f5SRafal Jaworowski case SIOCGIFMEDIA: /* fall through */
15259f55f5f5SRafal Jaworowski case SIOCSIFMEDIA:
15263c71b84fSZbigniew Bodek /*
15273c71b84fSZbigniew Bodek * Setting up media type via ioctls is *not* supported for MAC
15283c71b84fSZbigniew Bodek * which is connected to switch. Use etherswitchcfg.
15293c71b84fSZbigniew Bodek */
15303c71b84fSZbigniew Bodek if (!sc->phy_attached && (command == SIOCSIFMEDIA))
15313c71b84fSZbigniew Bodek return (0);
15323c71b84fSZbigniew Bodek else if (!sc->phy_attached) {
15333c71b84fSZbigniew Bodek error = ifmedia_ioctl(ifp, ifr, &sc->mge_ifmedia,
15343c71b84fSZbigniew Bodek command);
15353c71b84fSZbigniew Bodek break;
15363c71b84fSZbigniew Bodek }
15373c71b84fSZbigniew Bodek
15389f55f5f5SRafal Jaworowski if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T
15399f55f5f5SRafal Jaworowski && !(ifr->ifr_media & IFM_FDX)) {
15409f55f5f5SRafal Jaworowski device_printf(sc->dev,
15419f55f5f5SRafal Jaworowski "1000baseTX half-duplex unsupported\n");
15429f55f5f5SRafal Jaworowski return 0;
15439f55f5f5SRafal Jaworowski }
15449f55f5f5SRafal Jaworowski error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
15459f55f5f5SRafal Jaworowski break;
15469f55f5f5SRafal Jaworowski default:
15479f55f5f5SRafal Jaworowski error = ether_ioctl(ifp, command, data);
15489f55f5f5SRafal Jaworowski }
15499f55f5f5SRafal Jaworowski return (error);
15509f55f5f5SRafal Jaworowski }
15519f55f5f5SRafal Jaworowski
15529f55f5f5SRafal Jaworowski static int
mge_miibus_readreg(device_t dev,int phy,int reg)15539f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg)
15549f55f5f5SRafal Jaworowski {
15559f55f5f5SRafal Jaworowski
15563c71b84fSZbigniew Bodek KASSERT(!switch_attached, ("miibus used with switch attached"));
15579f55f5f5SRafal Jaworowski
15583c71b84fSZbigniew Bodek return (mv_read_ext_phy(dev, phy, reg));
15599f55f5f5SRafal Jaworowski }
15609f55f5f5SRafal Jaworowski
15618e45f0b7SAndriy Gapon static int
mge_miibus_writereg(device_t dev,int phy,int reg,int value)15629f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value)
15639f55f5f5SRafal Jaworowski {
1564db5ef4fcSRafal Jaworowski
15653c71b84fSZbigniew Bodek KASSERT(!switch_attached, ("miibus used with switch attached"));
15669f55f5f5SRafal Jaworowski
15673c71b84fSZbigniew Bodek mv_write_ext_phy(dev, phy, reg, value);
15689f55f5f5SRafal Jaworowski
15698e45f0b7SAndriy Gapon return (0);
15709f55f5f5SRafal Jaworowski }
15719f55f5f5SRafal Jaworowski
15729f55f5f5SRafal Jaworowski static int
mge_probe(device_t dev)15739f55f5f5SRafal Jaworowski mge_probe(device_t dev)
15749f55f5f5SRafal Jaworowski {
15759f55f5f5SRafal Jaworowski
1576add35ed5SIan Lepore if (!ofw_bus_status_okay(dev))
1577add35ed5SIan Lepore return (ENXIO);
1578add35ed5SIan Lepore
1579db5ef4fcSRafal Jaworowski if (!ofw_bus_is_compatible(dev, "mrvl,ge"))
1580db5ef4fcSRafal Jaworowski return (ENXIO);
1581db5ef4fcSRafal Jaworowski
15829f55f5f5SRafal Jaworowski device_set_desc(dev, "Marvell Gigabit Ethernet controller");
15839f55f5f5SRafal Jaworowski return (BUS_PROBE_DEFAULT);
15849f55f5f5SRafal Jaworowski }
15859f55f5f5SRafal Jaworowski
15869f55f5f5SRafal Jaworowski static int
mge_resume(device_t dev)15879f55f5f5SRafal Jaworowski mge_resume(device_t dev)
15889f55f5f5SRafal Jaworowski {
15899f55f5f5SRafal Jaworowski
15909f55f5f5SRafal Jaworowski device_printf(dev, "%s\n", __FUNCTION__);
15919f55f5f5SRafal Jaworowski return (0);
15929f55f5f5SRafal Jaworowski }
15939f55f5f5SRafal Jaworowski
15949f55f5f5SRafal Jaworowski static int
mge_shutdown(device_t dev)15959f55f5f5SRafal Jaworowski mge_shutdown(device_t dev)
15969f55f5f5SRafal Jaworowski {
15979f55f5f5SRafal Jaworowski struct mge_softc *sc = device_get_softc(dev);
15989f55f5f5SRafal Jaworowski
15999f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc);
16009f55f5f5SRafal Jaworowski
16019f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING
160296ab5e71SJustin Hibbits if (if_getcapenable(sc->ifp) & IFCAP_POLLING)
16039f55f5f5SRafal Jaworowski ether_poll_deregister(sc->ifp);
16049f55f5f5SRafal Jaworowski #endif
16059f55f5f5SRafal Jaworowski
16069f55f5f5SRafal Jaworowski mge_stop(sc);
16079f55f5f5SRafal Jaworowski
16089f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc);
16099f55f5f5SRafal Jaworowski
16109f55f5f5SRafal Jaworowski return (0);
16119f55f5f5SRafal Jaworowski }
16129f55f5f5SRafal Jaworowski
16139f55f5f5SRafal Jaworowski static int
mge_encap(struct mge_softc * sc,struct mbuf * m0)16149f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0)
16159f55f5f5SRafal Jaworowski {
16169f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw = NULL;
16179f55f5f5SRafal Jaworowski bus_dma_segment_t segs[MGE_TX_DESC_NUM];
16189f55f5f5SRafal Jaworowski bus_dmamap_t mapp;
16199f55f5f5SRafal Jaworowski int error;
16209f55f5f5SRafal Jaworowski int seg, nsegs;
16219f55f5f5SRafal Jaworowski int desc_no;
16229f55f5f5SRafal Jaworowski
16239f55f5f5SRafal Jaworowski /* Fetch unused map */
16249f55f5f5SRafal Jaworowski desc_no = sc->tx_desc_curr;
16259f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[desc_no];
16269f55f5f5SRafal Jaworowski mapp = dw->buffer_dmap;
16279f55f5f5SRafal Jaworowski
16289f55f5f5SRafal Jaworowski /* Create mapping in DMA memory */
16299f55f5f5SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs,
16309f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT);
1631b8fad6c0SFabien Thomas if (error != 0) {
1632b8fad6c0SFabien Thomas m_freem(m0);
1633b8fad6c0SFabien Thomas return (error);
1634b8fad6c0SFabien Thomas }
1635b8fad6c0SFabien Thomas
1636b8fad6c0SFabien Thomas /* Only one segment is supported. */
1637b8fad6c0SFabien Thomas if (nsegs != 1) {
16389f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, mapp);
1639b8fad6c0SFabien Thomas m_freem(m0);
1640b8fad6c0SFabien Thomas return (-1);
16419f55f5f5SRafal Jaworowski }
16429f55f5f5SRafal Jaworowski
16439f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE);
16449f55f5f5SRafal Jaworowski
16459f55f5f5SRafal Jaworowski /* Everything is ok, now we can send buffers */
16469f55f5f5SRafal Jaworowski for (seg = 0; seg < nsegs; seg++) {
16479f55f5f5SRafal Jaworowski dw->mge_desc->byte_count = segs[seg].ds_len;
16489f55f5f5SRafal Jaworowski dw->mge_desc->buffer = segs[seg].ds_addr;
16499f55f5f5SRafal Jaworowski dw->buffer = m0;
165075f1438bSOleksandr Tymoshenko dw->mge_desc->cmd_status = 0;
16519f55f5f5SRafal Jaworowski if (seg == 0)
16529f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(sc, dw);
165375f1438bSOleksandr Tymoshenko dw->mge_desc->cmd_status |= MGE_TX_LAST | MGE_TX_FIRST |
165475f1438bSOleksandr Tymoshenko MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING |
165575f1438bSOleksandr Tymoshenko MGE_DMA_OWNED;
16569f55f5f5SRafal Jaworowski }
16579f55f5f5SRafal Jaworowski
1658d6bdd318SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
16599f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
16609f55f5f5SRafal Jaworowski
16619f55f5f5SRafal Jaworowski sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM;
16629f55f5f5SRafal Jaworowski sc->tx_desc_used_count++;
16639f55f5f5SRafal Jaworowski return (0);
16649f55f5f5SRafal Jaworowski }
16659f55f5f5SRafal Jaworowski
16669f55f5f5SRafal Jaworowski static void
mge_tick(void * msc)16679f55f5f5SRafal Jaworowski mge_tick(void *msc)
16689f55f5f5SRafal Jaworowski {
16699f55f5f5SRafal Jaworowski struct mge_softc *sc = msc;
16709f55f5f5SRafal Jaworowski
16713c71b84fSZbigniew Bodek KASSERT(sc->phy_attached == 1, ("mge_tick while PHY not attached"));
16723c71b84fSZbigniew Bodek
16733c71b84fSZbigniew Bodek MGE_GLOBAL_LOCK(sc);
16743c71b84fSZbigniew Bodek
16759f55f5f5SRafal Jaworowski /* Check for TX timeout */
16769f55f5f5SRafal Jaworowski mge_watchdog(sc);
16779f55f5f5SRafal Jaworowski
16789f55f5f5SRafal Jaworowski mii_tick(sc->mii);
16799f55f5f5SRafal Jaworowski
16809f55f5f5SRafal Jaworowski /* Check for media type change */
16819f55f5f5SRafal Jaworowski if(sc->mge_media_status != sc->mii->mii_media.ifm_media)
16829f55f5f5SRafal Jaworowski mge_ifmedia_upd(sc->ifp);
16839f55f5f5SRafal Jaworowski
16843c71b84fSZbigniew Bodek MGE_GLOBAL_UNLOCK(sc);
16853c71b84fSZbigniew Bodek
16869f55f5f5SRafal Jaworowski /* Schedule another timeout one second from now */
16879f55f5f5SRafal Jaworowski callout_reset(&sc->wd_callout, hz, mge_tick, sc);
16883c71b84fSZbigniew Bodek
16893c71b84fSZbigniew Bodek return;
16909f55f5f5SRafal Jaworowski }
16919f55f5f5SRafal Jaworowski
16929f55f5f5SRafal Jaworowski static void
mge_watchdog(struct mge_softc * sc)16939f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc)
16949f55f5f5SRafal Jaworowski {
169598fe10c8SJustin Hibbits if_t ifp;
16969f55f5f5SRafal Jaworowski
16979f55f5f5SRafal Jaworowski ifp = sc->ifp;
16989f55f5f5SRafal Jaworowski
16999f55f5f5SRafal Jaworowski if (sc->wd_timer == 0 || --sc->wd_timer) {
17009f55f5f5SRafal Jaworowski return;
17019f55f5f5SRafal Jaworowski }
17029f55f5f5SRafal Jaworowski
1703c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
17049f55f5f5SRafal Jaworowski if_printf(ifp, "watchdog timeout\n");
17059f55f5f5SRafal Jaworowski
17069f55f5f5SRafal Jaworowski mge_stop(sc);
17079f55f5f5SRafal Jaworowski mge_init_locked(sc);
17089f55f5f5SRafal Jaworowski }
17099f55f5f5SRafal Jaworowski
17109f55f5f5SRafal Jaworowski static void
mge_start(if_t ifp)171198fe10c8SJustin Hibbits mge_start(if_t ifp)
17129f55f5f5SRafal Jaworowski {
171398fe10c8SJustin Hibbits struct mge_softc *sc = if_getsoftc(ifp);
17149f55f5f5SRafal Jaworowski
17159f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc);
17169f55f5f5SRafal Jaworowski
17179f55f5f5SRafal Jaworowski mge_start_locked(ifp);
17189f55f5f5SRafal Jaworowski
17199f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc);
17209f55f5f5SRafal Jaworowski }
17219f55f5f5SRafal Jaworowski
17229f55f5f5SRafal Jaworowski static void
mge_start_locked(if_t ifp)172398fe10c8SJustin Hibbits mge_start_locked(if_t ifp)
17249f55f5f5SRafal Jaworowski {
17259f55f5f5SRafal Jaworowski struct mge_softc *sc;
17269f55f5f5SRafal Jaworowski struct mbuf *m0, *mtmp;
17279f55f5f5SRafal Jaworowski uint32_t reg_val, queued = 0;
17289f55f5f5SRafal Jaworowski
172998fe10c8SJustin Hibbits sc = if_getsoftc(ifp);
17309f55f5f5SRafal Jaworowski
17319f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK_ASSERT(sc);
17329f55f5f5SRafal Jaworowski
173398fe10c8SJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
17349f55f5f5SRafal Jaworowski IFF_DRV_RUNNING)
17359f55f5f5SRafal Jaworowski return;
17369f55f5f5SRafal Jaworowski
17379f55f5f5SRafal Jaworowski for (;;) {
17389f55f5f5SRafal Jaworowski /* Get packet from the queue */
173998fe10c8SJustin Hibbits m0 = if_dequeue(ifp);
17409f55f5f5SRafal Jaworowski if (m0 == NULL)
17419f55f5f5SRafal Jaworowski break;
17429f55f5f5SRafal Jaworowski
1743b8fad6c0SFabien Thomas if (m0->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP) ||
1744b8fad6c0SFabien Thomas m0->m_flags & M_VLANTAG) {
1745b8fad6c0SFabien Thomas if (M_WRITABLE(m0) == 0) {
1746b8fad6c0SFabien Thomas mtmp = m_dup(m0, M_NOWAIT);
1747b8fad6c0SFabien Thomas m_freem(m0);
1748b8fad6c0SFabien Thomas if (mtmp == NULL)
1749b8fad6c0SFabien Thomas continue;
1750b8fad6c0SFabien Thomas m0 = mtmp;
1751b8fad6c0SFabien Thomas }
1752b8fad6c0SFabien Thomas }
1753b8fad6c0SFabien Thomas /* The driver support only one DMA fragment. */
1754b8fad6c0SFabien Thomas if (m0->m_next != NULL) {
1755c6499eccSGleb Smirnoff mtmp = m_defrag(m0, M_NOWAIT);
17564ac30cc1SZbigniew Bodek if (mtmp != NULL)
17579f55f5f5SRafal Jaworowski m0 = mtmp;
1758b8fad6c0SFabien Thomas }
17599f55f5f5SRafal Jaworowski
1760b8fad6c0SFabien Thomas /* Check for free descriptors */
1761b8fad6c0SFabien Thomas if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) {
176298fe10c8SJustin Hibbits if_sendq_prepend(ifp, m0);
176398fe10c8SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
17649f55f5f5SRafal Jaworowski break;
17659f55f5f5SRafal Jaworowski }
1766b8fad6c0SFabien Thomas
1767b8fad6c0SFabien Thomas if (mge_encap(sc, m0) != 0)
1768b8fad6c0SFabien Thomas break;
1769b8fad6c0SFabien Thomas
17709f55f5f5SRafal Jaworowski queued++;
17719f55f5f5SRafal Jaworowski BPF_MTAP(ifp, m0);
17729f55f5f5SRafal Jaworowski }
17739f55f5f5SRafal Jaworowski
17749f55f5f5SRafal Jaworowski if (queued) {
17759f55f5f5SRafal Jaworowski /* Enable transmitter and watchdog timer */
17769f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
17779f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ);
17789f55f5f5SRafal Jaworowski sc->wd_timer = 5;
17799f55f5f5SRafal Jaworowski }
17809f55f5f5SRafal Jaworowski }
17819f55f5f5SRafal Jaworowski
17829f55f5f5SRafal Jaworowski static void
mge_stop(struct mge_softc * sc)17839f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc)
17849f55f5f5SRafal Jaworowski {
178598fe10c8SJustin Hibbits if_t ifp;
17869f55f5f5SRafal Jaworowski volatile uint32_t reg_val, status;
17879f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw;
17889f55f5f5SRafal Jaworowski struct mge_desc *desc;
17899f55f5f5SRafal Jaworowski int count;
17909f55f5f5SRafal Jaworowski
17919f55f5f5SRafal Jaworowski ifp = sc->ifp;
17929f55f5f5SRafal Jaworowski
179398fe10c8SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
17949f55f5f5SRafal Jaworowski return;
17959f55f5f5SRafal Jaworowski
17969f55f5f5SRafal Jaworowski /* Stop tick engine */
17979f55f5f5SRafal Jaworowski callout_stop(&sc->wd_callout);
17989f55f5f5SRafal Jaworowski
17999f55f5f5SRafal Jaworowski /* Disable interface */
180098fe10c8SJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
18019f55f5f5SRafal Jaworowski sc->wd_timer = 0;
18029f55f5f5SRafal Jaworowski
18039f55f5f5SRafal Jaworowski /* Disable interrupts */
18049f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0);
18059f55f5f5SRafal Jaworowski
18069f55f5f5SRafal Jaworowski /* Disable Rx and Tx */
18079f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD);
18089f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ);
18099f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL);
18109f55f5f5SRafal Jaworowski
18119f55f5f5SRafal Jaworowski /* Remove pending data from TX queue */
18125817716fSRafal Jaworowski while (sc->tx_desc_used_idx != sc->tx_desc_curr &&
18135817716fSRafal Jaworowski sc->tx_desc_used_count) {
18149f55f5f5SRafal Jaworowski /* Get the descriptor */
18159f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
18169f55f5f5SRafal Jaworowski desc = dw->mge_desc;
18179f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
18189f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD);
18199f55f5f5SRafal Jaworowski
18209f55f5f5SRafal Jaworowski /* Get descriptor status */
18219f55f5f5SRafal Jaworowski status = desc->cmd_status;
18229f55f5f5SRafal Jaworowski
18239f55f5f5SRafal Jaworowski if (status & MGE_DMA_OWNED)
18249f55f5f5SRafal Jaworowski break;
18259f55f5f5SRafal Jaworowski
18269f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) %
18279f55f5f5SRafal Jaworowski MGE_TX_DESC_NUM;
18285817716fSRafal Jaworowski sc->tx_desc_used_count--;
18299f55f5f5SRafal Jaworowski
18309f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
18319f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTWRITE);
18329f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap);
18339f55f5f5SRafal Jaworowski
18349f55f5f5SRafal Jaworowski m_freem(dw->buffer);
18359f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL;
18369f55f5f5SRafal Jaworowski }
18379f55f5f5SRafal Jaworowski
18389f55f5f5SRafal Jaworowski /* Wait for end of transmission */
18399f55f5f5SRafal Jaworowski count = 0x100000;
18409f55f5f5SRafal Jaworowski while (count--) {
18419f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_STATUS);
18429f55f5f5SRafal Jaworowski if ( !(reg_val & MGE_STATUS_TX_IN_PROG) &&
18439f55f5f5SRafal Jaworowski (reg_val & MGE_STATUS_TX_FIFO_EMPTY))
18449f55f5f5SRafal Jaworowski break;
18459f55f5f5SRafal Jaworowski DELAY(100);
18469f55f5f5SRafal Jaworowski }
18479f55f5f5SRafal Jaworowski
18484ac30cc1SZbigniew Bodek if (count == 0)
18494ac30cc1SZbigniew Bodek if_printf(ifp,
18504ac30cc1SZbigniew Bodek "%s: timeout while waiting for end of transmission\n",
18519f55f5f5SRafal Jaworowski __FUNCTION__);
18529f55f5f5SRafal Jaworowski
18539f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL);
18549f55f5f5SRafal Jaworowski reg_val &= ~(PORT_SERIAL_ENABLE);
18559f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val);
18569f55f5f5SRafal Jaworowski }
18579f55f5f5SRafal Jaworowski
18589f55f5f5SRafal Jaworowski static int
mge_suspend(device_t dev)18599f55f5f5SRafal Jaworowski mge_suspend(device_t dev)
18609f55f5f5SRafal Jaworowski {
18619f55f5f5SRafal Jaworowski
18629f55f5f5SRafal Jaworowski device_printf(dev, "%s\n", __FUNCTION__);
18639f55f5f5SRafal Jaworowski return (0);
18649f55f5f5SRafal Jaworowski }
18659f55f5f5SRafal Jaworowski
18669f55f5f5SRafal Jaworowski static void
mge_offload_process_frame(if_t ifp,struct mbuf * frame,uint32_t status,uint16_t bufsize)186798fe10c8SJustin Hibbits mge_offload_process_frame(if_t ifp, struct mbuf *frame,
18689f55f5f5SRafal Jaworowski uint32_t status, uint16_t bufsize)
18699f55f5f5SRafal Jaworowski {
18709f55f5f5SRafal Jaworowski int csum_flags = 0;
18719f55f5f5SRafal Jaworowski
187298fe10c8SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_RXCSUM) {
18739f55f5f5SRafal Jaworowski if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK))
18749f55f5f5SRafal Jaworowski csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID;
18759f55f5f5SRafal Jaworowski
18769f55f5f5SRafal Jaworowski if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 &&
18779f55f5f5SRafal Jaworowski (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) &&
18789f55f5f5SRafal Jaworowski (status & MGE_RX_L4_CSUM_OK)) {
18799f55f5f5SRafal Jaworowski csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
18809f55f5f5SRafal Jaworowski frame->m_pkthdr.csum_data = 0xFFFF;
18819f55f5f5SRafal Jaworowski }
18829f55f5f5SRafal Jaworowski
18839f55f5f5SRafal Jaworowski frame->m_pkthdr.csum_flags = csum_flags;
18849f55f5f5SRafal Jaworowski }
18859f55f5f5SRafal Jaworowski }
18869f55f5f5SRafal Jaworowski
18879f55f5f5SRafal Jaworowski static void
mge_offload_setup_descriptor(struct mge_softc * sc,struct mge_desc_wrapper * dw)18889f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw)
18899f55f5f5SRafal Jaworowski {
18909f55f5f5SRafal Jaworowski struct mbuf *m0 = dw->buffer;
18919f55f5f5SRafal Jaworowski struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *);
18929f55f5f5SRafal Jaworowski int csum_flags = m0->m_pkthdr.csum_flags;
18939f55f5f5SRafal Jaworowski int cmd_status = 0;
18949f55f5f5SRafal Jaworowski struct ip *ip;
18959f55f5f5SRafal Jaworowski int ehlen, etype;
18969f55f5f5SRafal Jaworowski
18974ac30cc1SZbigniew Bodek if (csum_flags != 0) {
18989f55f5f5SRafal Jaworowski if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
18999f55f5f5SRafal Jaworowski etype = ntohs(eh->evl_proto);
19009f55f5f5SRafal Jaworowski ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
19019f55f5f5SRafal Jaworowski csum_flags |= MGE_TX_VLAN_TAGGED;
19029f55f5f5SRafal Jaworowski } else {
19039f55f5f5SRafal Jaworowski etype = ntohs(eh->evl_encap_proto);
19049f55f5f5SRafal Jaworowski ehlen = ETHER_HDR_LEN;
19059f55f5f5SRafal Jaworowski }
19069f55f5f5SRafal Jaworowski
19079f55f5f5SRafal Jaworowski if (etype != ETHERTYPE_IP) {
19089f55f5f5SRafal Jaworowski if_printf(sc->ifp,
19099f55f5f5SRafal Jaworowski "TCP/IP Offload enabled for unsupported "
19109f55f5f5SRafal Jaworowski "protocol!\n");
19119f55f5f5SRafal Jaworowski return;
19129f55f5f5SRafal Jaworowski }
19139f55f5f5SRafal Jaworowski
19149f55f5f5SRafal Jaworowski ip = (struct ip *)(m0->m_data + ehlen);
19159f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl);
19169f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_NOT_FRAGMENT;
19179f55f5f5SRafal Jaworowski }
19189f55f5f5SRafal Jaworowski
19199f55f5f5SRafal Jaworowski if (csum_flags & CSUM_IP)
19209f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_IP_CSUM;
19219f55f5f5SRafal Jaworowski
19229f55f5f5SRafal Jaworowski if (csum_flags & CSUM_TCP)
19239f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_L4_CSUM;
19249f55f5f5SRafal Jaworowski
19259f55f5f5SRafal Jaworowski if (csum_flags & CSUM_UDP)
19269f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP;
19279f55f5f5SRafal Jaworowski
19289f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status |= cmd_status;
19299f55f5f5SRafal Jaworowski }
19309f55f5f5SRafal Jaworowski
19319f55f5f5SRafal Jaworowski static void
mge_intrs_ctrl(struct mge_softc * sc,int enable)19329f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable)
19339f55f5f5SRafal Jaworowski {
19349f55f5f5SRafal Jaworowski
19359f55f5f5SRafal Jaworowski if (enable) {
19369f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 |
19379f55f5f5SRafal Jaworowski MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0);
19389f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 |
19399f55f5f5SRafal Jaworowski MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR |
19409f55f5f5SRafal Jaworowski MGE_PORT_INT_EXT_TXBUF0);
19419f55f5f5SRafal Jaworowski } else {
19429f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_INT_CAUSE, 0x0);
19439f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_INT_MASK, 0x0);
19449f55f5f5SRafal Jaworowski
19459f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0);
19469f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0);
19479f55f5f5SRafal Jaworowski
19489f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0);
19499f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0);
19509f55f5f5SRafal Jaworowski }
19519f55f5f5SRafal Jaworowski }
19529f55f5f5SRafal Jaworowski
19539f55f5f5SRafal Jaworowski static uint8_t
mge_crc8(uint8_t * data,int size)19549f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size)
19559f55f5f5SRafal Jaworowski {
19569f55f5f5SRafal Jaworowski uint8_t crc = 0;
19579f55f5f5SRafal Jaworowski static const uint8_t ct[256] = {
19589f55f5f5SRafal Jaworowski 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
19599f55f5f5SRafal Jaworowski 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
19609f55f5f5SRafal Jaworowski 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
19619f55f5f5SRafal Jaworowski 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
19629f55f5f5SRafal Jaworowski 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
19639f55f5f5SRafal Jaworowski 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
19649f55f5f5SRafal Jaworowski 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
19659f55f5f5SRafal Jaworowski 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
19669f55f5f5SRafal Jaworowski 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
19679f55f5f5SRafal Jaworowski 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
19689f55f5f5SRafal Jaworowski 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
19699f55f5f5SRafal Jaworowski 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
19709f55f5f5SRafal Jaworowski 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
19719f55f5f5SRafal Jaworowski 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
19729f55f5f5SRafal Jaworowski 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
19739f55f5f5SRafal Jaworowski 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
19749f55f5f5SRafal Jaworowski 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
19759f55f5f5SRafal Jaworowski 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
19769f55f5f5SRafal Jaworowski 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
19779f55f5f5SRafal Jaworowski 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
19789f55f5f5SRafal Jaworowski 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
19799f55f5f5SRafal Jaworowski 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
19809f55f5f5SRafal Jaworowski 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
19819f55f5f5SRafal Jaworowski 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
19829f55f5f5SRafal Jaworowski 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
19839f55f5f5SRafal Jaworowski 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
19849f55f5f5SRafal Jaworowski 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
19859f55f5f5SRafal Jaworowski 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
19869f55f5f5SRafal Jaworowski 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
19879f55f5f5SRafal Jaworowski 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
19889f55f5f5SRafal Jaworowski 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
19899f55f5f5SRafal Jaworowski 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
19909f55f5f5SRafal Jaworowski };
19919f55f5f5SRafal Jaworowski
19929f55f5f5SRafal Jaworowski while(size--)
19939f55f5f5SRafal Jaworowski crc = ct[crc ^ *(data++)];
19949f55f5f5SRafal Jaworowski
19959f55f5f5SRafal Jaworowski return(crc);
19969f55f5f5SRafal Jaworowski }
19979f55f5f5SRafal Jaworowski
199853dc8c23SGleb Smirnoff struct mge_hash_maddr_ctx {
199953dc8c23SGleb Smirnoff uint32_t smt[MGE_MCAST_REG_NUMBER];
200053dc8c23SGleb Smirnoff uint32_t omt[MGE_MCAST_REG_NUMBER];
200153dc8c23SGleb Smirnoff };
200253dc8c23SGleb Smirnoff
200353dc8c23SGleb Smirnoff static u_int
mge_hash_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)200453dc8c23SGleb Smirnoff mge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
200553dc8c23SGleb Smirnoff {
200653dc8c23SGleb Smirnoff static const uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 };
200753dc8c23SGleb Smirnoff struct mge_hash_maddr_ctx *ctx = arg;
200853dc8c23SGleb Smirnoff static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
200953dc8c23SGleb Smirnoff uint8_t *mac;
201053dc8c23SGleb Smirnoff int i;
201153dc8c23SGleb Smirnoff
201253dc8c23SGleb Smirnoff mac = LLADDR(sdl);
201353dc8c23SGleb Smirnoff if (memcmp(mac, special, sizeof(special)) == 0) {
201453dc8c23SGleb Smirnoff i = mac[5];
201553dc8c23SGleb Smirnoff ctx->smt[i >> 2] |= v << ((i & 0x03) << 3);
201653dc8c23SGleb Smirnoff } else {
201753dc8c23SGleb Smirnoff i = mge_crc8(mac, ETHER_ADDR_LEN);
201853dc8c23SGleb Smirnoff ctx->omt[i >> 2] |= v << ((i & 0x03) << 3);
201953dc8c23SGleb Smirnoff }
202053dc8c23SGleb Smirnoff return (1);
202153dc8c23SGleb Smirnoff }
202253dc8c23SGleb Smirnoff
20239f55f5f5SRafal Jaworowski static void
mge_setup_multicast(struct mge_softc * sc)20249f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc)
20259f55f5f5SRafal Jaworowski {
202653dc8c23SGleb Smirnoff struct mge_hash_maddr_ctx ctx;
202798fe10c8SJustin Hibbits if_t ifp = sc->ifp;
202853dc8c23SGleb Smirnoff static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1;
20299f55f5f5SRafal Jaworowski int i;
20309f55f5f5SRafal Jaworowski
203198fe10c8SJustin Hibbits if (if_getflags(ifp) & IFF_ALLMULTI) {
20329f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++)
203353dc8c23SGleb Smirnoff ctx.smt[i] = ctx.omt[i] =
203453dc8c23SGleb Smirnoff (v << 24) | (v << 16) | (v << 8) | v;
20359f55f5f5SRafal Jaworowski } else {
203653dc8c23SGleb Smirnoff memset(&ctx, 0, sizeof(ctx));
203753dc8c23SGleb Smirnoff if_foreach_llmaddr(ifp, mge_hash_maddr, &ctx);
20389f55f5f5SRafal Jaworowski }
20399f55f5f5SRafal Jaworowski
20409f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) {
204153dc8c23SGleb Smirnoff MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), ctx.smt[i]);
204253dc8c23SGleb Smirnoff MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), ctx.omt[i]);
20439f55f5f5SRafal Jaworowski }
20449f55f5f5SRafal Jaworowski }
20459f55f5f5SRafal Jaworowski
20469f55f5f5SRafal Jaworowski static void
mge_set_rxic(struct mge_softc * sc)20479f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc)
20489f55f5f5SRafal Jaworowski {
20499f55f5f5SRafal Jaworowski uint32_t reg;
20509f55f5f5SRafal Jaworowski
20518e1dc58eSRafal Jaworowski if (sc->rx_ic_time > sc->mge_rx_ipg_max)
20528e1dc58eSRafal Jaworowski sc->rx_ic_time = sc->mge_rx_ipg_max;
20539f55f5f5SRafal Jaworowski
20549f55f5f5SRafal Jaworowski reg = MGE_READ(sc, MGE_SDMA_CONFIG);
20558e1dc58eSRafal Jaworowski reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver);
20568e1dc58eSRafal Jaworowski reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver);
20579f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_SDMA_CONFIG, reg);
20589f55f5f5SRafal Jaworowski }
20599f55f5f5SRafal Jaworowski
20609f55f5f5SRafal Jaworowski static void
mge_set_txic(struct mge_softc * sc)20619f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc)
20629f55f5f5SRafal Jaworowski {
20639f55f5f5SRafal Jaworowski uint32_t reg;
20649f55f5f5SRafal Jaworowski
20658e1dc58eSRafal Jaworowski if (sc->tx_ic_time > sc->mge_tfut_ipg_max)
20668e1dc58eSRafal Jaworowski sc->tx_ic_time = sc->mge_tfut_ipg_max;
20679f55f5f5SRafal Jaworowski
20689f55f5f5SRafal Jaworowski reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH);
20698e1dc58eSRafal Jaworowski reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver);
20708e1dc58eSRafal Jaworowski reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver);
20719f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg);
20729f55f5f5SRafal Jaworowski }
20739f55f5f5SRafal Jaworowski
20749f55f5f5SRafal Jaworowski static int
mge_sysctl_ic(SYSCTL_HANDLER_ARGS)20759f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS)
20769f55f5f5SRafal Jaworowski {
20779f55f5f5SRafal Jaworowski struct mge_softc *sc = (struct mge_softc *)arg1;
20788e1dc58eSRafal Jaworowski uint32_t time;
20799f55f5f5SRafal Jaworowski int error;
20809f55f5f5SRafal Jaworowski
20818e1dc58eSRafal Jaworowski time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time;
20829f55f5f5SRafal Jaworowski error = sysctl_handle_int(oidp, &time, 0, req);
20839f55f5f5SRafal Jaworowski if (error != 0)
20849f55f5f5SRafal Jaworowski return(error);
20859f55f5f5SRafal Jaworowski
20869f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc);
20879f55f5f5SRafal Jaworowski if (arg2 == MGE_IC_RX) {
20889f55f5f5SRafal Jaworowski sc->rx_ic_time = time;
20899f55f5f5SRafal Jaworowski mge_set_rxic(sc);
20909f55f5f5SRafal Jaworowski } else {
20919f55f5f5SRafal Jaworowski sc->tx_ic_time = time;
20929f55f5f5SRafal Jaworowski mge_set_txic(sc);
20939f55f5f5SRafal Jaworowski }
20949f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc);
20959f55f5f5SRafal Jaworowski
20969f55f5f5SRafal Jaworowski return(0);
20979f55f5f5SRafal Jaworowski }
20989f55f5f5SRafal Jaworowski
20999f55f5f5SRafal Jaworowski static void
mge_add_sysctls(struct mge_softc * sc)21009f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc)
21019f55f5f5SRafal Jaworowski {
21029f55f5f5SRafal Jaworowski struct sysctl_ctx_list *ctx;
21039f55f5f5SRafal Jaworowski struct sysctl_oid_list *children;
21049f55f5f5SRafal Jaworowski struct sysctl_oid *tree;
21059f55f5f5SRafal Jaworowski
21069f55f5f5SRafal Jaworowski ctx = device_get_sysctl_ctx(sc->dev);
21079f55f5f5SRafal Jaworowski children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
21089f55f5f5SRafal Jaworowski tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal",
21097029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "MGE Interrupts coalescing");
21109f55f5f5SRafal Jaworowski children = SYSCTL_CHILDREN(tree);
21119f55f5f5SRafal Jaworowski
21129f55f5f5SRafal Jaworowski SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time",
21136b2ff27cSAlexander Motin CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, MGE_IC_RX,
21147029da5cSPawel Biernacki mge_sysctl_ic, "I", "IC RX time threshold");
21159f55f5f5SRafal Jaworowski SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time",
21166b2ff27cSAlexander Motin CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, MGE_IC_TX,
21177029da5cSPawel Biernacki mge_sysctl_ic, "I", "IC TX time threshold");
21189f55f5f5SRafal Jaworowski }
21193c71b84fSZbigniew Bodek
21203c71b84fSZbigniew Bodek static int
mge_mdio_writereg(device_t dev,int phy,int reg,int value)21213c71b84fSZbigniew Bodek mge_mdio_writereg(device_t dev, int phy, int reg, int value)
21223c71b84fSZbigniew Bodek {
21233c71b84fSZbigniew Bodek
21243c71b84fSZbigniew Bodek mv_write_ge_smi(dev, phy, reg, value);
21253c71b84fSZbigniew Bodek
21263c71b84fSZbigniew Bodek return (0);
21273c71b84fSZbigniew Bodek }
21283c71b84fSZbigniew Bodek
21293c71b84fSZbigniew Bodek
21303c71b84fSZbigniew Bodek static int
mge_mdio_readreg(device_t dev,int phy,int reg)21313c71b84fSZbigniew Bodek mge_mdio_readreg(device_t dev, int phy, int reg)
21323c71b84fSZbigniew Bodek {
21333c71b84fSZbigniew Bodek int ret;
21343c71b84fSZbigniew Bodek
21353c71b84fSZbigniew Bodek ret = mv_read_ge_smi(dev, phy, reg);
21363c71b84fSZbigniew Bodek
21373c71b84fSZbigniew Bodek return (ret);
21383c71b84fSZbigniew Bodek }
2139