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> 5376039bc8SGleb Smirnoff #include <net/if_var.h> 549f55f5f5SRafal Jaworowski #include <net/if_arp.h> 559f55f5f5SRafal Jaworowski #include <net/if_dl.h> 569f55f5f5SRafal Jaworowski #include <net/if_media.h> 579f55f5f5SRafal Jaworowski #include <net/if_types.h> 589f55f5f5SRafal Jaworowski #include <net/if_vlan_var.h> 599f55f5f5SRafal Jaworowski 609f55f5f5SRafal Jaworowski #include <netinet/in_systm.h> 619f55f5f5SRafal Jaworowski #include <netinet/in.h> 629f55f5f5SRafal Jaworowski #include <netinet/ip.h> 639f55f5f5SRafal Jaworowski 649f55f5f5SRafal Jaworowski #include <sys/sockio.h> 659f55f5f5SRafal Jaworowski #include <sys/bus.h> 669f55f5f5SRafal Jaworowski #include <machine/bus.h> 679f55f5f5SRafal Jaworowski #include <sys/rman.h> 689f55f5f5SRafal Jaworowski #include <machine/resource.h> 699f55f5f5SRafal Jaworowski 709f55f5f5SRafal Jaworowski #include <dev/mii/mii.h> 719f55f5f5SRafal Jaworowski #include <dev/mii/miivar.h> 729f55f5f5SRafal Jaworowski 73db5ef4fcSRafal Jaworowski #include <dev/fdt/fdt_common.h> 74db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h> 75db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 769f55f5f5SRafal Jaworowski 779f55f5f5SRafal Jaworowski #include <dev/mge/if_mgevar.h> 789f55f5f5SRafal Jaworowski #include <arm/mv/mvreg.h> 798e1dc58eSRafal Jaworowski #include <arm/mv/mvvar.h> 809f55f5f5SRafal Jaworowski 819f55f5f5SRafal Jaworowski #include "miibus_if.h" 829f55f5f5SRafal Jaworowski 839f55f5f5SRafal Jaworowski static int mge_probe(device_t dev); 849f55f5f5SRafal Jaworowski static int mge_attach(device_t dev); 859f55f5f5SRafal Jaworowski static int mge_detach(device_t dev); 869f55f5f5SRafal Jaworowski static int mge_shutdown(device_t dev); 879f55f5f5SRafal Jaworowski static int mge_suspend(device_t dev); 889f55f5f5SRafal Jaworowski static int mge_resume(device_t dev); 899f55f5f5SRafal Jaworowski 909f55f5f5SRafal Jaworowski static int mge_miibus_readreg(device_t dev, int phy, int reg); 918e45f0b7SAndriy Gapon static int mge_miibus_writereg(device_t dev, int phy, int reg, int value); 929f55f5f5SRafal Jaworowski 939f55f5f5SRafal Jaworowski static int mge_ifmedia_upd(struct ifnet *ifp); 949f55f5f5SRafal Jaworowski static void mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 959f55f5f5SRafal Jaworowski 969f55f5f5SRafal Jaworowski static void mge_init(void *arg); 979f55f5f5SRafal Jaworowski static void mge_init_locked(void *arg); 989f55f5f5SRafal Jaworowski static void mge_start(struct ifnet *ifp); 999f55f5f5SRafal Jaworowski static void mge_start_locked(struct ifnet *ifp); 1009f55f5f5SRafal Jaworowski static void mge_watchdog(struct mge_softc *sc); 1019f55f5f5SRafal Jaworowski static int mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 1029f55f5f5SRafal Jaworowski 1038e1dc58eSRafal Jaworowski static uint32_t mge_tfut_ipg(uint32_t val, int ver); 1048e1dc58eSRafal Jaworowski static uint32_t mge_rx_ipg(uint32_t val, int ver); 1058e1dc58eSRafal Jaworowski static void mge_ver_params(struct mge_softc *sc); 1068e1dc58eSRafal Jaworowski 1079f55f5f5SRafal Jaworowski static void mge_intrs_ctrl(struct mge_softc *sc, int enable); 10875f1438bSOleksandr Tymoshenko static void mge_intr_rxtx(void *arg); 1099f55f5f5SRafal Jaworowski static void mge_intr_rx(void *arg); 11075f1438bSOleksandr Tymoshenko static void mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause, 11175f1438bSOleksandr Tymoshenko uint32_t int_cause_ext); 1121abcdbd1SAttilio Rao static int mge_intr_rx_locked(struct mge_softc *sc, int count); 1139f55f5f5SRafal Jaworowski static void mge_intr_tx(void *arg); 1149f55f5f5SRafal Jaworowski static void mge_intr_tx_locked(struct mge_softc *sc); 1159f55f5f5SRafal Jaworowski static void mge_intr_misc(void *arg); 1169f55f5f5SRafal Jaworowski static void mge_intr_sum(void *arg); 1179f55f5f5SRafal Jaworowski static void mge_intr_err(void *arg); 1189f55f5f5SRafal Jaworowski static void mge_stop(struct mge_softc *sc); 1199f55f5f5SRafal Jaworowski static void mge_tick(void *msc); 1209f55f5f5SRafal Jaworowski static uint32_t mge_set_port_serial_control(uint32_t media); 1219f55f5f5SRafal Jaworowski static void mge_get_mac_address(struct mge_softc *sc, uint8_t *addr); 1229f55f5f5SRafal Jaworowski static void mge_set_mac_address(struct mge_softc *sc); 1239f55f5f5SRafal Jaworowski static void mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, 1249f55f5f5SRafal Jaworowski uint8_t queue); 1259f55f5f5SRafal Jaworowski static void mge_set_prom_mode(struct mge_softc *sc, uint8_t queue); 1269f55f5f5SRafal Jaworowski static int mge_allocate_dma(struct mge_softc *sc); 1279f55f5f5SRafal Jaworowski static int mge_alloc_desc_dma(struct mge_softc *sc, 1289f55f5f5SRafal Jaworowski struct mge_desc_wrapper* desc_tab, uint32_t size, bus_dma_tag_t *buffer_tag); 1299f55f5f5SRafal Jaworowski static int mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, 1309f55f5f5SRafal Jaworowski struct mbuf **mbufp, bus_addr_t *paddr); 1319f55f5f5SRafal Jaworowski static void mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error); 1329f55f5f5SRafal Jaworowski static void mge_free_dma(struct mge_softc *sc); 1339f55f5f5SRafal Jaworowski static void mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab, uint32_t size, 1349f55f5f5SRafal Jaworowski bus_dma_tag_t buffer_tag, uint8_t free_mbufs); 1359f55f5f5SRafal Jaworowski static void mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame, 1369f55f5f5SRafal Jaworowski uint32_t status, uint16_t bufsize); 1379f55f5f5SRafal Jaworowski static void mge_offload_setup_descriptor(struct mge_softc *sc, 1389f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw); 1399f55f5f5SRafal Jaworowski static uint8_t mge_crc8(uint8_t *data, int size); 1409f55f5f5SRafal Jaworowski static void mge_setup_multicast(struct mge_softc *sc); 1419f55f5f5SRafal Jaworowski static void mge_set_rxic(struct mge_softc *sc); 1429f55f5f5SRafal Jaworowski static void mge_set_txic(struct mge_softc *sc); 1439f55f5f5SRafal Jaworowski static void mge_add_sysctls(struct mge_softc *sc); 1449f55f5f5SRafal Jaworowski static int mge_sysctl_ic(SYSCTL_HANDLER_ARGS); 1459f55f5f5SRafal Jaworowski 1469f55f5f5SRafal Jaworowski static device_method_t mge_methods[] = { 1479f55f5f5SRafal Jaworowski /* Device interface */ 1489f55f5f5SRafal Jaworowski DEVMETHOD(device_probe, mge_probe), 1499f55f5f5SRafal Jaworowski DEVMETHOD(device_attach, mge_attach), 1509f55f5f5SRafal Jaworowski DEVMETHOD(device_detach, mge_detach), 1519f55f5f5SRafal Jaworowski DEVMETHOD(device_shutdown, mge_shutdown), 1529f55f5f5SRafal Jaworowski DEVMETHOD(device_suspend, mge_suspend), 1539f55f5f5SRafal Jaworowski DEVMETHOD(device_resume, mge_resume), 1549f55f5f5SRafal Jaworowski /* MII interface */ 1559f55f5f5SRafal Jaworowski DEVMETHOD(miibus_readreg, mge_miibus_readreg), 1569f55f5f5SRafal Jaworowski DEVMETHOD(miibus_writereg, mge_miibus_writereg), 1579f55f5f5SRafal Jaworowski { 0, 0 } 1589f55f5f5SRafal Jaworowski }; 1599f55f5f5SRafal Jaworowski 1609f55f5f5SRafal Jaworowski static driver_t mge_driver = { 1619f55f5f5SRafal Jaworowski "mge", 1629f55f5f5SRafal Jaworowski mge_methods, 1639f55f5f5SRafal Jaworowski sizeof(struct mge_softc), 1649f55f5f5SRafal Jaworowski }; 1659f55f5f5SRafal Jaworowski 1669f55f5f5SRafal Jaworowski static devclass_t mge_devclass; 1679f55f5f5SRafal Jaworowski 168db5ef4fcSRafal Jaworowski DRIVER_MODULE(mge, simplebus, mge_driver, mge_devclass, 0, 0); 1699f55f5f5SRafal Jaworowski DRIVER_MODULE(miibus, mge, miibus_driver, miibus_devclass, 0, 0); 1709f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, ether, 1, 1, 1); 1719f55f5f5SRafal Jaworowski MODULE_DEPEND(mge, miibus, 1, 1, 1); 1729f55f5f5SRafal Jaworowski 1739f55f5f5SRafal Jaworowski static struct resource_spec res_spec[] = { 1749f55f5f5SRafal Jaworowski { SYS_RES_MEMORY, 0, RF_ACTIVE }, 1759f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 1769f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE }, 1779f55f5f5SRafal Jaworowski { SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE }, 1789f55f5f5SRafal Jaworowski { -1, 0 } 1799f55f5f5SRafal Jaworowski }; 1809f55f5f5SRafal Jaworowski 1819f55f5f5SRafal Jaworowski static struct { 1829f55f5f5SRafal Jaworowski driver_intr_t *handler; 1839f55f5f5SRafal Jaworowski char * description; 18475f1438bSOleksandr Tymoshenko } mge_intrs[MGE_INTR_COUNT + 1] = { 18575f1438bSOleksandr Tymoshenko { mge_intr_rxtx,"GbE aggregated interrupt" }, 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; 197db5ef4fcSRafal Jaworowski uint8_t lmac[6]; 198db5ef4fcSRafal Jaworowski int i, valid; 1999f55f5f5SRafal Jaworowski 200db5ef4fcSRafal Jaworowski /* 201db5ef4fcSRafal Jaworowski * Retrieve hw address from the device tree. 202db5ef4fcSRafal Jaworowski */ 203db5ef4fcSRafal Jaworowski i = OF_getprop(sc->node, "local-mac-address", (void *)lmac, 6); 204db5ef4fcSRafal Jaworowski if (i == 6) { 205db5ef4fcSRafal Jaworowski valid = 0; 206db5ef4fcSRafal Jaworowski for (i = 0; i < 6; i++) 207db5ef4fcSRafal Jaworowski if (lmac[i] != 0) { 208db5ef4fcSRafal Jaworowski valid = 1; 209db5ef4fcSRafal Jaworowski break; 210db5ef4fcSRafal Jaworowski } 2119f55f5f5SRafal Jaworowski 212db5ef4fcSRafal Jaworowski if (valid) { 213db5ef4fcSRafal Jaworowski bcopy(lmac, addr, 6); 214db5ef4fcSRafal Jaworowski return; 215db5ef4fcSRafal Jaworowski } 216db5ef4fcSRafal Jaworowski } 217db5ef4fcSRafal Jaworowski 218db5ef4fcSRafal Jaworowski /* 219db5ef4fcSRafal Jaworowski * Fall back -- use the currently programmed address. 220db5ef4fcSRafal Jaworowski */ 2219f55f5f5SRafal Jaworowski mac_l = MGE_READ(sc, MGE_MAC_ADDR_L); 2229f55f5f5SRafal Jaworowski mac_h = MGE_READ(sc, MGE_MAC_ADDR_H); 2239f55f5f5SRafal Jaworowski 2249f55f5f5SRafal Jaworowski addr[0] = (mac_h & 0xff000000) >> 24; 2259f55f5f5SRafal Jaworowski addr[1] = (mac_h & 0x00ff0000) >> 16; 2269f55f5f5SRafal Jaworowski addr[2] = (mac_h & 0x0000ff00) >> 8; 2279f55f5f5SRafal Jaworowski addr[3] = (mac_h & 0x000000ff); 2289f55f5f5SRafal Jaworowski addr[4] = (mac_l & 0x0000ff00) >> 8; 2299f55f5f5SRafal Jaworowski addr[5] = (mac_l & 0x000000ff); 2309f55f5f5SRafal Jaworowski } 2319f55f5f5SRafal Jaworowski 2328e1dc58eSRafal Jaworowski static uint32_t 2338e1dc58eSRafal Jaworowski mge_tfut_ipg(uint32_t val, int ver) 2348e1dc58eSRafal Jaworowski { 2358e1dc58eSRafal Jaworowski 2368e1dc58eSRafal Jaworowski switch (ver) { 2378e1dc58eSRafal Jaworowski case 1: 2388e1dc58eSRafal Jaworowski return ((val & 0x3fff) << 4); 2398e1dc58eSRafal Jaworowski case 2: 2408e1dc58eSRafal Jaworowski default: 2418e1dc58eSRafal Jaworowski return ((val & 0xffff) << 4); 2428e1dc58eSRafal Jaworowski } 2438e1dc58eSRafal Jaworowski } 2448e1dc58eSRafal Jaworowski 2458e1dc58eSRafal Jaworowski static uint32_t 2468e1dc58eSRafal Jaworowski mge_rx_ipg(uint32_t val, int ver) 2478e1dc58eSRafal Jaworowski { 2488e1dc58eSRafal Jaworowski 2498e1dc58eSRafal Jaworowski switch (ver) { 2508e1dc58eSRafal Jaworowski case 1: 2518e1dc58eSRafal Jaworowski return ((val & 0x3fff) << 8); 2528e1dc58eSRafal Jaworowski case 2: 2538e1dc58eSRafal Jaworowski default: 2548e1dc58eSRafal Jaworowski return (((val & 0x8000) << 10) | ((val & 0x7fff) << 7)); 2558e1dc58eSRafal Jaworowski } 2568e1dc58eSRafal Jaworowski } 2578e1dc58eSRafal Jaworowski 2588e1dc58eSRafal Jaworowski static void 2598e1dc58eSRafal Jaworowski mge_ver_params(struct mge_softc *sc) 2608e1dc58eSRafal Jaworowski { 2618e1dc58eSRafal Jaworowski uint32_t d, r; 2628e1dc58eSRafal Jaworowski 2638e1dc58eSRafal Jaworowski soc_id(&d, &r); 26475f1438bSOleksandr Tymoshenko if (d == MV_DEV_88F6281 || d == MV_DEV_88F6781 || 265c8953e12SHiroki Sato d == MV_DEV_88F6282 || 266c8953e12SHiroki Sato d == MV_DEV_MV78100 || 26775f1438bSOleksandr Tymoshenko d == MV_DEV_MV78100_Z0 || 26875f1438bSOleksandr Tymoshenko (d & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY) { 2698e1dc58eSRafal Jaworowski sc->mge_ver = 2; 2708e1dc58eSRafal Jaworowski sc->mge_mtu = 0x4e8; 2718e1dc58eSRafal Jaworowski sc->mge_tfut_ipg_max = 0xFFFF; 2728e1dc58eSRafal Jaworowski sc->mge_rx_ipg_max = 0xFFFF; 2738e1dc58eSRafal Jaworowski sc->mge_tx_arb_cfg = 0xFC0000FF; 2748e1dc58eSRafal Jaworowski sc->mge_tx_tok_cfg = 0xFFFF7FFF; 2758e1dc58eSRafal Jaworowski sc->mge_tx_tok_cnt = 0x3FFFFFFF; 2768e1dc58eSRafal Jaworowski } else { 2778e1dc58eSRafal Jaworowski sc->mge_ver = 1; 2788e1dc58eSRafal Jaworowski sc->mge_mtu = 0x458; 2798e1dc58eSRafal Jaworowski sc->mge_tfut_ipg_max = 0x3FFF; 2808e1dc58eSRafal Jaworowski sc->mge_rx_ipg_max = 0x3FFF; 2818e1dc58eSRafal Jaworowski sc->mge_tx_arb_cfg = 0x000000FF; 2828e1dc58eSRafal Jaworowski sc->mge_tx_tok_cfg = 0x3FFFFFFF; 2838e1dc58eSRafal Jaworowski sc->mge_tx_tok_cnt = 0x3FFFFFFF; 2848e1dc58eSRafal Jaworowski } 28575f1438bSOleksandr Tymoshenko if (d == MV_DEV_88RC8180) 28675f1438bSOleksandr Tymoshenko sc->mge_intr_cnt = 1; 28775f1438bSOleksandr Tymoshenko else 28875f1438bSOleksandr Tymoshenko sc->mge_intr_cnt = 2; 28975f1438bSOleksandr Tymoshenko 29075f1438bSOleksandr Tymoshenko if (d == MV_DEV_MV78160 || d == MV_DEV_MV78260 || d == MV_DEV_MV78460) 29175f1438bSOleksandr Tymoshenko sc->mge_hw_csum = 0; 29275f1438bSOleksandr Tymoshenko else 29375f1438bSOleksandr Tymoshenko sc->mge_hw_csum = 1; 2948e1dc58eSRafal Jaworowski } 2958e1dc58eSRafal Jaworowski 2969f55f5f5SRafal Jaworowski static void 2979f55f5f5SRafal Jaworowski mge_set_mac_address(struct mge_softc *sc) 2989f55f5f5SRafal Jaworowski { 2999f55f5f5SRafal Jaworowski char *if_mac; 3009f55f5f5SRafal Jaworowski uint32_t mac_l, mac_h; 3019f55f5f5SRafal Jaworowski 3029f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK_ASSERT(sc); 3039f55f5f5SRafal Jaworowski 3049f55f5f5SRafal Jaworowski if_mac = (char *)IF_LLADDR(sc->ifp); 3059f55f5f5SRafal Jaworowski 3069f55f5f5SRafal Jaworowski mac_l = (if_mac[4] << 8) | (if_mac[5]); 3079f55f5f5SRafal Jaworowski mac_h = (if_mac[0] << 24)| (if_mac[1] << 16) | 3089f55f5f5SRafal Jaworowski (if_mac[2] << 8) | (if_mac[3] << 0); 3099f55f5f5SRafal Jaworowski 3109f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_MAC_ADDR_L, mac_l); 3119f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_MAC_ADDR_H, mac_h); 3129f55f5f5SRafal Jaworowski 3139f55f5f5SRafal Jaworowski mge_set_ucast_address(sc, if_mac[5], MGE_RX_DEFAULT_QUEUE); 3149f55f5f5SRafal Jaworowski } 3159f55f5f5SRafal Jaworowski 3169f55f5f5SRafal Jaworowski static void 3179f55f5f5SRafal Jaworowski mge_set_ucast_address(struct mge_softc *sc, uint8_t last_byte, uint8_t queue) 3189f55f5f5SRafal Jaworowski { 3199f55f5f5SRafal Jaworowski uint32_t reg_idx, reg_off, reg_val, i; 3209f55f5f5SRafal Jaworowski 3219f55f5f5SRafal Jaworowski last_byte &= 0xf; 3229f55f5f5SRafal Jaworowski reg_idx = last_byte / MGE_UCAST_REG_NUMBER; 3239f55f5f5SRafal Jaworowski reg_off = (last_byte % MGE_UCAST_REG_NUMBER) * 8; 3249f55f5f5SRafal Jaworowski reg_val = (1 | (queue << 1)) << reg_off; 3259f55f5f5SRafal Jaworowski 3269f55f5f5SRafal Jaworowski for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) { 3279f55f5f5SRafal Jaworowski if ( i == reg_idx) 3289f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val); 3299f55f5f5SRafal Jaworowski else 3309f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), 0); 3319f55f5f5SRafal Jaworowski } 3329f55f5f5SRafal Jaworowski } 3339f55f5f5SRafal Jaworowski 3349f55f5f5SRafal Jaworowski static void 3359f55f5f5SRafal Jaworowski mge_set_prom_mode(struct mge_softc *sc, uint8_t queue) 3369f55f5f5SRafal Jaworowski { 3379f55f5f5SRafal Jaworowski uint32_t port_config; 3389f55f5f5SRafal Jaworowski uint32_t reg_val, i; 3399f55f5f5SRafal Jaworowski 3409f55f5f5SRafal Jaworowski /* Enable or disable promiscuous mode as needed */ 3419f55f5f5SRafal Jaworowski if (sc->ifp->if_flags & IFF_PROMISC) { 3429f55f5f5SRafal Jaworowski port_config = MGE_READ(sc, MGE_PORT_CONFIG); 3439f55f5f5SRafal Jaworowski port_config |= PORT_CONFIG_UPM; 3449f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, port_config); 3459f55f5f5SRafal Jaworowski 3469f55f5f5SRafal Jaworowski reg_val = ((1 | (queue << 1)) | (1 | (queue << 1)) << 8 | 3479f55f5f5SRafal Jaworowski (1 | (queue << 1)) << 16 | (1 | (queue << 1)) << 24); 3489f55f5f5SRafal Jaworowski 3499f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 3509f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), reg_val); 3519f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), reg_val); 3529f55f5f5SRafal Jaworowski } 3539f55f5f5SRafal Jaworowski 3549f55f5f5SRafal Jaworowski for (i = 0; i < MGE_UCAST_REG_NUMBER; i++) 3559f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_UCAST(i), reg_val); 3569f55f5f5SRafal Jaworowski 3579f55f5f5SRafal Jaworowski } else { 3589f55f5f5SRafal Jaworowski port_config = MGE_READ(sc, MGE_PORT_CONFIG); 3599f55f5f5SRafal Jaworowski port_config &= ~PORT_CONFIG_UPM; 3609f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, port_config); 3619f55f5f5SRafal Jaworowski 3629f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 3639f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), 0); 3649f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), 0); 3659f55f5f5SRafal Jaworowski } 3669f55f5f5SRafal Jaworowski 3679f55f5f5SRafal Jaworowski mge_set_mac_address(sc); 3689f55f5f5SRafal Jaworowski } 3699f55f5f5SRafal Jaworowski } 3709f55f5f5SRafal Jaworowski 3719f55f5f5SRafal Jaworowski static void 3729f55f5f5SRafal Jaworowski mge_get_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3739f55f5f5SRafal Jaworowski { 3749f55f5f5SRafal Jaworowski u_int32_t *paddr; 3759f55f5f5SRafal Jaworowski 3769f55f5f5SRafal Jaworowski KASSERT(nseg == 1, ("wrong number of segments, should be 1")); 3779f55f5f5SRafal Jaworowski paddr = arg; 3789f55f5f5SRafal Jaworowski 3799f55f5f5SRafal Jaworowski *paddr = segs->ds_addr; 3809f55f5f5SRafal Jaworowski } 3819f55f5f5SRafal Jaworowski 3829f55f5f5SRafal Jaworowski static int 3839f55f5f5SRafal Jaworowski mge_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp, 3849f55f5f5SRafal Jaworowski bus_addr_t *paddr) 3859f55f5f5SRafal Jaworowski { 3869f55f5f5SRafal Jaworowski struct mbuf *new_mbuf; 3879f55f5f5SRafal Jaworowski bus_dma_segment_t seg[1]; 3889f55f5f5SRafal Jaworowski int error; 3899f55f5f5SRafal Jaworowski int nsegs; 3909f55f5f5SRafal Jaworowski 3919f55f5f5SRafal Jaworowski KASSERT(mbufp != NULL, ("NULL mbuf pointer!")); 3929f55f5f5SRafal Jaworowski 393c6499eccSGleb Smirnoff new_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 3949f55f5f5SRafal Jaworowski if (new_mbuf == NULL) 3959f55f5f5SRafal Jaworowski return (ENOBUFS); 3969f55f5f5SRafal Jaworowski new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size; 3979f55f5f5SRafal Jaworowski 3989f55f5f5SRafal Jaworowski if (*mbufp) { 3999f55f5f5SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD); 4009f55f5f5SRafal Jaworowski bus_dmamap_unload(tag, map); 4019f55f5f5SRafal Jaworowski } 4029f55f5f5SRafal Jaworowski 4039f55f5f5SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs, 4049f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT); 4059f55f5f5SRafal Jaworowski KASSERT(nsegs == 1, ("Too many segments returned!")); 4069f55f5f5SRafal Jaworowski if (nsegs != 1 || error) 4079f55f5f5SRafal Jaworowski panic("mge_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error); 4089f55f5f5SRafal Jaworowski 4099f55f5f5SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD); 4109f55f5f5SRafal Jaworowski 4119f55f5f5SRafal Jaworowski (*mbufp) = new_mbuf; 4129f55f5f5SRafal Jaworowski (*paddr) = seg->ds_addr; 4139f55f5f5SRafal Jaworowski return (0); 4149f55f5f5SRafal Jaworowski } 4159f55f5f5SRafal Jaworowski 4169f55f5f5SRafal Jaworowski static int 4179f55f5f5SRafal Jaworowski mge_alloc_desc_dma(struct mge_softc *sc, struct mge_desc_wrapper* tab, 4189f55f5f5SRafal Jaworowski uint32_t size, bus_dma_tag_t *buffer_tag) 4199f55f5f5SRafal Jaworowski { 4209f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 4219f55f5f5SRafal Jaworowski bus_addr_t desc_paddr; 4229f55f5f5SRafal Jaworowski int i, error; 4239f55f5f5SRafal Jaworowski 4249f55f5f5SRafal Jaworowski desc_paddr = 0; 4259f55f5f5SRafal Jaworowski for (i = size - 1; i >= 0; i--) { 4269f55f5f5SRafal Jaworowski dw = &(tab[i]); 4279f55f5f5SRafal Jaworowski error = bus_dmamem_alloc(sc->mge_desc_dtag, 4289f55f5f5SRafal Jaworowski (void**)&(dw->mge_desc), 4299f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 4309f55f5f5SRafal Jaworowski &(dw->desc_dmap)); 4319f55f5f5SRafal Jaworowski 4329f55f5f5SRafal Jaworowski if (error) { 4339f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to allocate DMA memory\n"); 4349f55f5f5SRafal Jaworowski dw->mge_desc = NULL; 4359f55f5f5SRafal Jaworowski return (ENXIO); 4369f55f5f5SRafal Jaworowski } 4379f55f5f5SRafal Jaworowski 4389f55f5f5SRafal Jaworowski error = bus_dmamap_load(sc->mge_desc_dtag, dw->desc_dmap, 4399f55f5f5SRafal Jaworowski dw->mge_desc, sizeof(struct mge_desc), mge_get_dma_addr, 4409f55f5f5SRafal Jaworowski &(dw->mge_desc_paddr), BUS_DMA_NOWAIT); 4419f55f5f5SRafal Jaworowski 4429f55f5f5SRafal Jaworowski if (error) { 4439f55f5f5SRafal Jaworowski if_printf(sc->ifp, "can't load descriptor\n"); 4449f55f5f5SRafal Jaworowski bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc, 4459f55f5f5SRafal Jaworowski dw->desc_dmap); 4469f55f5f5SRafal Jaworowski dw->mge_desc = NULL; 4479f55f5f5SRafal Jaworowski return (ENXIO); 4489f55f5f5SRafal Jaworowski } 4499f55f5f5SRafal Jaworowski 4509f55f5f5SRafal Jaworowski /* Chain descriptors */ 4519f55f5f5SRafal Jaworowski dw->mge_desc->next_desc = desc_paddr; 4529f55f5f5SRafal Jaworowski desc_paddr = dw->mge_desc_paddr; 4539f55f5f5SRafal Jaworowski } 4549f55f5f5SRafal Jaworowski tab[size - 1].mge_desc->next_desc = desc_paddr; 4559f55f5f5SRafal Jaworowski 4569f55f5f5SRafal Jaworowski /* Allocate a busdma tag for mbufs. */ 45762ce43ccSScott Long error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), /* parent */ 45875f1438bSOleksandr Tymoshenko 1, 0, /* alignment, boundary */ 4599f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 4609f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 4619f55f5f5SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 4629f55f5f5SRafal Jaworowski MCLBYTES, 1, /* maxsize, nsegments */ 4639f55f5f5SRafal Jaworowski MCLBYTES, 0, /* maxsegsz, flags */ 4649f55f5f5SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 4659f55f5f5SRafal Jaworowski buffer_tag); /* dmat */ 4669f55f5f5SRafal Jaworowski if (error) { 4679f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to create busdma tag for mbufs\n"); 4689f55f5f5SRafal Jaworowski return (ENXIO); 4699f55f5f5SRafal Jaworowski } 4709f55f5f5SRafal Jaworowski 4719f55f5f5SRafal Jaworowski /* Create TX busdma maps */ 4729f55f5f5SRafal Jaworowski for (i = 0; i < size; i++) { 4739f55f5f5SRafal Jaworowski dw = &(tab[i]); 4749f55f5f5SRafal Jaworowski error = bus_dmamap_create(*buffer_tag, 0, &dw->buffer_dmap); 4759f55f5f5SRafal Jaworowski if (error) { 4769f55f5f5SRafal Jaworowski if_printf(sc->ifp, "failed to create map for mbuf\n"); 4779f55f5f5SRafal Jaworowski return (ENXIO); 4789f55f5f5SRafal Jaworowski } 4799f55f5f5SRafal Jaworowski 4809f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 4819f55f5f5SRafal Jaworowski dw->mge_desc->buffer = (bus_addr_t)NULL; 4829f55f5f5SRafal Jaworowski } 4839f55f5f5SRafal Jaworowski 4849f55f5f5SRafal Jaworowski return (0); 4859f55f5f5SRafal Jaworowski } 4869f55f5f5SRafal Jaworowski 4879f55f5f5SRafal Jaworowski static int 4889f55f5f5SRafal Jaworowski mge_allocate_dma(struct mge_softc *sc) 4899f55f5f5SRafal Jaworowski { 4909f55f5f5SRafal Jaworowski int error; 4919f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 492d6bdd318SRafal Jaworowski int i; 4939f55f5f5SRafal Jaworowski 4949f55f5f5SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ 49562ce43ccSScott Long error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), /* parent */ 4969f55f5f5SRafal Jaworowski 16, 0, /* alignment, boundary */ 4979f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 4989f55f5f5SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 4999f55f5f5SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 5009f55f5f5SRafal Jaworowski sizeof(struct mge_desc), 1, /* maxsize, nsegments */ 5019f55f5f5SRafal Jaworowski sizeof(struct mge_desc), 0, /* maxsegsz, flags */ 5029f55f5f5SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 5039f55f5f5SRafal Jaworowski &sc->mge_desc_dtag); /* dmat */ 5049f55f5f5SRafal Jaworowski 5059f55f5f5SRafal Jaworowski 5069f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, 5079f55f5f5SRafal Jaworowski &sc->mge_tx_dtag); 5089f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, 5099f55f5f5SRafal Jaworowski &sc->mge_rx_dtag); 5109f55f5f5SRafal Jaworowski 5119f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 5129f55f5f5SRafal Jaworowski dw = &(sc->mge_rx_desc[i]); 5139f55f5f5SRafal Jaworowski mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer, 5149f55f5f5SRafal Jaworowski &dw->mge_desc->buffer); 5159f55f5f5SRafal Jaworowski } 5169f55f5f5SRafal Jaworowski 5179f55f5f5SRafal Jaworowski sc->tx_desc_start = sc->mge_tx_desc[0].mge_desc_paddr; 5189f55f5f5SRafal Jaworowski sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr; 5199f55f5f5SRafal Jaworowski 5209f55f5f5SRafal Jaworowski return (0); 5219f55f5f5SRafal Jaworowski } 5229f55f5f5SRafal Jaworowski 5239f55f5f5SRafal Jaworowski static void 5249f55f5f5SRafal Jaworowski mge_free_desc(struct mge_softc *sc, struct mge_desc_wrapper* tab, 5259f55f5f5SRafal Jaworowski uint32_t size, bus_dma_tag_t buffer_tag, uint8_t free_mbufs) 5269f55f5f5SRafal Jaworowski { 5279f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 5289f55f5f5SRafal Jaworowski int i; 5299f55f5f5SRafal Jaworowski 5309f55f5f5SRafal Jaworowski for (i = 0; i < size; i++) { 5319f55f5f5SRafal Jaworowski /* Free RX mbuf */ 5329f55f5f5SRafal Jaworowski dw = &(tab[i]); 5339f55f5f5SRafal Jaworowski 5349f55f5f5SRafal Jaworowski if (dw->buffer_dmap) { 5359f55f5f5SRafal Jaworowski if (free_mbufs) { 5369f55f5f5SRafal Jaworowski bus_dmamap_sync(buffer_tag, dw->buffer_dmap, 5379f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 5389f55f5f5SRafal Jaworowski bus_dmamap_unload(buffer_tag, dw->buffer_dmap); 5399f55f5f5SRafal Jaworowski } 5409f55f5f5SRafal Jaworowski bus_dmamap_destroy(buffer_tag, dw->buffer_dmap); 5419f55f5f5SRafal Jaworowski if (free_mbufs) 5429f55f5f5SRafal Jaworowski m_freem(dw->buffer); 5439f55f5f5SRafal Jaworowski } 5449f55f5f5SRafal Jaworowski /* Free RX descriptors */ 5459f55f5f5SRafal Jaworowski if (dw->desc_dmap) { 5469f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 5479f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 5489f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_desc_dtag, dw->desc_dmap); 5499f55f5f5SRafal Jaworowski bus_dmamem_free(sc->mge_desc_dtag, dw->mge_desc, 5509f55f5f5SRafal Jaworowski dw->desc_dmap); 5519f55f5f5SRafal Jaworowski } 5529f55f5f5SRafal Jaworowski } 5539f55f5f5SRafal Jaworowski } 5549f55f5f5SRafal Jaworowski 5559f55f5f5SRafal Jaworowski static void 5569f55f5f5SRafal Jaworowski mge_free_dma(struct mge_softc *sc) 5579f55f5f5SRafal Jaworowski { 5589f55f5f5SRafal Jaworowski /* Free desciptors and mbufs */ 5599f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1); 5609f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_tx_desc, MGE_TX_DESC_NUM, sc->mge_tx_dtag, 0); 5619f55f5f5SRafal Jaworowski 5629f55f5f5SRafal Jaworowski /* Destroy mbuf dma tag */ 5639f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_tx_dtag); 5649f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_rx_dtag); 5659f55f5f5SRafal Jaworowski /* Destroy descriptors tag */ 5669f55f5f5SRafal Jaworowski bus_dma_tag_destroy(sc->mge_desc_dtag); 5679f55f5f5SRafal Jaworowski } 5689f55f5f5SRafal Jaworowski 5699f55f5f5SRafal Jaworowski static void 5709f55f5f5SRafal Jaworowski mge_reinit_rx(struct mge_softc *sc) 5719f55f5f5SRafal Jaworowski { 5729f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 5739f55f5f5SRafal Jaworowski int i; 5749f55f5f5SRafal Jaworowski 575d6bdd318SRafal Jaworowski MGE_RECEIVE_LOCK_ASSERT(sc); 5769f55f5f5SRafal Jaworowski 5779f55f5f5SRafal Jaworowski mge_free_desc(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, sc->mge_rx_dtag, 1); 5789f55f5f5SRafal Jaworowski 5799f55f5f5SRafal Jaworowski mge_alloc_desc_dma(sc, sc->mge_rx_desc, MGE_RX_DESC_NUM, 5809f55f5f5SRafal Jaworowski &sc->mge_rx_dtag); 5819f55f5f5SRafal Jaworowski 5829f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 5839f55f5f5SRafal Jaworowski dw = &(sc->mge_rx_desc[i]); 5849f55f5f5SRafal Jaworowski mge_new_rxbuf(sc->mge_rx_dtag, dw->buffer_dmap, &dw->buffer, 5859f55f5f5SRafal Jaworowski &dw->mge_desc->buffer); 5869f55f5f5SRafal Jaworowski } 5879f55f5f5SRafal Jaworowski 5889f55f5f5SRafal Jaworowski sc->rx_desc_start = sc->mge_rx_desc[0].mge_desc_paddr; 5899f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 5909f55f5f5SRafal Jaworowski 5919f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE), 5929f55f5f5SRafal Jaworowski sc->rx_desc_start); 5939f55f5f5SRafal Jaworowski 5949f55f5f5SRafal Jaworowski /* Enable RX queue */ 5959f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE)); 5969f55f5f5SRafal Jaworowski } 5979f55f5f5SRafal Jaworowski 5989f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 5999f55f5f5SRafal Jaworowski static poll_handler_t mge_poll; 6009f55f5f5SRafal Jaworowski 6011abcdbd1SAttilio Rao static int 6029f55f5f5SRafal Jaworowski mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 6039f55f5f5SRafal Jaworowski { 6049f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 6059f55f5f5SRafal Jaworowski uint32_t int_cause, int_cause_ext; 6061abcdbd1SAttilio Rao int rx_npkts = 0; 6079f55f5f5SRafal Jaworowski 6089f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 6099f55f5f5SRafal Jaworowski 6109f55f5f5SRafal Jaworowski if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 6119f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 6121abcdbd1SAttilio Rao return (rx_npkts); 6139f55f5f5SRafal Jaworowski } 6149f55f5f5SRafal Jaworowski 6159f55f5f5SRafal Jaworowski if (cmd == POLL_AND_CHECK_STATUS) { 6169f55f5f5SRafal Jaworowski int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE); 6179f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 6189f55f5f5SRafal Jaworowski 6199f55f5f5SRafal Jaworowski /* Check for resource error */ 6209f55f5f5SRafal Jaworowski if (int_cause & MGE_PORT_INT_RXERRQ0) 6219f55f5f5SRafal Jaworowski mge_reinit_rx(sc); 6229f55f5f5SRafal Jaworowski 6239f55f5f5SRafal Jaworowski if (int_cause || int_cause_ext) { 6249f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause); 6259f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext); 6269f55f5f5SRafal Jaworowski } 6279f55f5f5SRafal Jaworowski } 6289f55f5f5SRafal Jaworowski 6299f55f5f5SRafal Jaworowski mge_intr_tx_locked(sc); 6301abcdbd1SAttilio Rao rx_npkts = mge_intr_rx_locked(sc, count); 6319f55f5f5SRafal Jaworowski 6329f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 6331abcdbd1SAttilio Rao return (rx_npkts); 6349f55f5f5SRafal Jaworowski } 6359f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */ 6369f55f5f5SRafal Jaworowski 6379f55f5f5SRafal Jaworowski static int 6389f55f5f5SRafal Jaworowski mge_attach(device_t dev) 6399f55f5f5SRafal Jaworowski { 6409f55f5f5SRafal Jaworowski struct mge_softc *sc; 641a6eb469dSPhilip Paeps struct mii_softc *miisc; 6429f55f5f5SRafal Jaworowski struct ifnet *ifp; 6439f55f5f5SRafal Jaworowski uint8_t hwaddr[ETHER_ADDR_LEN]; 6448e5d93dbSMarius Strobl int i, error, phy; 6459f55f5f5SRafal Jaworowski 6469f55f5f5SRafal Jaworowski sc = device_get_softc(dev); 6479f55f5f5SRafal Jaworowski sc->dev = dev; 648db5ef4fcSRafal Jaworowski sc->node = ofw_bus_get_node(dev); 6499f55f5f5SRafal Jaworowski 6508e1dc58eSRafal Jaworowski /* Set chip version-dependent parameters */ 6518e1dc58eSRafal Jaworowski mge_ver_params(sc); 6528e1dc58eSRafal Jaworowski 653aa15e881SRafal Jaworowski /* Get phy address and used softc from fdt */ 654aa15e881SRafal Jaworowski if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) != 0) 655db5ef4fcSRafal Jaworowski return (ENXIO); 656db5ef4fcSRafal Jaworowski 6579f55f5f5SRafal Jaworowski /* Initialize mutexes */ 6589f55f5f5SRafal Jaworowski mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock", MTX_DEF); 6599f55f5f5SRafal Jaworowski mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock", MTX_DEF); 6609f55f5f5SRafal Jaworowski 6619f55f5f5SRafal Jaworowski /* Allocate IO and IRQ resources */ 6629f55f5f5SRafal Jaworowski error = bus_alloc_resources(dev, res_spec, sc->res); 6639f55f5f5SRafal Jaworowski if (error) { 6649f55f5f5SRafal Jaworowski device_printf(dev, "could not allocate resources\n"); 6659f55f5f5SRafal Jaworowski mge_detach(dev); 6669f55f5f5SRafal Jaworowski return (ENXIO); 6679f55f5f5SRafal Jaworowski } 6689f55f5f5SRafal Jaworowski 6699f55f5f5SRafal Jaworowski /* Allocate DMA, buffers, buffer descriptors */ 6709f55f5f5SRafal Jaworowski error = mge_allocate_dma(sc); 6719f55f5f5SRafal Jaworowski if (error) { 6729f55f5f5SRafal Jaworowski mge_detach(dev); 6739f55f5f5SRafal Jaworowski return (ENXIO); 6749f55f5f5SRafal Jaworowski } 6759f55f5f5SRafal Jaworowski 6769f55f5f5SRafal Jaworowski sc->tx_desc_curr = 0; 6779f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 6789f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 0; 6795817716fSRafal Jaworowski sc->tx_desc_used_count = 0; 6809f55f5f5SRafal Jaworowski 6819f55f5f5SRafal Jaworowski /* Configure defaults for interrupts coalescing */ 6829f55f5f5SRafal Jaworowski sc->rx_ic_time = 768; 6839f55f5f5SRafal Jaworowski sc->tx_ic_time = 768; 6849f55f5f5SRafal Jaworowski mge_add_sysctls(sc); 6859f55f5f5SRafal Jaworowski 6869f55f5f5SRafal Jaworowski /* Allocate network interface */ 6879f55f5f5SRafal Jaworowski ifp = sc->ifp = if_alloc(IFT_ETHER); 6889f55f5f5SRafal Jaworowski if (ifp == NULL) { 6899f55f5f5SRafal Jaworowski device_printf(dev, "if_alloc() failed\n"); 6909f55f5f5SRafal Jaworowski mge_detach(dev); 6919f55f5f5SRafal Jaworowski return (ENOMEM); 6929f55f5f5SRafal Jaworowski } 6939f55f5f5SRafal Jaworowski 6949f55f5f5SRafal Jaworowski if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 6959f55f5f5SRafal Jaworowski ifp->if_softc = sc; 6969f55f5f5SRafal Jaworowski ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST; 69775f1438bSOleksandr Tymoshenko ifp->if_capabilities = IFCAP_VLAN_MTU; 69875f1438bSOleksandr Tymoshenko if (sc->mge_hw_csum) { 69975f1438bSOleksandr Tymoshenko ifp->if_capabilities |= IFCAP_HWCSUM; 7009f55f5f5SRafal Jaworowski ifp->if_hwassist = MGE_CHECKSUM_FEATURES; 70175f1438bSOleksandr Tymoshenko } 70275f1438bSOleksandr Tymoshenko ifp->if_capenable = ifp->if_capabilities; 7039f55f5f5SRafal Jaworowski 7049f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 7059f55f5f5SRafal Jaworowski /* Advertise that polling is supported */ 7069f55f5f5SRafal Jaworowski ifp->if_capabilities |= IFCAP_POLLING; 7079f55f5f5SRafal Jaworowski #endif 7089f55f5f5SRafal Jaworowski 7099f55f5f5SRafal Jaworowski ifp->if_init = mge_init; 7109f55f5f5SRafal Jaworowski ifp->if_start = mge_start; 7119f55f5f5SRafal Jaworowski ifp->if_ioctl = mge_ioctl; 7129f55f5f5SRafal Jaworowski 7139f55f5f5SRafal Jaworowski ifp->if_snd.ifq_drv_maxlen = MGE_TX_DESC_NUM - 1; 7149f55f5f5SRafal Jaworowski IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 7159f55f5f5SRafal Jaworowski IFQ_SET_READY(&ifp->if_snd); 7169f55f5f5SRafal Jaworowski 7179f55f5f5SRafal Jaworowski mge_get_mac_address(sc, hwaddr); 7189f55f5f5SRafal Jaworowski ether_ifattach(ifp, hwaddr); 7199f55f5f5SRafal Jaworowski callout_init(&sc->wd_callout, 0); 7209f55f5f5SRafal Jaworowski 7218e5d93dbSMarius Strobl /* Attach PHY(s) */ 7228e5d93dbSMarius Strobl error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd, 7238e5d93dbSMarius Strobl mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 7249f55f5f5SRafal Jaworowski if (error) { 7258e5d93dbSMarius Strobl device_printf(dev, "attaching PHYs failed\n"); 7269f55f5f5SRafal Jaworowski mge_detach(dev); 7279f55f5f5SRafal Jaworowski return (error); 7289f55f5f5SRafal Jaworowski } 7299f55f5f5SRafal Jaworowski sc->mii = device_get_softc(sc->miibus); 7309f55f5f5SRafal Jaworowski 731a6eb469dSPhilip Paeps /* Tell the MAC where to find the PHY so autoneg works */ 732a6eb469dSPhilip Paeps miisc = LIST_FIRST(&sc->mii->mii_phys); 733a6eb469dSPhilip Paeps MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy); 734a6eb469dSPhilip Paeps 7359f55f5f5SRafal Jaworowski /* Attach interrupt handlers */ 73675f1438bSOleksandr Tymoshenko /* TODO: review flags, in part. mark RX as INTR_ENTROPY ? */ 73775f1438bSOleksandr Tymoshenko for (i = 1; i <= sc->mge_intr_cnt; ++i) { 73875f1438bSOleksandr Tymoshenko error = bus_setup_intr(dev, sc->res[i], 73975f1438bSOleksandr Tymoshenko INTR_TYPE_NET | INTR_MPSAFE, 74075f1438bSOleksandr Tymoshenko NULL, *mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].handler, 74175f1438bSOleksandr Tymoshenko sc, &sc->ih_cookie[i - 1]); 7429f55f5f5SRafal Jaworowski if (error) { 7439f55f5f5SRafal Jaworowski device_printf(dev, "could not setup %s\n", 74475f1438bSOleksandr Tymoshenko mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i)].description); 745a6eb469dSPhilip Paeps mge_detach(dev); 7469f55f5f5SRafal Jaworowski return (error); 7479f55f5f5SRafal Jaworowski } 7489f55f5f5SRafal Jaworowski } 7499f55f5f5SRafal Jaworowski 7509f55f5f5SRafal Jaworowski return (0); 7519f55f5f5SRafal Jaworowski } 7529f55f5f5SRafal Jaworowski 7539f55f5f5SRafal Jaworowski static int 7549f55f5f5SRafal Jaworowski mge_detach(device_t dev) 7559f55f5f5SRafal Jaworowski { 7569f55f5f5SRafal Jaworowski struct mge_softc *sc; 7579f55f5f5SRafal Jaworowski int error,i; 7589f55f5f5SRafal Jaworowski 7599f55f5f5SRafal Jaworowski sc = device_get_softc(dev); 7609f55f5f5SRafal Jaworowski 7619f55f5f5SRafal Jaworowski /* Stop controller and free TX queue */ 7629f55f5f5SRafal Jaworowski if (sc->ifp) 7639f55f5f5SRafal Jaworowski mge_shutdown(dev); 7649f55f5f5SRafal Jaworowski 7659f55f5f5SRafal Jaworowski /* Wait for stopping ticks */ 7669f55f5f5SRafal Jaworowski callout_drain(&sc->wd_callout); 7679f55f5f5SRafal Jaworowski 7689f55f5f5SRafal Jaworowski /* Stop and release all interrupts */ 76975f1438bSOleksandr Tymoshenko for (i = 0; i < sc->mge_intr_cnt; ++i) { 770a6eb469dSPhilip Paeps if (!sc->ih_cookie[i]) 771a6eb469dSPhilip Paeps continue; 772a6eb469dSPhilip Paeps 7739f55f5f5SRafal Jaworowski error = bus_teardown_intr(dev, sc->res[1 + i], sc->ih_cookie[i]); 7749f55f5f5SRafal Jaworowski if (error) 7759f55f5f5SRafal Jaworowski device_printf(dev, "could not release %s\n", 77675f1438bSOleksandr Tymoshenko mge_intrs[(sc->mge_intr_cnt == 1 ? 0 : i + 1)].description); 7779f55f5f5SRafal Jaworowski } 7789f55f5f5SRafal Jaworowski 7799f55f5f5SRafal Jaworowski /* Detach network interface */ 7809f55f5f5SRafal Jaworowski if (sc->ifp) { 7819f55f5f5SRafal Jaworowski ether_ifdetach(sc->ifp); 7829f55f5f5SRafal Jaworowski if_free(sc->ifp); 7839f55f5f5SRafal Jaworowski } 7849f55f5f5SRafal Jaworowski 7859f55f5f5SRafal Jaworowski /* Free DMA resources */ 7869f55f5f5SRafal Jaworowski mge_free_dma(sc); 7879f55f5f5SRafal Jaworowski 7889f55f5f5SRafal Jaworowski /* Free IO memory handler */ 7899f55f5f5SRafal Jaworowski bus_release_resources(dev, res_spec, sc->res); 7909f55f5f5SRafal Jaworowski 7919f55f5f5SRafal Jaworowski /* Destroy mutexes */ 7929f55f5f5SRafal Jaworowski mtx_destroy(&sc->receive_lock); 7939f55f5f5SRafal Jaworowski mtx_destroy(&sc->transmit_lock); 7949f55f5f5SRafal Jaworowski 7959f55f5f5SRafal Jaworowski return (0); 7969f55f5f5SRafal Jaworowski } 7979f55f5f5SRafal Jaworowski 7989f55f5f5SRafal Jaworowski static void 7999f55f5f5SRafal Jaworowski mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 8009f55f5f5SRafal Jaworowski { 8019f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 8029f55f5f5SRafal Jaworowski struct mii_data *mii; 8039f55f5f5SRafal Jaworowski 8049f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc); 8059f55f5f5SRafal Jaworowski 8069f55f5f5SRafal Jaworowski mii = sc->mii; 8079f55f5f5SRafal Jaworowski mii_pollstat(mii); 8089f55f5f5SRafal Jaworowski 8099f55f5f5SRafal Jaworowski ifmr->ifm_active = mii->mii_media_active; 8109f55f5f5SRafal Jaworowski ifmr->ifm_status = mii->mii_media_status; 8119f55f5f5SRafal Jaworowski 8129f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 8139f55f5f5SRafal Jaworowski } 8149f55f5f5SRafal Jaworowski 8159f55f5f5SRafal Jaworowski static uint32_t 8169f55f5f5SRafal Jaworowski mge_set_port_serial_control(uint32_t media) 8179f55f5f5SRafal Jaworowski { 8189f55f5f5SRafal Jaworowski uint32_t port_config; 8199f55f5f5SRafal Jaworowski 8209f55f5f5SRafal Jaworowski port_config = PORT_SERIAL_RES_BIT9 | PORT_SERIAL_FORCE_LINK_FAIL | 8219f55f5f5SRafal Jaworowski PORT_SERIAL_MRU(PORT_SERIAL_MRU_1552); 8229f55f5f5SRafal Jaworowski 8239f55f5f5SRafal Jaworowski if (IFM_TYPE(media) == IFM_ETHER) { 8249f55f5f5SRafal Jaworowski switch(IFM_SUBTYPE(media)) { 8259f55f5f5SRafal Jaworowski case IFM_AUTO: 8269f55f5f5SRafal Jaworowski break; 8279f55f5f5SRafal Jaworowski case IFM_1000_T: 8289f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_GMII_SPEED_1000 | 8299f55f5f5SRafal Jaworowski PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC | 8309f55f5f5SRafal Jaworowski PORT_SERIAL_SPEED_AUTONEG); 8319f55f5f5SRafal Jaworowski break; 8329f55f5f5SRafal Jaworowski case IFM_100_TX: 8339f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_MII_SPEED_100 | 8349f55f5f5SRafal Jaworowski PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC | 8359f55f5f5SRafal Jaworowski PORT_SERIAL_SPEED_AUTONEG); 8369f55f5f5SRafal Jaworowski break; 8379f55f5f5SRafal Jaworowski case IFM_10_T: 8389f55f5f5SRafal Jaworowski port_config |= (PORT_SERIAL_AUTONEG | 8399f55f5f5SRafal Jaworowski PORT_SERIAL_AUTONEG_FC | 8409f55f5f5SRafal Jaworowski PORT_SERIAL_SPEED_AUTONEG); 8419f55f5f5SRafal Jaworowski break; 8429f55f5f5SRafal Jaworowski } 8439f55f5f5SRafal Jaworowski if (media & IFM_FDX) 8449f55f5f5SRafal Jaworowski port_config |= PORT_SERIAL_FULL_DUPLEX; 8459f55f5f5SRafal Jaworowski } 8469f55f5f5SRafal Jaworowski return (port_config); 8479f55f5f5SRafal Jaworowski } 8489f55f5f5SRafal Jaworowski 8499f55f5f5SRafal Jaworowski static int 8509f55f5f5SRafal Jaworowski mge_ifmedia_upd(struct ifnet *ifp) 8519f55f5f5SRafal Jaworowski { 8529f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 8539f55f5f5SRafal Jaworowski 8549f55f5f5SRafal Jaworowski if (ifp->if_flags & IFF_UP) { 8559f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 8569f55f5f5SRafal Jaworowski 8579f55f5f5SRafal Jaworowski sc->mge_media_status = sc->mii->mii_media.ifm_media; 8589f55f5f5SRafal Jaworowski mii_mediachg(sc->mii); 8599f55f5f5SRafal Jaworowski mge_init_locked(sc); 8609f55f5f5SRafal Jaworowski 8619f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 8629f55f5f5SRafal Jaworowski } 8639f55f5f5SRafal Jaworowski 8649f55f5f5SRafal Jaworowski return (0); 8659f55f5f5SRafal Jaworowski } 8669f55f5f5SRafal Jaworowski 8679f55f5f5SRafal Jaworowski static void 8689f55f5f5SRafal Jaworowski mge_init(void *arg) 8699f55f5f5SRafal Jaworowski { 8709f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 8719f55f5f5SRafal Jaworowski 8729f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 8739f55f5f5SRafal Jaworowski 8749f55f5f5SRafal Jaworowski mge_init_locked(arg); 8759f55f5f5SRafal Jaworowski 8769f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 8779f55f5f5SRafal Jaworowski } 8789f55f5f5SRafal Jaworowski 8799f55f5f5SRafal Jaworowski static void 8809f55f5f5SRafal Jaworowski mge_init_locked(void *arg) 8819f55f5f5SRafal Jaworowski { 8829f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 8839f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 8849f55f5f5SRafal Jaworowski volatile uint32_t reg_val; 8859f55f5f5SRafal Jaworowski int i, count; 8869f55f5f5SRafal Jaworowski 8879f55f5f5SRafal Jaworowski 8889f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK_ASSERT(sc); 8899f55f5f5SRafal Jaworowski 8909f55f5f5SRafal Jaworowski /* Stop interface */ 8919f55f5f5SRafal Jaworowski mge_stop(sc); 8929f55f5f5SRafal Jaworowski 8939f55f5f5SRafal Jaworowski /* Disable interrupts */ 8949f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 8959f55f5f5SRafal Jaworowski 8969f55f5f5SRafal Jaworowski /* Set MAC address */ 8979f55f5f5SRafal Jaworowski mge_set_mac_address(sc); 8989f55f5f5SRafal Jaworowski 8999f55f5f5SRafal Jaworowski /* Setup multicast filters */ 9009f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 9019f55f5f5SRafal Jaworowski 9028e1dc58eSRafal Jaworowski if (sc->mge_ver == 2) { 9039f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL1, MGE_RGMII_EN); 9049f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_FIXED_PRIO_CONF, MGE_FIXED_PRIO_EN(0)); 9058e1dc58eSRafal Jaworowski } 9069f55f5f5SRafal Jaworowski 9078e1dc58eSRafal Jaworowski /* Initialize TX queue configuration registers */ 9088e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(0), sc->mge_tx_tok_cnt); 9098e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_CONF(0), sc->mge_tx_tok_cfg); 9108e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_ARBITER_CONF(0), sc->mge_tx_arb_cfg); 9118e1dc58eSRafal Jaworowski 9128e1dc58eSRafal Jaworowski /* Clear TX queue configuration registers for unused queues */ 9139f55f5f5SRafal Jaworowski for (i = 1; i < 7; i++) { 9148e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_COUNT(i), 0); 9158e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_TOKEN_CONF(i), 0); 9168e1dc58eSRafal Jaworowski MGE_WRITE(sc, MGE_TX_ARBITER_CONF(i), 0); 9179f55f5f5SRafal Jaworowski } 9189f55f5f5SRafal Jaworowski 9199f55f5f5SRafal Jaworowski /* Set default MTU */ 9208e1dc58eSRafal Jaworowski MGE_WRITE(sc, sc->mge_mtu, 0); 9219f55f5f5SRafal Jaworowski 9229f55f5f5SRafal Jaworowski /* Port configuration */ 9239f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_CONFIG, 9249f55f5f5SRafal Jaworowski PORT_CONFIG_RXCS | PORT_CONFIG_DFLT_RXQ(0) | 9259f55f5f5SRafal Jaworowski PORT_CONFIG_ARO_RXQ(0)); 9269f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0); 9279f55f5f5SRafal Jaworowski 9289f55f5f5SRafal Jaworowski /* Setup port configuration */ 9299f55f5f5SRafal Jaworowski reg_val = mge_set_port_serial_control(sc->mge_media_status); 9309f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val); 9319f55f5f5SRafal Jaworowski 9329f55f5f5SRafal Jaworowski /* Setup SDMA configuration */ 9339f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_SDMA_CONFIG , MGE_SDMA_RX_BYTE_SWAP | 9349f55f5f5SRafal Jaworowski MGE_SDMA_TX_BYTE_SWAP | 9359f55f5f5SRafal Jaworowski MGE_SDMA_RX_BURST_SIZE(MGE_SDMA_BURST_16_WORD) | 9369f55f5f5SRafal Jaworowski MGE_SDMA_TX_BURST_SIZE(MGE_SDMA_BURST_16_WORD)); 9379f55f5f5SRafal Jaworowski 9389f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, 0x0); 9399f55f5f5SRafal Jaworowski 9409f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_CUR_DESC_PTR, sc->tx_desc_start); 9419f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_CUR_DESC_PTR(MGE_RX_DEFAULT_QUEUE), 9429f55f5f5SRafal Jaworowski sc->rx_desc_start); 9439f55f5f5SRafal Jaworowski 9449f55f5f5SRafal Jaworowski /* Reset descriptor indexes */ 9459f55f5f5SRafal Jaworowski sc->tx_desc_curr = 0; 9469f55f5f5SRafal Jaworowski sc->rx_desc_curr = 0; 9479f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 0; 9485817716fSRafal Jaworowski sc->tx_desc_used_count = 0; 9499f55f5f5SRafal Jaworowski 9509f55f5f5SRafal Jaworowski /* Enable RX descriptors */ 9519f55f5f5SRafal Jaworowski for (i = 0; i < MGE_RX_DESC_NUM; i++) { 9529f55f5f5SRafal Jaworowski dw = &sc->mge_rx_desc[i]; 9539f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED; 9549f55f5f5SRafal Jaworowski dw->mge_desc->buff_size = MCLBYTES; 9559f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 9569f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 9579f55f5f5SRafal Jaworowski } 9589f55f5f5SRafal Jaworowski 9599f55f5f5SRafal Jaworowski /* Enable RX queue */ 9609f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_ENABLE_RXQ(MGE_RX_DEFAULT_QUEUE)); 9619f55f5f5SRafal Jaworowski 9629f55f5f5SRafal Jaworowski /* Enable port */ 9639f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL); 9649f55f5f5SRafal Jaworowski reg_val |= PORT_SERIAL_ENABLE; 9659f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val); 9669f55f5f5SRafal Jaworowski count = 0x100000; 9679f55f5f5SRafal Jaworowski for (;;) { 9689f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_STATUS); 9699f55f5f5SRafal Jaworowski if (reg_val & MGE_STATUS_LINKUP) 9709f55f5f5SRafal Jaworowski break; 9719f55f5f5SRafal Jaworowski DELAY(100); 9729f55f5f5SRafal Jaworowski if (--count == 0) { 9739f55f5f5SRafal Jaworowski if_printf(sc->ifp, "Timeout on link-up\n"); 9749f55f5f5SRafal Jaworowski break; 9759f55f5f5SRafal Jaworowski } 9769f55f5f5SRafal Jaworowski } 9779f55f5f5SRafal Jaworowski 9789f55f5f5SRafal Jaworowski /* Setup interrupts coalescing */ 9799f55f5f5SRafal Jaworowski mge_set_rxic(sc); 9809f55f5f5SRafal Jaworowski mge_set_txic(sc); 9819f55f5f5SRafal Jaworowski 9829f55f5f5SRafal Jaworowski /* Enable interrupts */ 9839f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 9849f55f5f5SRafal Jaworowski /* 9859f55f5f5SRafal Jaworowski * * ...only if polling is not turned on. Disable interrupts explicitly 9869f55f5f5SRafal Jaworowski * if polling is enabled. 9879f55f5f5SRafal Jaworowski */ 9889f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) 9899f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 9909f55f5f5SRafal Jaworowski else 9919f55f5f5SRafal Jaworowski #endif /* DEVICE_POLLING */ 9929f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 1); 9939f55f5f5SRafal Jaworowski 9949f55f5f5SRafal Jaworowski /* Activate network interface */ 9959f55f5f5SRafal Jaworowski sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 9969f55f5f5SRafal Jaworowski sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 9979f55f5f5SRafal Jaworowski sc->wd_timer = 0; 9989f55f5f5SRafal Jaworowski 9999f55f5f5SRafal Jaworowski /* Schedule watchdog timeout */ 10009f55f5f5SRafal Jaworowski callout_reset(&sc->wd_callout, hz, mge_tick, sc); 10019f55f5f5SRafal Jaworowski } 10029f55f5f5SRafal Jaworowski 10039f55f5f5SRafal Jaworowski static void 100475f1438bSOleksandr Tymoshenko mge_intr_rxtx(void *arg) 100575f1438bSOleksandr Tymoshenko { 100675f1438bSOleksandr Tymoshenko struct mge_softc *sc = arg; 100775f1438bSOleksandr Tymoshenko uint32_t int_cause, int_cause_ext; 100875f1438bSOleksandr Tymoshenko 100975f1438bSOleksandr Tymoshenko MGE_GLOBAL_LOCK(sc); 101075f1438bSOleksandr Tymoshenko 101175f1438bSOleksandr Tymoshenko #ifdef DEVICE_POLLING 101275f1438bSOleksandr Tymoshenko if (sc->ifp->if_capenable & IFCAP_POLLING) { 101375f1438bSOleksandr Tymoshenko MGE_GLOBAL_UNLOCK(sc); 101475f1438bSOleksandr Tymoshenko return; 101575f1438bSOleksandr Tymoshenko } 101675f1438bSOleksandr Tymoshenko #endif 101775f1438bSOleksandr Tymoshenko 101875f1438bSOleksandr Tymoshenko /* Get interrupt cause */ 101975f1438bSOleksandr Tymoshenko int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE); 102075f1438bSOleksandr Tymoshenko int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 102175f1438bSOleksandr Tymoshenko 102275f1438bSOleksandr Tymoshenko /* Check for Transmit interrupt */ 102375f1438bSOleksandr Tymoshenko if (int_cause_ext & (MGE_PORT_INT_EXT_TXBUF0 | 102475f1438bSOleksandr Tymoshenko MGE_PORT_INT_EXT_TXUR)) { 102575f1438bSOleksandr Tymoshenko MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext & 102675f1438bSOleksandr Tymoshenko (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR))); 102775f1438bSOleksandr Tymoshenko mge_intr_tx_locked(sc); 102875f1438bSOleksandr Tymoshenko } 102975f1438bSOleksandr Tymoshenko 103075f1438bSOleksandr Tymoshenko MGE_TRANSMIT_UNLOCK(sc); 103175f1438bSOleksandr Tymoshenko 103275f1438bSOleksandr Tymoshenko /* Check for Receive interrupt */ 103375f1438bSOleksandr Tymoshenko mge_intr_rx_check(sc, int_cause, int_cause_ext); 103475f1438bSOleksandr Tymoshenko 103575f1438bSOleksandr Tymoshenko MGE_RECEIVE_UNLOCK(sc); 103675f1438bSOleksandr Tymoshenko } 103775f1438bSOleksandr Tymoshenko 103875f1438bSOleksandr Tymoshenko static void 10399f55f5f5SRafal Jaworowski mge_intr_err(void *arg) 10409f55f5f5SRafal Jaworowski { 10419f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 10429f55f5f5SRafal Jaworowski struct ifnet *ifp; 10439f55f5f5SRafal Jaworowski 10449f55f5f5SRafal Jaworowski ifp = sc->ifp; 10459f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 10469f55f5f5SRafal Jaworowski } 10479f55f5f5SRafal Jaworowski 10489f55f5f5SRafal Jaworowski static void 10499f55f5f5SRafal Jaworowski mge_intr_misc(void *arg) 10509f55f5f5SRafal Jaworowski { 10519f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 10529f55f5f5SRafal Jaworowski struct ifnet *ifp; 10539f55f5f5SRafal Jaworowski 10549f55f5f5SRafal Jaworowski ifp = sc->ifp; 10559f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 10569f55f5f5SRafal Jaworowski } 10579f55f5f5SRafal Jaworowski 10589f55f5f5SRafal Jaworowski static void 10599f55f5f5SRafal Jaworowski mge_intr_rx(void *arg) { 10609f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 10619f55f5f5SRafal Jaworowski uint32_t int_cause, int_cause_ext; 10629f55f5f5SRafal Jaworowski 10639f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc); 10649f55f5f5SRafal Jaworowski 10659f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 10669f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) { 10679f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc); 10689f55f5f5SRafal Jaworowski return; 10699f55f5f5SRafal Jaworowski } 10709f55f5f5SRafal Jaworowski #endif 10719f55f5f5SRafal Jaworowski 10729f55f5f5SRafal Jaworowski /* Get interrupt cause */ 10739f55f5f5SRafal Jaworowski int_cause = MGE_READ(sc, MGE_PORT_INT_CAUSE); 10749f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 10759f55f5f5SRafal Jaworowski 107675f1438bSOleksandr Tymoshenko mge_intr_rx_check(sc, int_cause, int_cause_ext); 107775f1438bSOleksandr Tymoshenko 107875f1438bSOleksandr Tymoshenko MGE_RECEIVE_UNLOCK(sc); 107975f1438bSOleksandr Tymoshenko } 108075f1438bSOleksandr Tymoshenko 108175f1438bSOleksandr Tymoshenko static void 108275f1438bSOleksandr Tymoshenko mge_intr_rx_check(struct mge_softc *sc, uint32_t int_cause, 108375f1438bSOleksandr Tymoshenko uint32_t int_cause_ext) 108475f1438bSOleksandr Tymoshenko { 10859f55f5f5SRafal Jaworowski /* Check for resource error */ 10869f55f5f5SRafal Jaworowski if (int_cause & MGE_PORT_INT_RXERRQ0) { 10879f55f5f5SRafal Jaworowski mge_reinit_rx(sc); 10889f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 108975f1438bSOleksandr Tymoshenko ~(int_cause & MGE_PORT_INT_RXERRQ0)); 10909f55f5f5SRafal Jaworowski } 10919f55f5f5SRafal Jaworowski 10929f55f5f5SRafal Jaworowski int_cause &= MGE_PORT_INT_RXQ0; 10939f55f5f5SRafal Jaworowski int_cause_ext &= MGE_PORT_INT_EXT_RXOR; 10949f55f5f5SRafal Jaworowski 10959f55f5f5SRafal Jaworowski if (int_cause || int_cause_ext) { 10969f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, ~int_cause); 10979f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~int_cause_ext); 10989f55f5f5SRafal Jaworowski mge_intr_rx_locked(sc, -1); 10999f55f5f5SRafal Jaworowski } 11009f55f5f5SRafal Jaworowski } 11019f55f5f5SRafal Jaworowski 11021abcdbd1SAttilio Rao static int 11039f55f5f5SRafal Jaworowski mge_intr_rx_locked(struct mge_softc *sc, int count) 11049f55f5f5SRafal Jaworowski { 11059f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 11069f55f5f5SRafal Jaworowski uint32_t status; 11079f55f5f5SRafal Jaworowski uint16_t bufsize; 11089f55f5f5SRafal Jaworowski struct mge_desc_wrapper* dw; 11099f55f5f5SRafal Jaworowski struct mbuf *mb; 11101abcdbd1SAttilio Rao int rx_npkts = 0; 11119f55f5f5SRafal Jaworowski 11129f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK_ASSERT(sc); 11139f55f5f5SRafal Jaworowski 11149f55f5f5SRafal Jaworowski while (count != 0) { 11159f55f5f5SRafal Jaworowski dw = &sc->mge_rx_desc[sc->rx_desc_curr]; 11169f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 11179f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 11189f55f5f5SRafal Jaworowski 11199f55f5f5SRafal Jaworowski /* Get status */ 11209f55f5f5SRafal Jaworowski status = dw->mge_desc->cmd_status; 11219f55f5f5SRafal Jaworowski bufsize = dw->mge_desc->buff_size; 11229f55f5f5SRafal Jaworowski if ((status & MGE_DMA_OWNED) != 0) 11239f55f5f5SRafal Jaworowski break; 11249f55f5f5SRafal Jaworowski 11259f55f5f5SRafal Jaworowski if (dw->mge_desc->byte_count && 11269f55f5f5SRafal Jaworowski ~(status & MGE_ERR_SUMMARY)) { 11279f55f5f5SRafal Jaworowski 11289f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_rx_dtag, dw->buffer_dmap, 11299f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 11309f55f5f5SRafal Jaworowski 11319f55f5f5SRafal Jaworowski mb = m_devget(dw->buffer->m_data, 11329f55f5f5SRafal Jaworowski dw->mge_desc->byte_count - ETHER_CRC_LEN, 11339f55f5f5SRafal Jaworowski 0, ifp, NULL); 11349f55f5f5SRafal Jaworowski 11355817716fSRafal Jaworowski if (mb == NULL) 11365817716fSRafal Jaworowski /* Give up if no mbufs */ 11375817716fSRafal Jaworowski break; 11385817716fSRafal Jaworowski 11399f55f5f5SRafal Jaworowski mb->m_len -= 2; 11409f55f5f5SRafal Jaworowski mb->m_pkthdr.len -= 2; 11419f55f5f5SRafal Jaworowski mb->m_data += 2; 11429f55f5f5SRafal Jaworowski 1143*b8fad6c0SFabien Thomas mb->m_pkthdr.rcvif = ifp; 1144*b8fad6c0SFabien Thomas 11459f55f5f5SRafal Jaworowski mge_offload_process_frame(ifp, mb, status, 11469f55f5f5SRafal Jaworowski bufsize); 11479f55f5f5SRafal Jaworowski 11489f55f5f5SRafal Jaworowski MGE_RECEIVE_UNLOCK(sc); 11499f55f5f5SRafal Jaworowski (*ifp->if_input)(ifp, mb); 11509f55f5f5SRafal Jaworowski MGE_RECEIVE_LOCK(sc); 11511abcdbd1SAttilio Rao rx_npkts++; 11529f55f5f5SRafal Jaworowski } 11539f55f5f5SRafal Jaworowski 11549f55f5f5SRafal Jaworowski dw->mge_desc->byte_count = 0; 11559f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED; 11565817716fSRafal Jaworowski sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM); 11579f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 11589f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 11599f55f5f5SRafal Jaworowski 11609f55f5f5SRafal Jaworowski if (count > 0) 11619f55f5f5SRafal Jaworowski count -= 1; 11629f55f5f5SRafal Jaworowski } 11639f55f5f5SRafal Jaworowski 1164*b8fad6c0SFabien Thomas ifp->if_ipackets += rx_npkts; 1165*b8fad6c0SFabien Thomas 11661abcdbd1SAttilio Rao return (rx_npkts); 11679f55f5f5SRafal Jaworowski } 11689f55f5f5SRafal Jaworowski 11699f55f5f5SRafal Jaworowski static void 11709f55f5f5SRafal Jaworowski mge_intr_sum(void *arg) 11719f55f5f5SRafal Jaworowski { 11729f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 11739f55f5f5SRafal Jaworowski struct ifnet *ifp; 11749f55f5f5SRafal Jaworowski 11759f55f5f5SRafal Jaworowski ifp = sc->ifp; 11769f55f5f5SRafal Jaworowski if_printf(ifp, "%s\n", __FUNCTION__); 11779f55f5f5SRafal Jaworowski } 11789f55f5f5SRafal Jaworowski 11799f55f5f5SRafal Jaworowski static void 11809f55f5f5SRafal Jaworowski mge_intr_tx(void *arg) 11819f55f5f5SRafal Jaworowski { 11829f55f5f5SRafal Jaworowski struct mge_softc *sc = arg; 11839f55f5f5SRafal Jaworowski uint32_t int_cause_ext; 11849f55f5f5SRafal Jaworowski 11859f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc); 11869f55f5f5SRafal Jaworowski 11879f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 11889f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) { 11899f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 11909f55f5f5SRafal Jaworowski return; 11919f55f5f5SRafal Jaworowski } 11929f55f5f5SRafal Jaworowski #endif 11939f55f5f5SRafal Jaworowski 11949f55f5f5SRafal Jaworowski /* Ack the interrupt */ 11959f55f5f5SRafal Jaworowski int_cause_ext = MGE_READ(sc, MGE_PORT_INT_CAUSE_EXT); 119675f1438bSOleksandr Tymoshenko MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, ~(int_cause_ext & 119775f1438bSOleksandr Tymoshenko (MGE_PORT_INT_EXT_TXBUF0 | MGE_PORT_INT_EXT_TXUR))); 11989f55f5f5SRafal Jaworowski 11999f55f5f5SRafal Jaworowski mge_intr_tx_locked(sc); 12009f55f5f5SRafal Jaworowski 12019f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 12029f55f5f5SRafal Jaworowski } 12039f55f5f5SRafal Jaworowski 12049f55f5f5SRafal Jaworowski 12059f55f5f5SRafal Jaworowski static void 12069f55f5f5SRafal Jaworowski mge_intr_tx_locked(struct mge_softc *sc) 12079f55f5f5SRafal Jaworowski { 12089f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 12099f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 12109f55f5f5SRafal Jaworowski struct mge_desc *desc; 12119f55f5f5SRafal Jaworowski uint32_t status; 12129f55f5f5SRafal Jaworowski int send = 0; 12139f55f5f5SRafal Jaworowski 12149f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK_ASSERT(sc); 12159f55f5f5SRafal Jaworowski 12169f55f5f5SRafal Jaworowski /* Disable watchdog */ 12179f55f5f5SRafal Jaworowski sc->wd_timer = 0; 12189f55f5f5SRafal Jaworowski 12199f55f5f5SRafal Jaworowski while (sc->tx_desc_used_count) { 12209f55f5f5SRafal Jaworowski /* Get the descriptor */ 12219f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[sc->tx_desc_used_idx]; 12229f55f5f5SRafal Jaworowski desc = dw->mge_desc; 12239f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 12249f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 12259f55f5f5SRafal Jaworowski 12269f55f5f5SRafal Jaworowski /* Get descriptor status */ 12279f55f5f5SRafal Jaworowski status = desc->cmd_status; 12289f55f5f5SRafal Jaworowski 12299f55f5f5SRafal Jaworowski if (status & MGE_DMA_OWNED) 12309f55f5f5SRafal Jaworowski break; 12319f55f5f5SRafal Jaworowski 12329f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = 1233c2ede4b3SMartin Blapp (++sc->tx_desc_used_idx) % MGE_TX_DESC_NUM; 12349f55f5f5SRafal Jaworowski sc->tx_desc_used_count--; 12359f55f5f5SRafal Jaworowski 12369f55f5f5SRafal Jaworowski /* Update collision statistics */ 12379f55f5f5SRafal Jaworowski if (status & MGE_ERR_SUMMARY) { 12389f55f5f5SRafal Jaworowski if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_LC) 12399f55f5f5SRafal Jaworowski ifp->if_collisions++; 12409f55f5f5SRafal Jaworowski if ((status & MGE_ERR_MASK) == MGE_TX_ERROR_RL) 12419f55f5f5SRafal Jaworowski ifp->if_collisions += 16; 12429f55f5f5SRafal Jaworowski } 12439f55f5f5SRafal Jaworowski 12449f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap, 12459f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 12469f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap); 12479f55f5f5SRafal Jaworowski m_freem(dw->buffer); 12489f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 12499f55f5f5SRafal Jaworowski send++; 12509f55f5f5SRafal Jaworowski 12519f55f5f5SRafal Jaworowski ifp->if_opackets++; 12529f55f5f5SRafal Jaworowski } 12539f55f5f5SRafal Jaworowski 12549f55f5f5SRafal Jaworowski if (send) { 12559f55f5f5SRafal Jaworowski /* Now send anything that was pending */ 12569f55f5f5SRafal Jaworowski ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 12579f55f5f5SRafal Jaworowski mge_start_locked(ifp); 12589f55f5f5SRafal Jaworowski } 12599f55f5f5SRafal Jaworowski } 12609f55f5f5SRafal Jaworowski 12619f55f5f5SRafal Jaworowski static int 12629f55f5f5SRafal Jaworowski mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 12639f55f5f5SRafal Jaworowski { 12649f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 12659f55f5f5SRafal Jaworowski struct ifreq *ifr = (struct ifreq *)data; 12669f55f5f5SRafal Jaworowski int mask, error; 12679f55f5f5SRafal Jaworowski uint32_t flags; 12689f55f5f5SRafal Jaworowski 12699f55f5f5SRafal Jaworowski error = 0; 12709f55f5f5SRafal Jaworowski 12719f55f5f5SRafal Jaworowski switch (command) { 12729f55f5f5SRafal Jaworowski case SIOCSIFFLAGS: 12739f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 12749f55f5f5SRafal Jaworowski 12759f55f5f5SRafal Jaworowski if (ifp->if_flags & IFF_UP) { 12769f55f5f5SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 12779f55f5f5SRafal Jaworowski flags = ifp->if_flags ^ sc->mge_if_flags; 12789f55f5f5SRafal Jaworowski if (flags & IFF_PROMISC) 12799f55f5f5SRafal Jaworowski mge_set_prom_mode(sc, 12809f55f5f5SRafal Jaworowski MGE_RX_DEFAULT_QUEUE); 12819f55f5f5SRafal Jaworowski 12829f55f5f5SRafal Jaworowski if (flags & IFF_ALLMULTI) 12839f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 12849f55f5f5SRafal Jaworowski } else 12859f55f5f5SRafal Jaworowski mge_init_locked(sc); 12869f55f5f5SRafal Jaworowski } 12879f55f5f5SRafal Jaworowski else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 12889f55f5f5SRafal Jaworowski mge_stop(sc); 12899f55f5f5SRafal Jaworowski 12909f55f5f5SRafal Jaworowski sc->mge_if_flags = ifp->if_flags; 12919f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 12929f55f5f5SRafal Jaworowski break; 12939f55f5f5SRafal Jaworowski case SIOCADDMULTI: 12949f55f5f5SRafal Jaworowski case SIOCDELMULTI: 12959f55f5f5SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 12969f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 12979f55f5f5SRafal Jaworowski mge_setup_multicast(sc); 12989f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 12999f55f5f5SRafal Jaworowski } 13009f55f5f5SRafal Jaworowski break; 13019f55f5f5SRafal Jaworowski case SIOCSIFCAP: 13029f55f5f5SRafal Jaworowski mask = ifp->if_capenable ^ ifr->ifr_reqcap; 13039f55f5f5SRafal Jaworowski if (mask & IFCAP_HWCSUM) { 13049f55f5f5SRafal Jaworowski ifp->if_capenable &= ~IFCAP_HWCSUM; 13059f55f5f5SRafal Jaworowski ifp->if_capenable |= IFCAP_HWCSUM & ifr->ifr_reqcap; 13069f55f5f5SRafal Jaworowski if (ifp->if_capenable & IFCAP_TXCSUM) 13079f55f5f5SRafal Jaworowski ifp->if_hwassist = MGE_CHECKSUM_FEATURES; 13089f55f5f5SRafal Jaworowski else 13099f55f5f5SRafal Jaworowski ifp->if_hwassist = 0; 13109f55f5f5SRafal Jaworowski } 13119f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 13129f55f5f5SRafal Jaworowski if (mask & IFCAP_POLLING) { 13139f55f5f5SRafal Jaworowski if (ifr->ifr_reqcap & IFCAP_POLLING) { 13149f55f5f5SRafal Jaworowski error = ether_poll_register(mge_poll, ifp); 13159f55f5f5SRafal Jaworowski if (error) 13169f55f5f5SRafal Jaworowski return(error); 13179f55f5f5SRafal Jaworowski 13189f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 13199f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 13209f55f5f5SRafal Jaworowski ifp->if_capenable |= IFCAP_POLLING; 13219f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 13229f55f5f5SRafal Jaworowski } else { 13239f55f5f5SRafal Jaworowski error = ether_poll_deregister(ifp); 13249f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 13259f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 1); 13269f55f5f5SRafal Jaworowski ifp->if_capenable &= ~IFCAP_POLLING; 13279f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 13289f55f5f5SRafal Jaworowski } 13299f55f5f5SRafal Jaworowski } 13309f55f5f5SRafal Jaworowski #endif 13319f55f5f5SRafal Jaworowski break; 13329f55f5f5SRafal Jaworowski case SIOCGIFMEDIA: /* fall through */ 13339f55f5f5SRafal Jaworowski case SIOCSIFMEDIA: 13349f55f5f5SRafal Jaworowski if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T 13359f55f5f5SRafal Jaworowski && !(ifr->ifr_media & IFM_FDX)) { 13369f55f5f5SRafal Jaworowski device_printf(sc->dev, 13379f55f5f5SRafal Jaworowski "1000baseTX half-duplex unsupported\n"); 13389f55f5f5SRafal Jaworowski return 0; 13399f55f5f5SRafal Jaworowski } 13409f55f5f5SRafal Jaworowski error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command); 13419f55f5f5SRafal Jaworowski break; 13429f55f5f5SRafal Jaworowski default: 13439f55f5f5SRafal Jaworowski error = ether_ioctl(ifp, command, data); 13449f55f5f5SRafal Jaworowski } 13459f55f5f5SRafal Jaworowski return (error); 13469f55f5f5SRafal Jaworowski } 13479f55f5f5SRafal Jaworowski 13489f55f5f5SRafal Jaworowski static int 13499f55f5f5SRafal Jaworowski mge_miibus_readreg(device_t dev, int phy, int reg) 13509f55f5f5SRafal Jaworowski { 1351db5ef4fcSRafal Jaworowski struct mge_softc *sc; 13529f55f5f5SRafal Jaworowski uint32_t retries; 13539f55f5f5SRafal Jaworowski 1354db5ef4fcSRafal Jaworowski sc = device_get_softc(dev); 13559f55f5f5SRafal Jaworowski 1356aa15e881SRafal Jaworowski MGE_WRITE(sc->phy_sc, MGE_REG_SMI, 0x1fffffff & 13579f55f5f5SRafal Jaworowski (MGE_SMI_READ | (reg << 21) | (phy << 16))); 13589f55f5f5SRafal Jaworowski 13599f55f5f5SRafal Jaworowski retries = MGE_SMI_READ_RETRIES; 1360aa15e881SRafal Jaworowski while (--retries && 1361aa15e881SRafal Jaworowski !(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID)) 13629f55f5f5SRafal Jaworowski DELAY(MGE_SMI_READ_DELAY); 13639f55f5f5SRafal Jaworowski 13649f55f5f5SRafal Jaworowski if (retries == 0) 13659f55f5f5SRafal Jaworowski device_printf(dev, "Timeout while reading from PHY\n"); 13669f55f5f5SRafal Jaworowski 1367aa15e881SRafal Jaworowski return (MGE_READ(sc->phy_sc, MGE_REG_SMI) & 0xffff); 13689f55f5f5SRafal Jaworowski } 13699f55f5f5SRafal Jaworowski 13708e45f0b7SAndriy Gapon static int 13719f55f5f5SRafal Jaworowski mge_miibus_writereg(device_t dev, int phy, int reg, int value) 13729f55f5f5SRafal Jaworowski { 1373db5ef4fcSRafal Jaworowski struct mge_softc *sc; 13749f55f5f5SRafal Jaworowski uint32_t retries; 13759f55f5f5SRafal Jaworowski 1376db5ef4fcSRafal Jaworowski sc = device_get_softc(dev); 1377db5ef4fcSRafal Jaworowski 1378aa15e881SRafal Jaworowski MGE_WRITE(sc->phy_sc, MGE_REG_SMI, 0x1fffffff & 13799f55f5f5SRafal Jaworowski (MGE_SMI_WRITE | (reg << 21) | (phy << 16) | (value & 0xffff))); 13809f55f5f5SRafal Jaworowski 13819f55f5f5SRafal Jaworowski retries = MGE_SMI_WRITE_RETRIES; 1382aa15e881SRafal Jaworowski while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY) 13839f55f5f5SRafal Jaworowski DELAY(MGE_SMI_WRITE_DELAY); 13849f55f5f5SRafal Jaworowski 13859f55f5f5SRafal Jaworowski if (retries == 0) 13869f55f5f5SRafal Jaworowski device_printf(dev, "Timeout while writing to PHY\n"); 13878e45f0b7SAndriy Gapon return (0); 13889f55f5f5SRafal Jaworowski } 13899f55f5f5SRafal Jaworowski 13909f55f5f5SRafal Jaworowski static int 13919f55f5f5SRafal Jaworowski mge_probe(device_t dev) 13929f55f5f5SRafal Jaworowski { 13939f55f5f5SRafal Jaworowski 1394add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 1395add35ed5SIan Lepore return (ENXIO); 1396add35ed5SIan Lepore 1397db5ef4fcSRafal Jaworowski if (!ofw_bus_is_compatible(dev, "mrvl,ge")) 1398db5ef4fcSRafal Jaworowski return (ENXIO); 1399db5ef4fcSRafal Jaworowski 14009f55f5f5SRafal Jaworowski device_set_desc(dev, "Marvell Gigabit Ethernet controller"); 14019f55f5f5SRafal Jaworowski return (BUS_PROBE_DEFAULT); 14029f55f5f5SRafal Jaworowski } 14039f55f5f5SRafal Jaworowski 14049f55f5f5SRafal Jaworowski static int 14059f55f5f5SRafal Jaworowski mge_resume(device_t dev) 14069f55f5f5SRafal Jaworowski { 14079f55f5f5SRafal Jaworowski 14089f55f5f5SRafal Jaworowski device_printf(dev, "%s\n", __FUNCTION__); 14099f55f5f5SRafal Jaworowski return (0); 14109f55f5f5SRafal Jaworowski } 14119f55f5f5SRafal Jaworowski 14129f55f5f5SRafal Jaworowski static int 14139f55f5f5SRafal Jaworowski mge_shutdown(device_t dev) 14149f55f5f5SRafal Jaworowski { 14159f55f5f5SRafal Jaworowski struct mge_softc *sc = device_get_softc(dev); 14169f55f5f5SRafal Jaworowski 14179f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 14189f55f5f5SRafal Jaworowski 14199f55f5f5SRafal Jaworowski #ifdef DEVICE_POLLING 14209f55f5f5SRafal Jaworowski if (sc->ifp->if_capenable & IFCAP_POLLING) 14219f55f5f5SRafal Jaworowski ether_poll_deregister(sc->ifp); 14229f55f5f5SRafal Jaworowski #endif 14239f55f5f5SRafal Jaworowski 14249f55f5f5SRafal Jaworowski mge_stop(sc); 14259f55f5f5SRafal Jaworowski 14269f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 14279f55f5f5SRafal Jaworowski 14289f55f5f5SRafal Jaworowski return (0); 14299f55f5f5SRafal Jaworowski } 14309f55f5f5SRafal Jaworowski 14319f55f5f5SRafal Jaworowski static int 14329f55f5f5SRafal Jaworowski mge_encap(struct mge_softc *sc, struct mbuf *m0) 14339f55f5f5SRafal Jaworowski { 14349f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw = NULL; 14359f55f5f5SRafal Jaworowski struct ifnet *ifp; 14369f55f5f5SRafal Jaworowski bus_dma_segment_t segs[MGE_TX_DESC_NUM]; 14379f55f5f5SRafal Jaworowski bus_dmamap_t mapp; 14389f55f5f5SRafal Jaworowski int error; 14399f55f5f5SRafal Jaworowski int seg, nsegs; 14409f55f5f5SRafal Jaworowski int desc_no; 14419f55f5f5SRafal Jaworowski 14429f55f5f5SRafal Jaworowski ifp = sc->ifp; 14439f55f5f5SRafal Jaworowski 14449f55f5f5SRafal Jaworowski /* Fetch unused map */ 14459f55f5f5SRafal Jaworowski desc_no = sc->tx_desc_curr; 14469f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[desc_no]; 14479f55f5f5SRafal Jaworowski mapp = dw->buffer_dmap; 14489f55f5f5SRafal Jaworowski 14499f55f5f5SRafal Jaworowski /* Create mapping in DMA memory */ 14509f55f5f5SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(sc->mge_tx_dtag, mapp, m0, segs, &nsegs, 14519f55f5f5SRafal Jaworowski BUS_DMA_NOWAIT); 1452*b8fad6c0SFabien Thomas if (error != 0) { 1453*b8fad6c0SFabien Thomas m_freem(m0); 1454*b8fad6c0SFabien Thomas return (error); 1455*b8fad6c0SFabien Thomas } 1456*b8fad6c0SFabien Thomas 1457*b8fad6c0SFabien Thomas /* Only one segment is supported. */ 1458*b8fad6c0SFabien Thomas if (nsegs != 1) { 14599f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, mapp); 1460*b8fad6c0SFabien Thomas m_freem(m0); 1461*b8fad6c0SFabien Thomas return (-1); 14629f55f5f5SRafal Jaworowski } 14639f55f5f5SRafal Jaworowski 14649f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, mapp, BUS_DMASYNC_PREWRITE); 14659f55f5f5SRafal Jaworowski 14669f55f5f5SRafal Jaworowski /* Everything is ok, now we can send buffers */ 14679f55f5f5SRafal Jaworowski for (seg = 0; seg < nsegs; seg++) { 14689f55f5f5SRafal Jaworowski dw->mge_desc->byte_count = segs[seg].ds_len; 14699f55f5f5SRafal Jaworowski dw->mge_desc->buffer = segs[seg].ds_addr; 14709f55f5f5SRafal Jaworowski dw->buffer = m0; 147175f1438bSOleksandr Tymoshenko dw->mge_desc->cmd_status = 0; 14729f55f5f5SRafal Jaworowski if (seg == 0) 14739f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(sc, dw); 147475f1438bSOleksandr Tymoshenko dw->mge_desc->cmd_status |= MGE_TX_LAST | MGE_TX_FIRST | 147575f1438bSOleksandr Tymoshenko MGE_TX_ETH_CRC | MGE_TX_EN_INT | MGE_TX_PADDING | 147675f1438bSOleksandr Tymoshenko MGE_DMA_OWNED; 14779f55f5f5SRafal Jaworowski } 14789f55f5f5SRafal Jaworowski 1479d6bdd318SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 14809f55f5f5SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 14819f55f5f5SRafal Jaworowski 14829f55f5f5SRafal Jaworowski sc->tx_desc_curr = (++sc->tx_desc_curr) % MGE_TX_DESC_NUM; 14839f55f5f5SRafal Jaworowski sc->tx_desc_used_count++; 14849f55f5f5SRafal Jaworowski return (0); 14859f55f5f5SRafal Jaworowski } 14869f55f5f5SRafal Jaworowski 14879f55f5f5SRafal Jaworowski static void 14889f55f5f5SRafal Jaworowski mge_tick(void *msc) 14899f55f5f5SRafal Jaworowski { 14909f55f5f5SRafal Jaworowski struct mge_softc *sc = msc; 14919f55f5f5SRafal Jaworowski 14929f55f5f5SRafal Jaworowski /* Check for TX timeout */ 14939f55f5f5SRafal Jaworowski mge_watchdog(sc); 14949f55f5f5SRafal Jaworowski 14959f55f5f5SRafal Jaworowski mii_tick(sc->mii); 14969f55f5f5SRafal Jaworowski 14979f55f5f5SRafal Jaworowski /* Check for media type change */ 14989f55f5f5SRafal Jaworowski if(sc->mge_media_status != sc->mii->mii_media.ifm_media) 14999f55f5f5SRafal Jaworowski mge_ifmedia_upd(sc->ifp); 15009f55f5f5SRafal Jaworowski 15019f55f5f5SRafal Jaworowski /* Schedule another timeout one second from now */ 15029f55f5f5SRafal Jaworowski callout_reset(&sc->wd_callout, hz, mge_tick, sc); 15039f55f5f5SRafal Jaworowski } 15049f55f5f5SRafal Jaworowski 15059f55f5f5SRafal Jaworowski static void 15069f55f5f5SRafal Jaworowski mge_watchdog(struct mge_softc *sc) 15079f55f5f5SRafal Jaworowski { 15089f55f5f5SRafal Jaworowski struct ifnet *ifp; 15099f55f5f5SRafal Jaworowski 15109f55f5f5SRafal Jaworowski ifp = sc->ifp; 15119f55f5f5SRafal Jaworowski 15129f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 15139f55f5f5SRafal Jaworowski 15149f55f5f5SRafal Jaworowski if (sc->wd_timer == 0 || --sc->wd_timer) { 15159f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 15169f55f5f5SRafal Jaworowski return; 15179f55f5f5SRafal Jaworowski } 15189f55f5f5SRafal Jaworowski 15199f55f5f5SRafal Jaworowski ifp->if_oerrors++; 15209f55f5f5SRafal Jaworowski if_printf(ifp, "watchdog timeout\n"); 15219f55f5f5SRafal Jaworowski 15229f55f5f5SRafal Jaworowski mge_stop(sc); 15239f55f5f5SRafal Jaworowski mge_init_locked(sc); 15249f55f5f5SRafal Jaworowski 15259f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 15269f55f5f5SRafal Jaworowski } 15279f55f5f5SRafal Jaworowski 15289f55f5f5SRafal Jaworowski static void 15299f55f5f5SRafal Jaworowski mge_start(struct ifnet *ifp) 15309f55f5f5SRafal Jaworowski { 15319f55f5f5SRafal Jaworowski struct mge_softc *sc = ifp->if_softc; 15329f55f5f5SRafal Jaworowski 15339f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK(sc); 15349f55f5f5SRafal Jaworowski 15359f55f5f5SRafal Jaworowski mge_start_locked(ifp); 15369f55f5f5SRafal Jaworowski 15379f55f5f5SRafal Jaworowski MGE_TRANSMIT_UNLOCK(sc); 15389f55f5f5SRafal Jaworowski } 15399f55f5f5SRafal Jaworowski 15409f55f5f5SRafal Jaworowski static void 15419f55f5f5SRafal Jaworowski mge_start_locked(struct ifnet *ifp) 15429f55f5f5SRafal Jaworowski { 15439f55f5f5SRafal Jaworowski struct mge_softc *sc; 15449f55f5f5SRafal Jaworowski struct mbuf *m0, *mtmp; 15459f55f5f5SRafal Jaworowski uint32_t reg_val, queued = 0; 15469f55f5f5SRafal Jaworowski 15479f55f5f5SRafal Jaworowski sc = ifp->if_softc; 15489f55f5f5SRafal Jaworowski 15499f55f5f5SRafal Jaworowski MGE_TRANSMIT_LOCK_ASSERT(sc); 15509f55f5f5SRafal Jaworowski 15519f55f5f5SRafal Jaworowski if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 15529f55f5f5SRafal Jaworowski IFF_DRV_RUNNING) 15539f55f5f5SRafal Jaworowski return; 15549f55f5f5SRafal Jaworowski 15559f55f5f5SRafal Jaworowski for (;;) { 15569f55f5f5SRafal Jaworowski /* Get packet from the queue */ 15579f55f5f5SRafal Jaworowski IF_DEQUEUE(&ifp->if_snd, m0); 15589f55f5f5SRafal Jaworowski if (m0 == NULL) 15599f55f5f5SRafal Jaworowski break; 15609f55f5f5SRafal Jaworowski 1561*b8fad6c0SFabien Thomas if (m0->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP) || 1562*b8fad6c0SFabien Thomas m0->m_flags & M_VLANTAG) { 1563*b8fad6c0SFabien Thomas if (M_WRITABLE(m0) == 0) { 1564*b8fad6c0SFabien Thomas mtmp = m_dup(m0, M_NOWAIT); 1565*b8fad6c0SFabien Thomas m_freem(m0); 1566*b8fad6c0SFabien Thomas if (mtmp == NULL) 1567*b8fad6c0SFabien Thomas continue; 1568*b8fad6c0SFabien Thomas m0 = mtmp; 1569*b8fad6c0SFabien Thomas } 1570*b8fad6c0SFabien Thomas } 1571*b8fad6c0SFabien Thomas /* The driver support only one DMA fragment. */ 1572*b8fad6c0SFabien Thomas if (m0->m_next != NULL) { 1573c6499eccSGleb Smirnoff mtmp = m_defrag(m0, M_NOWAIT); 15749f55f5f5SRafal Jaworowski if (mtmp) 15759f55f5f5SRafal Jaworowski m0 = mtmp; 1576*b8fad6c0SFabien Thomas } 15779f55f5f5SRafal Jaworowski 1578*b8fad6c0SFabien Thomas /* Check for free descriptors */ 1579*b8fad6c0SFabien Thomas if (sc->tx_desc_used_count + 1 >= MGE_TX_DESC_NUM) { 15809f55f5f5SRafal Jaworowski IF_PREPEND(&ifp->if_snd, m0); 15819f55f5f5SRafal Jaworowski ifp->if_drv_flags |= IFF_DRV_OACTIVE; 15829f55f5f5SRafal Jaworowski break; 15839f55f5f5SRafal Jaworowski } 1584*b8fad6c0SFabien Thomas 1585*b8fad6c0SFabien Thomas if (mge_encap(sc, m0) != 0) 1586*b8fad6c0SFabien Thomas break; 1587*b8fad6c0SFabien Thomas 15889f55f5f5SRafal Jaworowski queued++; 15899f55f5f5SRafal Jaworowski BPF_MTAP(ifp, m0); 15909f55f5f5SRafal Jaworowski } 15919f55f5f5SRafal Jaworowski 15929f55f5f5SRafal Jaworowski if (queued) { 15939f55f5f5SRafal Jaworowski /* Enable transmitter and watchdog timer */ 15949f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD); 15959f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_ENABLE_TXQ); 15969f55f5f5SRafal Jaworowski sc->wd_timer = 5; 15979f55f5f5SRafal Jaworowski } 15989f55f5f5SRafal Jaworowski } 15999f55f5f5SRafal Jaworowski 16009f55f5f5SRafal Jaworowski static void 16019f55f5f5SRafal Jaworowski mge_stop(struct mge_softc *sc) 16029f55f5f5SRafal Jaworowski { 16039f55f5f5SRafal Jaworowski struct ifnet *ifp; 16049f55f5f5SRafal Jaworowski volatile uint32_t reg_val, status; 16059f55f5f5SRafal Jaworowski struct mge_desc_wrapper *dw; 16069f55f5f5SRafal Jaworowski struct mge_desc *desc; 16079f55f5f5SRafal Jaworowski int count; 16089f55f5f5SRafal Jaworowski 16099f55f5f5SRafal Jaworowski ifp = sc->ifp; 16109f55f5f5SRafal Jaworowski 16119f55f5f5SRafal Jaworowski if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 16129f55f5f5SRafal Jaworowski return; 16139f55f5f5SRafal Jaworowski 16149f55f5f5SRafal Jaworowski /* Stop tick engine */ 16159f55f5f5SRafal Jaworowski callout_stop(&sc->wd_callout); 16169f55f5f5SRafal Jaworowski 16179f55f5f5SRafal Jaworowski /* Disable interface */ 16189f55f5f5SRafal Jaworowski ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 16199f55f5f5SRafal Jaworowski sc->wd_timer = 0; 16209f55f5f5SRafal Jaworowski 16219f55f5f5SRafal Jaworowski /* Disable interrupts */ 16229f55f5f5SRafal Jaworowski mge_intrs_ctrl(sc, 0); 16239f55f5f5SRafal Jaworowski 16249f55f5f5SRafal Jaworowski /* Disable Rx and Tx */ 16259f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_TX_QUEUE_CMD); 16269f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_QUEUE_CMD, reg_val | MGE_DISABLE_TXQ); 16279f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL); 16289f55f5f5SRafal Jaworowski 16299f55f5f5SRafal Jaworowski /* Remove pending data from TX queue */ 16305817716fSRafal Jaworowski while (sc->tx_desc_used_idx != sc->tx_desc_curr && 16315817716fSRafal Jaworowski sc->tx_desc_used_count) { 16329f55f5f5SRafal Jaworowski /* Get the descriptor */ 16339f55f5f5SRafal Jaworowski dw = &sc->mge_tx_desc[sc->tx_desc_used_idx]; 16349f55f5f5SRafal Jaworowski desc = dw->mge_desc; 16359f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap, 16369f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTREAD); 16379f55f5f5SRafal Jaworowski 16389f55f5f5SRafal Jaworowski /* Get descriptor status */ 16399f55f5f5SRafal Jaworowski status = desc->cmd_status; 16409f55f5f5SRafal Jaworowski 16419f55f5f5SRafal Jaworowski if (status & MGE_DMA_OWNED) 16429f55f5f5SRafal Jaworowski break; 16439f55f5f5SRafal Jaworowski 16449f55f5f5SRafal Jaworowski sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) % 16459f55f5f5SRafal Jaworowski MGE_TX_DESC_NUM; 16465817716fSRafal Jaworowski sc->tx_desc_used_count--; 16479f55f5f5SRafal Jaworowski 16489f55f5f5SRafal Jaworowski bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap, 16499f55f5f5SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 16509f55f5f5SRafal Jaworowski bus_dmamap_unload(sc->mge_tx_dtag, dw->buffer_dmap); 16519f55f5f5SRafal Jaworowski 16529f55f5f5SRafal Jaworowski m_freem(dw->buffer); 16539f55f5f5SRafal Jaworowski dw->buffer = (struct mbuf*)NULL; 16549f55f5f5SRafal Jaworowski } 16559f55f5f5SRafal Jaworowski 16569f55f5f5SRafal Jaworowski /* Wait for end of transmission */ 16579f55f5f5SRafal Jaworowski count = 0x100000; 16589f55f5f5SRafal Jaworowski while (count--) { 16599f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_STATUS); 16609f55f5f5SRafal Jaworowski if ( !(reg_val & MGE_STATUS_TX_IN_PROG) && 16619f55f5f5SRafal Jaworowski (reg_val & MGE_STATUS_TX_FIFO_EMPTY)) 16629f55f5f5SRafal Jaworowski break; 16639f55f5f5SRafal Jaworowski DELAY(100); 16649f55f5f5SRafal Jaworowski } 16659f55f5f5SRafal Jaworowski 16669f55f5f5SRafal Jaworowski if(!count) 16679f55f5f5SRafal Jaworowski if_printf(ifp, "%s: timeout while waiting for end of transmission\n", 16689f55f5f5SRafal Jaworowski __FUNCTION__); 16699f55f5f5SRafal Jaworowski 16709f55f5f5SRafal Jaworowski reg_val = MGE_READ(sc, MGE_PORT_SERIAL_CTRL); 16719f55f5f5SRafal Jaworowski reg_val &= ~(PORT_SERIAL_ENABLE); 16729f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL ,reg_val); 16739f55f5f5SRafal Jaworowski } 16749f55f5f5SRafal Jaworowski 16759f55f5f5SRafal Jaworowski static int 16769f55f5f5SRafal Jaworowski mge_suspend(device_t dev) 16779f55f5f5SRafal Jaworowski { 16789f55f5f5SRafal Jaworowski 16799f55f5f5SRafal Jaworowski device_printf(dev, "%s\n", __FUNCTION__); 16809f55f5f5SRafal Jaworowski return (0); 16819f55f5f5SRafal Jaworowski } 16829f55f5f5SRafal Jaworowski 16839f55f5f5SRafal Jaworowski static void 16849f55f5f5SRafal Jaworowski mge_offload_process_frame(struct ifnet *ifp, struct mbuf *frame, 16859f55f5f5SRafal Jaworowski uint32_t status, uint16_t bufsize) 16869f55f5f5SRafal Jaworowski { 16879f55f5f5SRafal Jaworowski int csum_flags = 0; 16889f55f5f5SRafal Jaworowski 16899f55f5f5SRafal Jaworowski if (ifp->if_capenable & IFCAP_RXCSUM) { 16909f55f5f5SRafal Jaworowski if ((status & MGE_RX_L3_IS_IP) && (status & MGE_RX_IP_OK)) 16919f55f5f5SRafal Jaworowski csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID; 16929f55f5f5SRafal Jaworowski 16939f55f5f5SRafal Jaworowski if ((bufsize & MGE_RX_IP_FRAGMENT) == 0 && 16949f55f5f5SRafal Jaworowski (MGE_RX_L4_IS_TCP(status) || MGE_RX_L4_IS_UDP(status)) && 16959f55f5f5SRafal Jaworowski (status & MGE_RX_L4_CSUM_OK)) { 16969f55f5f5SRafal Jaworowski csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 16979f55f5f5SRafal Jaworowski frame->m_pkthdr.csum_data = 0xFFFF; 16989f55f5f5SRafal Jaworowski } 16999f55f5f5SRafal Jaworowski 17009f55f5f5SRafal Jaworowski frame->m_pkthdr.csum_flags = csum_flags; 17019f55f5f5SRafal Jaworowski } 17029f55f5f5SRafal Jaworowski } 17039f55f5f5SRafal Jaworowski 17049f55f5f5SRafal Jaworowski static void 17059f55f5f5SRafal Jaworowski mge_offload_setup_descriptor(struct mge_softc *sc, struct mge_desc_wrapper *dw) 17069f55f5f5SRafal Jaworowski { 17079f55f5f5SRafal Jaworowski struct mbuf *m0 = dw->buffer; 17089f55f5f5SRafal Jaworowski struct ether_vlan_header *eh = mtod(m0, struct ether_vlan_header *); 17099f55f5f5SRafal Jaworowski int csum_flags = m0->m_pkthdr.csum_flags; 17109f55f5f5SRafal Jaworowski int cmd_status = 0; 17119f55f5f5SRafal Jaworowski struct ip *ip; 17129f55f5f5SRafal Jaworowski int ehlen, etype; 17139f55f5f5SRafal Jaworowski 17149f55f5f5SRafal Jaworowski if (csum_flags) { 17159f55f5f5SRafal Jaworowski if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 17169f55f5f5SRafal Jaworowski etype = ntohs(eh->evl_proto); 17179f55f5f5SRafal Jaworowski ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 17189f55f5f5SRafal Jaworowski csum_flags |= MGE_TX_VLAN_TAGGED; 17199f55f5f5SRafal Jaworowski } else { 17209f55f5f5SRafal Jaworowski etype = ntohs(eh->evl_encap_proto); 17219f55f5f5SRafal Jaworowski ehlen = ETHER_HDR_LEN; 17229f55f5f5SRafal Jaworowski } 17239f55f5f5SRafal Jaworowski 17249f55f5f5SRafal Jaworowski if (etype != ETHERTYPE_IP) { 17259f55f5f5SRafal Jaworowski if_printf(sc->ifp, 17269f55f5f5SRafal Jaworowski "TCP/IP Offload enabled for unsupported " 17279f55f5f5SRafal Jaworowski "protocol!\n"); 17289f55f5f5SRafal Jaworowski return; 17299f55f5f5SRafal Jaworowski } 17309f55f5f5SRafal Jaworowski 17319f55f5f5SRafal Jaworowski ip = (struct ip *)(m0->m_data + ehlen); 17329f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_IP_HDR_SIZE(ip->ip_hl); 17339f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_NOT_FRAGMENT; 17349f55f5f5SRafal Jaworowski } 17359f55f5f5SRafal Jaworowski 17369f55f5f5SRafal Jaworowski if (csum_flags & CSUM_IP) 17379f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_IP_CSUM; 17389f55f5f5SRafal Jaworowski 17399f55f5f5SRafal Jaworowski if (csum_flags & CSUM_TCP) 17409f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_L4_CSUM; 17419f55f5f5SRafal Jaworowski 17429f55f5f5SRafal Jaworowski if (csum_flags & CSUM_UDP) 17439f55f5f5SRafal Jaworowski cmd_status |= MGE_TX_GEN_L4_CSUM | MGE_TX_UDP; 17449f55f5f5SRafal Jaworowski 17459f55f5f5SRafal Jaworowski dw->mge_desc->cmd_status |= cmd_status; 17469f55f5f5SRafal Jaworowski } 17479f55f5f5SRafal Jaworowski 17489f55f5f5SRafal Jaworowski static void 17499f55f5f5SRafal Jaworowski mge_intrs_ctrl(struct mge_softc *sc, int enable) 17509f55f5f5SRafal Jaworowski { 17519f55f5f5SRafal Jaworowski 17529f55f5f5SRafal Jaworowski if (enable) { 17539f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK , MGE_PORT_INT_RXQ0 | 17549f55f5f5SRafal Jaworowski MGE_PORT_INT_EXTEND | MGE_PORT_INT_RXERRQ0); 17559f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT , MGE_PORT_INT_EXT_TXERR0 | 17569f55f5f5SRafal Jaworowski MGE_PORT_INT_EXT_RXOR | MGE_PORT_INT_EXT_TXUR | 17579f55f5f5SRafal Jaworowski MGE_PORT_INT_EXT_TXBUF0); 17589f55f5f5SRafal Jaworowski } else { 17599f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_INT_CAUSE, 0x0); 17609f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_INT_MASK, 0x0); 17619f55f5f5SRafal Jaworowski 17629f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE, 0x0); 17639f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_CAUSE_EXT, 0x0); 17649f55f5f5SRafal Jaworowski 17659f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK, 0x0); 17669f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_PORT_INT_MASK_EXT, 0x0); 17679f55f5f5SRafal Jaworowski } 17689f55f5f5SRafal Jaworowski } 17699f55f5f5SRafal Jaworowski 17709f55f5f5SRafal Jaworowski static uint8_t 17719f55f5f5SRafal Jaworowski mge_crc8(uint8_t *data, int size) 17729f55f5f5SRafal Jaworowski { 17739f55f5f5SRafal Jaworowski uint8_t crc = 0; 17749f55f5f5SRafal Jaworowski static const uint8_t ct[256] = { 17759f55f5f5SRafal Jaworowski 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 17769f55f5f5SRafal Jaworowski 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 17779f55f5f5SRafal Jaworowski 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 17789f55f5f5SRafal Jaworowski 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 17799f55f5f5SRafal Jaworowski 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 17809f55f5f5SRafal Jaworowski 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, 17819f55f5f5SRafal Jaworowski 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 17829f55f5f5SRafal Jaworowski 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, 17839f55f5f5SRafal Jaworowski 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 17849f55f5f5SRafal Jaworowski 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 17859f55f5f5SRafal Jaworowski 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 17869f55f5f5SRafal Jaworowski 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, 17879f55f5f5SRafal Jaworowski 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 17889f55f5f5SRafal Jaworowski 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, 17899f55f5f5SRafal Jaworowski 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 17909f55f5f5SRafal Jaworowski 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 17919f55f5f5SRafal Jaworowski 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 17929f55f5f5SRafal Jaworowski 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 17939f55f5f5SRafal Jaworowski 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 17949f55f5f5SRafal Jaworowski 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, 17959f55f5f5SRafal Jaworowski 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 17969f55f5f5SRafal Jaworowski 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 17979f55f5f5SRafal Jaworowski 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 17989f55f5f5SRafal Jaworowski 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, 17999f55f5f5SRafal Jaworowski 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 18009f55f5f5SRafal Jaworowski 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, 18019f55f5f5SRafal Jaworowski 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 18029f55f5f5SRafal Jaworowski 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 18039f55f5f5SRafal Jaworowski 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 18049f55f5f5SRafal Jaworowski 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, 18059f55f5f5SRafal Jaworowski 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 18069f55f5f5SRafal Jaworowski 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 18079f55f5f5SRafal Jaworowski }; 18089f55f5f5SRafal Jaworowski 18099f55f5f5SRafal Jaworowski while(size--) 18109f55f5f5SRafal Jaworowski crc = ct[crc ^ *(data++)]; 18119f55f5f5SRafal Jaworowski 18129f55f5f5SRafal Jaworowski return(crc); 18139f55f5f5SRafal Jaworowski } 18149f55f5f5SRafal Jaworowski 18159f55f5f5SRafal Jaworowski static void 18169f55f5f5SRafal Jaworowski mge_setup_multicast(struct mge_softc *sc) 18179f55f5f5SRafal Jaworowski { 18189f55f5f5SRafal Jaworowski uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 }; 18199f55f5f5SRafal Jaworowski uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1; 18209f55f5f5SRafal Jaworowski uint32_t smt[MGE_MCAST_REG_NUMBER]; 18219f55f5f5SRafal Jaworowski uint32_t omt[MGE_MCAST_REG_NUMBER]; 18229f55f5f5SRafal Jaworowski struct ifnet *ifp = sc->ifp; 18239f55f5f5SRafal Jaworowski struct ifmultiaddr *ifma; 18249f55f5f5SRafal Jaworowski uint8_t *mac; 18259f55f5f5SRafal Jaworowski int i; 18269f55f5f5SRafal Jaworowski 18279f55f5f5SRafal Jaworowski if (ifp->if_flags & IFF_ALLMULTI) { 18289f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) 18299f55f5f5SRafal Jaworowski smt[i] = omt[i] = (v << 24) | (v << 16) | (v << 8) | v; 18309f55f5f5SRafal Jaworowski } else { 18319f55f5f5SRafal Jaworowski memset(smt, 0, sizeof(smt)); 18329f55f5f5SRafal Jaworowski memset(omt, 0, sizeof(omt)); 18339f55f5f5SRafal Jaworowski 1834eb956cd0SRobert Watson if_maddr_rlock(ifp); 18359f55f5f5SRafal Jaworowski TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 18369f55f5f5SRafal Jaworowski if (ifma->ifma_addr->sa_family != AF_LINK) 18379f55f5f5SRafal Jaworowski continue; 18389f55f5f5SRafal Jaworowski 18399f55f5f5SRafal Jaworowski mac = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 18409f55f5f5SRafal Jaworowski if (memcmp(mac, special, sizeof(special)) == 0) { 18419f55f5f5SRafal Jaworowski i = mac[5]; 18429f55f5f5SRafal Jaworowski smt[i >> 2] |= v << ((i & 0x03) << 3); 18439f55f5f5SRafal Jaworowski } else { 18449f55f5f5SRafal Jaworowski i = mge_crc8(mac, ETHER_ADDR_LEN); 18459f55f5f5SRafal Jaworowski omt[i >> 2] |= v << ((i & 0x03) << 3); 18469f55f5f5SRafal Jaworowski } 18479f55f5f5SRafal Jaworowski } 1848eb956cd0SRobert Watson if_maddr_runlock(ifp); 18499f55f5f5SRafal Jaworowski } 18509f55f5f5SRafal Jaworowski 18519f55f5f5SRafal Jaworowski for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { 18529f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), smt[i]); 18539f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), omt[i]); 18549f55f5f5SRafal Jaworowski } 18559f55f5f5SRafal Jaworowski } 18569f55f5f5SRafal Jaworowski 18579f55f5f5SRafal Jaworowski static void 18589f55f5f5SRafal Jaworowski mge_set_rxic(struct mge_softc *sc) 18599f55f5f5SRafal Jaworowski { 18609f55f5f5SRafal Jaworowski uint32_t reg; 18619f55f5f5SRafal Jaworowski 18628e1dc58eSRafal Jaworowski if (sc->rx_ic_time > sc->mge_rx_ipg_max) 18638e1dc58eSRafal Jaworowski sc->rx_ic_time = sc->mge_rx_ipg_max; 18649f55f5f5SRafal Jaworowski 18659f55f5f5SRafal Jaworowski reg = MGE_READ(sc, MGE_SDMA_CONFIG); 18668e1dc58eSRafal Jaworowski reg &= ~mge_rx_ipg(sc->mge_rx_ipg_max, sc->mge_ver); 18678e1dc58eSRafal Jaworowski reg |= mge_rx_ipg(sc->rx_ic_time, sc->mge_ver); 18689f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_SDMA_CONFIG, reg); 18699f55f5f5SRafal Jaworowski } 18709f55f5f5SRafal Jaworowski 18719f55f5f5SRafal Jaworowski static void 18729f55f5f5SRafal Jaworowski mge_set_txic(struct mge_softc *sc) 18739f55f5f5SRafal Jaworowski { 18749f55f5f5SRafal Jaworowski uint32_t reg; 18759f55f5f5SRafal Jaworowski 18768e1dc58eSRafal Jaworowski if (sc->tx_ic_time > sc->mge_tfut_ipg_max) 18778e1dc58eSRafal Jaworowski sc->tx_ic_time = sc->mge_tfut_ipg_max; 18789f55f5f5SRafal Jaworowski 18799f55f5f5SRafal Jaworowski reg = MGE_READ(sc, MGE_TX_FIFO_URGENT_TRSH); 18808e1dc58eSRafal Jaworowski reg &= ~mge_tfut_ipg(sc->mge_tfut_ipg_max, sc->mge_ver); 18818e1dc58eSRafal Jaworowski reg |= mge_tfut_ipg(sc->tx_ic_time, sc->mge_ver); 18829f55f5f5SRafal Jaworowski MGE_WRITE(sc, MGE_TX_FIFO_URGENT_TRSH, reg); 18839f55f5f5SRafal Jaworowski } 18849f55f5f5SRafal Jaworowski 18859f55f5f5SRafal Jaworowski static int 18869f55f5f5SRafal Jaworowski mge_sysctl_ic(SYSCTL_HANDLER_ARGS) 18879f55f5f5SRafal Jaworowski { 18889f55f5f5SRafal Jaworowski struct mge_softc *sc = (struct mge_softc *)arg1; 18898e1dc58eSRafal Jaworowski uint32_t time; 18909f55f5f5SRafal Jaworowski int error; 18919f55f5f5SRafal Jaworowski 18928e1dc58eSRafal Jaworowski time = (arg2 == MGE_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time; 18939f55f5f5SRafal Jaworowski error = sysctl_handle_int(oidp, &time, 0, req); 18949f55f5f5SRafal Jaworowski if (error != 0) 18959f55f5f5SRafal Jaworowski return(error); 18969f55f5f5SRafal Jaworowski 18979f55f5f5SRafal Jaworowski MGE_GLOBAL_LOCK(sc); 18989f55f5f5SRafal Jaworowski if (arg2 == MGE_IC_RX) { 18999f55f5f5SRafal Jaworowski sc->rx_ic_time = time; 19009f55f5f5SRafal Jaworowski mge_set_rxic(sc); 19019f55f5f5SRafal Jaworowski } else { 19029f55f5f5SRafal Jaworowski sc->tx_ic_time = time; 19039f55f5f5SRafal Jaworowski mge_set_txic(sc); 19049f55f5f5SRafal Jaworowski } 19059f55f5f5SRafal Jaworowski MGE_GLOBAL_UNLOCK(sc); 19069f55f5f5SRafal Jaworowski 19079f55f5f5SRafal Jaworowski return(0); 19089f55f5f5SRafal Jaworowski } 19099f55f5f5SRafal Jaworowski 19109f55f5f5SRafal Jaworowski static void 19119f55f5f5SRafal Jaworowski mge_add_sysctls(struct mge_softc *sc) 19129f55f5f5SRafal Jaworowski { 19139f55f5f5SRafal Jaworowski struct sysctl_ctx_list *ctx; 19149f55f5f5SRafal Jaworowski struct sysctl_oid_list *children; 19159f55f5f5SRafal Jaworowski struct sysctl_oid *tree; 19169f55f5f5SRafal Jaworowski 19179f55f5f5SRafal Jaworowski ctx = device_get_sysctl_ctx(sc->dev); 19189f55f5f5SRafal Jaworowski children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 19199f55f5f5SRafal Jaworowski tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal", 19209f55f5f5SRafal Jaworowski CTLFLAG_RD, 0, "MGE Interrupts coalescing"); 19219f55f5f5SRafal Jaworowski children = SYSCTL_CHILDREN(tree); 19229f55f5f5SRafal Jaworowski 19239f55f5f5SRafal Jaworowski SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time", 19249f55f5f5SRafal Jaworowski CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_RX, mge_sysctl_ic, 19259f55f5f5SRafal Jaworowski "I", "IC RX time threshold"); 19269f55f5f5SRafal Jaworowski SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time", 19279f55f5f5SRafal Jaworowski CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_TX, mge_sysctl_ic, 19289f55f5f5SRafal Jaworowski "I", "IC TX time threshold"); 19299f55f5f5SRafal Jaworowski } 1930