19f55f5f5SRafal Jaworowski /*- 29f55f5f5SRafal Jaworowski * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. 39f55f5f5SRafal Jaworowski * All rights reserved. 49f55f5f5SRafal Jaworowski * 59f55f5f5SRafal Jaworowski * Developed by Semihalf. 69f55f5f5SRafal Jaworowski * 79f55f5f5SRafal Jaworowski * Redistribution and use in source and binary forms, with or without 89f55f5f5SRafal Jaworowski * modification, are permitted provided that the following conditions 99f55f5f5SRafal Jaworowski * are met: 109f55f5f5SRafal Jaworowski * 1. Redistributions of source code must retain the above copyright 119f55f5f5SRafal Jaworowski * notice, this list of conditions and the following disclaimer. 129f55f5f5SRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright 139f55f5f5SRafal Jaworowski * notice, this list of conditions and the following disclaimer in the 149f55f5f5SRafal Jaworowski * documentation and/or other materials provided with the distribution. 159f55f5f5SRafal Jaworowski * 3. Neither the name of MARVELL nor the names of contributors 169f55f5f5SRafal Jaworowski * may be used to endorse or promote products derived from this software 179f55f5f5SRafal Jaworowski * without specific prior written permission. 189f55f5f5SRafal Jaworowski * 199f55f5f5SRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 209f55f5f5SRafal Jaworowski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 219f55f5f5SRafal Jaworowski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 229f55f5f5SRafal Jaworowski * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 239f55f5f5SRafal Jaworowski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 249f55f5f5SRafal Jaworowski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 259f55f5f5SRafal Jaworowski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 269f55f5f5SRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 279f55f5f5SRafal Jaworowski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 289f55f5f5SRafal Jaworowski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 299f55f5f5SRafal Jaworowski * SUCH DAMAGE. 309f55f5f5SRafal Jaworowski */ 319f55f5f5SRafal Jaworowski 329f55f5f5SRafal Jaworowski #ifdef HAVE_KERNEL_OPTION_HEADERS 339f55f5f5SRafal Jaworowski #include "opt_device_polling.h" 349f55f5f5SRafal Jaworowski #endif 359f55f5f5SRafal Jaworowski 369f55f5f5SRafal Jaworowski #include <sys/cdefs.h> 379f55f5f5SRafal Jaworowski __FBSDID("$FreeBSD$"); 389f55f5f5SRafal Jaworowski 399f55f5f5SRafal Jaworowski #include <sys/param.h> 409f55f5f5SRafal Jaworowski #include <sys/systm.h> 419f55f5f5SRafal Jaworowski #include <sys/endian.h> 429f55f5f5SRafal Jaworowski #include <sys/mbuf.h> 439f55f5f5SRafal Jaworowski #include <sys/lock.h> 449f55f5f5SRafal Jaworowski #include <sys/mutex.h> 459f55f5f5SRafal Jaworowski #include <sys/kernel.h> 469f55f5f5SRafal Jaworowski #include <sys/module.h> 479f55f5f5SRafal Jaworowski #include <sys/socket.h> 489f55f5f5SRafal Jaworowski #include <sys/sysctl.h> 499f55f5f5SRafal Jaworowski 509f55f5f5SRafal Jaworowski #include <net/ethernet.h> 519f55f5f5SRafal Jaworowski #include <net/bpf.h> 529f55f5f5SRafal Jaworowski #include <net/if.h> 539f55f5f5SRafal Jaworowski #include <net/if_arp.h> 549f55f5f5SRafal Jaworowski #include <net/if_dl.h> 559f55f5f5SRafal Jaworowski #include <net/if_media.h> 569f55f5f5SRafal Jaworowski #include <net/if_types.h> 579f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h> 589f55f5f5SRafal Jaworowski 599f55f5f5SRafal Jaworowski #include <netinet/in_systm.h> 609f55f5f5SRafal Jaworowski #include <netinet/in.h> 619f55f5f5SRafal Jaworowski #include <netinet/ip.h> 629f55f5f5SRafal Jaworowski 639f55f5f5SRafal Jaworowski #include <sys/sockio.h> 649f55f5f5SRafal Jaworowski #include <sys/bus.h> 659f55f5f5SRafal Jaworowski #include <machine/bus.h> 669f55f5f5SRafal Jaworowski #include <sys/rman.h> 679f55f5f5SRafal Jaworowski #include <machine/resource.h> 689f55f5f5SRafal Jaworowski 699f55f5f5SRafal Jaworowski #include <dev/mii/mii.h> 709f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h> 719f55f5f5SRafal Jaworowski 7218159f6aSRafal Jaworowski #ifndef MII_ADDR_BASE 7318159f6aSRafal Jaworowski #define MII_ADDR_BASE 8 7418159f6aSRafal Jaworowski #endif 759f55f5f5SRafal Jaworowski 769f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h> 779f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h> 788e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h> 799f55f5f5SRafal Jaworowski 809f55f5f5SRafal Jaworowski #include "miibus_if.h" 819f55f5f5SRafal Jaworowski 829f55f5f5SRafal Jaworowski /* PHY registers are in the address space of the first mge unit */ 839f55f5f5SRafal Jaworowski static struct mge_softc *sc_mge0 = NULL; 849f55f5f5SRafal Jaworowski 859f55f5f5SRafal Jaworowski static int mge_probe(device_t dev); 869f55f5f5SRafal Jaworowski static int mge_attach(device_t dev); 879f55f5f5SRafal Jaworowski static int mge_detach(device_t dev); 889f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev); 899f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev); 909f55f5f5SRafal Jaworowski static int mge_resume(device_t dev); 919f55f5f5SRafal Jaworowski 929f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg); 938e45f0b7SAndriy Gapon static int mge_miibus_writereg(device_t dev, int phy, int reg, int value); 949f55f5f5SRafal Jaworowski 959f55f5f5SRafal Jaworowski static int mge_ifmedia_upd(struct ifnet *ifp); 969f55f5f5SRafal Jaworowski static void mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 979f55f5f5SRafal Jaworowski 989f55f5f5SRafal Jaworowski static void mge_init(void *arg); 999f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg); 1009f55f5f5SRafal Jaworowski static void mge_start(struct ifnet *ifp); 1019f55f5f5SRafal Jaworowski static void mge_start_locked(struct ifnet *ifp); 1029f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc); 1039f55f5f5SRafal Jaworowski static int mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 1049f55f5f5SRafal Jaworowski 1058e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver); 1068e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver); 1078e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc); 1088e1dc58eSRafal Jaworowski 1099f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable); 1109f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg); 1111abcdbd1SAttilio Rao static int mge_intr_rx_locked(struct mge_softc *sc, int count); 1129f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg); 1139f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc); 1149f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg); 1159f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg); 1169f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg); 1179f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc); 1189f55f5f5SRafal Jaworowski static void mge_tick(void *msc); 1199f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media); 1209f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr); 1219f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc); 1229f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, 1239f55f5f5SRafal Jaworowski uint8_t queue); 1249f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue); 1259f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc); 1269f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc, 1279f55f5f5SRafal Jaworowski struct mge_desc_wrapper* desc_tab, uint32_t size, bus_dma_tag_t *buffer_tag); 1289f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, 1299f55f5f5SRafal Jaworowski struct mbuf **mbufp, bus_addr_t *paddr); 1309f55f5f5SRafal Jaworowski static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error); 1319f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc); 1329f55f5f5SRafal Jaworowski static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab, uint32_t size, 1339f55f5f5SRafal Jaworowski bus_dma_tag_t buffer_tag, uint8_t free_mbufs); 1349f55f5f5SRafal Jaworowski static void mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame, 1359f55f5f5SRafal Jaworowski uint32_t status, uint16_t bufsize); 1369f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc, 1379f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw); 1389f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size); 1399f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc); 1409f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc); 1419f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc); 1429f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc); 1439f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS); 1449f55f5f5SRafal Jaworowski 1459f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = { 1469f55f5f5SRafal Jaworowski /* Device interface */ 1479f55f5f5SRafal Jaworowski DEVMETHOD(device_probe, mge_probe), 1489f55f5f5SRafal Jaworowski DEVMETHOD(device_attach, mge_attach), 1499f55f5f5SRafal Jaworowski DEVMETHOD(device_detach, mge_detach), 1509f55f5f5SRafal Jaworowski DEVMETHOD(device_shutdown, mge_shutdown), 1519f55f5f5SRafal Jaworowski DEVMETHOD(device_suspend, mge_suspend), 1529f55f5f5SRafal Jaworowski DEVMETHOD(device_resume, mge_resume), 1539f55f5f5SRafal Jaworowski /* MII interface */ 1549f55f5f5SRafal Jaworowski DEVMETHOD(miibus_readreg, mge_miibus_readreg), 1559f55f5f5SRafal Jaworowski DEVMETHOD(miibus_writereg, mge_miibus_writereg), 1569f55f5f5SRafal Jaworowski { 0, 0 } 1579f55f5f5SRafal Jaworowski }; 1589f55f5f5SRafal Jaworowski 1599f55f5f5SRafal Jaworowski static driver_t mge_driver = { 1609f55f5f5SRafal Jaworowski "mge", 1619f55f5f5SRafal Jaworowski mge_methods, 1629f55f5f5SRafal Jaworowski sizeof(struct mge_softc), 1639f55f5f5SRafal Jaworowski }; 1649f55f5f5SRafal Jaworowski 1659f55f5f5SRafal Jaworowski static devclass_t mge_devclass; 1669f55f5f5SRafal Jaworowski 1679f55f5f5SRafal Jaworowski DRIVER_MODULE(mge, mbus, mge_driver, mge_devclass, 0, 0); 1689f55f5f5SRafal Jaworowski DRIVER_MODULE(miibus, mge, miibus_driver, miibus_devclass, 0, 0); 1699f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1); 1709f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1); 1719f55f5f5SRafal Jaworowski 1729f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = { 1739f55f5f5SRafal Jaworowski { SYS_RES_MEMORY, 0, RF_ACTIVE }, 1749f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 1759f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE }, 1769f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE }, 1779f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 3, RF_ACTIVE | RF_SHAREABLE }, 1789f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 4, RF_ACTIVE | RF_SHAREABLE }, 1799f55f5f5SRafal Jaworowski { -1, 0 } 1809f55f5f5SRafal Jaworowski }; 1819f55f5f5SRafal Jaworowski 1829f55f5f5SRafal Jaworowski static struct { 1839f55f5f5SRafal Jaworowski driver_intr_t *handler; 1849f55f5f5SRafal Jaworowski char * description; 1859f55f5f5SRafal Jaworowski } mge_intrs[MGE_INTR_COUNT] = { 1869f55f5f5SRafal Jaworowski { mge_intr_rx, "GbE receive interrupt" }, 1879f55f5f5SRafal Jaworowski { mge_intr_tx, "GbE transmit interrupt" }, 1889f55f5f5SRafal Jaworowski { mge_intr_misc,"GbE misc interrupt" }, 1899f55f5f5SRafal Jaworowski { mge_intr_sum, "GbE summary interrupt" }, 1909f55f5f5SRafal Jaworowski { mge_intr_err, "GbE error interrupt" }, 1919f55f5f5SRafal Jaworowski }; 1929f55f5f5SRafal Jaworowski 1939f55f5f5SRafal Jaworowski static void 1949f55f5f5SRafal Jaworowski mge_get_mac_address(struct mge_softc *sc, uint8_t *addr) 1959f55f5f5SRafal Jaworowski { 1969f55f5f5SRafal Jaworowski uint32_t mac_l, mac_h; 1979f55f5f5SRafal Jaworowski 1989f55f5f5SRafal Jaworowski /* XXX use currently programmed MAC address; eventually this info will 1999f55f5f5SRafal Jaworowski * be provided by the loader */ 2009f55f5f5SRafal Jaworowski 2019f55f5f5SRafal Jaworowski mac_l = MGE_READ(sc, MGE_MAC_ADDR_L); 2029f55f5f5SRafal Jaworowski mac_h = MGE_READ(sc, MGE_MAC_ADDR_H); 2039f55f5f5SRafal Jaworowski 2049f55f5f5SRafal Jaworowski addr[0] = (mac_h & 0xff000000) >> 24; 2059f55f5f5SRafal Jaworowski addr[1] = (mac_h & 0x00ff0000) >> 16; 2069f55f5f5SRafal Jaworowski addr[2] = (mac_h & 0x0000ff00) >> 8; 2079f55f5f5SRafal Jaworowski addr[3] = (mac_h & 0x000000ff); 2089f55f5f5SRafal Jaworowski addr[4] = (mac_l & 0x0000ff00) >> 8; 2099f55f5f5SRafal Jaworowski addr[5] = (mac_l & 0x000000ff); 2109f55f5f5SRafal Jaworowski } 2119f55f5f5SRafal Jaworowski 2128e1dc58eSRafal Jaworowski static uint32_t 2138e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver) 2148e1dc58eSRafal Jaworowski { 2158e1dc58eSRafal Jaworowski 2168e1dc58eSRafal Jaworowski switch (ver) { 2178e1dc58eSRafal Jaworowski case 1: 2188e1dc58eSRafal Jaworowski return ((val & 0x3fff) << 4); 2198e1dc58eSRafal Jaworowski case 2: 2208e1dc58eSRafal Jaworowski default: 2218e1dc58eSRafal Jaworowski return ((val & 0xffff) << 4); 2228e1dc58eSRafal Jaworowski } 2238e1dc58eSRafal Jaworowski } 2248e1dc58eSRafal Jaworowski 2258e1dc58eSRafal Jaworowski static uint32_t 2268e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver) 2278e1dc58eSRafal Jaworowski { 2288e1dc58eSRafal Jaworowski 2298e1dc58eSRafal Jaworowski switch (ver) { 2308e1dc58eSRafal Jaworowski case 1: 2318e1dc58eSRafal Jaworowski return ((val & 0x3fff) << 8); 2328e1dc58eSRafal Jaworowski case 2: 2338e1dc58eSRafal Jaworowski default: 2348e1dc58eSRafal Jaworowski return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7)); 2358e1dc58eSRafal Jaworowski } 2368e1dc58eSRafal Jaworowski } 2378e1dc58eSRafal Jaworowski 2388e1dc58eSRafal Jaworowski static void 2398e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc) 2408e1dc58eSRafal Jaworowski { 2418e1dc58eSRafal Jaworowski uint32_t d, r; 2428e1dc58eSRafal Jaworowski 2438e1dc58eSRafal Jaworowski soc_id(&d, &r); 244bc26e2e3SRafal Jaworowski if (d == MV_DEV_88F6281 || d == MV_DEV_MV78100 || 245bc26e2e3SRafal Jaworowski d == MV_DEV_MV78100_Z0) { 2468e1dc58eSRafal Jaworowski sc->mge_ver = 2; 2478e1dc58eSRafal Jaworowski sc->mge_mtu = 0x4e8; 2488e1dc58eSRafal Jaworowski sc->mge_tfut_ipg_max = 0xFFFF; 2498e1dc58eSRafal Jaworowski sc->mge_rx_ipg_max = 0xFFFF; 2508e1dc58eSRafal Jaworowski sc->mge_tx_arb_cfg = 0xFC0000FF; 2518e1dc58eSRafal Jaworowski sc->mge_tx_tok_cfg = 0xFFFF7FFF; 2528e1dc58eSRafal Jaworowski sc->mge_tx_tok_cnt = 0x3FFFFFFF; 2538e1dc58eSRafal Jaworowski } else { 2548e1dc58eSRafal Jaworowski sc->mge_ver = 1; 2558e1dc58eSRafal Jaworowski sc->mge_mtu = 0x458; 2568e1dc58eSRafal Jaworowski sc->mge_tfut_ipg_max = 0x3FFF; 2578e1dc58eSRafal Jaworowski sc->mge_rx_ipg_max = 0x3FFF; 2588e1dc58eSRafal Jaworowski sc->mge_tx_arb_cfg = 0x000000FF; 2598e1dc58eSRafal Jaworowski sc->mge_tx_tok_cfg = 0x3FFFFFFF; 2608e1dc58eSRafal Jaworowski sc->mge_tx_tok_cnt = 0x3FFFFFFF; 2618e1dc58eSRafal Jaworowski } 2628e1dc58eSRafal Jaworowski } 2638e1dc58eSRafal Jaworowski 2649f55f5f5SRafal Jaworowski static void 2659f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc) 2669f55f5f5SRafal Jaworowski { 2679f55f5f5SRafal Jaworowski char *if_mac; 2689f55f5f5SRafal Jaworowski uint32_t mac_l, mac_h; 2699f55f5f5SRafal Jaworowski 2709f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK_ASSERT(sc); 2719f55f5f5SRafal Jaworowski 2729f55f5f5SRafal Jaworowski if_mac = (char *)IF_LLADDR(sc->ifp); 2739f55f5f5SRafal Jaworowski 2749f55f5f5SRafal Jaworowski mac_l = (if_mac[4] << 8) | (if_mac[5]); 2759f55f5f5SRafal Jaworowski mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) | 2769f55f5f5SRafal Jaworowski (if_mac[2] << 8) | (if_mac[3] << 0); 2779f55f5f5SRafal Jaworowski 2789f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l); 2799f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h); 2809f55f5f5SRafal Jaworowski 2819f55f5f5SRafal Jaworowski mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE); 2829f55f5f5SRafal Jaworowski } 2839f55f5f5SRafal Jaworowski 2849f55f5f5SRafal Jaworowski static void 2859f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue) 2869f55f5f5SRafal Jaworowski { 2879f55f5f5SRafal Jaworowski uint32_t reg_idx, reg_off, reg_val, i; 2889f55f5f5SRafal Jaworowski 2899f55f5f5SRafal Jaworowski last_byte &= 0xf; 2909f55f5f5SRafal Jaworowski reg_idx = last_byte / MGE_UCAST_REG_NUMBER; 2919f55f5f5SRafal Jaworowski reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8; 2929f55f5f5SRafal Jaworowski reg_val = (1 | (queue << 1)) << reg_off; 2939f55f5f5SRafal Jaworowski 2949f55f5f5SRafal Jaworowski for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) { 2959f55f5f5SRafal Jaworowski if ( i == reg_idx) 2969f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val); 2979f55f5f5SRafal Jaworowski else 2989f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0); 2999f55f5f5SRafal Jaworowski } 3009f55f5f5SRafal Jaworowski } 3019f55f5f5SRafal Jaworowski 3029f55f5f5SRafal Jaworowski static void 3039f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue) 3049f55f5f5SRafal Jaworowski { 3059f55f5f5SRafal Jaworowski uint32_t port_config; 3069f55f5f5SRafal Jaworowski uint32_t reg_val, i; 3079f55f5f5SRafal Jaworowski 3089f55f5f5SRafal Jaworowski /* Enable or disable promiscuous mode as needed */ 3099f55f5f5SRafal Jaworowski if (sc->ifp->if_flags & IFF_PROMISC) { 3109f55f5f5SRafal Jaworowski port_config = MGE_READ(sc, MGE_PORT_CONFIG); 3119f55f5f5SRafal Jaworowski port_config |= PORT_CONFIG_UPM; 3129f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, port_config); 3139f55f5f5SRafal Jaworowski 3149f55f5f5SRafal Jaworowski reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 | 3159f55f5f5SRafal Jaworowski (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24); 3169f55f5f5SRafal Jaworowski 3179f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 3189f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val); 3199f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val); 3209f55f5f5SRafal Jaworowski } 3219f55f5f5SRafal Jaworowski 3229f55f5f5SRafal Jaworowski for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) 3239f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val); 3249f55f5f5SRafal Jaworowski 3259f55f5f5SRafal Jaworowski } else { 3269f55f5f5SRafal Jaworowski port_config = MGE_READ(sc, MGE_PORT_CONFIG); 3279f55f5f5SRafal Jaworowski port_config &= ~PORT_CONFIG_UPM; 3289f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, port_config); 3299f55f5f5SRafal Jaworowski 3309f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 3319f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0); 3329f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0); 3339f55f5f5SRafal Jaworowski } 3349f55f5f5SRafal Jaworowski 3359f55f5f5SRafal Jaworowski mge_set_mac_address(sc); 3369f55f5f5SRafal Jaworowski } 3379f55f5f5SRafal Jaworowski } 3389f55f5f5SRafal Jaworowski 3399f55f5f5SRafal Jaworowski static void 3409f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3419f55f5f5SRafal Jaworowski { 3429f55f5f5SRafal Jaworowski u_int32_t *paddr; 3439f55f5f5SRafal Jaworowski 3449f55f5f5SRafal Jaworowski KASSERT(nseg == 1, ("wrong number of segments, should be 1")); 3459f55f5f5SRafal Jaworowski paddr = arg; 3469f55f5f5SRafal Jaworowski 3479f55f5f5SRafal Jaworowski *paddr = segs->ds_addr; 3489f55f5f5SRafal Jaworowski } 3499f55f5f5SRafal Jaworowski 3509f55f5f5SRafal Jaworowski static int 3519f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp, 3529f55f5f5SRafal Jaworowski bus_addr_t *paddr) 3539f55f5f5SRafal Jaworowski { 3549f55f5f5SRafal Jaworowski struct mbuf *new_mbuf; 3559f55f5f5SRafal Jaworowski bus_dma_segment_t seg[1]; 3569f55f5f5SRafal Jaworowski int error; 3579f55f5f5SRafal Jaworowski int nsegs; 3589f55f5f5SRafal Jaworowski 3599f55f5f5SRafal Jaworowski KASSERT(mbufp != NULL, ("NULL mbuf pointer!")); 3609f55f5f5SRafal Jaworowski 3619f55f5f5SRafal Jaworowski new_mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 3629f55f5f5SRafal Jaworowski if (new_mbuf == NULL) 3639f55f5f5SRafal Jaworowski return (ENOBUFS); 3649f55f5f5SRafal Jaworowski new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size; 3659f55f5f5SRafal Jaworowski 3669f55f5f5SRafal Jaworowski if (*mbufp) { 3679f55f5f5SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD); 3689f55f5f5SRafal Jaworowski bus_dmamap_unload(tag, map); 3699f55f5f5SRafal Jaworowski } 3709f55f5f5SRafal Jaworowski 3719f55f5f5SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs, 3729f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT); 3739f55f5f5SRafal Jaworowski KASSERT(nsegs == 1, ("Too many segments returned!")); 3749f55f5f5SRafal Jaworowski if (nsegs != 1 || error) 3759f55f5f5SRafal Jaworowski panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error); 3769f55f5f5SRafal Jaworowski 3779f55f5f5SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD); 3789f55f5f5SRafal Jaworowski 3799f55f5f5SRafal Jaworowski (*mbufp) = new_mbuf; 3809f55f5f5SRafal Jaworowski (*paddr) = seg->ds_addr; 3819f55f5f5SRafal Jaworowski return (0); 3829f55f5f5SRafal Jaworowski } 3839f55f5f5SRafal Jaworowski 3849f55f5f5SRafal Jaworowski static int 3859f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab, 3869f55f5f5SRafal Jaworowski uint32_t size, bus_dma_tag_t *buffer_tag) 3879f55f5f5SRafal Jaworowski { 3889f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 3899f55f5f5SRafal Jaworowski bus_addr_t desc_paddr; 3909f55f5f5SRafal Jaworowski int i, error; 3919f55f5f5SRafal Jaworowski 3929f55f5f5SRafal Jaworowski desc_paddr = 0; 3939f55f5f5SRafal Jaworowski for (i = size - 1; i >= 0; i--) { 3949f55f5f5SRafal Jaworowski dw = &(tab[i]); 3959f55f5f5SRafal Jaworowski error = bus_dmamem_alloc(sc->mge_desc_dtag, 3969f55f5f5SRafal Jaworowski (void**)&(dw->mge_desc), 3979f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 3989f55f5f5SRafal Jaworowski &(dw->desc_dmap)); 3999f55f5f5SRafal Jaworowski 4009f55f5f5SRafal Jaworowski if (error) { 4019f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to allocate DMA memory\n"); 4029f55f5f5SRafal Jaworowski dw->mge_desc = NULL; 4039f55f5f5SRafal Jaworowski return (ENXIO); 4049f55f5f5SRafal Jaworowski } 4059f55f5f5SRafal Jaworowski 4069f55f5f5SRafal Jaworowski error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap, 4079f55f5f5SRafal Jaworowski dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr, 4089f55f5f5SRafal Jaworowski &(dw->mge_desc_paddr), BUS_DMA_NOWAIT); 4099f55f5f5SRafal Jaworowski 4109f55f5f5SRafal Jaworowski if (error) { 4119f55f5f5SRafal Jaworowski if_printf(sc->ifp, "can't load descriptor\n"); 4129f55f5f5SRafal Jaworowski bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc, 4139f55f5f5SRafal Jaworowski dw->desc_dmap); 4149f55f5f5SRafal Jaworowski dw->mge_desc = NULL; 4159f55f5f5SRafal Jaworowski return (ENXIO); 4169f55f5f5SRafal Jaworowski } 4179f55f5f5SRafal Jaworowski 4189f55f5f5SRafal Jaworowski /* Chain descriptors */ 4199f55f5f5SRafal Jaworowski dw->mge_desc->next_desc = desc_paddr; 4209f55f5f5SRafal Jaworowski desc_paddr = dw->mge_desc_paddr; 4219f55f5f5SRafal Jaworowski } 4229f55f5f5SRafal Jaworowski tab[size - 1].mge_desc->next_desc = desc_paddr; 4239f55f5f5SRafal Jaworowski 4249f55f5f5SRafal Jaworowski /* Allocate a busdma tag for mbufs. */ 4259f55f5f5SRafal Jaworowski error = bus_dma_tag_create(NULL, /* parent */ 4269f55f5f5SRafal Jaworowski 8, 0, /* alignment, boundary */ 4279f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 4289f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 4299f55f5f5SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 4309f55f5f5SRafal Jaworowski MCLBYTES, 1, /* maxsize, nsegments */ 4319f55f5f5SRafal Jaworowski MCLBYTES, 0, /* maxsegsz, flags */ 4329f55f5f5SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 4339f55f5f5SRafal Jaworowski buffer_tag); /* dmat */ 4349f55f5f5SRafal Jaworowski if (error) { 4359f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to create busdma tag for mbufs\n"); 4369f55f5f5SRafal Jaworowski return (ENXIO); 4379f55f5f5SRafal Jaworowski } 4389f55f5f5SRafal Jaworowski 4399f55f5f5SRafal Jaworowski /* Create TX busdma maps */ 4409f55f5f5SRafal Jaworowski for (i = 0; i < size; i++) { 4419f55f5f5SRafal Jaworowski dw = &(tab[i]); 4429f55f5f5SRafal Jaworowski error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap); 4439f55f5f5SRafal Jaworowski if (error) { 4449f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to create map for mbuf\n"); 4459f55f5f5SRafal Jaworowski return (ENXIO); 4469f55f5f5SRafal Jaworowski } 4479f55f5f5SRafal Jaworowski 4489f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 4499f55f5f5SRafal Jaworowski dw->mge_desc->buffer = (bus_addr_t)NULL; 4509f55f5f5SRafal Jaworowski } 4519f55f5f5SRafal Jaworowski 4529f55f5f5SRafal Jaworowski return (0); 4539f55f5f5SRafal Jaworowski } 4549f55f5f5SRafal Jaworowski 4559f55f5f5SRafal Jaworowski static int 4569f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc) 4579f55f5f5SRafal Jaworowski { 4589f55f5f5SRafal Jaworowski int error; 4599f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 4609f55f5f5SRafal Jaworowski int num, i; 4619f55f5f5SRafal Jaworowski 4629f55f5f5SRafal Jaworowski 4639f55f5f5SRafal Jaworowski num = MGE_TX_DESC_NUM + MGE_RX_DESC_NUM; 4649f55f5f5SRafal Jaworowski 4659f55f5f5SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ 4669f55f5f5SRafal Jaworowski error = bus_dma_tag_create(NULL, /* parent */ 4679f55f5f5SRafal Jaworowski 16, 0, /* alignment, boundary */ 4689f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 4699f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 4709f55f5f5SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 4719f55f5f5SRafal Jaworowski sizeof(struct mge_desc), 1, /* maxsize, nsegments */ 4729f55f5f5SRafal Jaworowski sizeof(struct mge_desc), 0, /* maxsegsz, flags */ 4739f55f5f5SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 4749f55f5f5SRafal Jaworowski &sc->mge_desc_dtag); /* dmat */ 4759f55f5f5SRafal Jaworowski 4769f55f5f5SRafal Jaworowski 4779f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, 4789f55f5f5SRafal Jaworowski &sc->mge_tx_dtag); 4799f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, 4809f55f5f5SRafal Jaworowski &sc->mge_rx_dtag); 4819f55f5f5SRafal Jaworowski 4829f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 4839f55f5f5SRafal Jaworowski dw = &(sc->mge_rx_desc[i]); 4849f55f5f5SRafal Jaworowski mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer, 4859f55f5f5SRafal Jaworowski &dw->mge_desc->buffer); 4869f55f5f5SRafal Jaworowski } 4879f55f5f5SRafal Jaworowski 4889f55f5f5SRafal Jaworowski sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr; 4899f55f5f5SRafal Jaworowski sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr; 4909f55f5f5SRafal Jaworowski 4919f55f5f5SRafal Jaworowski return (0); 4929f55f5f5SRafal Jaworowski } 4939f55f5f5SRafal Jaworowski 4949f55f5f5SRafal Jaworowski static void 4959f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab, 4969f55f5f5SRafal Jaworowski uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs) 4979f55f5f5SRafal Jaworowski { 4989f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 4999f55f5f5SRafal Jaworowski int i; 5009f55f5f5SRafal Jaworowski 5019f55f5f5SRafal Jaworowski for (i = 0; i < size; i++) { 5029f55f5f5SRafal Jaworowski /* Free RX mbuf */ 5039f55f5f5SRafal Jaworowski dw = &(tab[i]); 5049f55f5f5SRafal Jaworowski 5059f55f5f5SRafal Jaworowski if (dw->buffer_dmap) { 5069f55f5f5SRafal Jaworowski if (free_mbufs) { 5079f55f5f5SRafal Jaworowski bus_dmamap_sync(buffer_tag, dw->buffer_dmap, 5089f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 5099f55f5f5SRafal Jaworowski bus_dmamap_unload(buffer_tag, dw->buffer_dmap); 5109f55f5f5SRafal Jaworowski } 5119f55f5f5SRafal Jaworowski bus_dmamap_destroy(buffer_tag, dw->buffer_dmap); 5129f55f5f5SRafal Jaworowski if (free_mbufs) 5139f55f5f5SRafal Jaworowski m_freem(dw->buffer); 5149f55f5f5SRafal Jaworowski } 5159f55f5f5SRafal Jaworowski /* Free RX descriptors */ 5169f55f5f5SRafal Jaworowski if (dw->desc_dmap) { 5179f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 5189f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 5199f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap); 5209f55f5f5SRafal Jaworowski bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc, 5219f55f5f5SRafal Jaworowski dw->desc_dmap); 5229f55f5f5SRafal Jaworowski } 5239f55f5f5SRafal Jaworowski } 5249f55f5f5SRafal Jaworowski } 5259f55f5f5SRafal Jaworowski 5269f55f5f5SRafal Jaworowski static void 5279f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc) 5289f55f5f5SRafal Jaworowski { 5299f55f5f5SRafal Jaworowski /* Free desciptors and mbufs */ 5309f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1); 5319f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0); 5329f55f5f5SRafal Jaworowski 5339f55f5f5SRafal Jaworowski /* Destroy mbuf dma tag */ 5349f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_tx_dtag); 5359f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_rx_dtag); 5369f55f5f5SRafal Jaworowski /* Destroy descriptors tag */ 5379f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_desc_dtag); 5389f55f5f5SRafal Jaworowski } 5399f55f5f5SRafal Jaworowski 5409f55f5f5SRafal Jaworowski static void 5419f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc) 5429f55f5f5SRafal Jaworowski { 5439f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 5449f55f5f5SRafal Jaworowski int i; 5459f55f5f5SRafal Jaworowski 5469f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc); 5479f55f5f5SRafal Jaworowski 5489f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1); 5499f55f5f5SRafal Jaworowski 5509f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, 5519f55f5f5SRafal Jaworowski &sc->mge_rx_dtag); 5529f55f5f5SRafal Jaworowski 5539f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 5549f55f5f5SRafal Jaworowski dw = &(sc->mge_rx_desc[i]); 5559f55f5f5SRafal Jaworowski mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer, 5569f55f5f5SRafal Jaworowski &dw->mge_desc->buffer); 5579f55f5f5SRafal Jaworowski } 5589f55f5f5SRafal Jaworowski 5599f55f5f5SRafal Jaworowski sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr; 5609f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 5619f55f5f5SRafal Jaworowski 5629f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE), 5639f55f5f5SRafal Jaworowski sc->rx_desc_start); 5649f55f5f5SRafal Jaworowski 5659f55f5f5SRafal Jaworowski /* Enable RX queue */ 5669f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE)); 5679f55f5f5SRafal Jaworowski 5689f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc); 5699f55f5f5SRafal Jaworowski } 5709f55f5f5SRafal Jaworowski 5719f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 5729f55f5f5SRafal Jaworowski static poll_handler_t mge_poll; 5739f55f5f5SRafal Jaworowski 5741abcdbd1SAttilio Rao static int 5759f55f5f5SRafal Jaworowski mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 5769f55f5f5SRafal Jaworowski { 5779f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 5789f55f5f5SRafal Jaworowski uint32_t int_cause, int_cause_ext; 5791abcdbd1SAttilio Rao int rx_npkts = 0; 5809f55f5f5SRafal Jaworowski 5819f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 5829f55f5f5SRafal Jaworowski 5839f55f5f5SRafal Jaworowski if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 5849f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 5851abcdbd1SAttilio Rao return (rx_npkts); 5869f55f5f5SRafal Jaworowski } 5879f55f5f5SRafal Jaworowski 5889f55f5f5SRafal Jaworowski if (cmd == POLL_AND_CHECK_STATUS) { 5899f55f5f5SRafal Jaworowski int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE); 5909f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 5919f55f5f5SRafal Jaworowski 5929f55f5f5SRafal Jaworowski /* Check for resource error */ 5939f55f5f5SRafal Jaworowski if (int_cause & MGE_PORT_INT_RXERRQ0) 5949f55f5f5SRafal Jaworowski mge_reinit_rx(sc); 5959f55f5f5SRafal Jaworowski 5969f55f5f5SRafal Jaworowski if (int_cause || int_cause_ext) { 5979f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause); 5989f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext); 5999f55f5f5SRafal Jaworowski } 6009f55f5f5SRafal Jaworowski } 6019f55f5f5SRafal Jaworowski 6029f55f5f5SRafal Jaworowski mge_intr_tx_locked(sc); 6031abcdbd1SAttilio Rao rx_npkts = mge_intr_rx_locked(sc, count); 6049f55f5f5SRafal Jaworowski 6059f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 6061abcdbd1SAttilio Rao return (rx_npkts); 6079f55f5f5SRafal Jaworowski } 6089f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */ 6099f55f5f5SRafal Jaworowski 6109f55f5f5SRafal Jaworowski static int 6119f55f5f5SRafal Jaworowski mge_attach(device_t dev) 6129f55f5f5SRafal Jaworowski { 6139f55f5f5SRafal Jaworowski struct mge_softc *sc; 614a6eb469dSPhilip Paeps struct mii_softc *miisc; 6159f55f5f5SRafal Jaworowski struct ifnet *ifp; 6169f55f5f5SRafal Jaworowski uint8_t hwaddr[ETHER_ADDR_LEN]; 6179f55f5f5SRafal Jaworowski int i, error ; 6189f55f5f5SRafal Jaworowski 6199f55f5f5SRafal Jaworowski sc = device_get_softc(dev); 6209f55f5f5SRafal Jaworowski sc->dev = dev; 6219f55f5f5SRafal Jaworowski 6229f55f5f5SRafal Jaworowski if (device_get_unit(dev) == 0) 6239f55f5f5SRafal Jaworowski sc_mge0 = sc; 6249f55f5f5SRafal Jaworowski 6258e1dc58eSRafal Jaworowski /* Set chip version-dependent parameters */ 6268e1dc58eSRafal Jaworowski mge_ver_params(sc); 6278e1dc58eSRafal Jaworowski 6289f55f5f5SRafal Jaworowski /* Initialize mutexes */ 6299f55f5f5SRafal Jaworowski mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock", MTX_DEF); 6309f55f5f5SRafal Jaworowski mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock", MTX_DEF); 6319f55f5f5SRafal Jaworowski 6329f55f5f5SRafal Jaworowski /* Allocate IO and IRQ resources */ 6339f55f5f5SRafal Jaworowski error = bus_alloc_resources(dev, res_spec, sc->res); 6349f55f5f5SRafal Jaworowski if (error) { 6359f55f5f5SRafal Jaworowski device_printf(dev, "could not allocate resources\n"); 6369f55f5f5SRafal Jaworowski mge_detach(dev); 6379f55f5f5SRafal Jaworowski return (ENXIO); 6389f55f5f5SRafal Jaworowski } 6399f55f5f5SRafal Jaworowski 6409f55f5f5SRafal Jaworowski /* Allocate DMA, buffers, buffer descriptors */ 6419f55f5f5SRafal Jaworowski error = mge_allocate_dma(sc); 6429f55f5f5SRafal Jaworowski if (error) { 6439f55f5f5SRafal Jaworowski mge_detach(dev); 6449f55f5f5SRafal Jaworowski return (ENXIO); 6459f55f5f5SRafal Jaworowski } 6469f55f5f5SRafal Jaworowski 6479f55f5f5SRafal Jaworowski sc->tx_desc_curr = 0; 6489f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 6499f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 0; 6505817716fSRafal Jaworowski sc->tx_desc_used_count = 0; 6519f55f5f5SRafal Jaworowski 6529f55f5f5SRafal Jaworowski /* Configure defaults for interrupts coalescing */ 6539f55f5f5SRafal Jaworowski sc->rx_ic_time = 768; 6549f55f5f5SRafal Jaworowski sc->tx_ic_time = 768; 6559f55f5f5SRafal Jaworowski mge_add_sysctls(sc); 6569f55f5f5SRafal Jaworowski 6579f55f5f5SRafal Jaworowski /* Allocate network interface */ 6589f55f5f5SRafal Jaworowski ifp = sc->ifp = if_alloc(IFT_ETHER); 6599f55f5f5SRafal Jaworowski if (ifp == NULL) { 6609f55f5f5SRafal Jaworowski device_printf(dev, "if_alloc() failed\n"); 6619f55f5f5SRafal Jaworowski mge_detach(dev); 6629f55f5f5SRafal Jaworowski return (ENOMEM); 6639f55f5f5SRafal Jaworowski } 6649f55f5f5SRafal Jaworowski 6659f55f5f5SRafal Jaworowski if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 6669f55f5f5SRafal Jaworowski ifp->if_softc = sc; 6679f55f5f5SRafal Jaworowski ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST; 6689f55f5f5SRafal Jaworowski ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_MTU; 6699f55f5f5SRafal Jaworowski ifp->if_capenable = ifp->if_capabilities; 6709f55f5f5SRafal Jaworowski ifp->if_hwassist = MGE_CHECKSUM_FEATURES; 6719f55f5f5SRafal Jaworowski 6729f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 6739f55f5f5SRafal Jaworowski /* Advertise that polling is supported */ 6749f55f5f5SRafal Jaworowski ifp->if_capabilities |= IFCAP_POLLING; 6759f55f5f5SRafal Jaworowski #endif 6769f55f5f5SRafal Jaworowski 6779f55f5f5SRafal Jaworowski ifp->if_init = mge_init; 6789f55f5f5SRafal Jaworowski ifp->if_start = mge_start; 6799f55f5f5SRafal Jaworowski ifp->if_ioctl = mge_ioctl; 6809f55f5f5SRafal Jaworowski 6819f55f5f5SRafal Jaworowski ifp->if_snd.ifq_drv_maxlen = MGE_TX_DESC_NUM - 1; 6829f55f5f5SRafal Jaworowski IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 6839f55f5f5SRafal Jaworowski IFQ_SET_READY(&ifp->if_snd); 6849f55f5f5SRafal Jaworowski 6859f55f5f5SRafal Jaworowski mge_get_mac_address(sc, hwaddr); 6869f55f5f5SRafal Jaworowski ether_ifattach(ifp, hwaddr); 6879f55f5f5SRafal Jaworowski callout_init(&sc->wd_callout, 0); 6889f55f5f5SRafal Jaworowski 6899f55f5f5SRafal Jaworowski /* Probe PHY(s) */ 6909f55f5f5SRafal Jaworowski error = mii_phy_probe(dev, &sc->miibus, mge_ifmedia_upd, mge_ifmedia_sts); 6919f55f5f5SRafal Jaworowski if (error) { 6929f55f5f5SRafal Jaworowski device_printf(dev, "MII failed to find PHY\n"); 6939f55f5f5SRafal Jaworowski mge_detach(dev); 6949f55f5f5SRafal Jaworowski return (error); 6959f55f5f5SRafal Jaworowski } 6969f55f5f5SRafal Jaworowski sc->mii = device_get_softc(sc->miibus); 6979f55f5f5SRafal Jaworowski 698a6eb469dSPhilip Paeps /* Tell the MAC where to find the PHY so autoneg works */ 699a6eb469dSPhilip Paeps miisc = LIST_FIRST(&sc->mii->mii_phys); 700a6eb469dSPhilip Paeps MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy); 701a6eb469dSPhilip Paeps 7029f55f5f5SRafal Jaworowski /* Attach interrupt handlers */ 7039f55f5f5SRafal Jaworowski for (i = 0; i < 2; ++i) { 7049f55f5f5SRafal Jaworowski error = bus_setup_intr(dev, sc->res[1 + i], 7059f55f5f5SRafal Jaworowski INTR_TYPE_NET | INTR_MPSAFE, NULL, *mge_intrs[i].handler, 7069f55f5f5SRafal Jaworowski sc, &sc->ih_cookie[i]); 7079f55f5f5SRafal Jaworowski if (error) { 7089f55f5f5SRafal Jaworowski device_printf(dev, "could not setup %s\n", 7099f55f5f5SRafal Jaworowski mge_intrs[i].description); 710a6eb469dSPhilip Paeps mge_detach(dev); 7119f55f5f5SRafal Jaworowski return (error); 7129f55f5f5SRafal Jaworowski } 7139f55f5f5SRafal Jaworowski } 7149f55f5f5SRafal Jaworowski 7159f55f5f5SRafal Jaworowski return (0); 7169f55f5f5SRafal Jaworowski } 7179f55f5f5SRafal Jaworowski 7189f55f5f5SRafal Jaworowski static int 7199f55f5f5SRafal Jaworowski mge_detach(device_t dev) 7209f55f5f5SRafal Jaworowski { 7219f55f5f5SRafal Jaworowski struct mge_softc *sc; 7229f55f5f5SRafal Jaworowski int error,i; 7239f55f5f5SRafal Jaworowski 7249f55f5f5SRafal Jaworowski sc = device_get_softc(dev); 7259f55f5f5SRafal Jaworowski 7269f55f5f5SRafal Jaworowski /* Stop controller and free TX queue */ 7279f55f5f5SRafal Jaworowski if (sc->ifp) 7289f55f5f5SRafal Jaworowski mge_shutdown(dev); 7299f55f5f5SRafal Jaworowski 7309f55f5f5SRafal Jaworowski /* Wait for stopping ticks */ 7319f55f5f5SRafal Jaworowski callout_drain(&sc->wd_callout); 7329f55f5f5SRafal Jaworowski 7339f55f5f5SRafal Jaworowski /* Stop and release all interrupts */ 7349f55f5f5SRafal Jaworowski for (i = 0; i < 2; ++i) { 735a6eb469dSPhilip Paeps if (!sc->ih_cookie[i]) 736a6eb469dSPhilip Paeps continue; 737a6eb469dSPhilip Paeps 7389f55f5f5SRafal Jaworowski error = bus_teardown_intr(dev, sc->res[1 + i], sc->ih_cookie[i]); 7399f55f5f5SRafal Jaworowski if (error) 7409f55f5f5SRafal Jaworowski device_printf(dev, "could not release %s\n", 7419f55f5f5SRafal Jaworowski mge_intrs[i].description); 7429f55f5f5SRafal Jaworowski } 7439f55f5f5SRafal Jaworowski 7449f55f5f5SRafal Jaworowski /* Detach network interface */ 7459f55f5f5SRafal Jaworowski if (sc->ifp) { 7469f55f5f5SRafal Jaworowski ether_ifdetach(sc->ifp); 7479f55f5f5SRafal Jaworowski if_free(sc->ifp); 7489f55f5f5SRafal Jaworowski } 7499f55f5f5SRafal Jaworowski 7509f55f5f5SRafal Jaworowski /* Free DMA resources */ 7519f55f5f5SRafal Jaworowski mge_free_dma(sc); 7529f55f5f5SRafal Jaworowski 7539f55f5f5SRafal Jaworowski /* Free IO memory handler */ 7549f55f5f5SRafal Jaworowski bus_release_resources(dev, res_spec, sc->res); 7559f55f5f5SRafal Jaworowski 7569f55f5f5SRafal Jaworowski /* Destroy mutexes */ 7579f55f5f5SRafal Jaworowski mtx_destroy(&sc->receive_lock); 7589f55f5f5SRafal Jaworowski mtx_destroy(&sc->transmit_lock); 7599f55f5f5SRafal Jaworowski 7609f55f5f5SRafal Jaworowski return (0); 7619f55f5f5SRafal Jaworowski } 7629f55f5f5SRafal Jaworowski 7639f55f5f5SRafal Jaworowski static void 7649f55f5f5SRafal Jaworowski mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 7659f55f5f5SRafal Jaworowski { 7669f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 7679f55f5f5SRafal Jaworowski struct mii_data *mii; 7689f55f5f5SRafal Jaworowski 7699f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc); 7709f55f5f5SRafal Jaworowski 7719f55f5f5SRafal Jaworowski mii = sc->mii; 7729f55f5f5SRafal Jaworowski mii_pollstat(mii); 7739f55f5f5SRafal Jaworowski 7749f55f5f5SRafal Jaworowski ifmr->ifm_active = mii->mii_media_active; 7759f55f5f5SRafal Jaworowski ifmr->ifm_status = mii->mii_media_status; 7769f55f5f5SRafal Jaworowski 7779f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 7789f55f5f5SRafal Jaworowski } 7799f55f5f5SRafal Jaworowski 7809f55f5f5SRafal Jaworowski static uint32_t 7819f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media) 7829f55f5f5SRafal Jaworowski { 7839f55f5f5SRafal Jaworowski uint32_t port_config; 7849f55f5f5SRafal Jaworowski 7859f55f5f5SRafal Jaworowski port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL | 7869f55f5f5SRafal Jaworowski PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552); 7879f55f5f5SRafal Jaworowski 7889f55f5f5SRafal Jaworowski if (IFM_TYPE(media) == IFM_ETHER) { 7899f55f5f5SRafal Jaworowski switch(IFM_SUBTYPE(media)) { 7909f55f5f5SRafal Jaworowski case IFM_AUTO: 7919f55f5f5SRafal Jaworowski break; 7929f55f5f5SRafal Jaworowski case IFM_1000_T: 7939f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_GMII_SPEED_1000 | 7949f55f5f5SRafal Jaworowski PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC | 7959f55f5f5SRafal Jaworowski PORT_SERIAL_SPEED_AUTONEG); 7969f55f5f5SRafal Jaworowski break; 7979f55f5f5SRafal Jaworowski case IFM_100_TX: 7989f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_MII_SPEED_100 | 7999f55f5f5SRafal Jaworowski PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC | 8009f55f5f5SRafal Jaworowski PORT_SERIAL_SPEED_AUTONEG); 8019f55f5f5SRafal Jaworowski break; 8029f55f5f5SRafal Jaworowski case IFM_10_T: 8039f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_AUTONEG | 8049f55f5f5SRafal Jaworowski PORT_SERIAL_AUTONEG_FC | 8059f55f5f5SRafal Jaworowski PORT_SERIAL_SPEED_AUTONEG); 8069f55f5f5SRafal Jaworowski break; 8079f55f5f5SRafal Jaworowski } 8089f55f5f5SRafal Jaworowski if (media & IFM_FDX) 8099f55f5f5SRafal Jaworowski port_config |= PORT_SERIAL_FULL_DUPLEX; 8109f55f5f5SRafal Jaworowski } 8119f55f5f5SRafal Jaworowski return (port_config); 8129f55f5f5SRafal Jaworowski } 8139f55f5f5SRafal Jaworowski 8149f55f5f5SRafal Jaworowski static int 8159f55f5f5SRafal Jaworowski mge_ifmedia_upd(struct ifnet *ifp) 8169f55f5f5SRafal Jaworowski { 8179f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 8189f55f5f5SRafal Jaworowski 8199f55f5f5SRafal Jaworowski if (ifp->if_flags & IFF_UP) { 8209f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 8219f55f5f5SRafal Jaworowski 8229f55f5f5SRafal Jaworowski sc->mge_media_status = sc->mii->mii_media.ifm_media; 8239f55f5f5SRafal Jaworowski mii_mediachg(sc->mii); 8249f55f5f5SRafal Jaworowski mge_init_locked(sc); 8259f55f5f5SRafal Jaworowski 8269f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 8279f55f5f5SRafal Jaworowski } 8289f55f5f5SRafal Jaworowski 8299f55f5f5SRafal Jaworowski return (0); 8309f55f5f5SRafal Jaworowski } 8319f55f5f5SRafal Jaworowski 8329f55f5f5SRafal Jaworowski static void 8339f55f5f5SRafal Jaworowski mge_init(void *arg) 8349f55f5f5SRafal Jaworowski { 8359f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 8369f55f5f5SRafal Jaworowski 8379f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 8389f55f5f5SRafal Jaworowski 8399f55f5f5SRafal Jaworowski mge_init_locked(arg); 8409f55f5f5SRafal Jaworowski 8419f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 8429f55f5f5SRafal Jaworowski } 8439f55f5f5SRafal Jaworowski 8449f55f5f5SRafal Jaworowski static void 8459f55f5f5SRafal Jaworowski mge_init_locked(void *arg) 8469f55f5f5SRafal Jaworowski { 8479f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 8489f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 8499f55f5f5SRafal Jaworowski volatile uint32_t reg_val; 8509f55f5f5SRafal Jaworowski int i, count; 8519f55f5f5SRafal Jaworowski 8529f55f5f5SRafal Jaworowski 8539f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK_ASSERT(sc); 8549f55f5f5SRafal Jaworowski 8559f55f5f5SRafal Jaworowski /* Stop interface */ 8569f55f5f5SRafal Jaworowski mge_stop(sc); 8579f55f5f5SRafal Jaworowski 8589f55f5f5SRafal Jaworowski /* Disable interrupts */ 8599f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 8609f55f5f5SRafal Jaworowski 8619f55f5f5SRafal Jaworowski /* Set MAC address */ 8629f55f5f5SRafal Jaworowski mge_set_mac_address(sc); 8639f55f5f5SRafal Jaworowski 8649f55f5f5SRafal Jaworowski /* Setup multicast filters */ 8659f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 8669f55f5f5SRafal Jaworowski 8678e1dc58eSRafal Jaworowski if (sc->mge_ver == 2) { 8689f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN); 8699f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0)); 8708e1dc58eSRafal Jaworowski } 8719f55f5f5SRafal Jaworowski 8728e1dc58eSRafal Jaworowski /* Initialize TX queue configuration registers */ 8738e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt); 8748e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg); 8758e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg); 8768e1dc58eSRafal Jaworowski 8778e1dc58eSRafal Jaworowski /* Clear TX queue configuration registers for unused queues */ 8789f55f5f5SRafal Jaworowski for (i = 1; i < 7; i++) { 8798e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0); 8808e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0); 8818e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0); 8829f55f5f5SRafal Jaworowski } 8839f55f5f5SRafal Jaworowski 8849f55f5f5SRafal Jaworowski /* Set default MTU */ 8858e1dc58eSRafal Jaworowski MGE_WRITE(sc, sc->mge_mtu, 0); 8869f55f5f5SRafal Jaworowski 8879f55f5f5SRafal Jaworowski /* Port configuration */ 8889f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, 8899f55f5f5SRafal Jaworowski PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) | 8909f55f5f5SRafal Jaworowski PORT_CONFIG_ARO_RXQ(0)); 8919f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0); 8929f55f5f5SRafal Jaworowski 8939f55f5f5SRafal Jaworowski /* Setup port configuration */ 8949f55f5f5SRafal Jaworowski reg_val = mge_set_port_serial_control(sc->mge_media_status); 8959f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val); 8969f55f5f5SRafal Jaworowski 8979f55f5f5SRafal Jaworowski /* Setup SDMA configuration */ 8989f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP | 8999f55f5f5SRafal Jaworowski MGE_SDMA_TX_BYTE_SWAP | 9009f55f5f5SRafal Jaworowski MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) | 9019f55f5f5SRafal Jaworowski MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD)); 9029f55f5f5SRafal Jaworowski 9039f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0); 9049f55f5f5SRafal Jaworowski 9059f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start); 9069f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE), 9079f55f5f5SRafal Jaworowski sc->rx_desc_start); 9089f55f5f5SRafal Jaworowski 9099f55f5f5SRafal Jaworowski /* Reset descriptor indexes */ 9109f55f5f5SRafal Jaworowski sc->tx_desc_curr = 0; 9119f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 9129f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 0; 9135817716fSRafal Jaworowski sc->tx_desc_used_count = 0; 9149f55f5f5SRafal Jaworowski 9159f55f5f5SRafal Jaworowski /* Enable RX descriptors */ 9169f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 9179f55f5f5SRafal Jaworowski dw = &sc->mge_rx_desc[i]; 9189f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED; 9199f55f5f5SRafal Jaworowski dw->mge_desc->buff_size = MCLBYTES; 9209f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 9219f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 9229f55f5f5SRafal Jaworowski } 9239f55f5f5SRafal Jaworowski 9249f55f5f5SRafal Jaworowski /* Enable RX queue */ 9259f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE)); 9269f55f5f5SRafal Jaworowski 9279f55f5f5SRafal Jaworowski /* Enable port */ 9289f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL); 9299f55f5f5SRafal Jaworowski reg_val |= PORT_SERIAL_ENABLE; 9309f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val); 9319f55f5f5SRafal Jaworowski count = 0x100000; 9329f55f5f5SRafal Jaworowski for (;;) { 9339f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_STATUS); 9349f55f5f5SRafal Jaworowski if (reg_val & MGE_STATUS_LINKUP) 9359f55f5f5SRafal Jaworowski break; 9369f55f5f5SRafal Jaworowski DELAY(100); 9379f55f5f5SRafal Jaworowski if (--count == 0) { 9389f55f5f5SRafal Jaworowski if_printf(sc->ifp, "Timeout on link-up\n"); 9399f55f5f5SRafal Jaworowski break; 9409f55f5f5SRafal Jaworowski } 9419f55f5f5SRafal Jaworowski } 9429f55f5f5SRafal Jaworowski 9439f55f5f5SRafal Jaworowski /* Setup interrupts coalescing */ 9449f55f5f5SRafal Jaworowski mge_set_rxic(sc); 9459f55f5f5SRafal Jaworowski mge_set_txic(sc); 9469f55f5f5SRafal Jaworowski 9479f55f5f5SRafal Jaworowski /* Enable interrupts */ 9489f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 9499f55f5f5SRafal Jaworowski /* 9509f55f5f5SRafal Jaworowski * * ...only if polling is not turned on. Disable interrupts explicitly 9519f55f5f5SRafal Jaworowski * if polling is enabled. 9529f55f5f5SRafal Jaworowski */ 9539f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) 9549f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 9559f55f5f5SRafal Jaworowski else 9569f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */ 9579f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 1); 9589f55f5f5SRafal Jaworowski 9599f55f5f5SRafal Jaworowski /* Activate network interface */ 9609f55f5f5SRafal Jaworowski sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 9619f55f5f5SRafal Jaworowski sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 9629f55f5f5SRafal Jaworowski sc->wd_timer = 0; 9639f55f5f5SRafal Jaworowski 9649f55f5f5SRafal Jaworowski /* Schedule watchdog timeout */ 9659f55f5f5SRafal Jaworowski callout_reset(&sc->wd_callout, hz, mge_tick, sc); 9669f55f5f5SRafal Jaworowski } 9679f55f5f5SRafal Jaworowski 9689f55f5f5SRafal Jaworowski static void 9699f55f5f5SRafal Jaworowski mge_intr_err(void *arg) 9709f55f5f5SRafal Jaworowski { 9719f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 9729f55f5f5SRafal Jaworowski struct ifnet *ifp; 9739f55f5f5SRafal Jaworowski 9749f55f5f5SRafal Jaworowski ifp = sc->ifp; 9759f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 9769f55f5f5SRafal Jaworowski } 9779f55f5f5SRafal Jaworowski 9789f55f5f5SRafal Jaworowski static void 9799f55f5f5SRafal Jaworowski mge_intr_misc(void *arg) 9809f55f5f5SRafal Jaworowski { 9819f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 9829f55f5f5SRafal Jaworowski struct ifnet *ifp; 9839f55f5f5SRafal Jaworowski 9849f55f5f5SRafal Jaworowski ifp = sc->ifp; 9859f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 9869f55f5f5SRafal Jaworowski } 9879f55f5f5SRafal Jaworowski 9889f55f5f5SRafal Jaworowski static void 9899f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) { 9909f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 9919f55f5f5SRafal Jaworowski uint32_t int_cause, int_cause_ext; 9929f55f5f5SRafal Jaworowski 9939f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc); 9949f55f5f5SRafal Jaworowski 9959f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 9969f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) { 9979f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc); 9989f55f5f5SRafal Jaworowski return; 9999f55f5f5SRafal Jaworowski } 10009f55f5f5SRafal Jaworowski #endif 10019f55f5f5SRafal Jaworowski 10029f55f5f5SRafal Jaworowski /* Get interrupt cause */ 10039f55f5f5SRafal Jaworowski int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE); 10049f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 10059f55f5f5SRafal Jaworowski 10069f55f5f5SRafal Jaworowski /* Check for resource error */ 10079f55f5f5SRafal Jaworowski if (int_cause & MGE_PORT_INT_RXERRQ0) { 10089f55f5f5SRafal Jaworowski mge_reinit_rx(sc); 10099f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 10109f55f5f5SRafal Jaworowski int_cause & ~MGE_PORT_INT_RXERRQ0); 10119f55f5f5SRafal Jaworowski } 10129f55f5f5SRafal Jaworowski 10139f55f5f5SRafal Jaworowski int_cause &= MGE_PORT_INT_RXQ0; 10149f55f5f5SRafal Jaworowski int_cause_ext &= MGE_PORT_INT_EXT_RXOR; 10159f55f5f5SRafal Jaworowski 10169f55f5f5SRafal Jaworowski if (int_cause || int_cause_ext) { 10179f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause); 10189f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext); 10199f55f5f5SRafal Jaworowski mge_intr_rx_locked(sc, -1); 10209f55f5f5SRafal Jaworowski } 10219f55f5f5SRafal Jaworowski 10229f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc); 10239f55f5f5SRafal Jaworowski } 10249f55f5f5SRafal Jaworowski 10259f55f5f5SRafal Jaworowski 10261abcdbd1SAttilio Rao static int 10279f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count) 10289f55f5f5SRafal Jaworowski { 10299f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 10309f55f5f5SRafal Jaworowski uint32_t status; 10319f55f5f5SRafal Jaworowski uint16_t bufsize; 10329f55f5f5SRafal Jaworowski struct mge_desc_wrapper* dw; 10339f55f5f5SRafal Jaworowski struct mbuf *mb; 10341abcdbd1SAttilio Rao int rx_npkts = 0; 10359f55f5f5SRafal Jaworowski 10369f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK_ASSERT(sc); 10379f55f5f5SRafal Jaworowski 10389f55f5f5SRafal Jaworowski while (count != 0) { 10399f55f5f5SRafal Jaworowski dw = &sc->mge_rx_desc[sc->rx_desc_curr]; 10409f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 10419f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 10429f55f5f5SRafal Jaworowski 10439f55f5f5SRafal Jaworowski /* Get status */ 10449f55f5f5SRafal Jaworowski status = dw->mge_desc->cmd_status; 10459f55f5f5SRafal Jaworowski bufsize = dw->mge_desc->buff_size; 10469f55f5f5SRafal Jaworowski if ((status & MGE_DMA_OWNED) != 0) 10479f55f5f5SRafal Jaworowski break; 10489f55f5f5SRafal Jaworowski 10499f55f5f5SRafal Jaworowski if (dw->mge_desc->byte_count && 10509f55f5f5SRafal Jaworowski ~(status & MGE_ERR_SUMMARY)) { 10519f55f5f5SRafal Jaworowski 10529f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap, 10539f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 10549f55f5f5SRafal Jaworowski 10559f55f5f5SRafal Jaworowski mb = m_devget(dw->buffer->m_data, 10569f55f5f5SRafal Jaworowski dw->mge_desc->byte_count - ETHER_CRC_LEN, 10579f55f5f5SRafal Jaworowski 0, ifp, NULL); 10589f55f5f5SRafal Jaworowski 10595817716fSRafal Jaworowski if (mb == NULL) 10605817716fSRafal Jaworowski /* Give up if no mbufs */ 10615817716fSRafal Jaworowski break; 10625817716fSRafal Jaworowski 10639f55f5f5SRafal Jaworowski mb->m_len -= 2; 10649f55f5f5SRafal Jaworowski mb->m_pkthdr.len -= 2; 10659f55f5f5SRafal Jaworowski mb->m_data += 2; 10669f55f5f5SRafal Jaworowski 10679f55f5f5SRafal Jaworowski mge_offload_process_frame(ifp, mb, status, 10689f55f5f5SRafal Jaworowski bufsize); 10699f55f5f5SRafal Jaworowski 10709f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc); 10719f55f5f5SRafal Jaworowski (*ifp->if_input)(ifp, mb); 10729f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc); 10731abcdbd1SAttilio Rao rx_npkts++; 10749f55f5f5SRafal Jaworowski } 10759f55f5f5SRafal Jaworowski 10769f55f5f5SRafal Jaworowski dw->mge_desc->byte_count = 0; 10779f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED; 10785817716fSRafal Jaworowski sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM); 10799f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 10809f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 10819f55f5f5SRafal Jaworowski 10829f55f5f5SRafal Jaworowski if (count > 0) 10839f55f5f5SRafal Jaworowski count -= 1; 10849f55f5f5SRafal Jaworowski } 10859f55f5f5SRafal Jaworowski 10861abcdbd1SAttilio Rao return (rx_npkts); 10879f55f5f5SRafal Jaworowski } 10889f55f5f5SRafal Jaworowski 10899f55f5f5SRafal Jaworowski static void 10909f55f5f5SRafal Jaworowski mge_intr_sum(void *arg) 10919f55f5f5SRafal Jaworowski { 10929f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 10939f55f5f5SRafal Jaworowski struct ifnet *ifp; 10949f55f5f5SRafal Jaworowski 10959f55f5f5SRafal Jaworowski ifp = sc->ifp; 10969f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 10979f55f5f5SRafal Jaworowski } 10989f55f5f5SRafal Jaworowski 10999f55f5f5SRafal Jaworowski static void 11009f55f5f5SRafal Jaworowski mge_intr_tx(void *arg) 11019f55f5f5SRafal Jaworowski { 11029f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 11039f55f5f5SRafal Jaworowski uint32_t int_cause_ext; 11049f55f5f5SRafal Jaworowski 11059f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc); 11069f55f5f5SRafal Jaworowski 11079f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 11089f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) { 11099f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 11109f55f5f5SRafal Jaworowski return; 11119f55f5f5SRafal Jaworowski } 11129f55f5f5SRafal Jaworowski #endif 11139f55f5f5SRafal Jaworowski 11149f55f5f5SRafal Jaworowski /* Ack the interrupt */ 11159f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 11169f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 11179f55f5f5SRafal Jaworowski int_cause_ext & ~MGE_PORT_INT_EXT_TXBUF0); 11189f55f5f5SRafal Jaworowski 11199f55f5f5SRafal Jaworowski mge_intr_tx_locked(sc); 11209f55f5f5SRafal Jaworowski 11219f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 11229f55f5f5SRafal Jaworowski } 11239f55f5f5SRafal Jaworowski 11249f55f5f5SRafal Jaworowski 11259f55f5f5SRafal Jaworowski static void 11269f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc) 11279f55f5f5SRafal Jaworowski { 11289f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 11299f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 11309f55f5f5SRafal Jaworowski struct mge_desc *desc; 11319f55f5f5SRafal Jaworowski uint32_t status; 11329f55f5f5SRafal Jaworowski int send = 0; 11339f55f5f5SRafal Jaworowski 11349f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK_ASSERT(sc); 11359f55f5f5SRafal Jaworowski 11369f55f5f5SRafal Jaworowski /* Disable watchdog */ 11379f55f5f5SRafal Jaworowski sc->wd_timer = 0; 11389f55f5f5SRafal Jaworowski 11399f55f5f5SRafal Jaworowski while (sc->tx_desc_used_count) { 11409f55f5f5SRafal Jaworowski /* Get the descriptor */ 11419f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[sc->tx_desc_used_idx]; 11429f55f5f5SRafal Jaworowski desc = dw->mge_desc; 11439f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 11449f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 11459f55f5f5SRafal Jaworowski 11469f55f5f5SRafal Jaworowski /* Get descriptor status */ 11479f55f5f5SRafal Jaworowski status = desc->cmd_status; 11489f55f5f5SRafal Jaworowski 11499f55f5f5SRafal Jaworowski if (status & MGE_DMA_OWNED) 11509f55f5f5SRafal Jaworowski break; 11519f55f5f5SRafal Jaworowski 11529f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 11539f55f5f5SRafal Jaworowski (++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM;; 11549f55f5f5SRafal Jaworowski sc->tx_desc_used_count--; 11559f55f5f5SRafal Jaworowski 11569f55f5f5SRafal Jaworowski /* Update collision statistics */ 11579f55f5f5SRafal Jaworowski if (status & MGE_ERR_SUMMARY) { 11589f55f5f5SRafal Jaworowski if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC) 11599f55f5f5SRafal Jaworowski ifp->if_collisions++; 11609f55f5f5SRafal Jaworowski if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL) 11619f55f5f5SRafal Jaworowski ifp->if_collisions += 16; 11629f55f5f5SRafal Jaworowski } 11639f55f5f5SRafal Jaworowski 11649f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap, 11659f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 11669f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap); 11679f55f5f5SRafal Jaworowski m_freem(dw->buffer); 11689f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 11699f55f5f5SRafal Jaworowski send++; 11709f55f5f5SRafal Jaworowski 11719f55f5f5SRafal Jaworowski ifp->if_opackets++; 11729f55f5f5SRafal Jaworowski } 11739f55f5f5SRafal Jaworowski 11749f55f5f5SRafal Jaworowski if (send) { 11759f55f5f5SRafal Jaworowski /* Now send anything that was pending */ 11769f55f5f5SRafal Jaworowski ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 11779f55f5f5SRafal Jaworowski mge_start_locked(ifp); 11789f55f5f5SRafal Jaworowski } 11799f55f5f5SRafal Jaworowski } 11809f55f5f5SRafal Jaworowski 11819f55f5f5SRafal Jaworowski static int 11829f55f5f5SRafal Jaworowski mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 11839f55f5f5SRafal Jaworowski { 11849f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 11859f55f5f5SRafal Jaworowski struct ifreq *ifr = (struct ifreq *)data; 11869f55f5f5SRafal Jaworowski int mask, error; 11879f55f5f5SRafal Jaworowski uint32_t flags; 11889f55f5f5SRafal Jaworowski 11899f55f5f5SRafal Jaworowski error = 0; 11909f55f5f5SRafal Jaworowski 11919f55f5f5SRafal Jaworowski switch (command) { 11929f55f5f5SRafal Jaworowski case SIOCSIFFLAGS: 11939f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 11949f55f5f5SRafal Jaworowski 11959f55f5f5SRafal Jaworowski if (ifp->if_flags & IFF_UP) { 11969f55f5f5SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 11979f55f5f5SRafal Jaworowski flags = ifp->if_flags ^ sc->mge_if_flags; 11989f55f5f5SRafal Jaworowski if (flags & IFF_PROMISC) 11999f55f5f5SRafal Jaworowski mge_set_prom_mode(sc, 12009f55f5f5SRafal Jaworowski MGE_RX_DEFAULT_QUEUE); 12019f55f5f5SRafal Jaworowski 12029f55f5f5SRafal Jaworowski if (flags & IFF_ALLMULTI) 12039f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 12049f55f5f5SRafal Jaworowski } else 12059f55f5f5SRafal Jaworowski mge_init_locked(sc); 12069f55f5f5SRafal Jaworowski } 12079f55f5f5SRafal Jaworowski else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 12089f55f5f5SRafal Jaworowski mge_stop(sc); 12099f55f5f5SRafal Jaworowski 12109f55f5f5SRafal Jaworowski sc->mge_if_flags = ifp->if_flags; 12119f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 12129f55f5f5SRafal Jaworowski break; 12139f55f5f5SRafal Jaworowski case SIOCADDMULTI: 12149f55f5f5SRafal Jaworowski case SIOCDELMULTI: 12159f55f5f5SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 12169f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 12179f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 12189f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 12199f55f5f5SRafal Jaworowski } 12209f55f5f5SRafal Jaworowski break; 12219f55f5f5SRafal Jaworowski case SIOCSIFCAP: 12229f55f5f5SRafal Jaworowski mask = ifp->if_capenable ^ ifr->ifr_reqcap; 12239f55f5f5SRafal Jaworowski if (mask & IFCAP_HWCSUM) { 12249f55f5f5SRafal Jaworowski ifp->if_capenable &= ~IFCAP_HWCSUM; 12259f55f5f5SRafal Jaworowski ifp->if_capenable |= IFCAP_HWCSUM & ifr->ifr_reqcap; 12269f55f5f5SRafal Jaworowski if (ifp->if_capenable & IFCAP_TXCSUM) 12279f55f5f5SRafal Jaworowski ifp->if_hwassist = MGE_CHECKSUM_FEATURES; 12289f55f5f5SRafal Jaworowski else 12299f55f5f5SRafal Jaworowski ifp->if_hwassist = 0; 12309f55f5f5SRafal Jaworowski } 12319f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 12329f55f5f5SRafal Jaworowski if (mask & IFCAP_POLLING) { 12339f55f5f5SRafal Jaworowski if (ifr->ifr_reqcap & IFCAP_POLLING) { 12349f55f5f5SRafal Jaworowski error = ether_poll_register(mge_poll, ifp); 12359f55f5f5SRafal Jaworowski if (error) 12369f55f5f5SRafal Jaworowski return(error); 12379f55f5f5SRafal Jaworowski 12389f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 12399f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 12409f55f5f5SRafal Jaworowski ifp->if_capenable |= IFCAP_POLLING; 12419f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 12429f55f5f5SRafal Jaworowski } else { 12439f55f5f5SRafal Jaworowski error = ether_poll_deregister(ifp); 12449f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 12459f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 1); 12469f55f5f5SRafal Jaworowski ifp->if_capenable &= ~IFCAP_POLLING; 12479f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 12489f55f5f5SRafal Jaworowski } 12499f55f5f5SRafal Jaworowski } 12509f55f5f5SRafal Jaworowski #endif 12519f55f5f5SRafal Jaworowski break; 12529f55f5f5SRafal Jaworowski case SIOCGIFMEDIA: /* fall through */ 12539f55f5f5SRafal Jaworowski case SIOCSIFMEDIA: 12549f55f5f5SRafal Jaworowski if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T 12559f55f5f5SRafal Jaworowski && !(ifr->ifr_media & IFM_FDX)) { 12569f55f5f5SRafal Jaworowski device_printf(sc->dev, 12579f55f5f5SRafal Jaworowski "1000baseTX half-duplex unsupported\n"); 12589f55f5f5SRafal Jaworowski return 0; 12599f55f5f5SRafal Jaworowski } 12609f55f5f5SRafal Jaworowski error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command); 12619f55f5f5SRafal Jaworowski break; 12629f55f5f5SRafal Jaworowski default: 12639f55f5f5SRafal Jaworowski error = ether_ioctl(ifp, command, data); 12649f55f5f5SRafal Jaworowski } 12659f55f5f5SRafal Jaworowski return (error); 12669f55f5f5SRafal Jaworowski } 12679f55f5f5SRafal Jaworowski 12689f55f5f5SRafal Jaworowski static int 12699f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg) 12709f55f5f5SRafal Jaworowski { 12719f55f5f5SRafal Jaworowski uint32_t retries; 12729f55f5f5SRafal Jaworowski 12739f55f5f5SRafal Jaworowski /* 12749f55f5f5SRafal Jaworowski * We assume static PHY address <=> device unit mapping: 127518159f6aSRafal Jaworowski * PHY Address = MII_ADDR_BASE + devce unit. 12769f55f5f5SRafal Jaworowski * This is true for most Marvell boards. 12779f55f5f5SRafal Jaworowski * 12789f55f5f5SRafal Jaworowski * Code below grants proper PHY detection on each device 12799f55f5f5SRafal Jaworowski * unit. 12809f55f5f5SRafal Jaworowski */ 12819f55f5f5SRafal Jaworowski 128218159f6aSRafal Jaworowski 128318159f6aSRafal Jaworowski if ((MII_ADDR_BASE + device_get_unit(dev)) != phy) 12849f55f5f5SRafal Jaworowski return (0); 12859f55f5f5SRafal Jaworowski 12869f55f5f5SRafal Jaworowski MGE_WRITE(sc_mge0, MGE_REG_SMI, 0x1fffffff & 12879f55f5f5SRafal Jaworowski (MGE_SMI_READ | (reg << 21) | (phy << 16))); 12889f55f5f5SRafal Jaworowski 12899f55f5f5SRafal Jaworowski retries = MGE_SMI_READ_RETRIES; 12909f55f5f5SRafal Jaworowski while (--retries && !(MGE_READ(sc_mge0, MGE_REG_SMI) & MGE_SMI_READVALID)) 12919f55f5f5SRafal Jaworowski DELAY(MGE_SMI_READ_DELAY); 12929f55f5f5SRafal Jaworowski 12939f55f5f5SRafal Jaworowski if (retries == 0) 12949f55f5f5SRafal Jaworowski device_printf(dev, "Timeout while reading from PHY\n"); 12959f55f5f5SRafal Jaworowski 12969f55f5f5SRafal Jaworowski return (MGE_READ(sc_mge0, MGE_REG_SMI) & 0xffff); 12979f55f5f5SRafal Jaworowski } 12989f55f5f5SRafal Jaworowski 12998e45f0b7SAndriy Gapon static int 13009f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value) 13019f55f5f5SRafal Jaworowski { 13029f55f5f5SRafal Jaworowski uint32_t retries; 13039f55f5f5SRafal Jaworowski 130418159f6aSRafal Jaworowski if ((MII_ADDR_BASE + device_get_unit(dev)) != phy) 13058e45f0b7SAndriy Gapon return (0); 13069f55f5f5SRafal Jaworowski 13079f55f5f5SRafal Jaworowski MGE_WRITE(sc_mge0, MGE_REG_SMI, 0x1fffffff & 13089f55f5f5SRafal Jaworowski (MGE_SMI_WRITE | (reg << 21) | (phy << 16) | (value & 0xffff))); 13099f55f5f5SRafal Jaworowski 13109f55f5f5SRafal Jaworowski retries = MGE_SMI_WRITE_RETRIES; 13119f55f5f5SRafal Jaworowski while (--retries && MGE_READ(sc_mge0, MGE_REG_SMI) & MGE_SMI_BUSY) 13129f55f5f5SRafal Jaworowski DELAY(MGE_SMI_WRITE_DELAY); 13139f55f5f5SRafal Jaworowski 13149f55f5f5SRafal Jaworowski if (retries == 0) 13159f55f5f5SRafal Jaworowski device_printf(dev, "Timeout while writing to PHY\n"); 13168e45f0b7SAndriy Gapon return (0); 13179f55f5f5SRafal Jaworowski } 13189f55f5f5SRafal Jaworowski 13199f55f5f5SRafal Jaworowski static int 13209f55f5f5SRafal Jaworowski mge_probe(device_t dev) 13219f55f5f5SRafal Jaworowski { 13229f55f5f5SRafal Jaworowski 13239f55f5f5SRafal Jaworowski device_set_desc(dev, "Marvell Gigabit Ethernet controller"); 13249f55f5f5SRafal Jaworowski return (BUS_PROBE_DEFAULT); 13259f55f5f5SRafal Jaworowski } 13269f55f5f5SRafal Jaworowski 13279f55f5f5SRafal Jaworowski static int 13289f55f5f5SRafal Jaworowski mge_resume(device_t dev) 13299f55f5f5SRafal Jaworowski { 13309f55f5f5SRafal Jaworowski 13319f55f5f5SRafal Jaworowski device_printf(dev, "%s\n", __FUNCTION__); 13329f55f5f5SRafal Jaworowski return (0); 13339f55f5f5SRafal Jaworowski } 13349f55f5f5SRafal Jaworowski 13359f55f5f5SRafal Jaworowski static int 13369f55f5f5SRafal Jaworowski mge_shutdown(device_t dev) 13379f55f5f5SRafal Jaworowski { 13389f55f5f5SRafal Jaworowski struct mge_softc *sc = device_get_softc(dev); 13399f55f5f5SRafal Jaworowski 13409f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 13419f55f5f5SRafal Jaworowski 13429f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 13439f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) 13449f55f5f5SRafal Jaworowski ether_poll_deregister(sc->ifp); 13459f55f5f5SRafal Jaworowski #endif 13469f55f5f5SRafal Jaworowski 13479f55f5f5SRafal Jaworowski mge_stop(sc); 13489f55f5f5SRafal Jaworowski 13499f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 13509f55f5f5SRafal Jaworowski 13519f55f5f5SRafal Jaworowski return (0); 13529f55f5f5SRafal Jaworowski } 13539f55f5f5SRafal Jaworowski 13549f55f5f5SRafal Jaworowski static int 13559f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0) 13569f55f5f5SRafal Jaworowski { 13579f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw = NULL; 13589f55f5f5SRafal Jaworowski struct ifnet *ifp; 13599f55f5f5SRafal Jaworowski bus_dma_segment_t segs[MGE_TX_DESC_NUM]; 13609f55f5f5SRafal Jaworowski bus_dmamap_t mapp; 13619f55f5f5SRafal Jaworowski int error; 13629f55f5f5SRafal Jaworowski int seg, nsegs; 13639f55f5f5SRafal Jaworowski int desc_no; 13649f55f5f5SRafal Jaworowski 13659f55f5f5SRafal Jaworowski ifp = sc->ifp; 13669f55f5f5SRafal Jaworowski 13679f55f5f5SRafal Jaworowski /* Check for free descriptors */ 13689f55f5f5SRafal Jaworowski if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) { 13699f55f5f5SRafal Jaworowski /* No free descriptors */ 13709f55f5f5SRafal Jaworowski return (-1); 13719f55f5f5SRafal Jaworowski } 13729f55f5f5SRafal Jaworowski 13739f55f5f5SRafal Jaworowski /* Fetch unused map */ 13749f55f5f5SRafal Jaworowski desc_no = sc->tx_desc_curr; 13759f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[desc_no]; 13769f55f5f5SRafal Jaworowski mapp = dw->buffer_dmap; 13779f55f5f5SRafal Jaworowski 13789f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, mapp, 13799f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 13809f55f5f5SRafal Jaworowski 13819f55f5f5SRafal Jaworowski /* Create mapping in DMA memory */ 13829f55f5f5SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs, 13839f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT); 13849f55f5f5SRafal Jaworowski if (error != 0 || nsegs != 1 ) { 13859f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, mapp); 13869f55f5f5SRafal Jaworowski return ((error != 0) ? error : -1); 13879f55f5f5SRafal Jaworowski } 13889f55f5f5SRafal Jaworowski 13899f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE); 13909f55f5f5SRafal Jaworowski 13919f55f5f5SRafal Jaworowski /* Everything is ok, now we can send buffers */ 13929f55f5f5SRafal Jaworowski for (seg = 0; seg < nsegs; seg++) { 13939f55f5f5SRafal Jaworowski dw->mge_desc->byte_count = segs[seg].ds_len; 13949f55f5f5SRafal Jaworowski dw->mge_desc->buffer = segs[seg].ds_addr; 13959f55f5f5SRafal Jaworowski dw->buffer = m0; 13969f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_TX_LAST | MGE_TX_FIRST | 13979f55f5f5SRafal Jaworowski MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING | 13989f55f5f5SRafal Jaworowski MGE_DMA_OWNED; 13999f55f5f5SRafal Jaworowski 14009f55f5f5SRafal Jaworowski if (seg == 0) 14019f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(sc, dw); 14029f55f5f5SRafal Jaworowski } 14039f55f5f5SRafal Jaworowski 14049f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, mapp, 14059f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 14069f55f5f5SRafal Jaworowski 14079f55f5f5SRafal Jaworowski sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM; 14089f55f5f5SRafal Jaworowski sc->tx_desc_used_count++; 14099f55f5f5SRafal Jaworowski return (0); 14109f55f5f5SRafal Jaworowski } 14119f55f5f5SRafal Jaworowski 14129f55f5f5SRafal Jaworowski static void 14139f55f5f5SRafal Jaworowski mge_tick(void *msc) 14149f55f5f5SRafal Jaworowski { 14159f55f5f5SRafal Jaworowski struct mge_softc *sc = msc; 14169f55f5f5SRafal Jaworowski 14179f55f5f5SRafal Jaworowski /* Check for TX timeout */ 14189f55f5f5SRafal Jaworowski mge_watchdog(sc); 14199f55f5f5SRafal Jaworowski 14209f55f5f5SRafal Jaworowski mii_tick(sc->mii); 14219f55f5f5SRafal Jaworowski 14229f55f5f5SRafal Jaworowski /* Check for media type change */ 14239f55f5f5SRafal Jaworowski if(sc->mge_media_status != sc->mii->mii_media.ifm_media) 14249f55f5f5SRafal Jaworowski mge_ifmedia_upd(sc->ifp); 14259f55f5f5SRafal Jaworowski 14269f55f5f5SRafal Jaworowski /* Schedule another timeout one second from now */ 14279f55f5f5SRafal Jaworowski callout_reset(&sc->wd_callout, hz, mge_tick, sc); 14289f55f5f5SRafal Jaworowski } 14299f55f5f5SRafal Jaworowski 14309f55f5f5SRafal Jaworowski static void 14319f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc) 14329f55f5f5SRafal Jaworowski { 14339f55f5f5SRafal Jaworowski struct ifnet *ifp; 14349f55f5f5SRafal Jaworowski 14359f55f5f5SRafal Jaworowski ifp = sc->ifp; 14369f55f5f5SRafal Jaworowski 14379f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 14389f55f5f5SRafal Jaworowski 14399f55f5f5SRafal Jaworowski if (sc->wd_timer == 0 || --sc->wd_timer) { 14409f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 14419f55f5f5SRafal Jaworowski return; 14429f55f5f5SRafal Jaworowski } 14439f55f5f5SRafal Jaworowski 14449f55f5f5SRafal Jaworowski ifp->if_oerrors++; 14459f55f5f5SRafal Jaworowski if_printf(ifp, "watchdog timeout\n"); 14469f55f5f5SRafal Jaworowski 14479f55f5f5SRafal Jaworowski mge_stop(sc); 14489f55f5f5SRafal Jaworowski mge_init_locked(sc); 14499f55f5f5SRafal Jaworowski 14509f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 14519f55f5f5SRafal Jaworowski } 14529f55f5f5SRafal Jaworowski 14539f55f5f5SRafal Jaworowski static void 14549f55f5f5SRafal Jaworowski mge_start(struct ifnet *ifp) 14559f55f5f5SRafal Jaworowski { 14569f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 14579f55f5f5SRafal Jaworowski 14589f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc); 14599f55f5f5SRafal Jaworowski 14609f55f5f5SRafal Jaworowski mge_start_locked(ifp); 14619f55f5f5SRafal Jaworowski 14629f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 14639f55f5f5SRafal Jaworowski } 14649f55f5f5SRafal Jaworowski 14659f55f5f5SRafal Jaworowski static void 14669f55f5f5SRafal Jaworowski mge_start_locked(struct ifnet *ifp) 14679f55f5f5SRafal Jaworowski { 14689f55f5f5SRafal Jaworowski struct mge_softc *sc; 14699f55f5f5SRafal Jaworowski struct mbuf *m0, *mtmp; 14709f55f5f5SRafal Jaworowski uint32_t reg_val, queued = 0; 14719f55f5f5SRafal Jaworowski 14729f55f5f5SRafal Jaworowski sc = ifp->if_softc; 14739f55f5f5SRafal Jaworowski 14749f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK_ASSERT(sc); 14759f55f5f5SRafal Jaworowski 14769f55f5f5SRafal Jaworowski if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 14779f55f5f5SRafal Jaworowski IFF_DRV_RUNNING) 14789f55f5f5SRafal Jaworowski return; 14799f55f5f5SRafal Jaworowski 14809f55f5f5SRafal Jaworowski for (;;) { 14819f55f5f5SRafal Jaworowski /* Get packet from the queue */ 14829f55f5f5SRafal Jaworowski IF_DEQUEUE(&ifp->if_snd, m0); 14839f55f5f5SRafal Jaworowski if (m0 == NULL) 14849f55f5f5SRafal Jaworowski break; 14859f55f5f5SRafal Jaworowski 14869f55f5f5SRafal Jaworowski mtmp = m_defrag(m0, M_DONTWAIT); 14879f55f5f5SRafal Jaworowski if (mtmp) 14889f55f5f5SRafal Jaworowski m0 = mtmp; 14899f55f5f5SRafal Jaworowski 14909f55f5f5SRafal Jaworowski if (mge_encap(sc, m0)) { 14919f55f5f5SRafal Jaworowski IF_PREPEND(&ifp->if_snd, m0); 14929f55f5f5SRafal Jaworowski ifp->if_drv_flags |= IFF_DRV_OACTIVE; 14939f55f5f5SRafal Jaworowski break; 14949f55f5f5SRafal Jaworowski } 14959f55f5f5SRafal Jaworowski queued++; 14969f55f5f5SRafal Jaworowski BPF_MTAP(ifp, m0); 14979f55f5f5SRafal Jaworowski } 14989f55f5f5SRafal Jaworowski 14999f55f5f5SRafal Jaworowski if (queued) { 15009f55f5f5SRafal Jaworowski /* Enable transmitter and watchdog timer */ 15019f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD); 15029f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ); 15039f55f5f5SRafal Jaworowski sc->wd_timer = 5; 15049f55f5f5SRafal Jaworowski } 15059f55f5f5SRafal Jaworowski } 15069f55f5f5SRafal Jaworowski 15079f55f5f5SRafal Jaworowski static void 15089f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc) 15099f55f5f5SRafal Jaworowski { 15109f55f5f5SRafal Jaworowski struct ifnet *ifp; 15119f55f5f5SRafal Jaworowski volatile uint32_t reg_val, status; 15129f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 15139f55f5f5SRafal Jaworowski struct mge_desc *desc; 15149f55f5f5SRafal Jaworowski int count; 15159f55f5f5SRafal Jaworowski 15169f55f5f5SRafal Jaworowski ifp = sc->ifp; 15179f55f5f5SRafal Jaworowski 15189f55f5f5SRafal Jaworowski if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 15199f55f5f5SRafal Jaworowski return; 15209f55f5f5SRafal Jaworowski 15219f55f5f5SRafal Jaworowski /* Stop tick engine */ 15229f55f5f5SRafal Jaworowski callout_stop(&sc->wd_callout); 15239f55f5f5SRafal Jaworowski 15249f55f5f5SRafal Jaworowski /* Disable interface */ 15259f55f5f5SRafal Jaworowski ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 15269f55f5f5SRafal Jaworowski sc->wd_timer = 0; 15279f55f5f5SRafal Jaworowski 15289f55f5f5SRafal Jaworowski /* Disable interrupts */ 15299f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 15309f55f5f5SRafal Jaworowski 15319f55f5f5SRafal Jaworowski /* Disable Rx and Tx */ 15329f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD); 15339f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ); 15349f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL); 15359f55f5f5SRafal Jaworowski 15369f55f5f5SRafal Jaworowski /* Remove pending data from TX queue */ 15375817716fSRafal Jaworowski while (sc->tx_desc_used_idx != sc->tx_desc_curr && 15385817716fSRafal Jaworowski sc->tx_desc_used_count) { 15399f55f5f5SRafal Jaworowski /* Get the descriptor */ 15409f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[sc->tx_desc_used_idx]; 15419f55f5f5SRafal Jaworowski desc = dw->mge_desc; 15429f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 15439f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 15449f55f5f5SRafal Jaworowski 15459f55f5f5SRafal Jaworowski /* Get descriptor status */ 15469f55f5f5SRafal Jaworowski status = desc->cmd_status; 15479f55f5f5SRafal Jaworowski 15489f55f5f5SRafal Jaworowski if (status & MGE_DMA_OWNED) 15499f55f5f5SRafal Jaworowski break; 15509f55f5f5SRafal Jaworowski 15519f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) % 15529f55f5f5SRafal Jaworowski MGE_TX_DESC_NUM; 15535817716fSRafal Jaworowski sc->tx_desc_used_count--; 15549f55f5f5SRafal Jaworowski 15559f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap, 15569f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 15579f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap); 15589f55f5f5SRafal Jaworowski 15599f55f5f5SRafal Jaworowski m_freem(dw->buffer); 15609f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 15619f55f5f5SRafal Jaworowski } 15629f55f5f5SRafal Jaworowski 15639f55f5f5SRafal Jaworowski /* Wait for end of transmission */ 15649f55f5f5SRafal Jaworowski count = 0x100000; 15659f55f5f5SRafal Jaworowski while (count--) { 15669f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_STATUS); 15679f55f5f5SRafal Jaworowski if ( !(reg_val & MGE_STATUS_TX_IN_PROG) && 15689f55f5f5SRafal Jaworowski (reg_val & MGE_STATUS_TX_FIFO_EMPTY)) 15699f55f5f5SRafal Jaworowski break; 15709f55f5f5SRafal Jaworowski DELAY(100); 15719f55f5f5SRafal Jaworowski } 15729f55f5f5SRafal Jaworowski 15739f55f5f5SRafal Jaworowski if(!count) 15749f55f5f5SRafal Jaworowski if_printf(ifp, "%s: timeout while waiting for end of transmission\n", 15759f55f5f5SRafal Jaworowski __FUNCTION__); 15769f55f5f5SRafal Jaworowski 15779f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL); 15789f55f5f5SRafal Jaworowski reg_val &= ~(PORT_SERIAL_ENABLE); 15799f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val); 15809f55f5f5SRafal Jaworowski } 15819f55f5f5SRafal Jaworowski 15829f55f5f5SRafal Jaworowski static int 15839f55f5f5SRafal Jaworowski mge_suspend(device_t dev) 15849f55f5f5SRafal Jaworowski { 15859f55f5f5SRafal Jaworowski 15869f55f5f5SRafal Jaworowski device_printf(dev, "%s\n", __FUNCTION__); 15879f55f5f5SRafal Jaworowski return (0); 15889f55f5f5SRafal Jaworowski } 15899f55f5f5SRafal Jaworowski 15909f55f5f5SRafal Jaworowski static void 15919f55f5f5SRafal Jaworowski mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame, 15929f55f5f5SRafal Jaworowski uint32_t status, uint16_t bufsize) 15939f55f5f5SRafal Jaworowski { 15949f55f5f5SRafal Jaworowski int csum_flags = 0; 15959f55f5f5SRafal Jaworowski 15969f55f5f5SRafal Jaworowski if (ifp->if_capenable & IFCAP_RXCSUM) { 15979f55f5f5SRafal Jaworowski if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK)) 15989f55f5f5SRafal Jaworowski csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID; 15999f55f5f5SRafal Jaworowski 16009f55f5f5SRafal Jaworowski if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 && 16019f55f5f5SRafal Jaworowski (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) && 16029f55f5f5SRafal Jaworowski (status & MGE_RX_L4_CSUM_OK)) { 16039f55f5f5SRafal Jaworowski csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 16049f55f5f5SRafal Jaworowski frame->m_pkthdr.csum_data = 0xFFFF; 16059f55f5f5SRafal Jaworowski } 16069f55f5f5SRafal Jaworowski 16079f55f5f5SRafal Jaworowski frame->m_pkthdr.csum_flags = csum_flags; 16089f55f5f5SRafal Jaworowski } 16099f55f5f5SRafal Jaworowski } 16109f55f5f5SRafal Jaworowski 16119f55f5f5SRafal Jaworowski static void 16129f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw) 16139f55f5f5SRafal Jaworowski { 16149f55f5f5SRafal Jaworowski struct mbuf *m0 = dw->buffer; 16159f55f5f5SRafal Jaworowski struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *); 16169f55f5f5SRafal Jaworowski int csum_flags = m0->m_pkthdr.csum_flags; 16179f55f5f5SRafal Jaworowski int cmd_status = 0; 16189f55f5f5SRafal Jaworowski struct ip *ip; 16199f55f5f5SRafal Jaworowski int ehlen, etype; 16209f55f5f5SRafal Jaworowski 16219f55f5f5SRafal Jaworowski if (csum_flags) { 16229f55f5f5SRafal Jaworowski if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 16239f55f5f5SRafal Jaworowski etype = ntohs(eh->evl_proto); 16249f55f5f5SRafal Jaworowski ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 16259f55f5f5SRafal Jaworowski csum_flags |= MGE_TX_VLAN_TAGGED; 16269f55f5f5SRafal Jaworowski } else { 16279f55f5f5SRafal Jaworowski etype = ntohs(eh->evl_encap_proto); 16289f55f5f5SRafal Jaworowski ehlen = ETHER_HDR_LEN; 16299f55f5f5SRafal Jaworowski } 16309f55f5f5SRafal Jaworowski 16319f55f5f5SRafal Jaworowski if (etype != ETHERTYPE_IP) { 16329f55f5f5SRafal Jaworowski if_printf(sc->ifp, 16339f55f5f5SRafal Jaworowski "TCP/IP Offload enabled for unsupported " 16349f55f5f5SRafal Jaworowski "protocol!\n"); 16359f55f5f5SRafal Jaworowski return; 16369f55f5f5SRafal Jaworowski } 16379f55f5f5SRafal Jaworowski 16389f55f5f5SRafal Jaworowski ip = (struct ip *)(m0->m_data + ehlen); 16399f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl); 16409f55f5f5SRafal Jaworowski 16419f55f5f5SRafal Jaworowski if ((m0->m_flags & M_FRAG) == 0) 16429f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_NOT_FRAGMENT; 16439f55f5f5SRafal Jaworowski } 16449f55f5f5SRafal Jaworowski 16459f55f5f5SRafal Jaworowski if (csum_flags & CSUM_IP) 16469f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_IP_CSUM; 16479f55f5f5SRafal Jaworowski 16489f55f5f5SRafal Jaworowski if (csum_flags & CSUM_TCP) 16499f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_L4_CSUM; 16509f55f5f5SRafal Jaworowski 16519f55f5f5SRafal Jaworowski if (csum_flags & CSUM_UDP) 16529f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP; 16539f55f5f5SRafal Jaworowski 16549f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status |= cmd_status; 16559f55f5f5SRafal Jaworowski } 16569f55f5f5SRafal Jaworowski 16579f55f5f5SRafal Jaworowski static void 16589f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable) 16599f55f5f5SRafal Jaworowski { 16609f55f5f5SRafal Jaworowski 16619f55f5f5SRafal Jaworowski if (enable) { 16629f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 | 16639f55f5f5SRafal Jaworowski MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0); 16649f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 | 16659f55f5f5SRafal Jaworowski MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR | 16669f55f5f5SRafal Jaworowski MGE_PORT_INT_EXT_TXBUF0); 16679f55f5f5SRafal Jaworowski } else { 16689f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_INT_CAUSE, 0x0); 16699f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_INT_MASK, 0x0); 16709f55f5f5SRafal Jaworowski 16719f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0); 16729f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0); 16739f55f5f5SRafal Jaworowski 16749f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0); 16759f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0); 16769f55f5f5SRafal Jaworowski } 16779f55f5f5SRafal Jaworowski } 16789f55f5f5SRafal Jaworowski 16799f55f5f5SRafal Jaworowski static uint8_t 16809f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size) 16819f55f5f5SRafal Jaworowski { 16829f55f5f5SRafal Jaworowski uint8_t crc = 0; 16839f55f5f5SRafal Jaworowski static const uint8_t ct[256] = { 16849f55f5f5SRafal Jaworowski 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 16859f55f5f5SRafal Jaworowski 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 16869f55f5f5SRafal Jaworowski 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 16879f55f5f5SRafal Jaworowski 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 16889f55f5f5SRafal Jaworowski 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 16899f55f5f5SRafal Jaworowski 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, 16909f55f5f5SRafal Jaworowski 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 16919f55f5f5SRafal Jaworowski 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, 16929f55f5f5SRafal Jaworowski 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 16939f55f5f5SRafal Jaworowski 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 16949f55f5f5SRafal Jaworowski 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 16959f55f5f5SRafal Jaworowski 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, 16969f55f5f5SRafal Jaworowski 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 16979f55f5f5SRafal Jaworowski 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, 16989f55f5f5SRafal Jaworowski 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 16999f55f5f5SRafal Jaworowski 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 17009f55f5f5SRafal Jaworowski 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 17019f55f5f5SRafal Jaworowski 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 17029f55f5f5SRafal Jaworowski 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 17039f55f5f5SRafal Jaworowski 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, 17049f55f5f5SRafal Jaworowski 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 17059f55f5f5SRafal Jaworowski 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 17069f55f5f5SRafal Jaworowski 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 17079f55f5f5SRafal Jaworowski 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, 17089f55f5f5SRafal Jaworowski 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 17099f55f5f5SRafal Jaworowski 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, 17109f55f5f5SRafal Jaworowski 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 17119f55f5f5SRafal Jaworowski 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 17129f55f5f5SRafal Jaworowski 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 17139f55f5f5SRafal Jaworowski 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, 17149f55f5f5SRafal Jaworowski 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 17159f55f5f5SRafal Jaworowski 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 17169f55f5f5SRafal Jaworowski }; 17179f55f5f5SRafal Jaworowski 17189f55f5f5SRafal Jaworowski while(size--) 17199f55f5f5SRafal Jaworowski crc = ct[crc ^ *(data++)]; 17209f55f5f5SRafal Jaworowski 17219f55f5f5SRafal Jaworowski return(crc); 17229f55f5f5SRafal Jaworowski } 17239f55f5f5SRafal Jaworowski 17249f55f5f5SRafal Jaworowski static void 17259f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc) 17269f55f5f5SRafal Jaworowski { 17279f55f5f5SRafal Jaworowski uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 }; 17289f55f5f5SRafal Jaworowski uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1; 17299f55f5f5SRafal Jaworowski uint32_t smt[MGE_MCAST_REG_NUMBER]; 17309f55f5f5SRafal Jaworowski uint32_t omt[MGE_MCAST_REG_NUMBER]; 17319f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 17329f55f5f5SRafal Jaworowski struct ifmultiaddr *ifma; 17339f55f5f5SRafal Jaworowski uint8_t *mac; 17349f55f5f5SRafal Jaworowski int i; 17359f55f5f5SRafal Jaworowski 17369f55f5f5SRafal Jaworowski if (ifp->if_flags & IFF_ALLMULTI) { 17379f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) 17389f55f5f5SRafal Jaworowski smt[i] = omt[i] = (v << 24) | (v << 16) | (v << 8) | v; 17399f55f5f5SRafal Jaworowski } else { 17409f55f5f5SRafal Jaworowski memset(smt, 0, sizeof(smt)); 17419f55f5f5SRafal Jaworowski memset(omt, 0, sizeof(omt)); 17429f55f5f5SRafal Jaworowski 1743eb956cd0SRobert Watson if_maddr_rlock(ifp); 17449f55f5f5SRafal Jaworowski TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 17459f55f5f5SRafal Jaworowski if (ifma->ifma_addr->sa_family != AF_LINK) 17469f55f5f5SRafal Jaworowski continue; 17479f55f5f5SRafal Jaworowski 17489f55f5f5SRafal Jaworowski mac = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 17499f55f5f5SRafal Jaworowski if (memcmp(mac, special, sizeof(special)) == 0) { 17509f55f5f5SRafal Jaworowski i = mac[5]; 17519f55f5f5SRafal Jaworowski smt[i >> 2] |= v << ((i & 0x03) << 3); 17529f55f5f5SRafal Jaworowski } else { 17539f55f5f5SRafal Jaworowski i = mge_crc8(mac, ETHER_ADDR_LEN); 17549f55f5f5SRafal Jaworowski omt[i >> 2] |= v << ((i & 0x03) << 3); 17559f55f5f5SRafal Jaworowski } 17569f55f5f5SRafal Jaworowski } 1757eb956cd0SRobert Watson if_maddr_runlock(ifp); 17589f55f5f5SRafal Jaworowski } 17599f55f5f5SRafal Jaworowski 17609f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 17619f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), smt[i]); 17629f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), omt[i]); 17639f55f5f5SRafal Jaworowski } 17649f55f5f5SRafal Jaworowski } 17659f55f5f5SRafal Jaworowski 17669f55f5f5SRafal Jaworowski static void 17679f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc) 17689f55f5f5SRafal Jaworowski { 17699f55f5f5SRafal Jaworowski uint32_t reg; 17709f55f5f5SRafal Jaworowski 17718e1dc58eSRafal Jaworowski if (sc->rx_ic_time > sc->mge_rx_ipg_max) 17728e1dc58eSRafal Jaworowski sc->rx_ic_time = sc->mge_rx_ipg_max; 17739f55f5f5SRafal Jaworowski 17749f55f5f5SRafal Jaworowski reg = MGE_READ(sc, MGE_SDMA_CONFIG); 17758e1dc58eSRafal Jaworowski reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver); 17768e1dc58eSRafal Jaworowski reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver); 17779f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_SDMA_CONFIG, reg); 17789f55f5f5SRafal Jaworowski } 17799f55f5f5SRafal Jaworowski 17809f55f5f5SRafal Jaworowski static void 17819f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc) 17829f55f5f5SRafal Jaworowski { 17839f55f5f5SRafal Jaworowski uint32_t reg; 17849f55f5f5SRafal Jaworowski 17858e1dc58eSRafal Jaworowski if (sc->tx_ic_time > sc->mge_tfut_ipg_max) 17868e1dc58eSRafal Jaworowski sc->tx_ic_time = sc->mge_tfut_ipg_max; 17879f55f5f5SRafal Jaworowski 17889f55f5f5SRafal Jaworowski reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH); 17898e1dc58eSRafal Jaworowski reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver); 17908e1dc58eSRafal Jaworowski reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver); 17919f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg); 17929f55f5f5SRafal Jaworowski } 17939f55f5f5SRafal Jaworowski 17949f55f5f5SRafal Jaworowski static int 17959f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS) 17969f55f5f5SRafal Jaworowski { 17979f55f5f5SRafal Jaworowski struct mge_softc *sc = (struct mge_softc *)arg1; 17988e1dc58eSRafal Jaworowski uint32_t time; 17999f55f5f5SRafal Jaworowski int error; 18009f55f5f5SRafal Jaworowski 18018e1dc58eSRafal Jaworowski time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time; 18029f55f5f5SRafal Jaworowski error = sysctl_handle_int(oidp, &time, 0, req); 18039f55f5f5SRafal Jaworowski if (error != 0) 18049f55f5f5SRafal Jaworowski return(error); 18059f55f5f5SRafal Jaworowski 18069f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 18079f55f5f5SRafal Jaworowski if (arg2 == MGE_IC_RX) { 18089f55f5f5SRafal Jaworowski sc->rx_ic_time = time; 18099f55f5f5SRafal Jaworowski mge_set_rxic(sc); 18109f55f5f5SRafal Jaworowski } else { 18119f55f5f5SRafal Jaworowski sc->tx_ic_time = time; 18129f55f5f5SRafal Jaworowski mge_set_txic(sc); 18139f55f5f5SRafal Jaworowski } 18149f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 18159f55f5f5SRafal Jaworowski 18169f55f5f5SRafal Jaworowski return(0); 18179f55f5f5SRafal Jaworowski } 18189f55f5f5SRafal Jaworowski 18199f55f5f5SRafal Jaworowski static void 18209f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc) 18219f55f5f5SRafal Jaworowski { 18229f55f5f5SRafal Jaworowski struct sysctl_ctx_list *ctx; 18239f55f5f5SRafal Jaworowski struct sysctl_oid_list *children; 18249f55f5f5SRafal Jaworowski struct sysctl_oid *tree; 18259f55f5f5SRafal Jaworowski 18269f55f5f5SRafal Jaworowski ctx = device_get_sysctl_ctx(sc->dev); 18279f55f5f5SRafal Jaworowski children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 18289f55f5f5SRafal Jaworowski tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal", 18299f55f5f5SRafal Jaworowski CTLFLAG_RD, 0, "MGE Interrupts coalescing"); 18309f55f5f5SRafal Jaworowski children = SYSCTL_CHILDREN(tree); 18319f55f5f5SRafal Jaworowski 18329f55f5f5SRafal Jaworowski SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time", 18339f55f5f5SRafal Jaworowski CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_RX, mge_sysctl_ic, 18349f55f5f5SRafal Jaworowski "I", "IC RX time threshold"); 18359f55f5f5SRafal Jaworowski SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time", 18369f55f5f5SRafal Jaworowski CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_TX, mge_sysctl_ic, 18379f55f5f5SRafal Jaworowski "I", "IC TX time threshold"); 18389f55f5f5SRafal Jaworowski } 1839