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/cdefs.h> 419f55f5f5SRafal Jaworowski __FBSDID("$FreeBSD$"); 429f55f5f5SRafal Jaworowski 439f55f5f5SRafal Jaworowski #include <sys/param.h> 449f55f5f5SRafal Jaworowski #include <sys/systm.h> 459f55f5f5SRafal Jaworowski #include <sys/endian.h> 469f55f5f5SRafal Jaworowski #include <sys/mbuf.h> 479f55f5f5SRafal Jaworowski #include <sys/lock.h> 489f55f5f5SRafal Jaworowski #include <sys/mutex.h> 499f55f5f5SRafal Jaworowski #include <sys/kernel.h> 509f55f5f5SRafal Jaworowski #include <sys/module.h> 519f55f5f5SRafal Jaworowski #include <sys/socket.h> 529f55f5f5SRafal Jaworowski #include <sys/sysctl.h> 539f55f5f5SRafal Jaworowski 549f55f5f5SRafal Jaworowski #include <net/ethernet.h> 559f55f5f5SRafal Jaworowski #include <net/bpf.h> 569f55f5f5SRafal Jaworowski #include <net/if.h> 579f55f5f5SRafal Jaworowski #include <net/if_arp.h> 589f55f5f5SRafal Jaworowski #include <net/if_dl.h> 599f55f5f5SRafal Jaworowski #include <net/if_media.h> 609f55f5f5SRafal Jaworowski #include <net/if_types.h> 619f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h> 629f55f5f5SRafal Jaworowski 639f55f5f5SRafal Jaworowski #include <netinet/in_systm.h> 649f55f5f5SRafal Jaworowski #include <netinet/in.h> 659f55f5f5SRafal Jaworowski #include <netinet/ip.h> 669f55f5f5SRafal Jaworowski 679f55f5f5SRafal Jaworowski #include <sys/sockio.h> 689f55f5f5SRafal Jaworowski #include <sys/bus.h> 699f55f5f5SRafal Jaworowski #include <machine/bus.h> 709f55f5f5SRafal Jaworowski #include <sys/rman.h> 719f55f5f5SRafal Jaworowski #include <machine/resource.h> 729f55f5f5SRafal Jaworowski 739f55f5f5SRafal Jaworowski #include <dev/mii/mii.h> 749f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h> 759f55f5f5SRafal Jaworowski 76db5ef4fcSRafal Jaworowski #include <dev/fdt/fdt_common.h> 77db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h> 78db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 7971e8eac4SAdrian Chadd #include <dev/mdio/mdio.h> 809f55f5f5SRafal Jaworowski 819f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h> 829f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h> 838e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h> 849f55f5f5SRafal Jaworowski 859f55f5f5SRafal Jaworowski #include "miibus_if.h" 863c71b84fSZbigniew Bodek #include "mdio_if.h" 873c71b84fSZbigniew Bodek 883c71b84fSZbigniew Bodek #define MGE_DELAY(x) pause("SMI access sleep", (x) / tick_sbt) 899f55f5f5SRafal Jaworowski 909f55f5f5SRafal Jaworowski static int mge_probe(device_t dev); 919f55f5f5SRafal Jaworowski static int mge_attach(device_t dev); 929f55f5f5SRafal Jaworowski static int mge_detach(device_t dev); 939f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev); 949f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev); 959f55f5f5SRafal Jaworowski static int mge_resume(device_t dev); 969f55f5f5SRafal Jaworowski 979f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg); 988e45f0b7SAndriy Gapon static int mge_miibus_writereg(device_t dev, int phy, int reg, int value); 999f55f5f5SRafal Jaworowski 1003c71b84fSZbigniew Bodek static int mge_mdio_readreg(device_t dev, int phy, int reg); 1013c71b84fSZbigniew Bodek static int mge_mdio_writereg(device_t dev, int phy, int reg, int value); 1023c71b84fSZbigniew Bodek 1039f55f5f5SRafal Jaworowski static int mge_ifmedia_upd(struct ifnet *ifp); 1049f55f5f5SRafal Jaworowski static void mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 1059f55f5f5SRafal Jaworowski 1069f55f5f5SRafal Jaworowski static void mge_init(void *arg); 1079f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg); 1089f55f5f5SRafal Jaworowski static void mge_start(struct ifnet *ifp); 1099f55f5f5SRafal Jaworowski static void mge_start_locked(struct ifnet *ifp); 1109f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc); 1119f55f5f5SRafal Jaworowski static int mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 1129f55f5f5SRafal Jaworowski 1138e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver); 1148e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver); 1158e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc); 1168e1dc58eSRafal Jaworowski 1179f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable); 11875f1438bSOleksandr Tymoshenko static void mge_intr_rxtx(void *arg); 1199f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg); 12075f1438bSOleksandr Tymoshenko static void mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause, 12175f1438bSOleksandr Tymoshenko uint32_t int_cause_ext); 1221abcdbd1SAttilio Rao static int mge_intr_rx_locked(struct mge_softc *sc, int count); 1239f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg); 1249f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc); 1259f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg); 1269f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg); 1279f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg); 1289f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc); 1299f55f5f5SRafal Jaworowski static void mge_tick(void *msc); 1309f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media); 1319f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr); 1329f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc); 1339f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, 1349f55f5f5SRafal Jaworowski uint8_t queue); 1359f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue); 1369f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc); 1379f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc, 1384ac30cc1SZbigniew Bodek struct mge_desc_wrapper* desc_tab, uint32_t size, 1394ac30cc1SZbigniew Bodek bus_dma_tag_t *buffer_tag); 1409f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, 1419f55f5f5SRafal Jaworowski struct mbuf **mbufp, bus_addr_t *paddr); 1424ac30cc1SZbigniew Bodek static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, 1434ac30cc1SZbigniew Bodek int error); 1449f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc); 1454ac30cc1SZbigniew Bodek static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab, 1464ac30cc1SZbigniew Bodek uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs); 1479f55f5f5SRafal Jaworowski static void mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame, 1489f55f5f5SRafal Jaworowski uint32_t status, uint16_t bufsize); 1499f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc, 1509f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw); 1519f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size); 1529f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc); 1539f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc); 1549f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc); 1559f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc); 1569f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS); 1579f55f5f5SRafal Jaworowski 1589f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = { 1599f55f5f5SRafal Jaworowski /* Device interface */ 1609f55f5f5SRafal Jaworowski DEVMETHOD(device_probe, mge_probe), 1619f55f5f5SRafal Jaworowski DEVMETHOD(device_attach, mge_attach), 1629f55f5f5SRafal Jaworowski DEVMETHOD(device_detach, mge_detach), 1639f55f5f5SRafal Jaworowski DEVMETHOD(device_shutdown, mge_shutdown), 1649f55f5f5SRafal Jaworowski DEVMETHOD(device_suspend, mge_suspend), 1659f55f5f5SRafal Jaworowski DEVMETHOD(device_resume, mge_resume), 1669f55f5f5SRafal Jaworowski /* MII interface */ 1679f55f5f5SRafal Jaworowski DEVMETHOD(miibus_readreg, mge_miibus_readreg), 1689f55f5f5SRafal Jaworowski DEVMETHOD(miibus_writereg, mge_miibus_writereg), 1693c71b84fSZbigniew Bodek /* MDIO interface */ 1703c71b84fSZbigniew Bodek DEVMETHOD(mdio_readreg, mge_mdio_readreg), 1713c71b84fSZbigniew Bodek DEVMETHOD(mdio_writereg, mge_mdio_writereg), 1729f55f5f5SRafal Jaworowski { 0, 0 } 1739f55f5f5SRafal Jaworowski }; 1749f55f5f5SRafal Jaworowski 1753c71b84fSZbigniew Bodek DEFINE_CLASS_0(mge, mge_driver, mge_methods, sizeof(struct mge_softc)); 1769f55f5f5SRafal Jaworowski 1779f55f5f5SRafal Jaworowski static devclass_t mge_devclass; 1783c71b84fSZbigniew Bodek static int switch_attached = 0; 1799f55f5f5SRafal Jaworowski 180db5ef4fcSRafal Jaworowski DRIVER_MODULE(mge, simplebus, mge_driver, mge_devclass, 0, 0); 1813e38757dSJohn Baldwin DRIVER_MODULE(miibus, mge, miibus_driver, 0, 0); 182*8933f7d6SJohn Baldwin DRIVER_MODULE(mdio, mge, mdio_driver, 0, 0); 1839f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1); 1849f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1); 1853c71b84fSZbigniew Bodek MODULE_DEPEND(mge, mdio, 1, 1, 1); 1869f55f5f5SRafal Jaworowski 1879f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = { 1889f55f5f5SRafal Jaworowski { SYS_RES_MEMORY, 0, RF_ACTIVE }, 1899f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 1909f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE }, 1919f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE }, 1929f55f5f5SRafal Jaworowski { -1, 0 } 1939f55f5f5SRafal Jaworowski }; 1949f55f5f5SRafal Jaworowski 1959f55f5f5SRafal Jaworowski static struct { 1969f55f5f5SRafal Jaworowski driver_intr_t *handler; 1979f55f5f5SRafal Jaworowski char * description; 19875f1438bSOleksandr Tymoshenko } mge_intrs[MGE_INTR_COUNT + 1] = { 19975f1438bSOleksandr Tymoshenko { mge_intr_rxtx,"GbE aggregated interrupt" }, 2009f55f5f5SRafal Jaworowski { mge_intr_rx, "GbE receive interrupt" }, 2019f55f5f5SRafal Jaworowski { mge_intr_tx, "GbE transmit interrupt" }, 2029f55f5f5SRafal Jaworowski { mge_intr_misc,"GbE misc interrupt" }, 2039f55f5f5SRafal Jaworowski { mge_intr_sum, "GbE summary interrupt" }, 2049f55f5f5SRafal Jaworowski { mge_intr_err, "GbE error interrupt" }, 2059f55f5f5SRafal Jaworowski }; 2069f55f5f5SRafal Jaworowski 2073c71b84fSZbigniew Bodek /* SMI access interlock */ 2083c71b84fSZbigniew Bodek static struct sx sx_smi; 2093c71b84fSZbigniew Bodek 2103c71b84fSZbigniew Bodek static uint32_t 2113c71b84fSZbigniew Bodek mv_read_ge_smi(device_t dev, int phy, int reg) 2123c71b84fSZbigniew Bodek { 2133c71b84fSZbigniew Bodek uint32_t timeout; 2143c71b84fSZbigniew Bodek uint32_t ret; 2153c71b84fSZbigniew Bodek struct mge_softc *sc; 2163c71b84fSZbigniew Bodek 2173c71b84fSZbigniew Bodek sc = device_get_softc(dev); 2183c71b84fSZbigniew Bodek KASSERT(sc != NULL, ("NULL softc ptr!")); 2193c71b84fSZbigniew Bodek timeout = MGE_SMI_WRITE_RETRIES; 2203c71b84fSZbigniew Bodek 2213c71b84fSZbigniew Bodek MGE_SMI_LOCK(); 2223c71b84fSZbigniew Bodek while (--timeout && 2233c71b84fSZbigniew Bodek (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY)) 2243c71b84fSZbigniew Bodek MGE_DELAY(MGE_SMI_WRITE_DELAY); 2253c71b84fSZbigniew Bodek 2263c71b84fSZbigniew Bodek if (timeout == 0) { 2273c71b84fSZbigniew Bodek device_printf(dev, "SMI write timeout.\n"); 2283c71b84fSZbigniew Bodek ret = ~0U; 2293c71b84fSZbigniew Bodek goto out; 2303c71b84fSZbigniew Bodek } 2313c71b84fSZbigniew Bodek 2323c71b84fSZbigniew Bodek MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK & 2333c71b84fSZbigniew Bodek (MGE_SMI_READ | (reg << 21) | (phy << 16))); 2343c71b84fSZbigniew Bodek 2353c71b84fSZbigniew Bodek /* Wait till finished. */ 2363c71b84fSZbigniew Bodek timeout = MGE_SMI_WRITE_RETRIES; 2373c71b84fSZbigniew Bodek while (--timeout && 2383c71b84fSZbigniew Bodek !((MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_READVALID))) 2393c71b84fSZbigniew Bodek MGE_DELAY(MGE_SMI_WRITE_DELAY); 2403c71b84fSZbigniew Bodek 2413c71b84fSZbigniew Bodek if (timeout == 0) { 2423c71b84fSZbigniew Bodek device_printf(dev, "SMI write validation timeout.\n"); 2433c71b84fSZbigniew Bodek ret = ~0U; 2443c71b84fSZbigniew Bodek goto out; 2453c71b84fSZbigniew Bodek } 2463c71b84fSZbigniew Bodek 2473c71b84fSZbigniew Bodek /* Wait for the data to update in the SMI register */ 2483c71b84fSZbigniew Bodek MGE_DELAY(MGE_SMI_DELAY); 2493c71b84fSZbigniew Bodek ret = MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK; 2503c71b84fSZbigniew Bodek 2513c71b84fSZbigniew Bodek out: 2523c71b84fSZbigniew Bodek MGE_SMI_UNLOCK(); 2533c71b84fSZbigniew Bodek return (ret); 2543c71b84fSZbigniew Bodek 2553c71b84fSZbigniew Bodek } 2563c71b84fSZbigniew Bodek 2573c71b84fSZbigniew Bodek static void 2583c71b84fSZbigniew Bodek mv_write_ge_smi(device_t dev, int phy, int reg, uint32_t value) 2593c71b84fSZbigniew Bodek { 2603c71b84fSZbigniew Bodek uint32_t timeout; 2613c71b84fSZbigniew Bodek struct mge_softc *sc; 2623c71b84fSZbigniew Bodek 2633c71b84fSZbigniew Bodek sc = device_get_softc(dev); 2643c71b84fSZbigniew Bodek KASSERT(sc != NULL, ("NULL softc ptr!")); 2653c71b84fSZbigniew Bodek 2663c71b84fSZbigniew Bodek MGE_SMI_LOCK(); 2673c71b84fSZbigniew Bodek timeout = MGE_SMI_READ_RETRIES; 2683c71b84fSZbigniew Bodek while (--timeout && 2693c71b84fSZbigniew Bodek (MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY)) 2703c71b84fSZbigniew Bodek MGE_DELAY(MGE_SMI_READ_DELAY); 2713c71b84fSZbigniew Bodek 2723c71b84fSZbigniew Bodek if (timeout == 0) { 2733c71b84fSZbigniew Bodek device_printf(dev, "SMI read timeout.\n"); 2743c71b84fSZbigniew Bodek goto out; 2753c71b84fSZbigniew Bodek } 2763c71b84fSZbigniew Bodek 2773c71b84fSZbigniew Bodek MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK & 2783c71b84fSZbigniew Bodek (MGE_SMI_WRITE | (reg << 21) | (phy << 16) | 2793c71b84fSZbigniew Bodek (value & MGE_SMI_DATA_MASK))); 2803c71b84fSZbigniew Bodek 2813c71b84fSZbigniew Bodek out: 2823c71b84fSZbigniew Bodek MGE_SMI_UNLOCK(); 2833c71b84fSZbigniew Bodek } 2843c71b84fSZbigniew Bodek 2853c71b84fSZbigniew Bodek static int 2863c71b84fSZbigniew Bodek mv_read_ext_phy(device_t dev, int phy, int reg) 2873c71b84fSZbigniew Bodek { 2883c71b84fSZbigniew Bodek uint32_t retries; 2893c71b84fSZbigniew Bodek struct mge_softc *sc; 2903c71b84fSZbigniew Bodek uint32_t ret; 2913c71b84fSZbigniew Bodek 2923c71b84fSZbigniew Bodek sc = device_get_softc(dev); 2933c71b84fSZbigniew Bodek 2943c71b84fSZbigniew Bodek MGE_SMI_LOCK(); 2953c71b84fSZbigniew Bodek MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK & 2963c71b84fSZbigniew Bodek (MGE_SMI_READ | (reg << 21) | (phy << 16))); 2973c71b84fSZbigniew Bodek 2983c71b84fSZbigniew Bodek retries = MGE_SMI_READ_RETRIES; 2993c71b84fSZbigniew Bodek while (--retries && 3003c71b84fSZbigniew Bodek !(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID)) 3013c71b84fSZbigniew Bodek DELAY(MGE_SMI_READ_DELAY); 3023c71b84fSZbigniew Bodek 3033c71b84fSZbigniew Bodek if (retries == 0) 3043c71b84fSZbigniew Bodek device_printf(dev, "Timeout while reading from PHY\n"); 3053c71b84fSZbigniew Bodek 3063c71b84fSZbigniew Bodek ret = MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK; 3073c71b84fSZbigniew Bodek MGE_SMI_UNLOCK(); 3083c71b84fSZbigniew Bodek 3093c71b84fSZbigniew Bodek return (ret); 3103c71b84fSZbigniew Bodek } 3113c71b84fSZbigniew Bodek 3123c71b84fSZbigniew Bodek static void 3133c71b84fSZbigniew Bodek mv_write_ext_phy(device_t dev, int phy, int reg, int value) 3143c71b84fSZbigniew Bodek { 3153c71b84fSZbigniew Bodek uint32_t retries; 3163c71b84fSZbigniew Bodek struct mge_softc *sc; 3173c71b84fSZbigniew Bodek 3183c71b84fSZbigniew Bodek sc = device_get_softc(dev); 3193c71b84fSZbigniew Bodek 3203c71b84fSZbigniew Bodek MGE_SMI_LOCK(); 3213c71b84fSZbigniew Bodek MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK & 3223c71b84fSZbigniew Bodek (MGE_SMI_WRITE | (reg << 21) | (phy << 16) | 3233c71b84fSZbigniew Bodek (value & MGE_SMI_DATA_MASK))); 3243c71b84fSZbigniew Bodek 3253c71b84fSZbigniew Bodek retries = MGE_SMI_WRITE_RETRIES; 3263c71b84fSZbigniew Bodek while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY) 3273c71b84fSZbigniew Bodek DELAY(MGE_SMI_WRITE_DELAY); 3283c71b84fSZbigniew Bodek 3293c71b84fSZbigniew Bodek if (retries == 0) 3303c71b84fSZbigniew Bodek device_printf(dev, "Timeout while writing to PHY\n"); 3313c71b84fSZbigniew Bodek MGE_SMI_UNLOCK(); 3323c71b84fSZbigniew Bodek } 3333c71b84fSZbigniew Bodek 3349f55f5f5SRafal Jaworowski static void 3359f55f5f5SRafal Jaworowski mge_get_mac_address(struct mge_softc *sc, uint8_t *addr) 3369f55f5f5SRafal Jaworowski { 3379f55f5f5SRafal Jaworowski uint32_t mac_l, mac_h; 338db5ef4fcSRafal Jaworowski uint8_t lmac[6]; 339db5ef4fcSRafal Jaworowski int i, valid; 3409f55f5f5SRafal Jaworowski 341db5ef4fcSRafal Jaworowski /* 342db5ef4fcSRafal Jaworowski * Retrieve hw address from the device tree. 343db5ef4fcSRafal Jaworowski */ 344db5ef4fcSRafal Jaworowski i = OF_getprop(sc->node, "local-mac-address", (void *)lmac, 6); 345db5ef4fcSRafal Jaworowski if (i == 6) { 346db5ef4fcSRafal Jaworowski valid = 0; 347db5ef4fcSRafal Jaworowski for (i = 0; i < 6; i++) 348db5ef4fcSRafal Jaworowski if (lmac[i] != 0) { 349db5ef4fcSRafal Jaworowski valid = 1; 350db5ef4fcSRafal Jaworowski break; 351db5ef4fcSRafal Jaworowski } 3529f55f5f5SRafal Jaworowski 353db5ef4fcSRafal Jaworowski if (valid) { 354db5ef4fcSRafal Jaworowski bcopy(lmac, addr, 6); 355db5ef4fcSRafal Jaworowski return; 356db5ef4fcSRafal Jaworowski } 357db5ef4fcSRafal Jaworowski } 358db5ef4fcSRafal Jaworowski 359db5ef4fcSRafal Jaworowski /* 360db5ef4fcSRafal Jaworowski * Fall back -- use the currently programmed address. 361db5ef4fcSRafal Jaworowski */ 3629f55f5f5SRafal Jaworowski mac_l = MGE_READ(sc, MGE_MAC_ADDR_L); 3639f55f5f5SRafal Jaworowski mac_h = MGE_READ(sc, MGE_MAC_ADDR_H); 3649f55f5f5SRafal Jaworowski 3659f55f5f5SRafal Jaworowski addr[0] = (mac_h & 0xff000000) >> 24; 3669f55f5f5SRafal Jaworowski addr[1] = (mac_h & 0x00ff0000) >> 16; 3679f55f5f5SRafal Jaworowski addr[2] = (mac_h & 0x0000ff00) >> 8; 3689f55f5f5SRafal Jaworowski addr[3] = (mac_h & 0x000000ff); 3699f55f5f5SRafal Jaworowski addr[4] = (mac_l & 0x0000ff00) >> 8; 3709f55f5f5SRafal Jaworowski addr[5] = (mac_l & 0x000000ff); 3719f55f5f5SRafal Jaworowski } 3729f55f5f5SRafal Jaworowski 3738e1dc58eSRafal Jaworowski static uint32_t 3748e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver) 3758e1dc58eSRafal Jaworowski { 3768e1dc58eSRafal Jaworowski 3778e1dc58eSRafal Jaworowski switch (ver) { 3788e1dc58eSRafal Jaworowski case 1: 3798e1dc58eSRafal Jaworowski return ((val & 0x3fff) << 4); 3808e1dc58eSRafal Jaworowski case 2: 3818e1dc58eSRafal Jaworowski default: 3828e1dc58eSRafal Jaworowski return ((val & 0xffff) << 4); 3838e1dc58eSRafal Jaworowski } 3848e1dc58eSRafal Jaworowski } 3858e1dc58eSRafal Jaworowski 3868e1dc58eSRafal Jaworowski static uint32_t 3878e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver) 3888e1dc58eSRafal Jaworowski { 3898e1dc58eSRafal Jaworowski 3908e1dc58eSRafal Jaworowski switch (ver) { 3918e1dc58eSRafal Jaworowski case 1: 3928e1dc58eSRafal Jaworowski return ((val & 0x3fff) << 8); 3938e1dc58eSRafal Jaworowski case 2: 3948e1dc58eSRafal Jaworowski default: 3958e1dc58eSRafal Jaworowski return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7)); 3968e1dc58eSRafal Jaworowski } 3978e1dc58eSRafal Jaworowski } 3988e1dc58eSRafal Jaworowski 3998e1dc58eSRafal Jaworowski static void 4008e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc) 4018e1dc58eSRafal Jaworowski { 4028e1dc58eSRafal Jaworowski uint32_t d, r; 4038e1dc58eSRafal Jaworowski 4048e1dc58eSRafal Jaworowski soc_id(&d, &r); 40575f1438bSOleksandr Tymoshenko if (d == MV_DEV_88F6281 || d == MV_DEV_88F6781 || 406c8953e12SHiroki Sato d == MV_DEV_88F6282 || 407c8953e12SHiroki Sato d == MV_DEV_MV78100 || 40875f1438bSOleksandr Tymoshenko d == MV_DEV_MV78100_Z0 || 40975f1438bSOleksandr Tymoshenko (d & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY) { 4108e1dc58eSRafal Jaworowski sc->mge_ver = 2; 4118e1dc58eSRafal Jaworowski sc->mge_mtu = 0x4e8; 4128e1dc58eSRafal Jaworowski sc->mge_tfut_ipg_max = 0xFFFF; 4138e1dc58eSRafal Jaworowski sc->mge_rx_ipg_max = 0xFFFF; 4148e1dc58eSRafal Jaworowski sc->mge_tx_arb_cfg = 0xFC0000FF; 4158e1dc58eSRafal Jaworowski sc->mge_tx_tok_cfg = 0xFFFF7FFF; 4168e1dc58eSRafal Jaworowski sc->mge_tx_tok_cnt = 0x3FFFFFFF; 4178e1dc58eSRafal Jaworowski } else { 4188e1dc58eSRafal Jaworowski sc->mge_ver = 1; 4198e1dc58eSRafal Jaworowski sc->mge_mtu = 0x458; 4208e1dc58eSRafal Jaworowski sc->mge_tfut_ipg_max = 0x3FFF; 4218e1dc58eSRafal Jaworowski sc->mge_rx_ipg_max = 0x3FFF; 4228e1dc58eSRafal Jaworowski sc->mge_tx_arb_cfg = 0x000000FF; 4238e1dc58eSRafal Jaworowski sc->mge_tx_tok_cfg = 0x3FFFFFFF; 4248e1dc58eSRafal Jaworowski sc->mge_tx_tok_cnt = 0x3FFFFFFF; 4258e1dc58eSRafal Jaworowski } 42675f1438bSOleksandr Tymoshenko if (d == MV_DEV_88RC8180) 42775f1438bSOleksandr Tymoshenko sc->mge_intr_cnt = 1; 42875f1438bSOleksandr Tymoshenko else 42975f1438bSOleksandr Tymoshenko sc->mge_intr_cnt = 2; 43075f1438bSOleksandr Tymoshenko 43175f1438bSOleksandr Tymoshenko if (d == MV_DEV_MV78160 || d == MV_DEV_MV78260 || d == MV_DEV_MV78460) 43275f1438bSOleksandr Tymoshenko sc->mge_hw_csum = 0; 43375f1438bSOleksandr Tymoshenko else 43475f1438bSOleksandr Tymoshenko sc->mge_hw_csum = 1; 4358e1dc58eSRafal Jaworowski } 4368e1dc58eSRafal Jaworowski 4379f55f5f5SRafal Jaworowski static void 4389f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc) 4399f55f5f5SRafal Jaworowski { 4409f55f5f5SRafal Jaworowski char *if_mac; 4419f55f5f5SRafal Jaworowski uint32_t mac_l, mac_h; 4429f55f5f5SRafal Jaworowski 4439f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK_ASSERT(sc); 4449f55f5f5SRafal Jaworowski 4459f55f5f5SRafal Jaworowski if_mac = (char *)IF_LLADDR(sc->ifp); 4469f55f5f5SRafal Jaworowski 4479f55f5f5SRafal Jaworowski mac_l = (if_mac[4] << 8) | (if_mac[5]); 4489f55f5f5SRafal Jaworowski mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) | 4499f55f5f5SRafal Jaworowski (if_mac[2] << 8) | (if_mac[3] << 0); 4509f55f5f5SRafal Jaworowski 4519f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l); 4529f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h); 4539f55f5f5SRafal Jaworowski 4549f55f5f5SRafal Jaworowski mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE); 4559f55f5f5SRafal Jaworowski } 4569f55f5f5SRafal Jaworowski 4579f55f5f5SRafal Jaworowski static void 4589f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue) 4599f55f5f5SRafal Jaworowski { 4609f55f5f5SRafal Jaworowski uint32_t reg_idx, reg_off, reg_val, i; 4619f55f5f5SRafal Jaworowski 4629f55f5f5SRafal Jaworowski last_byte &= 0xf; 4639f55f5f5SRafal Jaworowski reg_idx = last_byte / MGE_UCAST_REG_NUMBER; 4649f55f5f5SRafal Jaworowski reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8; 4659f55f5f5SRafal Jaworowski reg_val = (1 | (queue << 1)) << reg_off; 4669f55f5f5SRafal Jaworowski 4679f55f5f5SRafal Jaworowski for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) { 4689f55f5f5SRafal Jaworowski if ( i == reg_idx) 4699f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val); 4709f55f5f5SRafal Jaworowski else 4719f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0); 4729f55f5f5SRafal Jaworowski } 4739f55f5f5SRafal Jaworowski } 4749f55f5f5SRafal Jaworowski 4759f55f5f5SRafal Jaworowski static void 4769f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue) 4779f55f5f5SRafal Jaworowski { 4789f55f5f5SRafal Jaworowski uint32_t port_config; 4799f55f5f5SRafal Jaworowski uint32_t reg_val, i; 4809f55f5f5SRafal Jaworowski 4819f55f5f5SRafal Jaworowski /* Enable or disable promiscuous mode as needed */ 4829f55f5f5SRafal Jaworowski if (sc->ifp->if_flags & IFF_PROMISC) { 4839f55f5f5SRafal Jaworowski port_config = MGE_READ(sc, MGE_PORT_CONFIG); 4849f55f5f5SRafal Jaworowski port_config |= PORT_CONFIG_UPM; 4859f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, port_config); 4869f55f5f5SRafal Jaworowski 4879f55f5f5SRafal Jaworowski reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 | 4889f55f5f5SRafal Jaworowski (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24); 4899f55f5f5SRafal Jaworowski 4909f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 4919f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val); 4929f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val); 4939f55f5f5SRafal Jaworowski } 4949f55f5f5SRafal Jaworowski 4959f55f5f5SRafal Jaworowski for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) 4969f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val); 4979f55f5f5SRafal Jaworowski 4989f55f5f5SRafal Jaworowski } else { 4999f55f5f5SRafal Jaworowski port_config = MGE_READ(sc, MGE_PORT_CONFIG); 5009f55f5f5SRafal Jaworowski port_config &= ~PORT_CONFIG_UPM; 5019f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, port_config); 5029f55f5f5SRafal Jaworowski 5039f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 5049f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0); 5059f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0); 5069f55f5f5SRafal Jaworowski } 5079f55f5f5SRafal Jaworowski 5089f55f5f5SRafal Jaworowski mge_set_mac_address(sc); 5099f55f5f5SRafal Jaworowski } 5109f55f5f5SRafal Jaworowski } 5119f55f5f5SRafal Jaworowski 5129f55f5f5SRafal Jaworowski static void 5139f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 5149f55f5f5SRafal Jaworowski { 5159f55f5f5SRafal Jaworowski u_int32_t *paddr; 5169f55f5f5SRafal Jaworowski 5179f55f5f5SRafal Jaworowski KASSERT(nseg == 1, ("wrong number of segments, should be 1")); 5189f55f5f5SRafal Jaworowski paddr = arg; 5199f55f5f5SRafal Jaworowski 5209f55f5f5SRafal Jaworowski *paddr = segs->ds_addr; 5219f55f5f5SRafal Jaworowski } 5229f55f5f5SRafal Jaworowski 5239f55f5f5SRafal Jaworowski static int 5249f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp, 5259f55f5f5SRafal Jaworowski bus_addr_t *paddr) 5269f55f5f5SRafal Jaworowski { 5279f55f5f5SRafal Jaworowski struct mbuf *new_mbuf; 5289f55f5f5SRafal Jaworowski bus_dma_segment_t seg[1]; 5299f55f5f5SRafal Jaworowski int error; 5309f55f5f5SRafal Jaworowski int nsegs; 5319f55f5f5SRafal Jaworowski 5329f55f5f5SRafal Jaworowski KASSERT(mbufp != NULL, ("NULL mbuf pointer!")); 5339f55f5f5SRafal Jaworowski 534c6499eccSGleb Smirnoff new_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 5359f55f5f5SRafal Jaworowski if (new_mbuf == NULL) 5369f55f5f5SRafal Jaworowski return (ENOBUFS); 5379f55f5f5SRafal Jaworowski new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size; 5389f55f5f5SRafal Jaworowski 5399f55f5f5SRafal Jaworowski if (*mbufp) { 5409f55f5f5SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD); 5419f55f5f5SRafal Jaworowski bus_dmamap_unload(tag, map); 5429f55f5f5SRafal Jaworowski } 5439f55f5f5SRafal Jaworowski 5449f55f5f5SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs, 5459f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT); 5469f55f5f5SRafal Jaworowski KASSERT(nsegs == 1, ("Too many segments returned!")); 5479f55f5f5SRafal Jaworowski if (nsegs != 1 || error) 5489f55f5f5SRafal Jaworowski panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error); 5499f55f5f5SRafal Jaworowski 5509f55f5f5SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD); 5519f55f5f5SRafal Jaworowski 5529f55f5f5SRafal Jaworowski (*mbufp) = new_mbuf; 5539f55f5f5SRafal Jaworowski (*paddr) = seg->ds_addr; 5549f55f5f5SRafal Jaworowski return (0); 5559f55f5f5SRafal Jaworowski } 5569f55f5f5SRafal Jaworowski 5579f55f5f5SRafal Jaworowski static int 5589f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab, 5599f55f5f5SRafal Jaworowski uint32_t size, bus_dma_tag_t *buffer_tag) 5609f55f5f5SRafal Jaworowski { 5619f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 5629f55f5f5SRafal Jaworowski bus_addr_t desc_paddr; 5639f55f5f5SRafal Jaworowski int i, error; 5649f55f5f5SRafal Jaworowski 5659f55f5f5SRafal Jaworowski desc_paddr = 0; 5669f55f5f5SRafal Jaworowski for (i = size - 1; i >= 0; i--) { 5679f55f5f5SRafal Jaworowski dw = &(tab[i]); 5689f55f5f5SRafal Jaworowski error = bus_dmamem_alloc(sc->mge_desc_dtag, 5699f55f5f5SRafal Jaworowski (void**)&(dw->mge_desc), 5709f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 5719f55f5f5SRafal Jaworowski &(dw->desc_dmap)); 5729f55f5f5SRafal Jaworowski 5739f55f5f5SRafal Jaworowski if (error) { 5749f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to allocate DMA memory\n"); 5759f55f5f5SRafal Jaworowski dw->mge_desc = NULL; 5769f55f5f5SRafal Jaworowski return (ENXIO); 5779f55f5f5SRafal Jaworowski } 5789f55f5f5SRafal Jaworowski 5799f55f5f5SRafal Jaworowski error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap, 5809f55f5f5SRafal Jaworowski dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr, 5819f55f5f5SRafal Jaworowski &(dw->mge_desc_paddr), BUS_DMA_NOWAIT); 5829f55f5f5SRafal Jaworowski 5839f55f5f5SRafal Jaworowski if (error) { 5849f55f5f5SRafal Jaworowski if_printf(sc->ifp, "can't load descriptor\n"); 5859f55f5f5SRafal Jaworowski bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc, 5869f55f5f5SRafal Jaworowski dw->desc_dmap); 5879f55f5f5SRafal Jaworowski dw->mge_desc = NULL; 5889f55f5f5SRafal Jaworowski return (ENXIO); 5899f55f5f5SRafal Jaworowski } 5909f55f5f5SRafal Jaworowski 5919f55f5f5SRafal Jaworowski /* Chain descriptors */ 5929f55f5f5SRafal Jaworowski dw->mge_desc->next_desc = desc_paddr; 5939f55f5f5SRafal Jaworowski desc_paddr = dw->mge_desc_paddr; 5949f55f5f5SRafal Jaworowski } 5959f55f5f5SRafal Jaworowski tab[size - 1].mge_desc->next_desc = desc_paddr; 5969f55f5f5SRafal Jaworowski 5979f55f5f5SRafal Jaworowski /* Allocate a busdma tag for mbufs. */ 59862ce43ccSScott Long error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), /* parent */ 59975f1438bSOleksandr Tymoshenko 1, 0, /* alignment, boundary */ 6009f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 6019f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 6029f55f5f5SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 6039f55f5f5SRafal Jaworowski MCLBYTES, 1, /* maxsize, nsegments */ 6049f55f5f5SRafal Jaworowski MCLBYTES, 0, /* maxsegsz, flags */ 6059f55f5f5SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 6069f55f5f5SRafal Jaworowski buffer_tag); /* dmat */ 6079f55f5f5SRafal Jaworowski if (error) { 6089f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to create busdma tag for mbufs\n"); 6099f55f5f5SRafal Jaworowski return (ENXIO); 6109f55f5f5SRafal Jaworowski } 6119f55f5f5SRafal Jaworowski 6129f55f5f5SRafal Jaworowski /* Create TX busdma maps */ 6139f55f5f5SRafal Jaworowski for (i = 0; i < size; i++) { 6149f55f5f5SRafal Jaworowski dw = &(tab[i]); 6159f55f5f5SRafal Jaworowski error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap); 6169f55f5f5SRafal Jaworowski if (error) { 6179f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to create map for mbuf\n"); 6189f55f5f5SRafal Jaworowski return (ENXIO); 6199f55f5f5SRafal Jaworowski } 6209f55f5f5SRafal Jaworowski 6219f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 6229f55f5f5SRafal Jaworowski dw->mge_desc->buffer = (bus_addr_t)NULL; 6239f55f5f5SRafal Jaworowski } 6249f55f5f5SRafal Jaworowski 6259f55f5f5SRafal Jaworowski return (0); 6269f55f5f5SRafal Jaworowski } 6279f55f5f5SRafal Jaworowski 6289f55f5f5SRafal Jaworowski static int 6299f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc) 6309f55f5f5SRafal Jaworowski { 6319f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 632d6bdd318SRafal Jaworowski int i; 6339f55f5f5SRafal Jaworowski 6349f55f5f5SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ 635f8967810SWarner Losh bus_dma_tag_create(bus_get_dma_tag(sc->dev), /* parent */ 6369f55f5f5SRafal Jaworowski 16, 0, /* alignment, boundary */ 6379f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 6389f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 6399f55f5f5SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 6409f55f5f5SRafal Jaworowski sizeof(struct mge_desc), 1, /* maxsize, nsegments */ 6419f55f5f5SRafal Jaworowski sizeof(struct mge_desc), 0, /* maxsegsz, flags */ 6429f55f5f5SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 6439f55f5f5SRafal Jaworowski &sc->mge_desc_dtag); /* dmat */ 6449f55f5f5SRafal Jaworowski 6459f55f5f5SRafal Jaworowski 6469f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, 6479f55f5f5SRafal Jaworowski &sc->mge_tx_dtag); 6489f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, 6499f55f5f5SRafal Jaworowski &sc->mge_rx_dtag); 6509f55f5f5SRafal Jaworowski 6519f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 6529f55f5f5SRafal Jaworowski dw = &(sc->mge_rx_desc[i]); 6539f55f5f5SRafal Jaworowski mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer, 6549f55f5f5SRafal Jaworowski &dw->mge_desc->buffer); 6559f55f5f5SRafal Jaworowski } 6569f55f5f5SRafal Jaworowski 6579f55f5f5SRafal Jaworowski sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr; 6589f55f5f5SRafal Jaworowski sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr; 6599f55f5f5SRafal Jaworowski 6609f55f5f5SRafal Jaworowski return (0); 6619f55f5f5SRafal Jaworowski } 6629f55f5f5SRafal Jaworowski 6639f55f5f5SRafal Jaworowski static void 6649f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab, 6659f55f5f5SRafal Jaworowski uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs) 6669f55f5f5SRafal Jaworowski { 6679f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 6689f55f5f5SRafal Jaworowski int i; 6699f55f5f5SRafal Jaworowski 6709f55f5f5SRafal Jaworowski for (i = 0; i < size; i++) { 6719f55f5f5SRafal Jaworowski /* Free RX mbuf */ 6729f55f5f5SRafal Jaworowski dw = &(tab[i]); 6739f55f5f5SRafal Jaworowski 6749f55f5f5SRafal Jaworowski if (dw->buffer_dmap) { 6759f55f5f5SRafal Jaworowski if (free_mbufs) { 6769f55f5f5SRafal Jaworowski bus_dmamap_sync(buffer_tag, dw->buffer_dmap, 6779f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 6789f55f5f5SRafal Jaworowski bus_dmamap_unload(buffer_tag, dw->buffer_dmap); 6799f55f5f5SRafal Jaworowski } 6809f55f5f5SRafal Jaworowski bus_dmamap_destroy(buffer_tag, dw->buffer_dmap); 6819f55f5f5SRafal Jaworowski if (free_mbufs) 6829f55f5f5SRafal Jaworowski m_freem(dw->buffer); 6839f55f5f5SRafal Jaworowski } 6849f55f5f5SRafal Jaworowski /* Free RX descriptors */ 6859f55f5f5SRafal Jaworowski if (dw->desc_dmap) { 6869f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 6879f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 6889f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap); 6899f55f5f5SRafal Jaworowski bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc, 6909f55f5f5SRafal Jaworowski dw->desc_dmap); 6919f55f5f5SRafal Jaworowski } 6929f55f5f5SRafal Jaworowski } 6939f55f5f5SRafal Jaworowski } 6949f55f5f5SRafal Jaworowski 6959f55f5f5SRafal Jaworowski static void 6969f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc) 6979f55f5f5SRafal Jaworowski { 6984ac30cc1SZbigniew Bodek 699b1603638SGordon Bergling /* Free descriptors and mbufs */ 7009f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1); 7019f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0); 7029f55f5f5SRafal Jaworowski 7039f55f5f5SRafal Jaworowski /* Destroy mbuf dma tag */ 7049f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_tx_dtag); 7059f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_rx_dtag); 7069f55f5f5SRafal Jaworowski /* Destroy descriptors tag */ 7079f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_desc_dtag); 7089f55f5f5SRafal Jaworowski } 7099f55f5f5SRafal Jaworowski 7109f55f5f5SRafal Jaworowski static void 7119f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc) 7129f55f5f5SRafal Jaworowski { 7139f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 7149f55f5f5SRafal Jaworowski int i; 7159f55f5f5SRafal Jaworowski 716d6bdd318SRafal Jaworowski MGE_RECEIVE_LOCK_ASSERT(sc); 7179f55f5f5SRafal Jaworowski 7189f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1); 7199f55f5f5SRafal Jaworowski 7209f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, 7219f55f5f5SRafal Jaworowski &sc->mge_rx_dtag); 7229f55f5f5SRafal Jaworowski 7239f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 7249f55f5f5SRafal Jaworowski dw = &(sc->mge_rx_desc[i]); 7259f55f5f5SRafal Jaworowski mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer, 7269f55f5f5SRafal Jaworowski &dw->mge_desc->buffer); 7279f55f5f5SRafal Jaworowski } 7289f55f5f5SRafal Jaworowski 7299f55f5f5SRafal Jaworowski sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr; 7309f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 7319f55f5f5SRafal Jaworowski 7329f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE), 7339f55f5f5SRafal Jaworowski sc->rx_desc_start); 7349f55f5f5SRafal Jaworowski 7359f55f5f5SRafal Jaworowski /* Enable RX queue */ 7369f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE)); 7379f55f5f5SRafal Jaworowski } 7389f55f5f5SRafal Jaworowski 7399f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 7409f55f5f5SRafal Jaworowski static poll_handler_t mge_poll; 7419f55f5f5SRafal Jaworowski 7421abcdbd1SAttilio Rao static int 7439f55f5f5SRafal Jaworowski mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 7449f55f5f5SRafal Jaworowski { 7459f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 7469f55f5f5SRafal Jaworowski uint32_t int_cause, int_cause_ext; 7471abcdbd1SAttilio Rao int rx_npkts = 0; 7489f55f5f5SRafal Jaworowski 7493c71b84fSZbigniew Bodek MGE_RECEIVE_LOCK(sc); 7509f55f5f5SRafal Jaworowski 7519f55f5f5SRafal Jaworowski if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 7523c71b84fSZbigniew Bodek MGE_RECEIVE_UNLOCK(sc); 7531abcdbd1SAttilio Rao return (rx_npkts); 7549f55f5f5SRafal Jaworowski } 7559f55f5f5SRafal Jaworowski 7569f55f5f5SRafal Jaworowski if (cmd == POLL_AND_CHECK_STATUS) { 7579f55f5f5SRafal Jaworowski int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE); 7589f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 7599f55f5f5SRafal Jaworowski 7609f55f5f5SRafal Jaworowski /* Check for resource error */ 7619f55f5f5SRafal Jaworowski if (int_cause & MGE_PORT_INT_RXERRQ0) 7629f55f5f5SRafal Jaworowski mge_reinit_rx(sc); 7639f55f5f5SRafal Jaworowski 7649f55f5f5SRafal Jaworowski if (int_cause || int_cause_ext) { 7659f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause); 7669f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext); 7679f55f5f5SRafal Jaworowski } 7689f55f5f5SRafal Jaworowski } 7699f55f5f5SRafal Jaworowski 7703c71b84fSZbigniew Bodek 7711abcdbd1SAttilio Rao rx_npkts = mge_intr_rx_locked(sc, count); 7729f55f5f5SRafal Jaworowski 7733c71b84fSZbigniew Bodek MGE_RECEIVE_UNLOCK(sc); 7743c71b84fSZbigniew Bodek MGE_TRANSMIT_LOCK(sc); 7753c71b84fSZbigniew Bodek mge_intr_tx_locked(sc); 7763c71b84fSZbigniew Bodek MGE_TRANSMIT_UNLOCK(sc); 7771abcdbd1SAttilio Rao return (rx_npkts); 7789f55f5f5SRafal Jaworowski } 7799f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */ 7809f55f5f5SRafal Jaworowski 7819f55f5f5SRafal Jaworowski static int 7829f55f5f5SRafal Jaworowski mge_attach(device_t dev) 7839f55f5f5SRafal Jaworowski { 7849f55f5f5SRafal Jaworowski struct mge_softc *sc; 785a6eb469dSPhilip Paeps struct mii_softc *miisc; 7869f55f5f5SRafal Jaworowski struct ifnet *ifp; 7879f55f5f5SRafal Jaworowski uint8_t hwaddr[ETHER_ADDR_LEN]; 7888e5d93dbSMarius Strobl int i, error, phy; 7899f55f5f5SRafal Jaworowski 7909f55f5f5SRafal Jaworowski sc = device_get_softc(dev); 7919f55f5f5SRafal Jaworowski sc->dev = dev; 792db5ef4fcSRafal Jaworowski sc->node = ofw_bus_get_node(dev); 7933c71b84fSZbigniew Bodek phy = 0; 7943c71b84fSZbigniew Bodek 7953c71b84fSZbigniew Bodek if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) == 0) { 7963c71b84fSZbigniew Bodek device_printf(dev, "PHY%i attached, phy_sc points to %s\n", phy, 7973c71b84fSZbigniew Bodek device_get_nameunit(sc->phy_sc->dev)); 7983c71b84fSZbigniew Bodek sc->phy_attached = 1; 7993c71b84fSZbigniew Bodek } else { 8003c71b84fSZbigniew Bodek device_printf(dev, "PHY not attached.\n"); 8013c71b84fSZbigniew Bodek sc->phy_attached = 0; 8023c71b84fSZbigniew Bodek sc->phy_sc = sc; 8033c71b84fSZbigniew Bodek } 8043c71b84fSZbigniew Bodek 8053c71b84fSZbigniew Bodek if (fdt_find_compatible(sc->node, "mrvl,sw", 1) != 0) { 8063c71b84fSZbigniew Bodek device_printf(dev, "Switch attached.\n"); 8073c71b84fSZbigniew Bodek sc->switch_attached = 1; 8083c71b84fSZbigniew Bodek /* additional variable available across instances */ 8093c71b84fSZbigniew Bodek switch_attached = 1; 8103c71b84fSZbigniew Bodek } else { 8113c71b84fSZbigniew Bodek sc->switch_attached = 0; 8123c71b84fSZbigniew Bodek } 8133c71b84fSZbigniew Bodek 8143c71b84fSZbigniew Bodek if (device_get_unit(dev) == 0) { 8153c71b84fSZbigniew Bodek sx_init(&sx_smi, "mge_tick() SMI access threads interlock"); 8163c71b84fSZbigniew Bodek } 8179f55f5f5SRafal Jaworowski 8188e1dc58eSRafal Jaworowski /* Set chip version-dependent parameters */ 8198e1dc58eSRafal Jaworowski mge_ver_params(sc); 8208e1dc58eSRafal Jaworowski 8219f55f5f5SRafal Jaworowski /* Initialize mutexes */ 8224ac30cc1SZbigniew Bodek mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock", 8234ac30cc1SZbigniew Bodek MTX_DEF); 8244ac30cc1SZbigniew Bodek mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock", 8254ac30cc1SZbigniew Bodek MTX_DEF); 8269f55f5f5SRafal Jaworowski 8279f55f5f5SRafal Jaworowski /* Allocate IO and IRQ resources */ 8289f55f5f5SRafal Jaworowski error = bus_alloc_resources(dev, res_spec, sc->res); 8299f55f5f5SRafal Jaworowski if (error) { 8309f55f5f5SRafal Jaworowski device_printf(dev, "could not allocate resources\n"); 8319f55f5f5SRafal Jaworowski mge_detach(dev); 8329f55f5f5SRafal Jaworowski return (ENXIO); 8339f55f5f5SRafal Jaworowski } 8349f55f5f5SRafal Jaworowski 8359f55f5f5SRafal Jaworowski /* Allocate DMA, buffers, buffer descriptors */ 8369f55f5f5SRafal Jaworowski error = mge_allocate_dma(sc); 8379f55f5f5SRafal Jaworowski if (error) { 8389f55f5f5SRafal Jaworowski mge_detach(dev); 8399f55f5f5SRafal Jaworowski return (ENXIO); 8409f55f5f5SRafal Jaworowski } 8419f55f5f5SRafal Jaworowski 8429f55f5f5SRafal Jaworowski sc->tx_desc_curr = 0; 8439f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 8449f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 0; 8455817716fSRafal Jaworowski sc->tx_desc_used_count = 0; 8469f55f5f5SRafal Jaworowski 8479f55f5f5SRafal Jaworowski /* Configure defaults for interrupts coalescing */ 8489f55f5f5SRafal Jaworowski sc->rx_ic_time = 768; 8499f55f5f5SRafal Jaworowski sc->tx_ic_time = 768; 8509f55f5f5SRafal Jaworowski mge_add_sysctls(sc); 8519f55f5f5SRafal Jaworowski 8529f55f5f5SRafal Jaworowski /* Allocate network interface */ 8539f55f5f5SRafal Jaworowski ifp = sc->ifp = if_alloc(IFT_ETHER); 8549f55f5f5SRafal Jaworowski if (ifp == NULL) { 8559f55f5f5SRafal Jaworowski device_printf(dev, "if_alloc() failed\n"); 8569f55f5f5SRafal Jaworowski mge_detach(dev); 8579f55f5f5SRafal Jaworowski return (ENOMEM); 8589f55f5f5SRafal Jaworowski } 8599f55f5f5SRafal Jaworowski 8609f55f5f5SRafal Jaworowski if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 8619f55f5f5SRafal Jaworowski ifp->if_softc = sc; 8629f55f5f5SRafal Jaworowski ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST; 86375f1438bSOleksandr Tymoshenko ifp->if_capabilities = IFCAP_VLAN_MTU; 86475f1438bSOleksandr Tymoshenko if (sc->mge_hw_csum) { 86575f1438bSOleksandr Tymoshenko ifp->if_capabilities |= IFCAP_HWCSUM; 8669f55f5f5SRafal Jaworowski ifp->if_hwassist = MGE_CHECKSUM_FEATURES; 86775f1438bSOleksandr Tymoshenko } 86875f1438bSOleksandr Tymoshenko ifp->if_capenable = ifp->if_capabilities; 8699f55f5f5SRafal Jaworowski 8709f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 8719f55f5f5SRafal Jaworowski /* Advertise that polling is supported */ 8729f55f5f5SRafal Jaworowski ifp->if_capabilities |= IFCAP_POLLING; 8739f55f5f5SRafal Jaworowski #endif 8749f55f5f5SRafal Jaworowski 8759f55f5f5SRafal Jaworowski ifp->if_init = mge_init; 8769f55f5f5SRafal Jaworowski ifp->if_start = mge_start; 8779f55f5f5SRafal Jaworowski ifp->if_ioctl = mge_ioctl; 8789f55f5f5SRafal Jaworowski 8799f55f5f5SRafal Jaworowski ifp->if_snd.ifq_drv_maxlen = MGE_TX_DESC_NUM - 1; 8809f55f5f5SRafal Jaworowski IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 8819f55f5f5SRafal Jaworowski IFQ_SET_READY(&ifp->if_snd); 8829f55f5f5SRafal Jaworowski 8839f55f5f5SRafal Jaworowski mge_get_mac_address(sc, hwaddr); 8849f55f5f5SRafal Jaworowski ether_ifattach(ifp, hwaddr); 8856b2ff27cSAlexander Motin callout_init(&sc->wd_callout, 1); 8869f55f5f5SRafal Jaworowski 8878e5d93dbSMarius Strobl /* Attach PHY(s) */ 8883c71b84fSZbigniew Bodek if (sc->phy_attached) { 8898e5d93dbSMarius Strobl error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd, 8908e5d93dbSMarius Strobl mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 8919f55f5f5SRafal Jaworowski if (error) { 8923c71b84fSZbigniew Bodek device_printf(dev, "MII failed to find PHY\n"); 8933c71b84fSZbigniew Bodek if_free(ifp); 8943c71b84fSZbigniew Bodek sc->ifp = NULL; 8959f55f5f5SRafal Jaworowski mge_detach(dev); 8969f55f5f5SRafal Jaworowski return (error); 8979f55f5f5SRafal Jaworowski } 8989f55f5f5SRafal Jaworowski sc->mii = device_get_softc(sc->miibus); 8999f55f5f5SRafal Jaworowski 900a6eb469dSPhilip Paeps /* Tell the MAC where to find the PHY so autoneg works */ 901a6eb469dSPhilip Paeps miisc = LIST_FIRST(&sc->mii->mii_phys); 902a6eb469dSPhilip Paeps MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy); 9033c71b84fSZbigniew Bodek } else { 9043c71b84fSZbigniew Bodek /* no PHY, so use hard-coded values */ 9053c71b84fSZbigniew Bodek ifmedia_init(&sc->mge_ifmedia, 0, 9063c71b84fSZbigniew Bodek mge_ifmedia_upd, 9073c71b84fSZbigniew Bodek mge_ifmedia_sts); 9083c71b84fSZbigniew Bodek ifmedia_add(&sc->mge_ifmedia, 9093c71b84fSZbigniew Bodek IFM_ETHER | IFM_1000_T | IFM_FDX, 9103c71b84fSZbigniew Bodek 0, NULL); 9113c71b84fSZbigniew Bodek ifmedia_set(&sc->mge_ifmedia, 9123c71b84fSZbigniew Bodek IFM_ETHER | IFM_1000_T | IFM_FDX); 9133c71b84fSZbigniew Bodek } 914a6eb469dSPhilip Paeps 9159f55f5f5SRafal Jaworowski /* Attach interrupt handlers */ 91675f1438bSOleksandr Tymoshenko /* TODO: review flags, in part. mark RX as INTR_ENTROPY ? */ 91775f1438bSOleksandr Tymoshenko for (i = 1; i <= sc->mge_intr_cnt; ++i) { 91875f1438bSOleksandr Tymoshenko error = bus_setup_intr(dev, sc->res[i], 91975f1438bSOleksandr Tymoshenko INTR_TYPE_NET | INTR_MPSAFE, 92075f1438bSOleksandr Tymoshenko NULL, *mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].handler, 92175f1438bSOleksandr Tymoshenko sc, &sc->ih_cookie[i - 1]); 9229f55f5f5SRafal Jaworowski if (error) { 9239f55f5f5SRafal Jaworowski device_printf(dev, "could not setup %s\n", 92475f1438bSOleksandr Tymoshenko mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].description); 925a6eb469dSPhilip Paeps mge_detach(dev); 9269f55f5f5SRafal Jaworowski return (error); 9279f55f5f5SRafal Jaworowski } 9289f55f5f5SRafal Jaworowski } 9299f55f5f5SRafal Jaworowski 9303c71b84fSZbigniew Bodek if (sc->switch_attached) { 9313c71b84fSZbigniew Bodek MGE_WRITE(sc, MGE_REG_PHYDEV, MGE_SWITCH_PHYDEV); 932f8967810SWarner Losh device_add_child(dev, "mdio", -1); 9333c71b84fSZbigniew Bodek bus_generic_attach(dev); 9343c71b84fSZbigniew Bodek } 9353c71b84fSZbigniew Bodek 9369f55f5f5SRafal Jaworowski return (0); 9379f55f5f5SRafal Jaworowski } 9389f55f5f5SRafal Jaworowski 9399f55f5f5SRafal Jaworowski static int 9409f55f5f5SRafal Jaworowski mge_detach(device_t dev) 9419f55f5f5SRafal Jaworowski { 9429f55f5f5SRafal Jaworowski struct mge_softc *sc; 9439f55f5f5SRafal Jaworowski int error,i; 9449f55f5f5SRafal Jaworowski 9459f55f5f5SRafal Jaworowski sc = device_get_softc(dev); 9469f55f5f5SRafal Jaworowski 9479f55f5f5SRafal Jaworowski /* Stop controller and free TX queue */ 9489f55f5f5SRafal Jaworowski if (sc->ifp) 9499f55f5f5SRafal Jaworowski mge_shutdown(dev); 9509f55f5f5SRafal Jaworowski 9519f55f5f5SRafal Jaworowski /* Wait for stopping ticks */ 9529f55f5f5SRafal Jaworowski callout_drain(&sc->wd_callout); 9539f55f5f5SRafal Jaworowski 9549f55f5f5SRafal Jaworowski /* Stop and release all interrupts */ 95575f1438bSOleksandr Tymoshenko for (i = 0; i < sc->mge_intr_cnt; ++i) { 956a6eb469dSPhilip Paeps if (!sc->ih_cookie[i]) 957a6eb469dSPhilip Paeps continue; 958a6eb469dSPhilip Paeps 9594ac30cc1SZbigniew Bodek error = bus_teardown_intr(dev, sc->res[1 + i], 9604ac30cc1SZbigniew Bodek sc->ih_cookie[i]); 9619f55f5f5SRafal Jaworowski if (error) 9629f55f5f5SRafal Jaworowski device_printf(dev, "could not release %s\n", 96375f1438bSOleksandr Tymoshenko mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i + 1)].description); 9649f55f5f5SRafal Jaworowski } 9659f55f5f5SRafal Jaworowski 9669f55f5f5SRafal Jaworowski /* Detach network interface */ 9679f55f5f5SRafal Jaworowski if (sc->ifp) { 9689f55f5f5SRafal Jaworowski ether_ifdetach(sc->ifp); 9699f55f5f5SRafal Jaworowski if_free(sc->ifp); 9709f55f5f5SRafal Jaworowski } 9719f55f5f5SRafal Jaworowski 9729f55f5f5SRafal Jaworowski /* Free DMA resources */ 9739f55f5f5SRafal Jaworowski mge_free_dma(sc); 9749f55f5f5SRafal Jaworowski 9759f55f5f5SRafal Jaworowski /* Free IO memory handler */ 9769f55f5f5SRafal Jaworowski bus_release_resources(dev, res_spec, sc->res); 9779f55f5f5SRafal Jaworowski 9789f55f5f5SRafal Jaworowski /* Destroy mutexes */ 9799f55f5f5SRafal Jaworowski mtx_destroy(&sc->receive_lock); 9809f55f5f5SRafal Jaworowski mtx_destroy(&sc->transmit_lock); 9819f55f5f5SRafal Jaworowski 9823c71b84fSZbigniew Bodek if (device_get_unit(dev) == 0) 9833c71b84fSZbigniew Bodek sx_destroy(&sx_smi); 9843c71b84fSZbigniew Bodek 9859f55f5f5SRafal Jaworowski return (0); 9869f55f5f5SRafal Jaworowski } 9879f55f5f5SRafal Jaworowski 9889f55f5f5SRafal Jaworowski static void 9899f55f5f5SRafal Jaworowski mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 9909f55f5f5SRafal Jaworowski { 9914ac30cc1SZbigniew Bodek struct mge_softc *sc; 9929f55f5f5SRafal Jaworowski struct mii_data *mii; 9939f55f5f5SRafal Jaworowski 9944ac30cc1SZbigniew Bodek sc = ifp->if_softc; 9953c71b84fSZbigniew Bodek MGE_GLOBAL_LOCK(sc); 9963c71b84fSZbigniew Bodek 9973c71b84fSZbigniew Bodek if (!sc->phy_attached) { 9983c71b84fSZbigniew Bodek ifmr->ifm_active = IFM_1000_T | IFM_FDX | IFM_ETHER; 9993c71b84fSZbigniew Bodek ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 10003c71b84fSZbigniew Bodek goto out_unlock; 10013c71b84fSZbigniew Bodek } 10029f55f5f5SRafal Jaworowski 10039f55f5f5SRafal Jaworowski mii = sc->mii; 10049f55f5f5SRafal Jaworowski mii_pollstat(mii); 10059f55f5f5SRafal Jaworowski 10069f55f5f5SRafal Jaworowski ifmr->ifm_active = mii->mii_media_active; 10079f55f5f5SRafal Jaworowski ifmr->ifm_status = mii->mii_media_status; 10089f55f5f5SRafal Jaworowski 10093c71b84fSZbigniew Bodek out_unlock: 10103c71b84fSZbigniew Bodek MGE_GLOBAL_UNLOCK(sc); 10119f55f5f5SRafal Jaworowski } 10129f55f5f5SRafal Jaworowski 10139f55f5f5SRafal Jaworowski static uint32_t 10149f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media) 10159f55f5f5SRafal Jaworowski { 10169f55f5f5SRafal Jaworowski uint32_t port_config; 10179f55f5f5SRafal Jaworowski 10189f55f5f5SRafal Jaworowski port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL | 10199f55f5f5SRafal Jaworowski PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552); 10209f55f5f5SRafal Jaworowski 10219f55f5f5SRafal Jaworowski if (IFM_TYPE(media) == IFM_ETHER) { 10229f55f5f5SRafal Jaworowski switch(IFM_SUBTYPE(media)) { 10239f55f5f5SRafal Jaworowski case IFM_AUTO: 10249f55f5f5SRafal Jaworowski break; 10259f55f5f5SRafal Jaworowski case IFM_1000_T: 10269f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_GMII_SPEED_1000 | 10273c71b84fSZbigniew Bodek PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC 10283c71b84fSZbigniew Bodek | PORT_SERIAL_SPEED_AUTONEG); 10299f55f5f5SRafal Jaworowski break; 10309f55f5f5SRafal Jaworowski case IFM_100_TX: 10319f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_MII_SPEED_100 | 10323c71b84fSZbigniew Bodek PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC 10333c71b84fSZbigniew Bodek | PORT_SERIAL_SPEED_AUTONEG); 10349f55f5f5SRafal Jaworowski break; 10359f55f5f5SRafal Jaworowski case IFM_10_T: 10369f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_AUTONEG | 10379f55f5f5SRafal Jaworowski PORT_SERIAL_AUTONEG_FC | 10389f55f5f5SRafal Jaworowski PORT_SERIAL_SPEED_AUTONEG); 10399f55f5f5SRafal Jaworowski break; 10409f55f5f5SRafal Jaworowski } 10419f55f5f5SRafal Jaworowski if (media & IFM_FDX) 10429f55f5f5SRafal Jaworowski port_config |= PORT_SERIAL_FULL_DUPLEX; 10439f55f5f5SRafal Jaworowski } 10449f55f5f5SRafal Jaworowski return (port_config); 10459f55f5f5SRafal Jaworowski } 10469f55f5f5SRafal Jaworowski 10479f55f5f5SRafal Jaworowski static int 10489f55f5f5SRafal Jaworowski mge_ifmedia_upd(struct ifnet *ifp) 10499f55f5f5SRafal Jaworowski { 10509f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 10519f55f5f5SRafal Jaworowski 10523c71b84fSZbigniew Bodek /* 10533c71b84fSZbigniew Bodek * Do not do anything for switch here, as updating media between 10543c71b84fSZbigniew Bodek * MGE MAC and switch MAC is hardcoded in PCB. Changing it here would 10553c71b84fSZbigniew Bodek * break the link. 10563c71b84fSZbigniew Bodek */ 10573c71b84fSZbigniew Bodek if (sc->phy_attached) { 10589f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 10593c71b84fSZbigniew Bodek if (ifp->if_flags & IFF_UP) { 10609f55f5f5SRafal Jaworowski sc->mge_media_status = sc->mii->mii_media.ifm_media; 10619f55f5f5SRafal Jaworowski mii_mediachg(sc->mii); 10623c71b84fSZbigniew Bodek 10633c71b84fSZbigniew Bodek /* MGE MAC needs to be reinitialized. */ 10649f55f5f5SRafal Jaworowski mge_init_locked(sc); 10659f55f5f5SRafal Jaworowski 10663c71b84fSZbigniew Bodek } 10679f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 10689f55f5f5SRafal Jaworowski } 10699f55f5f5SRafal Jaworowski 10709f55f5f5SRafal Jaworowski return (0); 10719f55f5f5SRafal Jaworowski } 10729f55f5f5SRafal Jaworowski 10739f55f5f5SRafal Jaworowski static void 10749f55f5f5SRafal Jaworowski mge_init(void *arg) 10759f55f5f5SRafal Jaworowski { 10764ac30cc1SZbigniew Bodek struct mge_softc *sc; 10779f55f5f5SRafal Jaworowski 10784ac30cc1SZbigniew Bodek sc = arg; 10799f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 10809f55f5f5SRafal Jaworowski 10819f55f5f5SRafal Jaworowski mge_init_locked(arg); 10829f55f5f5SRafal Jaworowski 10839f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 10849f55f5f5SRafal Jaworowski } 10859f55f5f5SRafal Jaworowski 10869f55f5f5SRafal Jaworowski static void 10879f55f5f5SRafal Jaworowski mge_init_locked(void *arg) 10889f55f5f5SRafal Jaworowski { 10899f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 10909f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 10919f55f5f5SRafal Jaworowski volatile uint32_t reg_val; 10929f55f5f5SRafal Jaworowski int i, count; 10933c71b84fSZbigniew Bodek uint32_t media_status; 10949f55f5f5SRafal Jaworowski 10959f55f5f5SRafal Jaworowski 10969f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK_ASSERT(sc); 10979f55f5f5SRafal Jaworowski 10989f55f5f5SRafal Jaworowski /* Stop interface */ 10999f55f5f5SRafal Jaworowski mge_stop(sc); 11009f55f5f5SRafal Jaworowski 11019f55f5f5SRafal Jaworowski /* Disable interrupts */ 11029f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 11039f55f5f5SRafal Jaworowski 11049f55f5f5SRafal Jaworowski /* Set MAC address */ 11059f55f5f5SRafal Jaworowski mge_set_mac_address(sc); 11069f55f5f5SRafal Jaworowski 11079f55f5f5SRafal Jaworowski /* Setup multicast filters */ 11089f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 11099f55f5f5SRafal Jaworowski 11108e1dc58eSRafal Jaworowski if (sc->mge_ver == 2) { 11119f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN); 11129f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0)); 11138e1dc58eSRafal Jaworowski } 11149f55f5f5SRafal Jaworowski 11158e1dc58eSRafal Jaworowski /* Initialize TX queue configuration registers */ 11168e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt); 11178e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg); 11188e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg); 11198e1dc58eSRafal Jaworowski 11208e1dc58eSRafal Jaworowski /* Clear TX queue configuration registers for unused queues */ 11219f55f5f5SRafal Jaworowski for (i = 1; i < 7; i++) { 11228e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0); 11238e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0); 11248e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0); 11259f55f5f5SRafal Jaworowski } 11269f55f5f5SRafal Jaworowski 11279f55f5f5SRafal Jaworowski /* Set default MTU */ 11288e1dc58eSRafal Jaworowski MGE_WRITE(sc, sc->mge_mtu, 0); 11299f55f5f5SRafal Jaworowski 11309f55f5f5SRafal Jaworowski /* Port configuration */ 11319f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, 11329f55f5f5SRafal Jaworowski PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) | 11339f55f5f5SRafal Jaworowski PORT_CONFIG_ARO_RXQ(0)); 11349f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0); 11359f55f5f5SRafal Jaworowski 11363c71b84fSZbigniew Bodek /* Configure promisc mode */ 11373c71b84fSZbigniew Bodek mge_set_prom_mode(sc, MGE_RX_DEFAULT_QUEUE); 11383c71b84fSZbigniew Bodek 11393c71b84fSZbigniew Bodek media_status = sc->mge_media_status; 11403c71b84fSZbigniew Bodek if (sc->switch_attached) { 11413c71b84fSZbigniew Bodek media_status &= ~IFM_TMASK; 11423c71b84fSZbigniew Bodek media_status |= IFM_1000_T; 11433c71b84fSZbigniew Bodek } 11443c71b84fSZbigniew Bodek 11459f55f5f5SRafal Jaworowski /* Setup port configuration */ 11463c71b84fSZbigniew Bodek reg_val = mge_set_port_serial_control(media_status); 11479f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val); 11489f55f5f5SRafal Jaworowski 11499f55f5f5SRafal Jaworowski /* Setup SDMA configuration */ 11509f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP | 11519f55f5f5SRafal Jaworowski MGE_SDMA_TX_BYTE_SWAP | 11529f55f5f5SRafal Jaworowski MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) | 11539f55f5f5SRafal Jaworowski MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD)); 11549f55f5f5SRafal Jaworowski 11559f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0); 11569f55f5f5SRafal Jaworowski 11579f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start); 11589f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE), 11599f55f5f5SRafal Jaworowski sc->rx_desc_start); 11609f55f5f5SRafal Jaworowski 11619f55f5f5SRafal Jaworowski /* Reset descriptor indexes */ 11629f55f5f5SRafal Jaworowski sc->tx_desc_curr = 0; 11639f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 11649f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 0; 11655817716fSRafal Jaworowski sc->tx_desc_used_count = 0; 11669f55f5f5SRafal Jaworowski 11679f55f5f5SRafal Jaworowski /* Enable RX descriptors */ 11689f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 11699f55f5f5SRafal Jaworowski dw = &sc->mge_rx_desc[i]; 11709f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED; 11719f55f5f5SRafal Jaworowski dw->mge_desc->buff_size = MCLBYTES; 11729f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 11739f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 11749f55f5f5SRafal Jaworowski } 11759f55f5f5SRafal Jaworowski 11769f55f5f5SRafal Jaworowski /* Enable RX queue */ 11779f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE)); 11789f55f5f5SRafal Jaworowski 11799f55f5f5SRafal Jaworowski /* Enable port */ 11809f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL); 11819f55f5f5SRafal Jaworowski reg_val |= PORT_SERIAL_ENABLE; 11829f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val); 11839f55f5f5SRafal Jaworowski count = 0x100000; 11849f55f5f5SRafal Jaworowski for (;;) { 11859f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_STATUS); 11869f55f5f5SRafal Jaworowski if (reg_val & MGE_STATUS_LINKUP) 11879f55f5f5SRafal Jaworowski break; 11889f55f5f5SRafal Jaworowski DELAY(100); 11899f55f5f5SRafal Jaworowski if (--count == 0) { 11909f55f5f5SRafal Jaworowski if_printf(sc->ifp, "Timeout on link-up\n"); 11919f55f5f5SRafal Jaworowski break; 11929f55f5f5SRafal Jaworowski } 11939f55f5f5SRafal Jaworowski } 11949f55f5f5SRafal Jaworowski 11959f55f5f5SRafal Jaworowski /* Setup interrupts coalescing */ 11969f55f5f5SRafal Jaworowski mge_set_rxic(sc); 11979f55f5f5SRafal Jaworowski mge_set_txic(sc); 11989f55f5f5SRafal Jaworowski 11999f55f5f5SRafal Jaworowski /* Enable interrupts */ 12009f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 12019f55f5f5SRafal Jaworowski /* 12029f55f5f5SRafal Jaworowski * * ...only if polling is not turned on. Disable interrupts explicitly 12039f55f5f5SRafal Jaworowski * if polling is enabled. 12049f55f5f5SRafal Jaworowski */ 12059f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) 12069f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 12079f55f5f5SRafal Jaworowski else 12089f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */ 12099f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 1); 12109f55f5f5SRafal Jaworowski 12119f55f5f5SRafal Jaworowski /* Activate network interface */ 12129f55f5f5SRafal Jaworowski sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 12139f55f5f5SRafal Jaworowski sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 12149f55f5f5SRafal Jaworowski sc->wd_timer = 0; 12159f55f5f5SRafal Jaworowski 12169f55f5f5SRafal Jaworowski /* Schedule watchdog timeout */ 12173c71b84fSZbigniew Bodek if (sc->phy_attached) 12189f55f5f5SRafal Jaworowski callout_reset(&sc->wd_callout, hz, mge_tick, sc); 12199f55f5f5SRafal Jaworowski } 12209f55f5f5SRafal Jaworowski 12219f55f5f5SRafal Jaworowski static void 122275f1438bSOleksandr Tymoshenko mge_intr_rxtx(void *arg) 122375f1438bSOleksandr Tymoshenko { 12244ac30cc1SZbigniew Bodek struct mge_softc *sc; 122575f1438bSOleksandr Tymoshenko uint32_t int_cause, int_cause_ext; 122675f1438bSOleksandr Tymoshenko 12274ac30cc1SZbigniew Bodek sc = arg; 122875f1438bSOleksandr Tymoshenko MGE_GLOBAL_LOCK(sc); 122975f1438bSOleksandr Tymoshenko 123075f1438bSOleksandr Tymoshenko #ifdef DEVICE_POLLING 123175f1438bSOleksandr Tymoshenko if (sc->ifp->if_capenable & IFCAP_POLLING) { 123275f1438bSOleksandr Tymoshenko MGE_GLOBAL_UNLOCK(sc); 123375f1438bSOleksandr Tymoshenko return; 123475f1438bSOleksandr Tymoshenko } 123575f1438bSOleksandr Tymoshenko #endif 123675f1438bSOleksandr Tymoshenko 123775f1438bSOleksandr Tymoshenko /* Get interrupt cause */ 123875f1438bSOleksandr Tymoshenko int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE); 123975f1438bSOleksandr Tymoshenko int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 124075f1438bSOleksandr Tymoshenko 124175f1438bSOleksandr Tymoshenko /* Check for Transmit interrupt */ 124275f1438bSOleksandr Tymoshenko if (int_cause_ext & (MGE_PORT_INT_EXT_TXBUF0 | 124375f1438bSOleksandr Tymoshenko MGE_PORT_INT_EXT_TXUR)) { 124475f1438bSOleksandr Tymoshenko MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext & 124575f1438bSOleksandr Tymoshenko (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR))); 124675f1438bSOleksandr Tymoshenko mge_intr_tx_locked(sc); 124775f1438bSOleksandr Tymoshenko } 124875f1438bSOleksandr Tymoshenko 124975f1438bSOleksandr Tymoshenko MGE_TRANSMIT_UNLOCK(sc); 125075f1438bSOleksandr Tymoshenko 125175f1438bSOleksandr Tymoshenko /* Check for Receive interrupt */ 125275f1438bSOleksandr Tymoshenko mge_intr_rx_check(sc, int_cause, int_cause_ext); 125375f1438bSOleksandr Tymoshenko 125475f1438bSOleksandr Tymoshenko MGE_RECEIVE_UNLOCK(sc); 125575f1438bSOleksandr Tymoshenko } 125675f1438bSOleksandr Tymoshenko 125775f1438bSOleksandr Tymoshenko static void 12589f55f5f5SRafal Jaworowski mge_intr_err(void *arg) 12599f55f5f5SRafal Jaworowski { 12604ac30cc1SZbigniew Bodek struct mge_softc *sc; 12619f55f5f5SRafal Jaworowski struct ifnet *ifp; 12629f55f5f5SRafal Jaworowski 12634ac30cc1SZbigniew Bodek sc = arg; 12649f55f5f5SRafal Jaworowski ifp = sc->ifp; 12659f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 12669f55f5f5SRafal Jaworowski } 12679f55f5f5SRafal Jaworowski 12689f55f5f5SRafal Jaworowski static void 12699f55f5f5SRafal Jaworowski mge_intr_misc(void *arg) 12709f55f5f5SRafal Jaworowski { 12714ac30cc1SZbigniew Bodek struct mge_softc *sc; 12729f55f5f5SRafal Jaworowski struct ifnet *ifp; 12739f55f5f5SRafal Jaworowski 12744ac30cc1SZbigniew Bodek sc = arg; 12759f55f5f5SRafal Jaworowski ifp = sc->ifp; 12769f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 12779f55f5f5SRafal Jaworowski } 12789f55f5f5SRafal Jaworowski 12799f55f5f5SRafal Jaworowski static void 12809f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) { 12814ac30cc1SZbigniew Bodek struct mge_softc *sc; 12829f55f5f5SRafal Jaworowski uint32_t int_cause, int_cause_ext; 12839f55f5f5SRafal Jaworowski 12844ac30cc1SZbigniew Bodek sc = arg; 12859f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc); 12869f55f5f5SRafal Jaworowski 12879f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 12889f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) { 12899f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc); 12909f55f5f5SRafal Jaworowski return; 12919f55f5f5SRafal Jaworowski } 12929f55f5f5SRafal Jaworowski #endif 12939f55f5f5SRafal Jaworowski 12949f55f5f5SRafal Jaworowski /* Get interrupt cause */ 12959f55f5f5SRafal Jaworowski int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE); 12969f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 12979f55f5f5SRafal Jaworowski 129875f1438bSOleksandr Tymoshenko mge_intr_rx_check(sc, int_cause, int_cause_ext); 129975f1438bSOleksandr Tymoshenko 130075f1438bSOleksandr Tymoshenko MGE_RECEIVE_UNLOCK(sc); 130175f1438bSOleksandr Tymoshenko } 130275f1438bSOleksandr Tymoshenko 130375f1438bSOleksandr Tymoshenko static void 130475f1438bSOleksandr Tymoshenko mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause, 130575f1438bSOleksandr Tymoshenko uint32_t int_cause_ext) 130675f1438bSOleksandr Tymoshenko { 13079f55f5f5SRafal Jaworowski /* Check for resource error */ 13089f55f5f5SRafal Jaworowski if (int_cause & MGE_PORT_INT_RXERRQ0) { 13099f55f5f5SRafal Jaworowski mge_reinit_rx(sc); 13109f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 131175f1438bSOleksandr Tymoshenko ~(int_cause & MGE_PORT_INT_RXERRQ0)); 13129f55f5f5SRafal Jaworowski } 13139f55f5f5SRafal Jaworowski 13149f55f5f5SRafal Jaworowski int_cause &= MGE_PORT_INT_RXQ0; 13159f55f5f5SRafal Jaworowski int_cause_ext &= MGE_PORT_INT_EXT_RXOR; 13169f55f5f5SRafal Jaworowski 13179f55f5f5SRafal Jaworowski if (int_cause || int_cause_ext) { 13189f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause); 13199f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext); 13209f55f5f5SRafal Jaworowski mge_intr_rx_locked(sc, -1); 13219f55f5f5SRafal Jaworowski } 13229f55f5f5SRafal Jaworowski } 13239f55f5f5SRafal Jaworowski 13241abcdbd1SAttilio Rao static int 13259f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count) 13269f55f5f5SRafal Jaworowski { 13279f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 13289f55f5f5SRafal Jaworowski uint32_t status; 13299f55f5f5SRafal Jaworowski uint16_t bufsize; 13309f55f5f5SRafal Jaworowski struct mge_desc_wrapper* dw; 13319f55f5f5SRafal Jaworowski struct mbuf *mb; 13321abcdbd1SAttilio Rao int rx_npkts = 0; 13339f55f5f5SRafal Jaworowski 13349f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK_ASSERT(sc); 13359f55f5f5SRafal Jaworowski 13369f55f5f5SRafal Jaworowski while (count != 0) { 13379f55f5f5SRafal Jaworowski dw = &sc->mge_rx_desc[sc->rx_desc_curr]; 13389f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 13399f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 13409f55f5f5SRafal Jaworowski 13419f55f5f5SRafal Jaworowski /* Get status */ 13429f55f5f5SRafal Jaworowski status = dw->mge_desc->cmd_status; 13439f55f5f5SRafal Jaworowski bufsize = dw->mge_desc->buff_size; 13449f55f5f5SRafal Jaworowski if ((status & MGE_DMA_OWNED) != 0) 13459f55f5f5SRafal Jaworowski break; 13469f55f5f5SRafal Jaworowski 13479f55f5f5SRafal Jaworowski if (dw->mge_desc->byte_count && 13489f55f5f5SRafal Jaworowski ~(status & MGE_ERR_SUMMARY)) { 13499f55f5f5SRafal Jaworowski 13509f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap, 13519f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 13529f55f5f5SRafal Jaworowski 13539f55f5f5SRafal Jaworowski mb = m_devget(dw->buffer->m_data, 13549f55f5f5SRafal Jaworowski dw->mge_desc->byte_count - ETHER_CRC_LEN, 13559f55f5f5SRafal Jaworowski 0, ifp, NULL); 13569f55f5f5SRafal Jaworowski 13575817716fSRafal Jaworowski if (mb == NULL) 13585817716fSRafal Jaworowski /* Give up if no mbufs */ 13595817716fSRafal Jaworowski break; 13605817716fSRafal Jaworowski 13619f55f5f5SRafal Jaworowski mb->m_len -= 2; 13629f55f5f5SRafal Jaworowski mb->m_pkthdr.len -= 2; 13639f55f5f5SRafal Jaworowski mb->m_data += 2; 13649f55f5f5SRafal Jaworowski 1365b8fad6c0SFabien Thomas mb->m_pkthdr.rcvif = ifp; 1366b8fad6c0SFabien Thomas 13679f55f5f5SRafal Jaworowski mge_offload_process_frame(ifp, mb, status, 13689f55f5f5SRafal Jaworowski bufsize); 13699f55f5f5SRafal Jaworowski 13709f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc); 13719f55f5f5SRafal Jaworowski (*ifp->if_input)(ifp, mb); 13729f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc); 13731abcdbd1SAttilio Rao rx_npkts++; 13749f55f5f5SRafal Jaworowski } 13759f55f5f5SRafal Jaworowski 13769f55f5f5SRafal Jaworowski dw->mge_desc->byte_count = 0; 13779f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED; 13785817716fSRafal Jaworowski sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM); 13799f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 13809f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 13819f55f5f5SRafal Jaworowski 13829f55f5f5SRafal Jaworowski if (count > 0) 13839f55f5f5SRafal Jaworowski count -= 1; 13849f55f5f5SRafal Jaworowski } 13859f55f5f5SRafal Jaworowski 1386c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_npkts); 1387b8fad6c0SFabien Thomas 13881abcdbd1SAttilio Rao return (rx_npkts); 13899f55f5f5SRafal Jaworowski } 13909f55f5f5SRafal Jaworowski 13919f55f5f5SRafal Jaworowski static void 13929f55f5f5SRafal Jaworowski mge_intr_sum(void *arg) 13939f55f5f5SRafal Jaworowski { 13949f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 13959f55f5f5SRafal Jaworowski struct ifnet *ifp; 13969f55f5f5SRafal Jaworowski 13979f55f5f5SRafal Jaworowski ifp = sc->ifp; 13989f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 13999f55f5f5SRafal Jaworowski } 14009f55f5f5SRafal Jaworowski 14019f55f5f5SRafal Jaworowski static void 14029f55f5f5SRafal Jaworowski mge_intr_tx(void *arg) 14039f55f5f5SRafal Jaworowski { 14049f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 14059f55f5f5SRafal Jaworowski uint32_t int_cause_ext; 14069f55f5f5SRafal Jaworowski 14079f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc); 14089f55f5f5SRafal Jaworowski 14099f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 14109f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) { 14119f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 14129f55f5f5SRafal Jaworowski return; 14139f55f5f5SRafal Jaworowski } 14149f55f5f5SRafal Jaworowski #endif 14159f55f5f5SRafal Jaworowski 14169f55f5f5SRafal Jaworowski /* Ack the interrupt */ 14179f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 141875f1438bSOleksandr Tymoshenko MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext & 141975f1438bSOleksandr Tymoshenko (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR))); 14209f55f5f5SRafal Jaworowski 14219f55f5f5SRafal Jaworowski mge_intr_tx_locked(sc); 14229f55f5f5SRafal Jaworowski 14239f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 14249f55f5f5SRafal Jaworowski } 14259f55f5f5SRafal Jaworowski 14269f55f5f5SRafal Jaworowski static void 14279f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc) 14289f55f5f5SRafal Jaworowski { 14299f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 14309f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 14319f55f5f5SRafal Jaworowski struct mge_desc *desc; 14329f55f5f5SRafal Jaworowski uint32_t status; 14339f55f5f5SRafal Jaworowski int send = 0; 14349f55f5f5SRafal Jaworowski 14359f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK_ASSERT(sc); 14369f55f5f5SRafal Jaworowski 14379f55f5f5SRafal Jaworowski /* Disable watchdog */ 14389f55f5f5SRafal Jaworowski sc->wd_timer = 0; 14399f55f5f5SRafal Jaworowski 14409f55f5f5SRafal Jaworowski while (sc->tx_desc_used_count) { 14419f55f5f5SRafal Jaworowski /* Get the descriptor */ 14429f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[sc->tx_desc_used_idx]; 14439f55f5f5SRafal Jaworowski desc = dw->mge_desc; 14449f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 14459f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 14469f55f5f5SRafal Jaworowski 14479f55f5f5SRafal Jaworowski /* Get descriptor status */ 14489f55f5f5SRafal Jaworowski status = desc->cmd_status; 14499f55f5f5SRafal Jaworowski 14509f55f5f5SRafal Jaworowski if (status & MGE_DMA_OWNED) 14519f55f5f5SRafal Jaworowski break; 14529f55f5f5SRafal Jaworowski 14539f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 1454c2ede4b3SMartin Blapp (++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM; 14559f55f5f5SRafal Jaworowski sc->tx_desc_used_count--; 14569f55f5f5SRafal Jaworowski 14579f55f5f5SRafal Jaworowski /* Update collision statistics */ 14589f55f5f5SRafal Jaworowski if (status & MGE_ERR_SUMMARY) { 14599f55f5f5SRafal Jaworowski if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC) 1460c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1); 14619f55f5f5SRafal Jaworowski if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL) 1462c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 16); 14639f55f5f5SRafal Jaworowski } 14649f55f5f5SRafal Jaworowski 14659f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap, 14669f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 14679f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap); 14689f55f5f5SRafal Jaworowski m_freem(dw->buffer); 14699f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 14709f55f5f5SRafal Jaworowski send++; 14719f55f5f5SRafal Jaworowski 1472c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 14739f55f5f5SRafal Jaworowski } 14749f55f5f5SRafal Jaworowski 14759f55f5f5SRafal Jaworowski if (send) { 14769f55f5f5SRafal Jaworowski /* Now send anything that was pending */ 14779f55f5f5SRafal Jaworowski ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 14789f55f5f5SRafal Jaworowski mge_start_locked(ifp); 14799f55f5f5SRafal Jaworowski } 14809f55f5f5SRafal Jaworowski } 14819f55f5f5SRafal Jaworowski static int 14829f55f5f5SRafal Jaworowski mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 14839f55f5f5SRafal Jaworowski { 14849f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 14859f55f5f5SRafal Jaworowski struct ifreq *ifr = (struct ifreq *)data; 14869f55f5f5SRafal Jaworowski int mask, error; 14879f55f5f5SRafal Jaworowski uint32_t flags; 14889f55f5f5SRafal Jaworowski 14899f55f5f5SRafal Jaworowski error = 0; 14909f55f5f5SRafal Jaworowski 14919f55f5f5SRafal Jaworowski switch (command) { 14929f55f5f5SRafal Jaworowski case SIOCSIFFLAGS: 14939f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 14949f55f5f5SRafal Jaworowski 14959f55f5f5SRafal Jaworowski if (ifp->if_flags & IFF_UP) { 14969f55f5f5SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 14979f55f5f5SRafal Jaworowski flags = ifp->if_flags ^ sc->mge_if_flags; 14989f55f5f5SRafal Jaworowski if (flags & IFF_PROMISC) 14999f55f5f5SRafal Jaworowski mge_set_prom_mode(sc, 15009f55f5f5SRafal Jaworowski MGE_RX_DEFAULT_QUEUE); 15019f55f5f5SRafal Jaworowski 15029f55f5f5SRafal Jaworowski if (flags & IFF_ALLMULTI) 15039f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 15049f55f5f5SRafal Jaworowski } else 15059f55f5f5SRafal Jaworowski mge_init_locked(sc); 15069f55f5f5SRafal Jaworowski } 15079f55f5f5SRafal Jaworowski else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 15089f55f5f5SRafal Jaworowski mge_stop(sc); 15099f55f5f5SRafal Jaworowski 15109f55f5f5SRafal Jaworowski sc->mge_if_flags = ifp->if_flags; 15119f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 15129f55f5f5SRafal Jaworowski break; 15139f55f5f5SRafal Jaworowski case SIOCADDMULTI: 15149f55f5f5SRafal Jaworowski case SIOCDELMULTI: 15159f55f5f5SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 15169f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 15179f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 15189f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 15199f55f5f5SRafal Jaworowski } 15209f55f5f5SRafal Jaworowski break; 15219f55f5f5SRafal Jaworowski case SIOCSIFCAP: 15229f55f5f5SRafal Jaworowski mask = ifp->if_capenable ^ ifr->ifr_reqcap; 15239f55f5f5SRafal Jaworowski if (mask & IFCAP_HWCSUM) { 15249f55f5f5SRafal Jaworowski ifp->if_capenable &= ~IFCAP_HWCSUM; 15259f55f5f5SRafal Jaworowski ifp->if_capenable |= IFCAP_HWCSUM & ifr->ifr_reqcap; 15269f55f5f5SRafal Jaworowski if (ifp->if_capenable & IFCAP_TXCSUM) 15279f55f5f5SRafal Jaworowski ifp->if_hwassist = MGE_CHECKSUM_FEATURES; 15289f55f5f5SRafal Jaworowski else 15299f55f5f5SRafal Jaworowski ifp->if_hwassist = 0; 15309f55f5f5SRafal Jaworowski } 15319f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 15329f55f5f5SRafal Jaworowski if (mask & IFCAP_POLLING) { 15339f55f5f5SRafal Jaworowski if (ifr->ifr_reqcap & IFCAP_POLLING) { 15349f55f5f5SRafal Jaworowski error = ether_poll_register(mge_poll, ifp); 15359f55f5f5SRafal Jaworowski if (error) 15369f55f5f5SRafal Jaworowski return(error); 15379f55f5f5SRafal Jaworowski 15389f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 15399f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 15409f55f5f5SRafal Jaworowski ifp->if_capenable |= IFCAP_POLLING; 15419f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 15429f55f5f5SRafal Jaworowski } else { 15439f55f5f5SRafal Jaworowski error = ether_poll_deregister(ifp); 15449f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 15459f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 1); 15469f55f5f5SRafal Jaworowski ifp->if_capenable &= ~IFCAP_POLLING; 15479f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 15489f55f5f5SRafal Jaworowski } 15499f55f5f5SRafal Jaworowski } 15509f55f5f5SRafal Jaworowski #endif 15519f55f5f5SRafal Jaworowski break; 15529f55f5f5SRafal Jaworowski case SIOCGIFMEDIA: /* fall through */ 15539f55f5f5SRafal Jaworowski case SIOCSIFMEDIA: 15543c71b84fSZbigniew Bodek /* 15553c71b84fSZbigniew Bodek * Setting up media type via ioctls is *not* supported for MAC 15563c71b84fSZbigniew Bodek * which is connected to switch. Use etherswitchcfg. 15573c71b84fSZbigniew Bodek */ 15583c71b84fSZbigniew Bodek if (!sc->phy_attached && (command == SIOCSIFMEDIA)) 15593c71b84fSZbigniew Bodek return (0); 15603c71b84fSZbigniew Bodek else if (!sc->phy_attached) { 15613c71b84fSZbigniew Bodek error = ifmedia_ioctl(ifp, ifr, &sc->mge_ifmedia, 15623c71b84fSZbigniew Bodek command); 15633c71b84fSZbigniew Bodek break; 15643c71b84fSZbigniew Bodek } 15653c71b84fSZbigniew Bodek 15669f55f5f5SRafal Jaworowski if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T 15679f55f5f5SRafal Jaworowski && !(ifr->ifr_media & IFM_FDX)) { 15689f55f5f5SRafal Jaworowski device_printf(sc->dev, 15699f55f5f5SRafal Jaworowski "1000baseTX half-duplex unsupported\n"); 15709f55f5f5SRafal Jaworowski return 0; 15719f55f5f5SRafal Jaworowski } 15729f55f5f5SRafal Jaworowski error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command); 15739f55f5f5SRafal Jaworowski break; 15749f55f5f5SRafal Jaworowski default: 15759f55f5f5SRafal Jaworowski error = ether_ioctl(ifp, command, data); 15769f55f5f5SRafal Jaworowski } 15779f55f5f5SRafal Jaworowski return (error); 15789f55f5f5SRafal Jaworowski } 15799f55f5f5SRafal Jaworowski 15809f55f5f5SRafal Jaworowski static int 15819f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg) 15829f55f5f5SRafal Jaworowski { 15839f55f5f5SRafal Jaworowski 15843c71b84fSZbigniew Bodek KASSERT(!switch_attached, ("miibus used with switch attached")); 15859f55f5f5SRafal Jaworowski 15863c71b84fSZbigniew Bodek return (mv_read_ext_phy(dev, phy, reg)); 15879f55f5f5SRafal Jaworowski } 15889f55f5f5SRafal Jaworowski 15898e45f0b7SAndriy Gapon static int 15909f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value) 15919f55f5f5SRafal Jaworowski { 1592db5ef4fcSRafal Jaworowski 15933c71b84fSZbigniew Bodek KASSERT(!switch_attached, ("miibus used with switch attached")); 15949f55f5f5SRafal Jaworowski 15953c71b84fSZbigniew Bodek mv_write_ext_phy(dev, phy, reg, value); 15969f55f5f5SRafal Jaworowski 15978e45f0b7SAndriy Gapon return (0); 15989f55f5f5SRafal Jaworowski } 15999f55f5f5SRafal Jaworowski 16009f55f5f5SRafal Jaworowski static int 16019f55f5f5SRafal Jaworowski mge_probe(device_t dev) 16029f55f5f5SRafal Jaworowski { 16039f55f5f5SRafal Jaworowski 1604add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 1605add35ed5SIan Lepore return (ENXIO); 1606add35ed5SIan Lepore 1607db5ef4fcSRafal Jaworowski if (!ofw_bus_is_compatible(dev, "mrvl,ge")) 1608db5ef4fcSRafal Jaworowski return (ENXIO); 1609db5ef4fcSRafal Jaworowski 16109f55f5f5SRafal Jaworowski device_set_desc(dev, "Marvell Gigabit Ethernet controller"); 16119f55f5f5SRafal Jaworowski return (BUS_PROBE_DEFAULT); 16129f55f5f5SRafal Jaworowski } 16139f55f5f5SRafal Jaworowski 16149f55f5f5SRafal Jaworowski static int 16159f55f5f5SRafal Jaworowski mge_resume(device_t dev) 16169f55f5f5SRafal Jaworowski { 16179f55f5f5SRafal Jaworowski 16189f55f5f5SRafal Jaworowski device_printf(dev, "%s\n", __FUNCTION__); 16199f55f5f5SRafal Jaworowski return (0); 16209f55f5f5SRafal Jaworowski } 16219f55f5f5SRafal Jaworowski 16229f55f5f5SRafal Jaworowski static int 16239f55f5f5SRafal Jaworowski mge_shutdown(device_t dev) 16249f55f5f5SRafal Jaworowski { 16259f55f5f5SRafal Jaworowski struct mge_softc *sc = device_get_softc(dev); 16269f55f5f5SRafal Jaworowski 16279f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 16289f55f5f5SRafal Jaworowski 16299f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 16309f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) 16319f55f5f5SRafal Jaworowski ether_poll_deregister(sc->ifp); 16329f55f5f5SRafal Jaworowski #endif 16339f55f5f5SRafal Jaworowski 16349f55f5f5SRafal Jaworowski mge_stop(sc); 16359f55f5f5SRafal Jaworowski 16369f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 16379f55f5f5SRafal Jaworowski 16389f55f5f5SRafal Jaworowski return (0); 16399f55f5f5SRafal Jaworowski } 16409f55f5f5SRafal Jaworowski 16419f55f5f5SRafal Jaworowski static int 16429f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0) 16439f55f5f5SRafal Jaworowski { 16449f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw = NULL; 16459f55f5f5SRafal Jaworowski bus_dma_segment_t segs[MGE_TX_DESC_NUM]; 16469f55f5f5SRafal Jaworowski bus_dmamap_t mapp; 16479f55f5f5SRafal Jaworowski int error; 16489f55f5f5SRafal Jaworowski int seg, nsegs; 16499f55f5f5SRafal Jaworowski int desc_no; 16509f55f5f5SRafal Jaworowski 16519f55f5f5SRafal Jaworowski /* Fetch unused map */ 16529f55f5f5SRafal Jaworowski desc_no = sc->tx_desc_curr; 16539f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[desc_no]; 16549f55f5f5SRafal Jaworowski mapp = dw->buffer_dmap; 16559f55f5f5SRafal Jaworowski 16569f55f5f5SRafal Jaworowski /* Create mapping in DMA memory */ 16579f55f5f5SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs, 16589f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT); 1659b8fad6c0SFabien Thomas if (error != 0) { 1660b8fad6c0SFabien Thomas m_freem(m0); 1661b8fad6c0SFabien Thomas return (error); 1662b8fad6c0SFabien Thomas } 1663b8fad6c0SFabien Thomas 1664b8fad6c0SFabien Thomas /* Only one segment is supported. */ 1665b8fad6c0SFabien Thomas if (nsegs != 1) { 16669f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, mapp); 1667b8fad6c0SFabien Thomas m_freem(m0); 1668b8fad6c0SFabien Thomas return (-1); 16699f55f5f5SRafal Jaworowski } 16709f55f5f5SRafal Jaworowski 16719f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE); 16729f55f5f5SRafal Jaworowski 16739f55f5f5SRafal Jaworowski /* Everything is ok, now we can send buffers */ 16749f55f5f5SRafal Jaworowski for (seg = 0; seg < nsegs; seg++) { 16759f55f5f5SRafal Jaworowski dw->mge_desc->byte_count = segs[seg].ds_len; 16769f55f5f5SRafal Jaworowski dw->mge_desc->buffer = segs[seg].ds_addr; 16779f55f5f5SRafal Jaworowski dw->buffer = m0; 167875f1438bSOleksandr Tymoshenko dw->mge_desc->cmd_status = 0; 16799f55f5f5SRafal Jaworowski if (seg == 0) 16809f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(sc, dw); 168175f1438bSOleksandr Tymoshenko dw->mge_desc->cmd_status |= MGE_TX_LAST | MGE_TX_FIRST | 168275f1438bSOleksandr Tymoshenko MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING | 168375f1438bSOleksandr Tymoshenko MGE_DMA_OWNED; 16849f55f5f5SRafal Jaworowski } 16859f55f5f5SRafal Jaworowski 1686d6bdd318SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 16879f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 16889f55f5f5SRafal Jaworowski 16899f55f5f5SRafal Jaworowski sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM; 16909f55f5f5SRafal Jaworowski sc->tx_desc_used_count++; 16919f55f5f5SRafal Jaworowski return (0); 16929f55f5f5SRafal Jaworowski } 16939f55f5f5SRafal Jaworowski 16949f55f5f5SRafal Jaworowski static void 16959f55f5f5SRafal Jaworowski mge_tick(void *msc) 16969f55f5f5SRafal Jaworowski { 16979f55f5f5SRafal Jaworowski struct mge_softc *sc = msc; 16989f55f5f5SRafal Jaworowski 16993c71b84fSZbigniew Bodek KASSERT(sc->phy_attached == 1, ("mge_tick while PHY not attached")); 17003c71b84fSZbigniew Bodek 17013c71b84fSZbigniew Bodek MGE_GLOBAL_LOCK(sc); 17023c71b84fSZbigniew Bodek 17039f55f5f5SRafal Jaworowski /* Check for TX timeout */ 17049f55f5f5SRafal Jaworowski mge_watchdog(sc); 17059f55f5f5SRafal Jaworowski 17069f55f5f5SRafal Jaworowski mii_tick(sc->mii); 17079f55f5f5SRafal Jaworowski 17089f55f5f5SRafal Jaworowski /* Check for media type change */ 17099f55f5f5SRafal Jaworowski if(sc->mge_media_status != sc->mii->mii_media.ifm_media) 17109f55f5f5SRafal Jaworowski mge_ifmedia_upd(sc->ifp); 17119f55f5f5SRafal Jaworowski 17123c71b84fSZbigniew Bodek MGE_GLOBAL_UNLOCK(sc); 17133c71b84fSZbigniew Bodek 17149f55f5f5SRafal Jaworowski /* Schedule another timeout one second from now */ 17159f55f5f5SRafal Jaworowski callout_reset(&sc->wd_callout, hz, mge_tick, sc); 17163c71b84fSZbigniew Bodek 17173c71b84fSZbigniew Bodek return; 17189f55f5f5SRafal Jaworowski } 17199f55f5f5SRafal Jaworowski 17209f55f5f5SRafal Jaworowski static void 17219f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc) 17229f55f5f5SRafal Jaworowski { 17239f55f5f5SRafal Jaworowski struct ifnet *ifp; 17249f55f5f5SRafal Jaworowski 17259f55f5f5SRafal Jaworowski ifp = sc->ifp; 17269f55f5f5SRafal Jaworowski 17279f55f5f5SRafal Jaworowski if (sc->wd_timer == 0 || --sc->wd_timer) { 17289f55f5f5SRafal Jaworowski return; 17299f55f5f5SRafal Jaworowski } 17309f55f5f5SRafal Jaworowski 1731c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 17329f55f5f5SRafal Jaworowski if_printf(ifp, "watchdog timeout\n"); 17339f55f5f5SRafal Jaworowski 17349f55f5f5SRafal Jaworowski mge_stop(sc); 17359f55f5f5SRafal Jaworowski mge_init_locked(sc); 17369f55f5f5SRafal Jaworowski } 17379f55f5f5SRafal Jaworowski 17389f55f5f5SRafal Jaworowski static void 17399f55f5f5SRafal Jaworowski mge_start(struct ifnet *ifp) 17409f55f5f5SRafal Jaworowski { 17419f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 17429f55f5f5SRafal Jaworowski 17439f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc); 17449f55f5f5SRafal Jaworowski 17459f55f5f5SRafal Jaworowski mge_start_locked(ifp); 17469f55f5f5SRafal Jaworowski 17479f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 17489f55f5f5SRafal Jaworowski } 17499f55f5f5SRafal Jaworowski 17509f55f5f5SRafal Jaworowski static void 17519f55f5f5SRafal Jaworowski mge_start_locked(struct ifnet *ifp) 17529f55f5f5SRafal Jaworowski { 17539f55f5f5SRafal Jaworowski struct mge_softc *sc; 17549f55f5f5SRafal Jaworowski struct mbuf *m0, *mtmp; 17559f55f5f5SRafal Jaworowski uint32_t reg_val, queued = 0; 17569f55f5f5SRafal Jaworowski 17579f55f5f5SRafal Jaworowski sc = ifp->if_softc; 17589f55f5f5SRafal Jaworowski 17599f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK_ASSERT(sc); 17609f55f5f5SRafal Jaworowski 17619f55f5f5SRafal Jaworowski if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 17629f55f5f5SRafal Jaworowski IFF_DRV_RUNNING) 17639f55f5f5SRafal Jaworowski return; 17649f55f5f5SRafal Jaworowski 17659f55f5f5SRafal Jaworowski for (;;) { 17669f55f5f5SRafal Jaworowski /* Get packet from the queue */ 17679f55f5f5SRafal Jaworowski IF_DEQUEUE(&ifp->if_snd, m0); 17689f55f5f5SRafal Jaworowski if (m0 == NULL) 17699f55f5f5SRafal Jaworowski break; 17709f55f5f5SRafal Jaworowski 1771b8fad6c0SFabien Thomas if (m0->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP) || 1772b8fad6c0SFabien Thomas m0->m_flags & M_VLANTAG) { 1773b8fad6c0SFabien Thomas if (M_WRITABLE(m0) == 0) { 1774b8fad6c0SFabien Thomas mtmp = m_dup(m0, M_NOWAIT); 1775b8fad6c0SFabien Thomas m_freem(m0); 1776b8fad6c0SFabien Thomas if (mtmp == NULL) 1777b8fad6c0SFabien Thomas continue; 1778b8fad6c0SFabien Thomas m0 = mtmp; 1779b8fad6c0SFabien Thomas } 1780b8fad6c0SFabien Thomas } 1781b8fad6c0SFabien Thomas /* The driver support only one DMA fragment. */ 1782b8fad6c0SFabien Thomas if (m0->m_next != NULL) { 1783c6499eccSGleb Smirnoff mtmp = m_defrag(m0, M_NOWAIT); 17844ac30cc1SZbigniew Bodek if (mtmp != NULL) 17859f55f5f5SRafal Jaworowski m0 = mtmp; 1786b8fad6c0SFabien Thomas } 17879f55f5f5SRafal Jaworowski 1788b8fad6c0SFabien Thomas /* Check for free descriptors */ 1789b8fad6c0SFabien Thomas if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) { 17909f55f5f5SRafal Jaworowski IF_PREPEND(&ifp->if_snd, m0); 17919f55f5f5SRafal Jaworowski ifp->if_drv_flags |= IFF_DRV_OACTIVE; 17929f55f5f5SRafal Jaworowski break; 17939f55f5f5SRafal Jaworowski } 1794b8fad6c0SFabien Thomas 1795b8fad6c0SFabien Thomas if (mge_encap(sc, m0) != 0) 1796b8fad6c0SFabien Thomas break; 1797b8fad6c0SFabien Thomas 17989f55f5f5SRafal Jaworowski queued++; 17999f55f5f5SRafal Jaworowski BPF_MTAP(ifp, m0); 18009f55f5f5SRafal Jaworowski } 18019f55f5f5SRafal Jaworowski 18029f55f5f5SRafal Jaworowski if (queued) { 18039f55f5f5SRafal Jaworowski /* Enable transmitter and watchdog timer */ 18049f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD); 18059f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ); 18069f55f5f5SRafal Jaworowski sc->wd_timer = 5; 18079f55f5f5SRafal Jaworowski } 18089f55f5f5SRafal Jaworowski } 18099f55f5f5SRafal Jaworowski 18109f55f5f5SRafal Jaworowski static void 18119f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc) 18129f55f5f5SRafal Jaworowski { 18139f55f5f5SRafal Jaworowski struct ifnet *ifp; 18149f55f5f5SRafal Jaworowski volatile uint32_t reg_val, status; 18159f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 18169f55f5f5SRafal Jaworowski struct mge_desc *desc; 18179f55f5f5SRafal Jaworowski int count; 18189f55f5f5SRafal Jaworowski 18199f55f5f5SRafal Jaworowski ifp = sc->ifp; 18209f55f5f5SRafal Jaworowski 18219f55f5f5SRafal Jaworowski if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 18229f55f5f5SRafal Jaworowski return; 18239f55f5f5SRafal Jaworowski 18249f55f5f5SRafal Jaworowski /* Stop tick engine */ 18259f55f5f5SRafal Jaworowski callout_stop(&sc->wd_callout); 18269f55f5f5SRafal Jaworowski 18279f55f5f5SRafal Jaworowski /* Disable interface */ 18289f55f5f5SRafal Jaworowski ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 18299f55f5f5SRafal Jaworowski sc->wd_timer = 0; 18309f55f5f5SRafal Jaworowski 18319f55f5f5SRafal Jaworowski /* Disable interrupts */ 18329f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 18339f55f5f5SRafal Jaworowski 18349f55f5f5SRafal Jaworowski /* Disable Rx and Tx */ 18359f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD); 18369f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ); 18379f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL); 18389f55f5f5SRafal Jaworowski 18399f55f5f5SRafal Jaworowski /* Remove pending data from TX queue */ 18405817716fSRafal Jaworowski while (sc->tx_desc_used_idx != sc->tx_desc_curr && 18415817716fSRafal Jaworowski sc->tx_desc_used_count) { 18429f55f5f5SRafal Jaworowski /* Get the descriptor */ 18439f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[sc->tx_desc_used_idx]; 18449f55f5f5SRafal Jaworowski desc = dw->mge_desc; 18459f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 18469f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 18479f55f5f5SRafal Jaworowski 18489f55f5f5SRafal Jaworowski /* Get descriptor status */ 18499f55f5f5SRafal Jaworowski status = desc->cmd_status; 18509f55f5f5SRafal Jaworowski 18519f55f5f5SRafal Jaworowski if (status & MGE_DMA_OWNED) 18529f55f5f5SRafal Jaworowski break; 18539f55f5f5SRafal Jaworowski 18549f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) % 18559f55f5f5SRafal Jaworowski MGE_TX_DESC_NUM; 18565817716fSRafal Jaworowski sc->tx_desc_used_count--; 18579f55f5f5SRafal Jaworowski 18589f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap, 18599f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 18609f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap); 18619f55f5f5SRafal Jaworowski 18629f55f5f5SRafal Jaworowski m_freem(dw->buffer); 18639f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 18649f55f5f5SRafal Jaworowski } 18659f55f5f5SRafal Jaworowski 18669f55f5f5SRafal Jaworowski /* Wait for end of transmission */ 18679f55f5f5SRafal Jaworowski count = 0x100000; 18689f55f5f5SRafal Jaworowski while (count--) { 18699f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_STATUS); 18709f55f5f5SRafal Jaworowski if ( !(reg_val & MGE_STATUS_TX_IN_PROG) && 18719f55f5f5SRafal Jaworowski (reg_val & MGE_STATUS_TX_FIFO_EMPTY)) 18729f55f5f5SRafal Jaworowski break; 18739f55f5f5SRafal Jaworowski DELAY(100); 18749f55f5f5SRafal Jaworowski } 18759f55f5f5SRafal Jaworowski 18764ac30cc1SZbigniew Bodek if (count == 0) 18774ac30cc1SZbigniew Bodek if_printf(ifp, 18784ac30cc1SZbigniew Bodek "%s: timeout while waiting for end of transmission\n", 18799f55f5f5SRafal Jaworowski __FUNCTION__); 18809f55f5f5SRafal Jaworowski 18819f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL); 18829f55f5f5SRafal Jaworowski reg_val &= ~(PORT_SERIAL_ENABLE); 18839f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val); 18849f55f5f5SRafal Jaworowski } 18859f55f5f5SRafal Jaworowski 18869f55f5f5SRafal Jaworowski static int 18879f55f5f5SRafal Jaworowski mge_suspend(device_t dev) 18889f55f5f5SRafal Jaworowski { 18899f55f5f5SRafal Jaworowski 18909f55f5f5SRafal Jaworowski device_printf(dev, "%s\n", __FUNCTION__); 18919f55f5f5SRafal Jaworowski return (0); 18929f55f5f5SRafal Jaworowski } 18939f55f5f5SRafal Jaworowski 18949f55f5f5SRafal Jaworowski static void 18959f55f5f5SRafal Jaworowski mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame, 18969f55f5f5SRafal Jaworowski uint32_t status, uint16_t bufsize) 18979f55f5f5SRafal Jaworowski { 18989f55f5f5SRafal Jaworowski int csum_flags = 0; 18999f55f5f5SRafal Jaworowski 19009f55f5f5SRafal Jaworowski if (ifp->if_capenable & IFCAP_RXCSUM) { 19019f55f5f5SRafal Jaworowski if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK)) 19029f55f5f5SRafal Jaworowski csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID; 19039f55f5f5SRafal Jaworowski 19049f55f5f5SRafal Jaworowski if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 && 19059f55f5f5SRafal Jaworowski (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) && 19069f55f5f5SRafal Jaworowski (status & MGE_RX_L4_CSUM_OK)) { 19079f55f5f5SRafal Jaworowski csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 19089f55f5f5SRafal Jaworowski frame->m_pkthdr.csum_data = 0xFFFF; 19099f55f5f5SRafal Jaworowski } 19109f55f5f5SRafal Jaworowski 19119f55f5f5SRafal Jaworowski frame->m_pkthdr.csum_flags = csum_flags; 19129f55f5f5SRafal Jaworowski } 19139f55f5f5SRafal Jaworowski } 19149f55f5f5SRafal Jaworowski 19159f55f5f5SRafal Jaworowski static void 19169f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw) 19179f55f5f5SRafal Jaworowski { 19189f55f5f5SRafal Jaworowski struct mbuf *m0 = dw->buffer; 19199f55f5f5SRafal Jaworowski struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *); 19209f55f5f5SRafal Jaworowski int csum_flags = m0->m_pkthdr.csum_flags; 19219f55f5f5SRafal Jaworowski int cmd_status = 0; 19229f55f5f5SRafal Jaworowski struct ip *ip; 19239f55f5f5SRafal Jaworowski int ehlen, etype; 19249f55f5f5SRafal Jaworowski 19254ac30cc1SZbigniew Bodek if (csum_flags != 0) { 19269f55f5f5SRafal Jaworowski if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 19279f55f5f5SRafal Jaworowski etype = ntohs(eh->evl_proto); 19289f55f5f5SRafal Jaworowski ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 19299f55f5f5SRafal Jaworowski csum_flags |= MGE_TX_VLAN_TAGGED; 19309f55f5f5SRafal Jaworowski } else { 19319f55f5f5SRafal Jaworowski etype = ntohs(eh->evl_encap_proto); 19329f55f5f5SRafal Jaworowski ehlen = ETHER_HDR_LEN; 19339f55f5f5SRafal Jaworowski } 19349f55f5f5SRafal Jaworowski 19359f55f5f5SRafal Jaworowski if (etype != ETHERTYPE_IP) { 19369f55f5f5SRafal Jaworowski if_printf(sc->ifp, 19379f55f5f5SRafal Jaworowski "TCP/IP Offload enabled for unsupported " 19389f55f5f5SRafal Jaworowski "protocol!\n"); 19399f55f5f5SRafal Jaworowski return; 19409f55f5f5SRafal Jaworowski } 19419f55f5f5SRafal Jaworowski 19429f55f5f5SRafal Jaworowski ip = (struct ip *)(m0->m_data + ehlen); 19439f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl); 19449f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_NOT_FRAGMENT; 19459f55f5f5SRafal Jaworowski } 19469f55f5f5SRafal Jaworowski 19479f55f5f5SRafal Jaworowski if (csum_flags & CSUM_IP) 19489f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_IP_CSUM; 19499f55f5f5SRafal Jaworowski 19509f55f5f5SRafal Jaworowski if (csum_flags & CSUM_TCP) 19519f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_L4_CSUM; 19529f55f5f5SRafal Jaworowski 19539f55f5f5SRafal Jaworowski if (csum_flags & CSUM_UDP) 19549f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP; 19559f55f5f5SRafal Jaworowski 19569f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status |= cmd_status; 19579f55f5f5SRafal Jaworowski } 19589f55f5f5SRafal Jaworowski 19599f55f5f5SRafal Jaworowski static void 19609f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable) 19619f55f5f5SRafal Jaworowski { 19629f55f5f5SRafal Jaworowski 19639f55f5f5SRafal Jaworowski if (enable) { 19649f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 | 19659f55f5f5SRafal Jaworowski MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0); 19669f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 | 19679f55f5f5SRafal Jaworowski MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR | 19689f55f5f5SRafal Jaworowski MGE_PORT_INT_EXT_TXBUF0); 19699f55f5f5SRafal Jaworowski } else { 19709f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_INT_CAUSE, 0x0); 19719f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_INT_MASK, 0x0); 19729f55f5f5SRafal Jaworowski 19739f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0); 19749f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0); 19759f55f5f5SRafal Jaworowski 19769f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0); 19779f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0); 19789f55f5f5SRafal Jaworowski } 19799f55f5f5SRafal Jaworowski } 19809f55f5f5SRafal Jaworowski 19819f55f5f5SRafal Jaworowski static uint8_t 19829f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size) 19839f55f5f5SRafal Jaworowski { 19849f55f5f5SRafal Jaworowski uint8_t crc = 0; 19859f55f5f5SRafal Jaworowski static const uint8_t ct[256] = { 19869f55f5f5SRafal Jaworowski 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 19879f55f5f5SRafal Jaworowski 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 19889f55f5f5SRafal Jaworowski 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 19899f55f5f5SRafal Jaworowski 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 19909f55f5f5SRafal Jaworowski 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 19919f55f5f5SRafal Jaworowski 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, 19929f55f5f5SRafal Jaworowski 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 19939f55f5f5SRafal Jaworowski 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, 19949f55f5f5SRafal Jaworowski 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 19959f55f5f5SRafal Jaworowski 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 19969f55f5f5SRafal Jaworowski 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 19979f55f5f5SRafal Jaworowski 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, 19989f55f5f5SRafal Jaworowski 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 19999f55f5f5SRafal Jaworowski 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, 20009f55f5f5SRafal Jaworowski 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 20019f55f5f5SRafal Jaworowski 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 20029f55f5f5SRafal Jaworowski 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 20039f55f5f5SRafal Jaworowski 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 20049f55f5f5SRafal Jaworowski 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 20059f55f5f5SRafal Jaworowski 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, 20069f55f5f5SRafal Jaworowski 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 20079f55f5f5SRafal Jaworowski 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 20089f55f5f5SRafal Jaworowski 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 20099f55f5f5SRafal Jaworowski 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, 20109f55f5f5SRafal Jaworowski 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 20119f55f5f5SRafal Jaworowski 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, 20129f55f5f5SRafal Jaworowski 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 20139f55f5f5SRafal Jaworowski 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 20149f55f5f5SRafal Jaworowski 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 20159f55f5f5SRafal Jaworowski 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, 20169f55f5f5SRafal Jaworowski 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 20179f55f5f5SRafal Jaworowski 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 20189f55f5f5SRafal Jaworowski }; 20199f55f5f5SRafal Jaworowski 20209f55f5f5SRafal Jaworowski while(size--) 20219f55f5f5SRafal Jaworowski crc = ct[crc ^ *(data++)]; 20229f55f5f5SRafal Jaworowski 20239f55f5f5SRafal Jaworowski return(crc); 20249f55f5f5SRafal Jaworowski } 20259f55f5f5SRafal Jaworowski 202653dc8c23SGleb Smirnoff struct mge_hash_maddr_ctx { 202753dc8c23SGleb Smirnoff uint32_t smt[MGE_MCAST_REG_NUMBER]; 202853dc8c23SGleb Smirnoff uint32_t omt[MGE_MCAST_REG_NUMBER]; 202953dc8c23SGleb Smirnoff }; 203053dc8c23SGleb Smirnoff 203153dc8c23SGleb Smirnoff static u_int 203253dc8c23SGleb Smirnoff mge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 203353dc8c23SGleb Smirnoff { 203453dc8c23SGleb Smirnoff static const uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 }; 203553dc8c23SGleb Smirnoff struct mge_hash_maddr_ctx *ctx = arg; 203653dc8c23SGleb Smirnoff static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1; 203753dc8c23SGleb Smirnoff uint8_t *mac; 203853dc8c23SGleb Smirnoff int i; 203953dc8c23SGleb Smirnoff 204053dc8c23SGleb Smirnoff mac = LLADDR(sdl); 204153dc8c23SGleb Smirnoff if (memcmp(mac, special, sizeof(special)) == 0) { 204253dc8c23SGleb Smirnoff i = mac[5]; 204353dc8c23SGleb Smirnoff ctx->smt[i >> 2] |= v << ((i & 0x03) << 3); 204453dc8c23SGleb Smirnoff } else { 204553dc8c23SGleb Smirnoff i = mge_crc8(mac, ETHER_ADDR_LEN); 204653dc8c23SGleb Smirnoff ctx->omt[i >> 2] |= v << ((i & 0x03) << 3); 204753dc8c23SGleb Smirnoff } 204853dc8c23SGleb Smirnoff return (1); 204953dc8c23SGleb Smirnoff } 205053dc8c23SGleb Smirnoff 20519f55f5f5SRafal Jaworowski static void 20529f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc) 20539f55f5f5SRafal Jaworowski { 205453dc8c23SGleb Smirnoff struct mge_hash_maddr_ctx ctx; 20559f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 205653dc8c23SGleb Smirnoff static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1; 20579f55f5f5SRafal Jaworowski int i; 20589f55f5f5SRafal Jaworowski 20599f55f5f5SRafal Jaworowski if (ifp->if_flags & IFF_ALLMULTI) { 20609f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) 206153dc8c23SGleb Smirnoff ctx.smt[i] = ctx.omt[i] = 206253dc8c23SGleb Smirnoff (v << 24) | (v << 16) | (v << 8) | v; 20639f55f5f5SRafal Jaworowski } else { 206453dc8c23SGleb Smirnoff memset(&ctx, 0, sizeof(ctx)); 206553dc8c23SGleb Smirnoff if_foreach_llmaddr(ifp, mge_hash_maddr, &ctx); 20669f55f5f5SRafal Jaworowski } 20679f55f5f5SRafal Jaworowski 20689f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 206953dc8c23SGleb Smirnoff MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), ctx.smt[i]); 207053dc8c23SGleb Smirnoff MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), ctx.omt[i]); 20719f55f5f5SRafal Jaworowski } 20729f55f5f5SRafal Jaworowski } 20739f55f5f5SRafal Jaworowski 20749f55f5f5SRafal Jaworowski static void 20759f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc) 20769f55f5f5SRafal Jaworowski { 20779f55f5f5SRafal Jaworowski uint32_t reg; 20789f55f5f5SRafal Jaworowski 20798e1dc58eSRafal Jaworowski if (sc->rx_ic_time > sc->mge_rx_ipg_max) 20808e1dc58eSRafal Jaworowski sc->rx_ic_time = sc->mge_rx_ipg_max; 20819f55f5f5SRafal Jaworowski 20829f55f5f5SRafal Jaworowski reg = MGE_READ(sc, MGE_SDMA_CONFIG); 20838e1dc58eSRafal Jaworowski reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver); 20848e1dc58eSRafal Jaworowski reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver); 20859f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_SDMA_CONFIG, reg); 20869f55f5f5SRafal Jaworowski } 20879f55f5f5SRafal Jaworowski 20889f55f5f5SRafal Jaworowski static void 20899f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc) 20909f55f5f5SRafal Jaworowski { 20919f55f5f5SRafal Jaworowski uint32_t reg; 20929f55f5f5SRafal Jaworowski 20938e1dc58eSRafal Jaworowski if (sc->tx_ic_time > sc->mge_tfut_ipg_max) 20948e1dc58eSRafal Jaworowski sc->tx_ic_time = sc->mge_tfut_ipg_max; 20959f55f5f5SRafal Jaworowski 20969f55f5f5SRafal Jaworowski reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH); 20978e1dc58eSRafal Jaworowski reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver); 20988e1dc58eSRafal Jaworowski reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver); 20999f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg); 21009f55f5f5SRafal Jaworowski } 21019f55f5f5SRafal Jaworowski 21029f55f5f5SRafal Jaworowski static int 21039f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS) 21049f55f5f5SRafal Jaworowski { 21059f55f5f5SRafal Jaworowski struct mge_softc *sc = (struct mge_softc *)arg1; 21068e1dc58eSRafal Jaworowski uint32_t time; 21079f55f5f5SRafal Jaworowski int error; 21089f55f5f5SRafal Jaworowski 21098e1dc58eSRafal Jaworowski time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time; 21109f55f5f5SRafal Jaworowski error = sysctl_handle_int(oidp, &time, 0, req); 21119f55f5f5SRafal Jaworowski if (error != 0) 21129f55f5f5SRafal Jaworowski return(error); 21139f55f5f5SRafal Jaworowski 21149f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 21159f55f5f5SRafal Jaworowski if (arg2 == MGE_IC_RX) { 21169f55f5f5SRafal Jaworowski sc->rx_ic_time = time; 21179f55f5f5SRafal Jaworowski mge_set_rxic(sc); 21189f55f5f5SRafal Jaworowski } else { 21199f55f5f5SRafal Jaworowski sc->tx_ic_time = time; 21209f55f5f5SRafal Jaworowski mge_set_txic(sc); 21219f55f5f5SRafal Jaworowski } 21229f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 21239f55f5f5SRafal Jaworowski 21249f55f5f5SRafal Jaworowski return(0); 21259f55f5f5SRafal Jaworowski } 21269f55f5f5SRafal Jaworowski 21279f55f5f5SRafal Jaworowski static void 21289f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc) 21299f55f5f5SRafal Jaworowski { 21309f55f5f5SRafal Jaworowski struct sysctl_ctx_list *ctx; 21319f55f5f5SRafal Jaworowski struct sysctl_oid_list *children; 21329f55f5f5SRafal Jaworowski struct sysctl_oid *tree; 21339f55f5f5SRafal Jaworowski 21349f55f5f5SRafal Jaworowski ctx = device_get_sysctl_ctx(sc->dev); 21359f55f5f5SRafal Jaworowski children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 21369f55f5f5SRafal Jaworowski tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal", 21377029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "MGE Interrupts coalescing"); 21389f55f5f5SRafal Jaworowski children = SYSCTL_CHILDREN(tree); 21399f55f5f5SRafal Jaworowski 21409f55f5f5SRafal Jaworowski SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time", 21416b2ff27cSAlexander Motin CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, MGE_IC_RX, 21427029da5cSPawel Biernacki mge_sysctl_ic, "I", "IC RX time threshold"); 21439f55f5f5SRafal Jaworowski SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time", 21446b2ff27cSAlexander Motin CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, MGE_IC_TX, 21457029da5cSPawel Biernacki mge_sysctl_ic, "I", "IC TX time threshold"); 21469f55f5f5SRafal Jaworowski } 21473c71b84fSZbigniew Bodek 21483c71b84fSZbigniew Bodek static int 21493c71b84fSZbigniew Bodek mge_mdio_writereg(device_t dev, int phy, int reg, int value) 21503c71b84fSZbigniew Bodek { 21513c71b84fSZbigniew Bodek 21523c71b84fSZbigniew Bodek mv_write_ge_smi(dev, phy, reg, value); 21533c71b84fSZbigniew Bodek 21543c71b84fSZbigniew Bodek return (0); 21553c71b84fSZbigniew Bodek } 21563c71b84fSZbigniew Bodek 21573c71b84fSZbigniew Bodek 21583c71b84fSZbigniew Bodek static int 21593c71b84fSZbigniew Bodek mge_mdio_readreg(device_t dev, int phy, int reg) 21603c71b84fSZbigniew Bodek { 21613c71b84fSZbigniew Bodek int ret; 21623c71b84fSZbigniew Bodek 21633c71b84fSZbigniew Bodek ret = mv_read_ge_smi(dev, phy, reg); 21643c71b84fSZbigniew Bodek 21653c71b84fSZbigniew Bodek return (ret); 21663c71b84fSZbigniew Bodek } 2167