1188808Sgonzo/*- 2188808Sgonzo * Copyright (c) 2009, Oleksandr Tymoshenko 3188808Sgonzo * All rights reserved. 4188808Sgonzo * 5188808Sgonzo * Redistribution and use in source and binary forms, with or without 6188808Sgonzo * modification, are permitted provided that the following conditions 7188808Sgonzo * are met: 8188808Sgonzo * 1. Redistributions of source code must retain the above copyright 9188808Sgonzo * notice unmodified, this list of conditions, and the following 10188808Sgonzo * disclaimer. 11188808Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12188808Sgonzo * notice, this list of conditions and the following disclaimer in the 13188808Sgonzo * documentation and/or other materials provided with the distribution. 14188808Sgonzo * 15188808Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16188808Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17188808Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18188808Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19188808Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20188808Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21188808Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22188808Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23188808Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24188808Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25188808Sgonzo * SUCH DAMAGE. 26188808Sgonzo */ 27188808Sgonzo 28188808Sgonzo#include <sys/cdefs.h> 29188808Sgonzo__FBSDID("$FreeBSD$"); 30188808Sgonzo 31188808Sgonzo/* 32188808Sgonzo * AR71XX gigabit ethernet driver 33188808Sgonzo */ 34192783Sgonzo#ifdef HAVE_KERNEL_OPTION_HEADERS 35192783Sgonzo#include "opt_device_polling.h" 36192783Sgonzo#endif 37192783Sgonzo 38234859Sadrian#include "opt_arge.h" 39234859Sadrian 40188808Sgonzo#include <sys/param.h> 41188808Sgonzo#include <sys/endian.h> 42188808Sgonzo#include <sys/systm.h> 43188808Sgonzo#include <sys/sockio.h> 44188808Sgonzo#include <sys/mbuf.h> 45188808Sgonzo#include <sys/malloc.h> 46188808Sgonzo#include <sys/kernel.h> 47188808Sgonzo#include <sys/module.h> 48188808Sgonzo#include <sys/socket.h> 49188808Sgonzo#include <sys/taskqueue.h> 50209802Sadrian#include <sys/sysctl.h> 51188808Sgonzo 52188808Sgonzo#include <net/if.h> 53188808Sgonzo#include <net/if_arp.h> 54188808Sgonzo#include <net/ethernet.h> 55188808Sgonzo#include <net/if_dl.h> 56188808Sgonzo#include <net/if_media.h> 57188808Sgonzo#include <net/if_types.h> 58188808Sgonzo 59188808Sgonzo#include <net/bpf.h> 60188808Sgonzo 61188808Sgonzo#include <machine/bus.h> 62188808Sgonzo#include <machine/cache.h> 63188808Sgonzo#include <machine/resource.h> 64188808Sgonzo#include <vm/vm_param.h> 65188808Sgonzo#include <vm/vm.h> 66188808Sgonzo#include <vm/pmap.h> 67188808Sgonzo#include <machine/pmap.h> 68188808Sgonzo#include <sys/bus.h> 69188808Sgonzo#include <sys/rman.h> 70188808Sgonzo 71188808Sgonzo#include <dev/mii/mii.h> 72188808Sgonzo#include <dev/mii/miivar.h> 73188808Sgonzo 74188808Sgonzo#include <dev/pci/pcireg.h> 75188808Sgonzo#include <dev/pci/pcivar.h> 76188808Sgonzo 77234862Sadrian#include "opt_arge.h" 78234862Sadrian 79234862Sadrian#if defined(ARGE_MDIO) 80234862Sadrian#include <dev/etherswitch/mdio.h> 81234862Sadrian#include <dev/etherswitch/miiproxy.h> 82234862Sadrian#include "mdio_if.h" 83234862Sadrian#endif 84234862Sadrian 85234862Sadrian 86188808SgonzoMODULE_DEPEND(arge, ether, 1, 1, 1); 87188808SgonzoMODULE_DEPEND(arge, miibus, 1, 1, 1); 88234862SadrianMODULE_VERSION(arge, 1); 89188808Sgonzo 90188808Sgonzo#include "miibus_if.h" 91188808Sgonzo 92188808Sgonzo#include <mips/atheros/ar71xxreg.h> 93188808Sgonzo#include <mips/atheros/if_argevar.h> 94219589Sadrian#include <mips/atheros/ar71xx_setup.h> 95211477Sadrian#include <mips/atheros/ar71xx_cpudef.h> 96188808Sgonzo 97220354Sadriantypedef enum { 98220354Sadrian ARGE_DBG_MII = 0x00000001, 99220356Sadrian ARGE_DBG_INTR = 0x00000002, 100220356Sadrian ARGE_DBG_TX = 0x00000004, 101220356Sadrian ARGE_DBG_RX = 0x00000008, 102220356Sadrian ARGE_DBG_ERR = 0x00000010, 103220356Sadrian ARGE_DBG_RESET = 0x00000020, 104234919Sadrian ARGE_DBG_PLL = 0x00000040, 105220354Sadrian} arge_debug_flags; 106220354Sadrian 107234910Sadrianstatic const char * arge_miicfg_str[] = { 108234910Sadrian "NONE", 109234910Sadrian "GMII", 110234910Sadrian "MII", 111234910Sadrian "RGMII", 112234910Sadrian "RMII" 113234910Sadrian}; 114234910Sadrian 115188808Sgonzo#ifdef ARGE_DEBUG 116220354Sadrian#define ARGEDEBUG(_sc, _m, ...) \ 117220354Sadrian do { \ 118220354Sadrian if ((_m) & (_sc)->arge_debug) \ 119220354Sadrian device_printf((_sc)->arge_dev, __VA_ARGS__); \ 120220354Sadrian } while (0) 121188808Sgonzo#else 122220354Sadrian#define ARGEDEBUG(_sc, _m, ...) 123188808Sgonzo#endif 124188808Sgonzo 125188808Sgonzostatic int arge_attach(device_t); 126188808Sgonzostatic int arge_detach(device_t); 127188808Sgonzostatic void arge_flush_ddr(struct arge_softc *); 128188808Sgonzostatic int arge_ifmedia_upd(struct ifnet *); 129188808Sgonzostatic void arge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 130188808Sgonzostatic int arge_ioctl(struct ifnet *, u_long, caddr_t); 131188808Sgonzostatic void arge_init(void *); 132188808Sgonzostatic void arge_init_locked(struct arge_softc *); 133188808Sgonzostatic void arge_link_task(void *, int); 134232914Sadrianstatic void arge_update_link_locked(struct arge_softc *sc); 135199234Sgonzostatic void arge_set_pll(struct arge_softc *, int, int); 136188808Sgonzostatic int arge_miibus_readreg(device_t, int, int); 137188808Sgonzostatic void arge_miibus_statchg(device_t); 138188808Sgonzostatic int arge_miibus_writereg(device_t, int, int, int); 139188808Sgonzostatic int arge_probe(device_t); 140188808Sgonzostatic void arge_reset_dma(struct arge_softc *); 141188808Sgonzostatic int arge_resume(device_t); 142188808Sgonzostatic int arge_rx_ring_init(struct arge_softc *); 143232912Sadrianstatic void arge_rx_ring_free(struct arge_softc *sc); 144188808Sgonzostatic int arge_tx_ring_init(struct arge_softc *); 145255300Sloosstatic void arge_tx_ring_free(struct arge_softc *); 146192821Sgonzo#ifdef DEVICE_POLLING 147198667Sgonzostatic int arge_poll(struct ifnet *, enum poll_cmd, int); 148192821Sgonzo#endif 149194059Sgonzostatic int arge_shutdown(device_t); 150188808Sgonzostatic void arge_start(struct ifnet *); 151188808Sgonzostatic void arge_start_locked(struct ifnet *); 152188808Sgonzostatic void arge_stop(struct arge_softc *); 153188808Sgonzostatic int arge_suspend(device_t); 154188808Sgonzo 155198667Sgonzostatic int arge_rx_locked(struct arge_softc *); 156188808Sgonzostatic void arge_tx_locked(struct arge_softc *); 157188808Sgonzostatic void arge_intr(void *); 158188808Sgonzostatic int arge_intr_filter(void *); 159188808Sgonzostatic void arge_tick(void *); 160188808Sgonzo 161234862Sadrianstatic void arge_hinted_child(device_t bus, const char *dname, int dunit); 162234862Sadrian 163199234Sgonzo/* 164199234Sgonzo * ifmedia callbacks for multiPHY MAC 165199234Sgonzo */ 166199234Sgonzovoid arge_multiphy_mediastatus(struct ifnet *, struct ifmediareq *); 167199234Sgonzoint arge_multiphy_mediachange(struct ifnet *); 168199234Sgonzo 169188808Sgonzostatic void arge_dmamap_cb(void *, bus_dma_segment_t *, int, int); 170188808Sgonzostatic int arge_dma_alloc(struct arge_softc *); 171188808Sgonzostatic void arge_dma_free(struct arge_softc *); 172188808Sgonzostatic int arge_newbuf(struct arge_softc *, int); 173188808Sgonzostatic __inline void arge_fixup_rx(struct mbuf *); 174188808Sgonzo 175188808Sgonzostatic device_method_t arge_methods[] = { 176188808Sgonzo /* Device interface */ 177188808Sgonzo DEVMETHOD(device_probe, arge_probe), 178188808Sgonzo DEVMETHOD(device_attach, arge_attach), 179188808Sgonzo DEVMETHOD(device_detach, arge_detach), 180188808Sgonzo DEVMETHOD(device_suspend, arge_suspend), 181188808Sgonzo DEVMETHOD(device_resume, arge_resume), 182188808Sgonzo DEVMETHOD(device_shutdown, arge_shutdown), 183188808Sgonzo 184188808Sgonzo /* MII interface */ 185188808Sgonzo DEVMETHOD(miibus_readreg, arge_miibus_readreg), 186188808Sgonzo DEVMETHOD(miibus_writereg, arge_miibus_writereg), 187188808Sgonzo DEVMETHOD(miibus_statchg, arge_miibus_statchg), 188188808Sgonzo 189234862Sadrian /* bus interface */ 190234862Sadrian DEVMETHOD(bus_add_child, device_add_child_ordered), 191234862Sadrian DEVMETHOD(bus_hinted_child, arge_hinted_child), 192234862Sadrian 193227843Smarius DEVMETHOD_END 194188808Sgonzo}; 195188808Sgonzo 196188808Sgonzostatic driver_t arge_driver = { 197188808Sgonzo "arge", 198188808Sgonzo arge_methods, 199188808Sgonzo sizeof(struct arge_softc) 200188808Sgonzo}; 201188808Sgonzo 202188808Sgonzostatic devclass_t arge_devclass; 203188808Sgonzo 204188808SgonzoDRIVER_MODULE(arge, nexus, arge_driver, arge_devclass, 0, 0); 205188808SgonzoDRIVER_MODULE(miibus, arge, miibus_driver, miibus_devclass, 0, 0); 206188808Sgonzo 207234862Sadrian#if defined(ARGE_MDIO) 208234862Sadrianstatic int argemdio_probe(device_t); 209234862Sadrianstatic int argemdio_attach(device_t); 210234862Sadrianstatic int argemdio_detach(device_t); 211234862Sadrian 212188808Sgonzo/* 213234862Sadrian * Declare an additional, separate driver for accessing the MDIO bus. 214234862Sadrian */ 215234862Sadrianstatic device_method_t argemdio_methods[] = { 216234862Sadrian /* Device interface */ 217234862Sadrian DEVMETHOD(device_probe, argemdio_probe), 218234862Sadrian DEVMETHOD(device_attach, argemdio_attach), 219234862Sadrian DEVMETHOD(device_detach, argemdio_detach), 220234862Sadrian 221234862Sadrian /* bus interface */ 222234862Sadrian DEVMETHOD(bus_add_child, device_add_child_ordered), 223234862Sadrian 224234862Sadrian /* MDIO access */ 225234862Sadrian DEVMETHOD(mdio_readreg, arge_miibus_readreg), 226234862Sadrian DEVMETHOD(mdio_writereg, arge_miibus_writereg), 227234862Sadrian}; 228234862Sadrian 229234862SadrianDEFINE_CLASS_0(argemdio, argemdio_driver, argemdio_methods, 230234862Sadrian sizeof(struct arge_softc)); 231234862Sadrianstatic devclass_t argemdio_devclass; 232234862Sadrian 233234862SadrianDRIVER_MODULE(miiproxy, arge, miiproxy_driver, miiproxy_devclass, 0, 0); 234234862SadrianDRIVER_MODULE(argemdio, nexus, argemdio_driver, argemdio_devclass, 0, 0); 235234862SadrianDRIVER_MODULE(mdio, argemdio, mdio_driver, mdio_devclass, 0, 0); 236234862Sadrian#endif 237234862Sadrian 238234862Sadrian/* 239232627Sray * RedBoot passes MAC address to entry point as environment 240192179Sgonzo * variable. platfrom_start parses it and stores in this variable 241192179Sgonzo */ 242192179Sgonzoextern uint32_t ar711_base_mac[ETHER_ADDR_LEN]; 243192179Sgonzo 244199038Sgonzostatic struct mtx miibus_mtx; 245199038Sgonzo 246206400SgonzoMTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_DEF); 247199038Sgonzo 248192179Sgonzo/* 249232627Sray * Flushes all 250188808Sgonzo */ 251188808Sgonzostatic void 252188808Sgonzoarge_flush_ddr(struct arge_softc *sc) 253188808Sgonzo{ 254228064Sray 255228064Sray ar71xx_device_flush_ddr_ge(sc->arge_mac_unit); 256188808Sgonzo} 257188808Sgonzo 258232627Sraystatic int 259188808Sgonzoarge_probe(device_t dev) 260188808Sgonzo{ 261188808Sgonzo 262188808Sgonzo device_set_desc(dev, "Atheros AR71xx built-in ethernet interface"); 263188808Sgonzo return (0); 264188808Sgonzo} 265188808Sgonzo 266209802Sadrianstatic void 267209802Sadrianarge_attach_sysctl(device_t dev) 268209802Sadrian{ 269209802Sadrian struct arge_softc *sc = device_get_softc(dev); 270209802Sadrian struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 271209802Sadrian struct sysctl_oid *tree = device_get_sysctl_tree(dev); 272209802Sadrian 273220355Sadrian#ifdef ARGE_DEBUG 274209802Sadrian SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 275209802Sadrian "debug", CTLFLAG_RW, &sc->arge_debug, 0, 276209802Sadrian "arge interface debugging flags"); 277220355Sadrian#endif 278209809Sadrian 279209809Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 280209809Sadrian "tx_pkts_aligned", CTLFLAG_RW, &sc->stats.tx_pkts_aligned, 0, 281209809Sadrian "number of TX aligned packets"); 282209809Sadrian 283209809Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 284232628Sray "tx_pkts_unaligned", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned, 285232628Sray 0, "number of TX unaligned packets"); 286220354Sadrian 287220355Sadrian#ifdef ARGE_DEBUG 288220355Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_prod", 289220355Sadrian CTLFLAG_RW, &sc->arge_cdata.arge_tx_prod, 0, ""); 290220355Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cons", 291220355Sadrian CTLFLAG_RW, &sc->arge_cdata.arge_tx_cons, 0, ""); 292220355Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cnt", 293220355Sadrian CTLFLAG_RW, &sc->arge_cdata.arge_tx_cnt, 0, ""); 294220355Sadrian#endif 295209802Sadrian} 296209802Sadrian 297234862Sadrianstatic void 298234862Sadrianarge_reset_mac(struct arge_softc *sc) 299234862Sadrian{ 300234862Sadrian uint32_t reg; 301234862Sadrian 302234862Sadrian /* Step 1. Soft-reset MAC */ 303234862Sadrian ARGE_SET_BITS(sc, AR71XX_MAC_CFG1, MAC_CFG1_SOFT_RESET); 304234862Sadrian DELAY(20); 305234862Sadrian 306234862Sadrian /* Step 2. Punt the MAC core from the central reset register */ 307234862Sadrian ar71xx_device_stop(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC : 308234862Sadrian RST_RESET_GE1_MAC); 309234862Sadrian DELAY(100); 310234862Sadrian ar71xx_device_start(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC : 311234862Sadrian RST_RESET_GE1_MAC); 312234862Sadrian 313234862Sadrian /* Step 3. Reconfigure MAC block */ 314234862Sadrian ARGE_WRITE(sc, AR71XX_MAC_CFG1, 315234862Sadrian MAC_CFG1_SYNC_RX | MAC_CFG1_RX_ENABLE | 316234862Sadrian MAC_CFG1_SYNC_TX | MAC_CFG1_TX_ENABLE); 317234862Sadrian 318234862Sadrian reg = ARGE_READ(sc, AR71XX_MAC_CFG2); 319234862Sadrian reg |= MAC_CFG2_ENABLE_PADCRC | MAC_CFG2_LENGTH_FIELD ; 320234862Sadrian ARGE_WRITE(sc, AR71XX_MAC_CFG2, reg); 321234862Sadrian 322234862Sadrian ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536); 323234862Sadrian} 324234862Sadrian 325234862Sadrianstatic void 326234862Sadrianarge_reset_miibus(struct arge_softc *sc) 327234862Sadrian{ 328234862Sadrian 329234862Sadrian /* Reset MII bus */ 330234862Sadrian ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET); 331234862Sadrian DELAY(100); 332234862Sadrian ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_CLOCK_DIV_28); 333234862Sadrian DELAY(100); 334234862Sadrian} 335234862Sadrian 336234919Sadrianstatic void 337234919Sadrianarge_fetch_pll_config(struct arge_softc *sc) 338234919Sadrian{ 339234919Sadrian long int val; 340234919Sadrian 341234919Sadrian if (resource_long_value(device_get_name(sc->arge_dev), 342234919Sadrian device_get_unit(sc->arge_dev), 343234919Sadrian "pll_10", &val) == 0) { 344234919Sadrian sc->arge_pllcfg.pll_10 = val; 345234919Sadrian device_printf(sc->arge_dev, "%s: pll_10 = 0x%x\n", 346234919Sadrian __func__, (int) val); 347234919Sadrian } 348234919Sadrian if (resource_long_value(device_get_name(sc->arge_dev), 349234919Sadrian device_get_unit(sc->arge_dev), 350234919Sadrian "pll_100", &val) == 0) { 351234919Sadrian sc->arge_pllcfg.pll_100 = val; 352234919Sadrian device_printf(sc->arge_dev, "%s: pll_100 = 0x%x\n", 353234919Sadrian __func__, (int) val); 354234919Sadrian } 355234919Sadrian if (resource_long_value(device_get_name(sc->arge_dev), 356234919Sadrian device_get_unit(sc->arge_dev), 357234919Sadrian "pll_1000", &val) == 0) { 358234919Sadrian sc->arge_pllcfg.pll_1000 = val; 359234919Sadrian device_printf(sc->arge_dev, "%s: pll_1000 = 0x%x\n", 360234919Sadrian __func__, (int) val); 361234919Sadrian } 362234919Sadrian} 363234919Sadrian 364188808Sgonzostatic int 365188808Sgonzoarge_attach(device_t dev) 366188808Sgonzo{ 367188808Sgonzo struct ifnet *ifp; 368188808Sgonzo struct arge_softc *sc; 369234862Sadrian int error = 0, rid; 370234862Sadrian uint32_t rnd; 371234862Sadrian int is_base_mac_empty, i; 372199234Sgonzo uint32_t hint; 373220260Sadrian long eeprom_mac_addr = 0; 374234910Sadrian int miicfg = 0; 375254690Ssbruno int readascii = 0; 376188808Sgonzo 377188808Sgonzo sc = device_get_softc(dev); 378188808Sgonzo sc->arge_dev = dev; 379188808Sgonzo sc->arge_mac_unit = device_get_unit(dev); 380188808Sgonzo 381220260Sadrian /* 382220260Sadrian * Some units (eg the TP-Link WR-1043ND) do not have a convenient 383220260Sadrian * EEPROM location to read the ethernet MAC address from. 384220260Sadrian * OpenWRT simply snaffles it from a fixed location. 385220260Sadrian * 386220260Sadrian * Since multiple units seem to use this feature, include 387220260Sadrian * a method of setting the MAC address based on an flash location 388220260Sadrian * in CPU address space. 389254690Ssbruno * 390254690Ssbruno * Some vendors have decided to store the mac address as a literal 391254690Ssbruno * string of 18 characters in xx:xx:xx:xx:xx:xx format instead of 392254690Ssbruno * an array of numbers. Expose a hint to turn on this conversion 393254690Ssbruno * feature via strtol() 394220260Sadrian */ 395254690Ssbruno if (resource_long_value(device_get_name(dev), device_get_unit(dev), 396220260Sadrian "eeprommac", &eeprom_mac_addr) == 0) { 397220260Sadrian int i; 398232628Sray const char *mac = 399232628Sray (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr); 400220260Sadrian device_printf(dev, "Overriding MAC from EEPROM\n"); 401254690Ssbruno if (resource_int_value(device_get_name(dev), device_get_unit(dev), 402254690Ssbruno "readascii", &readascii) == 0) { 403254690Ssbruno device_printf(dev, "Vendor stores MAC in ASCII format\n"); 404254690Ssbruno for (i = 0; i < 6; i++) { 405254690Ssbruno ar711_base_mac[i] = strtol(&(mac[i*3]), NULL, 16); 406254690Ssbruno } 407254690Ssbruno } else { 408254690Ssbruno for (i = 0; i < 6; i++) { 409254690Ssbruno ar711_base_mac[i] = mac[i]; 410254690Ssbruno } 411220260Sadrian } 412220260Sadrian } 413220260Sadrian 414232627Sray KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)), 415188808Sgonzo ("if_arge: Only MAC0 and MAC1 supported")); 416188808Sgonzo 417188808Sgonzo /* 418234919Sadrian * Fetch the PLL configuration. 419234919Sadrian */ 420234919Sadrian arge_fetch_pll_config(sc); 421234919Sadrian 422234919Sadrian /* 423234910Sadrian * Get the MII configuration, if applicable. 424234910Sadrian */ 425234910Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 426234910Sadrian "miimode", &miicfg) == 0) { 427234910Sadrian /* XXX bounds check? */ 428234910Sadrian device_printf(dev, "%s: overriding MII mode to '%s'\n", 429234910Sadrian __func__, arge_miicfg_str[miicfg]); 430234910Sadrian sc->arge_miicfg = miicfg; 431234910Sadrian } 432234910Sadrian 433234910Sadrian /* 434188808Sgonzo * Get which PHY of 5 available we should use for this unit 435188808Sgonzo */ 436234862Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 437234862Sadrian "phymask", &sc->arge_phymask) != 0) { 438188808Sgonzo /* 439232627Sray * Use port 4 (WAN) for GE0. For any other port use 440232627Sray * its PHY the same as its unit number 441188808Sgonzo */ 442188808Sgonzo if (sc->arge_mac_unit == 0) 443234862Sadrian sc->arge_phymask = (1 << 4); 444188808Sgonzo else 445199234Sgonzo /* Use all phys up to 4 */ 446234862Sadrian sc->arge_phymask = (1 << 4) - 1; 447188808Sgonzo 448234862Sadrian device_printf(dev, "No PHY specified, using mask %d\n", sc->arge_phymask); 449188808Sgonzo } 450188808Sgonzo 451199234Sgonzo /* 452232627Sray * Get default media & duplex mode, by default its Base100T 453199234Sgonzo * and full duplex 454199234Sgonzo */ 455232627Sray if (resource_int_value(device_get_name(dev), device_get_unit(dev), 456199234Sgonzo "media", &hint) != 0) 457199234Sgonzo hint = 0; 458188808Sgonzo 459199234Sgonzo if (hint == 1000) 460199234Sgonzo sc->arge_media_type = IFM_1000_T; 461199234Sgonzo else 462199234Sgonzo sc->arge_media_type = IFM_100_TX; 463199234Sgonzo 464232627Sray if (resource_int_value(device_get_name(dev), device_get_unit(dev), 465199234Sgonzo "fduplex", &hint) != 0) 466199234Sgonzo hint = 1; 467199234Sgonzo 468199234Sgonzo if (hint) 469199234Sgonzo sc->arge_duplex_mode = IFM_FDX; 470199234Sgonzo else 471199234Sgonzo sc->arge_duplex_mode = 0; 472199234Sgonzo 473188808Sgonzo mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 474188808Sgonzo MTX_DEF); 475188808Sgonzo callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0); 476188808Sgonzo TASK_INIT(&sc->arge_link_task, 0, arge_link_task, sc); 477188808Sgonzo 478188808Sgonzo /* Map control/status registers. */ 479188808Sgonzo sc->arge_rid = 0; 480234862Sadrian sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 481234862Sadrian &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE); 482188808Sgonzo 483188808Sgonzo if (sc->arge_res == NULL) { 484188808Sgonzo device_printf(dev, "couldn't map memory\n"); 485188808Sgonzo error = ENXIO; 486188808Sgonzo goto fail; 487188808Sgonzo } 488188808Sgonzo 489188808Sgonzo /* Allocate interrupts */ 490188808Sgonzo rid = 0; 491232627Sray sc->arge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 492188808Sgonzo RF_SHAREABLE | RF_ACTIVE); 493188808Sgonzo 494188808Sgonzo if (sc->arge_irq == NULL) { 495188808Sgonzo device_printf(dev, "couldn't map interrupt\n"); 496188808Sgonzo error = ENXIO; 497188808Sgonzo goto fail; 498188808Sgonzo } 499188808Sgonzo 500188808Sgonzo /* Allocate ifnet structure. */ 501188808Sgonzo ifp = sc->arge_ifp = if_alloc(IFT_ETHER); 502188808Sgonzo 503188808Sgonzo if (ifp == NULL) { 504188808Sgonzo device_printf(dev, "couldn't allocate ifnet structure\n"); 505188808Sgonzo error = ENOSPC; 506188808Sgonzo goto fail; 507188808Sgonzo } 508188808Sgonzo 509188808Sgonzo ifp->if_softc = sc; 510188808Sgonzo if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 511188808Sgonzo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 512188808Sgonzo ifp->if_ioctl = arge_ioctl; 513188808Sgonzo ifp->if_start = arge_start; 514188808Sgonzo ifp->if_init = arge_init; 515198932Sgonzo sc->arge_if_flags = ifp->if_flags; 516188808Sgonzo 517188808Sgonzo /* XXX: add real size */ 518207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 519207554Ssobomax ifp->if_snd.ifq_maxlen = ifqmaxlen; 520188808Sgonzo IFQ_SET_READY(&ifp->if_snd); 521188808Sgonzo 522188808Sgonzo ifp->if_capenable = ifp->if_capabilities; 523192783Sgonzo#ifdef DEVICE_POLLING 524192783Sgonzo ifp->if_capabilities |= IFCAP_POLLING; 525192783Sgonzo#endif 526188808Sgonzo 527192179Sgonzo is_base_mac_empty = 1; 528192179Sgonzo for (i = 0; i < ETHER_ADDR_LEN; i++) { 529234862Sadrian sc->arge_eaddr[i] = ar711_base_mac[i] & 0xff; 530234862Sadrian if (sc->arge_eaddr[i] != 0) 531192179Sgonzo is_base_mac_empty = 0; 532192179Sgonzo } 533188808Sgonzo 534192179Sgonzo if (is_base_mac_empty) { 535192179Sgonzo /* 536192179Sgonzo * No MAC address configured. Generate the random one. 537192179Sgonzo */ 538198933Sgonzo if (bootverbose) 539232627Sray device_printf(dev, 540192179Sgonzo "Generating random ethernet address.\n"); 541192179Sgonzo 542192179Sgonzo rnd = arc4random(); 543234862Sadrian sc->arge_eaddr[0] = 'b'; 544234862Sadrian sc->arge_eaddr[1] = 's'; 545234862Sadrian sc->arge_eaddr[2] = 'd'; 546234862Sadrian sc->arge_eaddr[3] = (rnd >> 24) & 0xff; 547234862Sadrian sc->arge_eaddr[4] = (rnd >> 16) & 0xff; 548234862Sadrian sc->arge_eaddr[5] = (rnd >> 8) & 0xff; 549192179Sgonzo } 550198970Sgonzo if (sc->arge_mac_unit != 0) 551234862Sadrian sc->arge_eaddr[5] += sc->arge_mac_unit; 552198970Sgonzo 553188808Sgonzo if (arge_dma_alloc(sc) != 0) { 554188808Sgonzo error = ENXIO; 555188808Sgonzo goto fail; 556188808Sgonzo } 557188808Sgonzo 558234862Sadrian /* 559234862Sadrian * Don't do this for the MDIO bus case - it's already done 560234862Sadrian * as part of the MDIO bus attachment. 561234862Sadrian */ 562234862Sadrian#if !defined(ARGE_MDIO) 563192569Sdwhite /* Initialize the MAC block */ 564234862Sadrian arge_reset_mac(sc); 565234862Sadrian arge_reset_miibus(sc); 566234862Sadrian#endif 567232627Sray 568234910Sadrian /* Configure MII mode, just for convienence */ 569234910Sadrian if (sc->arge_miicfg != 0) 570234910Sadrian ar71xx_device_set_mii_if(sc->arge_mac_unit, sc->arge_miicfg); 571234910Sadrian 572232627Sray /* 573188808Sgonzo * Set all Ethernet address registers to the same initial values 574232627Sray * set all four addresses to 66-88-aa-cc-dd-ee 575188808Sgonzo */ 576234862Sadrian ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, (sc->arge_eaddr[2] << 24) 577234862Sadrian | (sc->arge_eaddr[3] << 16) | (sc->arge_eaddr[4] << 8) 578234862Sadrian | sc->arge_eaddr[5]); 579234862Sadrian ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (sc->arge_eaddr[0] << 8) 580234862Sadrian | sc->arge_eaddr[1]); 581188808Sgonzo 582232627Sray ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0, 583188808Sgonzo FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT); 584188808Sgonzo 585219589Sadrian switch (ar71xx_soc) { 586219589Sadrian case AR71XX_SOC_AR7240: 587219589Sadrian case AR71XX_SOC_AR7241: 588219589Sadrian case AR71XX_SOC_AR7242: 589249123Sadrian case AR71XX_SOC_AR9330: 590249123Sadrian case AR71XX_SOC_AR9331: 591219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0010ffff); 592219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x015500aa); 593219589Sadrian break; 594219589Sadrian default: 595219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0fff0000); 596219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff); 597219589Sadrian } 598219589Sadrian 599232627Sray ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH, 600192783Sgonzo FIFO_RX_FILTMATCH_DEFAULT); 601188808Sgonzo 602232627Sray ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, 603192783Sgonzo FIFO_RX_FILTMASK_DEFAULT); 604188808Sgonzo 605234862Sadrian#if defined(ARGE_MDIO) 606234862Sadrian sc->arge_miiproxy = mii_attach_proxy(sc->arge_dev); 607234862Sadrian#endif 608199234Sgonzo 609234862Sadrian device_printf(sc->arge_dev, "finishing attachment, phymask %04x" 610234862Sadrian ", proxy %s \n", sc->arge_phymask, sc->arge_miiproxy == NULL ? 611234862Sadrian "null" : "set"); 612234862Sadrian for (i = 0; i < ARGE_NPHY; i++) { 613234862Sadrian if (((1 << i) & sc->arge_phymask) != 0) { 614234862Sadrian error = mii_attach(sc->arge_miiproxy != NULL ? 615234862Sadrian sc->arge_miiproxy : sc->arge_dev, 616234862Sadrian &sc->arge_miibus, sc->arge_ifp, 617234862Sadrian arge_ifmedia_upd, arge_ifmedia_sts, 618234862Sadrian BMSR_DEFCAPMASK, i, MII_OFFSET_ANY, 0); 619234862Sadrian if (error != 0) { 620234862Sadrian device_printf(sc->arge_dev, "unable to attach" 621234862Sadrian " PHY %d: %d\n", i, error); 622234862Sadrian goto fail; 623234862Sadrian } 624199234Sgonzo } 625199234Sgonzo } 626234862Sadrian if (sc->arge_miibus == NULL) { 627234862Sadrian /* no PHY, so use hard-coded values */ 628234862Sadrian ifmedia_init(&sc->arge_ifmedia, 0, 629199234Sgonzo arge_multiphy_mediachange, 630199234Sgonzo arge_multiphy_mediastatus); 631199234Sgonzo ifmedia_add(&sc->arge_ifmedia, 632232627Sray IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode, 633199234Sgonzo 0, NULL); 634199234Sgonzo ifmedia_set(&sc->arge_ifmedia, 635199234Sgonzo IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode); 636199234Sgonzo arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode); 637199234Sgonzo } 638199234Sgonzo 639188808Sgonzo /* Call MI attach routine. */ 640234862Sadrian ether_ifattach(sc->arge_ifp, sc->arge_eaddr); 641188808Sgonzo 642188808Sgonzo /* Hook interrupt last to avoid having to lock softc */ 643234862Sadrian error = bus_setup_intr(sc->arge_dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE, 644188808Sgonzo arge_intr_filter, arge_intr, sc, &sc->arge_intrhand); 645188808Sgonzo 646188808Sgonzo if (error) { 647234862Sadrian device_printf(sc->arge_dev, "couldn't set up irq\n"); 648234862Sadrian ether_ifdetach(sc->arge_ifp); 649188808Sgonzo goto fail; 650188808Sgonzo } 651188808Sgonzo 652209802Sadrian /* setup sysctl variables */ 653234862Sadrian arge_attach_sysctl(sc->arge_dev); 654209802Sadrian 655188808Sgonzofail: 656234862Sadrian if (error) 657188808Sgonzo arge_detach(dev); 658188808Sgonzo 659188808Sgonzo return (error); 660188808Sgonzo} 661188808Sgonzo 662188808Sgonzostatic int 663188808Sgonzoarge_detach(device_t dev) 664188808Sgonzo{ 665192783Sgonzo struct arge_softc *sc = device_get_softc(dev); 666188808Sgonzo struct ifnet *ifp = sc->arge_ifp; 667188808Sgonzo 668232628Sray KASSERT(mtx_initialized(&sc->arge_mtx), 669232628Sray ("arge mutex not initialized")); 670188808Sgonzo 671188808Sgonzo /* These should only be active if attach succeeded */ 672188808Sgonzo if (device_is_attached(dev)) { 673188808Sgonzo ARGE_LOCK(sc); 674188808Sgonzo sc->arge_detach = 1; 675192783Sgonzo#ifdef DEVICE_POLLING 676192783Sgonzo if (ifp->if_capenable & IFCAP_POLLING) 677192783Sgonzo ether_poll_deregister(ifp); 678192783Sgonzo#endif 679192783Sgonzo 680188808Sgonzo arge_stop(sc); 681188808Sgonzo ARGE_UNLOCK(sc); 682188808Sgonzo taskqueue_drain(taskqueue_swi, &sc->arge_link_task); 683188808Sgonzo ether_ifdetach(ifp); 684188808Sgonzo } 685188808Sgonzo 686188808Sgonzo if (sc->arge_miibus) 687188808Sgonzo device_delete_child(dev, sc->arge_miibus); 688199234Sgonzo 689234862Sadrian if (sc->arge_miiproxy) 690234862Sadrian device_delete_child(dev, sc->arge_miiproxy); 691234862Sadrian 692188808Sgonzo bus_generic_detach(dev); 693188808Sgonzo 694188808Sgonzo if (sc->arge_intrhand) 695188808Sgonzo bus_teardown_intr(dev, sc->arge_irq, sc->arge_intrhand); 696188808Sgonzo 697188808Sgonzo if (sc->arge_res) 698232627Sray bus_release_resource(dev, SYS_RES_MEMORY, sc->arge_rid, 699188808Sgonzo sc->arge_res); 700188808Sgonzo 701188808Sgonzo if (ifp) 702188808Sgonzo if_free(ifp); 703188808Sgonzo 704188808Sgonzo arge_dma_free(sc); 705188808Sgonzo 706188808Sgonzo mtx_destroy(&sc->arge_mtx); 707188808Sgonzo 708188808Sgonzo return (0); 709188808Sgonzo 710188808Sgonzo} 711188808Sgonzo 712188808Sgonzostatic int 713188808Sgonzoarge_suspend(device_t dev) 714188808Sgonzo{ 715188808Sgonzo 716188808Sgonzo panic("%s", __func__); 717188808Sgonzo return 0; 718188808Sgonzo} 719188808Sgonzo 720188808Sgonzostatic int 721188808Sgonzoarge_resume(device_t dev) 722188808Sgonzo{ 723188808Sgonzo 724188808Sgonzo panic("%s", __func__); 725188808Sgonzo return 0; 726188808Sgonzo} 727188808Sgonzo 728194059Sgonzostatic int 729188808Sgonzoarge_shutdown(device_t dev) 730188808Sgonzo{ 731188808Sgonzo struct arge_softc *sc; 732188808Sgonzo 733188808Sgonzo sc = device_get_softc(dev); 734188808Sgonzo 735188808Sgonzo ARGE_LOCK(sc); 736188808Sgonzo arge_stop(sc); 737188808Sgonzo ARGE_UNLOCK(sc); 738194059Sgonzo 739194059Sgonzo return (0); 740188808Sgonzo} 741188808Sgonzo 742234862Sadrianstatic void 743234862Sadrianarge_hinted_child(device_t bus, const char *dname, int dunit) 744234862Sadrian{ 745234862Sadrian BUS_ADD_CHILD(bus, 0, dname, dunit); 746234862Sadrian device_printf(bus, "hinted child %s%d\n", dname, dunit); 747234862Sadrian} 748234862Sadrian 749188808Sgonzostatic int 750188808Sgonzoarge_miibus_readreg(device_t dev, int phy, int reg) 751188808Sgonzo{ 752188808Sgonzo struct arge_softc * sc = device_get_softc(dev); 753188808Sgonzo int i, result; 754232627Sray uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT) 755188808Sgonzo | (reg & MAC_MII_REG_MASK); 756188808Sgonzo 757199038Sgonzo mtx_lock(&miibus_mtx); 758234862Sadrian ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE); 759234862Sadrian ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr); 760234862Sadrian ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ); 761188808Sgonzo 762188808Sgonzo i = ARGE_MII_TIMEOUT; 763234862Sadrian while ((ARGE_MDIO_READ(sc, AR71XX_MAC_MII_INDICATOR) & 764188808Sgonzo MAC_MII_INDICATOR_BUSY) && (i--)) 765188808Sgonzo DELAY(5); 766188808Sgonzo 767188808Sgonzo if (i < 0) { 768199038Sgonzo mtx_unlock(&miibus_mtx); 769220354Sadrian ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__); 770188808Sgonzo /* XXX: return ERRNO istead? */ 771188808Sgonzo return (-1); 772188808Sgonzo } 773188808Sgonzo 774234862Sadrian result = ARGE_MDIO_READ(sc, AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK; 775234862Sadrian ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE); 776199038Sgonzo mtx_unlock(&miibus_mtx); 777199038Sgonzo 778232628Sray ARGEDEBUG(sc, ARGE_DBG_MII, 779232628Sray "%s: phy=%d, reg=%02x, value[%08x]=%04x\n", 780232628Sray __func__, phy, reg, addr, result); 781188808Sgonzo 782188808Sgonzo return (result); 783188808Sgonzo} 784188808Sgonzo 785188808Sgonzostatic int 786188808Sgonzoarge_miibus_writereg(device_t dev, int phy, int reg, int data) 787188808Sgonzo{ 788188808Sgonzo struct arge_softc * sc = device_get_softc(dev); 789188808Sgonzo int i; 790232627Sray uint32_t addr = 791196794Sgonzo (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK); 792188808Sgonzo 793234862Sadrian ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value=%04x\n", __func__, 794234862Sadrian phy, reg, data); 795199038Sgonzo 796199038Sgonzo mtx_lock(&miibus_mtx); 797234862Sadrian ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr); 798234862Sadrian ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CONTROL, data); 799188808Sgonzo 800188808Sgonzo i = ARGE_MII_TIMEOUT; 801234862Sadrian while ((ARGE_MDIO_READ(sc, AR71XX_MAC_MII_INDICATOR) & 802188808Sgonzo MAC_MII_INDICATOR_BUSY) && (i--)) 803188808Sgonzo DELAY(5); 804188808Sgonzo 805199038Sgonzo mtx_unlock(&miibus_mtx); 806199038Sgonzo 807188808Sgonzo if (i < 0) { 808220354Sadrian ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__); 809188808Sgonzo /* XXX: return ERRNO istead? */ 810188808Sgonzo return (-1); 811188808Sgonzo } 812188808Sgonzo 813188808Sgonzo return (0); 814188808Sgonzo} 815188808Sgonzo 816188808Sgonzostatic void 817188808Sgonzoarge_miibus_statchg(device_t dev) 818188808Sgonzo{ 819232627Sray struct arge_softc *sc; 820188808Sgonzo 821188808Sgonzo sc = device_get_softc(dev); 822188808Sgonzo taskqueue_enqueue(taskqueue_swi, &sc->arge_link_task); 823188808Sgonzo} 824188808Sgonzo 825188808Sgonzostatic void 826188808Sgonzoarge_link_task(void *arg, int pending) 827188808Sgonzo{ 828188808Sgonzo struct arge_softc *sc; 829232914Sadrian sc = (struct arge_softc *)arg; 830232914Sadrian 831232914Sadrian ARGE_LOCK(sc); 832232914Sadrian arge_update_link_locked(sc); 833232914Sadrian ARGE_UNLOCK(sc); 834232914Sadrian} 835232914Sadrian 836232914Sadrianstatic void 837232914Sadrianarge_update_link_locked(struct arge_softc *sc) 838232914Sadrian{ 839188808Sgonzo struct mii_data *mii; 840188808Sgonzo struct ifnet *ifp; 841199234Sgonzo uint32_t media, duplex; 842188808Sgonzo 843188808Sgonzo mii = device_get_softc(sc->arge_miibus); 844188808Sgonzo ifp = sc->arge_ifp; 845188808Sgonzo if (mii == NULL || ifp == NULL || 846188808Sgonzo (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 847188808Sgonzo return; 848188808Sgonzo } 849188808Sgonzo 850188808Sgonzo if (mii->mii_media_status & IFM_ACTIVE) { 851188808Sgonzo 852188808Sgonzo media = IFM_SUBTYPE(mii->mii_media_active); 853188808Sgonzo if (media != IFM_NONE) { 854188808Sgonzo sc->arge_link_status = 1; 855199234Sgonzo duplex = mii->mii_media_active & IFM_GMASK; 856234907Sadrian ARGEDEBUG(sc, ARGE_DBG_MII, "%s: media=%d, duplex=%d\n", 857234907Sadrian __func__, 858234907Sadrian media, 859234907Sadrian duplex); 860199234Sgonzo arge_set_pll(sc, media, duplex); 861199234Sgonzo } 862232914Sadrian } else { 863199234Sgonzo sc->arge_link_status = 0; 864232914Sadrian } 865199234Sgonzo} 866192783Sgonzo 867199234Sgonzostatic void 868199234Sgonzoarge_set_pll(struct arge_softc *sc, int media, int duplex) 869199234Sgonzo{ 870211511Sadrian uint32_t cfg, ifcontrol, rx_filtmask; 871234907Sadrian uint32_t fifo_tx, pll; 872211511Sadrian int if_speed; 873192783Sgonzo 874234919Sadrian ARGEDEBUG(sc, ARGE_DBG_PLL, "set_pll(%04x, %s)\n", media, 875234862Sadrian duplex == IFM_FDX ? "full" : "half"); 876199234Sgonzo cfg = ARGE_READ(sc, AR71XX_MAC_CFG2); 877232627Sray cfg &= ~(MAC_CFG2_IFACE_MODE_1000 878232627Sray | MAC_CFG2_IFACE_MODE_10_100 879199234Sgonzo | MAC_CFG2_FULL_DUPLEX); 880188808Sgonzo 881199234Sgonzo if (duplex == IFM_FDX) 882199234Sgonzo cfg |= MAC_CFG2_FULL_DUPLEX; 883188808Sgonzo 884199234Sgonzo ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL); 885199234Sgonzo ifcontrol &= ~MAC_IFCONTROL_SPEED; 886232627Sray rx_filtmask = 887199234Sgonzo ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK); 888199234Sgonzo rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE; 889188808Sgonzo 890199234Sgonzo switch(media) { 891199234Sgonzo case IFM_10_T: 892199234Sgonzo cfg |= MAC_CFG2_IFACE_MODE_10_100; 893211511Sadrian if_speed = 10; 894199234Sgonzo break; 895199234Sgonzo case IFM_100_TX: 896199234Sgonzo cfg |= MAC_CFG2_IFACE_MODE_10_100; 897199234Sgonzo ifcontrol |= MAC_IFCONTROL_SPEED; 898211511Sadrian if_speed = 100; 899199234Sgonzo break; 900199234Sgonzo case IFM_1000_T: 901199234Sgonzo case IFM_1000_SX: 902199234Sgonzo cfg |= MAC_CFG2_IFACE_MODE_1000; 903199234Sgonzo rx_filtmask |= FIFO_RX_MASK_BYTE_MODE; 904211511Sadrian if_speed = 1000; 905199234Sgonzo break; 906199234Sgonzo default: 907211511Sadrian if_speed = 100; 908232627Sray device_printf(sc->arge_dev, 909199234Sgonzo "Unknown media %d\n", media); 910199234Sgonzo } 911188808Sgonzo 912234919Sadrian ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: if_speed=%d\n", __func__, if_speed); 913234907Sadrian 914219589Sadrian switch (ar71xx_soc) { 915219589Sadrian case AR71XX_SOC_AR7240: 916219589Sadrian case AR71XX_SOC_AR7241: 917219589Sadrian case AR71XX_SOC_AR7242: 918249123Sadrian case AR71XX_SOC_AR9330: 919249123Sadrian case AR71XX_SOC_AR9331: 920219589Sadrian fifo_tx = 0x01f00140; 921219589Sadrian break; 922219589Sadrian case AR71XX_SOC_AR9130: 923219589Sadrian case AR71XX_SOC_AR9132: 924219589Sadrian fifo_tx = 0x00780fff; 925219589Sadrian break; 926219589Sadrian default: 927219589Sadrian fifo_tx = 0x008001ff; 928219589Sadrian } 929188808Sgonzo 930199234Sgonzo ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg); 931199234Sgonzo ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol); 932232627Sray ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, 933199234Sgonzo rx_filtmask); 934219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD, fifo_tx); 935188808Sgonzo 936234919Sadrian /* fetch PLL registers */ 937234907Sadrian pll = ar71xx_device_get_eth_pll(sc->arge_mac_unit, if_speed); 938234919Sadrian ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: pll=0x%x\n", __func__, pll); 939234907Sadrian 940234919Sadrian /* Override if required by platform data */ 941234919Sadrian if (if_speed == 10 && sc->arge_pllcfg.pll_10 != 0) 942234919Sadrian pll = sc->arge_pllcfg.pll_10; 943234919Sadrian else if (if_speed == 100 && sc->arge_pllcfg.pll_100 != 0) 944234919Sadrian pll = sc->arge_pllcfg.pll_100; 945234919Sadrian else if (if_speed == 1000 && sc->arge_pllcfg.pll_1000 != 0) 946234919Sadrian pll = sc->arge_pllcfg.pll_1000; 947234919Sadrian ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: final pll=0x%x\n", __func__, pll); 948234919Sadrian 949234907Sadrian /* XXX ensure pll != 0 */ 950234907Sadrian ar71xx_device_set_pll_ge(sc->arge_mac_unit, if_speed, pll); 951234907Sadrian 952234907Sadrian /* set MII registers */ 953234992Sadrian /* 954234992Sadrian * This was introduced to match what the Linux ag71xx ethernet 955234992Sadrian * driver does. For the AR71xx case, it does set the port 956234992Sadrian * MII speed. However, if this is done, non-gigabit speeds 957234992Sadrian * are not at all reliable when speaking via RGMII through 958234992Sadrian * 'bridge' PHY port that's pretending to be a local PHY. 959234992Sadrian * 960234992Sadrian * Until that gets root caused, and until an AR71xx + normal 961234992Sadrian * PHY board is tested, leave this disabled. 962234992Sadrian */ 963234992Sadrian#if 0 964234907Sadrian ar71xx_device_set_mii_speed(sc->arge_mac_unit, if_speed); 965234992Sadrian#endif 966188808Sgonzo} 967188808Sgonzo 968199234Sgonzo 969188808Sgonzostatic void 970188808Sgonzoarge_reset_dma(struct arge_softc *sc) 971188808Sgonzo{ 972188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0); 973188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 0); 974188808Sgonzo 975188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, 0); 976188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, 0); 977188808Sgonzo 978188808Sgonzo /* Clear all possible RX interrupts */ 979192569Sdwhite while(ARGE_READ(sc, AR71XX_DMA_RX_STATUS) & DMA_RX_STATUS_PKT_RECVD) 980188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD); 981188808Sgonzo 982232627Sray /* 983188808Sgonzo * Clear all possible TX interrupts 984188808Sgonzo */ 985192569Sdwhite while(ARGE_READ(sc, AR71XX_DMA_TX_STATUS) & DMA_TX_STATUS_PKT_SENT) 986188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT); 987188808Sgonzo 988232627Sray /* 989188808Sgonzo * Now Rx/Tx errors 990188808Sgonzo */ 991232627Sray ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, 992188808Sgonzo DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW); 993232627Sray ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, 994188808Sgonzo DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN); 995232912Sadrian 996232912Sadrian /* 997232912Sadrian * Force a DDR flush so any pending data is properly 998232912Sadrian * flushed to RAM before underlying buffers are freed. 999232912Sadrian */ 1000232912Sadrian arge_flush_ddr(sc); 1001188808Sgonzo} 1002188808Sgonzo 1003188808Sgonzo 1004188808Sgonzo 1005188808Sgonzostatic void 1006188808Sgonzoarge_init(void *xsc) 1007188808Sgonzo{ 1008188808Sgonzo struct arge_softc *sc = xsc; 1009188808Sgonzo 1010188808Sgonzo ARGE_LOCK(sc); 1011188808Sgonzo arge_init_locked(sc); 1012188808Sgonzo ARGE_UNLOCK(sc); 1013188808Sgonzo} 1014188808Sgonzo 1015188808Sgonzostatic void 1016188808Sgonzoarge_init_locked(struct arge_softc *sc) 1017188808Sgonzo{ 1018188808Sgonzo struct ifnet *ifp = sc->arge_ifp; 1019188808Sgonzo struct mii_data *mii; 1020188808Sgonzo 1021188808Sgonzo ARGE_LOCK_ASSERT(sc); 1022188808Sgonzo 1023255021Sloos if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 1024255021Sloos return; 1025188808Sgonzo 1026188808Sgonzo /* Init circular RX list. */ 1027188808Sgonzo if (arge_rx_ring_init(sc) != 0) { 1028188808Sgonzo device_printf(sc->arge_dev, 1029188808Sgonzo "initialization failed: no memory for rx buffers\n"); 1030188808Sgonzo arge_stop(sc); 1031188808Sgonzo return; 1032188808Sgonzo } 1033188808Sgonzo 1034188808Sgonzo /* Init tx descriptors. */ 1035188808Sgonzo arge_tx_ring_init(sc); 1036188808Sgonzo 1037188808Sgonzo arge_reset_dma(sc); 1038188808Sgonzo 1039199234Sgonzo if (sc->arge_miibus) { 1040199234Sgonzo mii = device_get_softc(sc->arge_miibus); 1041199234Sgonzo mii_mediachg(mii); 1042199234Sgonzo } 1043199234Sgonzo else { 1044199234Sgonzo /* 1045199234Sgonzo * Sun always shines over multiPHY interface 1046199234Sgonzo */ 1047199234Sgonzo sc->arge_link_status = 1; 1048199234Sgonzo } 1049199234Sgonzo 1050188808Sgonzo ifp->if_drv_flags |= IFF_DRV_RUNNING; 1051188808Sgonzo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1052188808Sgonzo 1053232914Sadrian if (sc->arge_miibus) { 1054199234Sgonzo callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); 1055232914Sadrian arge_update_link_locked(sc); 1056232914Sadrian } 1057192783Sgonzo 1058188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0)); 1059188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0)); 1060188808Sgonzo 1061188808Sgonzo /* Start listening */ 1062188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN); 1063188808Sgonzo 1064188808Sgonzo /* Enable interrupts */ 1065188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); 1066188808Sgonzo} 1067188808Sgonzo 1068188808Sgonzo/* 1069209807Sadrian * Return whether the mbuf chain is correctly aligned 1070209807Sadrian * for the arge TX engine. 1071209807Sadrian * 1072209807Sadrian * The TX engine requires each fragment to be aligned to a 1073209807Sadrian * 4 byte boundary and the size of each fragment except 1074209807Sadrian * the last to be a multiple of 4 bytes. 1075209807Sadrian */ 1076209807Sadrianstatic int 1077209807Sadrianarge_mbuf_chain_is_tx_aligned(struct mbuf *m0) 1078209807Sadrian{ 1079209807Sadrian struct mbuf *m; 1080209807Sadrian 1081209807Sadrian for (m = m0; m != NULL; m = m->m_next) { 1082209807Sadrian if((mtod(m, intptr_t) & 3) != 0) 1083209807Sadrian return 0; 1084209807Sadrian if ((m->m_next != NULL) && ((m->m_len & 0x03) != 0)) 1085209807Sadrian return 0; 1086209807Sadrian } 1087209807Sadrian return 1; 1088209807Sadrian} 1089209807Sadrian 1090209807Sadrian/* 1091188808Sgonzo * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 1092188808Sgonzo * pointers to the fragment pointers. 1093188808Sgonzo */ 1094188808Sgonzostatic int 1095188808Sgonzoarge_encap(struct arge_softc *sc, struct mbuf **m_head) 1096188808Sgonzo{ 1097188808Sgonzo struct arge_txdesc *txd; 1098188808Sgonzo struct arge_desc *desc, *prev_desc; 1099188808Sgonzo bus_dma_segment_t txsegs[ARGE_MAXFRAGS]; 1100192569Sdwhite int error, i, nsegs, prod, prev_prod; 1101192783Sgonzo struct mbuf *m; 1102188808Sgonzo 1103188808Sgonzo ARGE_LOCK_ASSERT(sc); 1104188808Sgonzo 1105192783Sgonzo /* 1106192783Sgonzo * Fix mbuf chain, all fragments should be 4 bytes aligned and 1107192783Sgonzo * even 4 bytes 1108192783Sgonzo */ 1109192783Sgonzo m = *m_head; 1110209807Sadrian if (! arge_mbuf_chain_is_tx_aligned(m)) { 1111209809Sadrian sc->stats.tx_pkts_unaligned++; 1112243882Sglebius m = m_defrag(*m_head, M_NOWAIT); 1113192783Sgonzo if (m == NULL) { 1114192783Sgonzo *m_head = NULL; 1115192783Sgonzo return (ENOBUFS); 1116192783Sgonzo } 1117192783Sgonzo *m_head = m; 1118209809Sadrian } else 1119209809Sadrian sc->stats.tx_pkts_aligned++; 1120192783Sgonzo 1121188808Sgonzo prod = sc->arge_cdata.arge_tx_prod; 1122188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[prod]; 1123232627Sray error = bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_tx_tag, 1124188808Sgonzo txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); 1125188808Sgonzo 1126188808Sgonzo if (error == EFBIG) { 1127188808Sgonzo panic("EFBIG"); 1128188808Sgonzo } else if (error != 0) 1129188808Sgonzo return (error); 1130188808Sgonzo 1131188808Sgonzo if (nsegs == 0) { 1132188808Sgonzo m_freem(*m_head); 1133188808Sgonzo *m_head = NULL; 1134188808Sgonzo return (EIO); 1135188808Sgonzo } 1136188808Sgonzo 1137188808Sgonzo /* Check number of available descriptors. */ 1138188808Sgonzo if (sc->arge_cdata.arge_tx_cnt + nsegs >= (ARGE_TX_RING_COUNT - 1)) { 1139188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap); 1140188808Sgonzo return (ENOBUFS); 1141188808Sgonzo } 1142188808Sgonzo 1143188808Sgonzo txd->tx_m = *m_head; 1144188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap, 1145188808Sgonzo BUS_DMASYNC_PREWRITE); 1146188808Sgonzo 1147232627Sray /* 1148188808Sgonzo * Make a list of descriptors for this packet. DMA controller will 1149188808Sgonzo * walk through it while arge_link is not zero. 1150188808Sgonzo */ 1151188808Sgonzo prev_prod = prod; 1152188808Sgonzo desc = prev_desc = NULL; 1153188808Sgonzo for (i = 0; i < nsegs; i++) { 1154188808Sgonzo desc = &sc->arge_rdata.arge_tx_ring[prod]; 1155188808Sgonzo desc->packet_ctrl = ARGE_DMASIZE(txsegs[i].ds_len); 1156188808Sgonzo 1157192783Sgonzo if (txsegs[i].ds_addr & 3) 1158192783Sgonzo panic("TX packet address unaligned\n"); 1159192783Sgonzo 1160188808Sgonzo desc->packet_addr = txsegs[i].ds_addr; 1161232627Sray 1162188808Sgonzo /* link with previous descriptor */ 1163188808Sgonzo if (prev_desc) 1164188808Sgonzo prev_desc->packet_ctrl |= ARGE_DESC_MORE; 1165188808Sgonzo 1166188808Sgonzo sc->arge_cdata.arge_tx_cnt++; 1167188808Sgonzo prev_desc = desc; 1168188808Sgonzo ARGE_INC(prod, ARGE_TX_RING_COUNT); 1169188808Sgonzo } 1170188808Sgonzo 1171188808Sgonzo /* Update producer index. */ 1172188808Sgonzo sc->arge_cdata.arge_tx_prod = prod; 1173188808Sgonzo 1174188808Sgonzo /* Sync descriptors. */ 1175188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, 1176188808Sgonzo sc->arge_cdata.arge_tx_ring_map, 1177188808Sgonzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1178188808Sgonzo 1179188808Sgonzo /* Start transmitting */ 1180232628Sray ARGEDEBUG(sc, ARGE_DBG_TX, "%s: setting DMA_TX_CONTROL_EN\n", 1181232628Sray __func__); 1182188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN); 1183188808Sgonzo return (0); 1184188808Sgonzo} 1185188808Sgonzo 1186188808Sgonzostatic void 1187188808Sgonzoarge_start(struct ifnet *ifp) 1188188808Sgonzo{ 1189188808Sgonzo struct arge_softc *sc; 1190188808Sgonzo 1191188808Sgonzo sc = ifp->if_softc; 1192188808Sgonzo 1193188808Sgonzo ARGE_LOCK(sc); 1194188808Sgonzo arge_start_locked(ifp); 1195188808Sgonzo ARGE_UNLOCK(sc); 1196188808Sgonzo} 1197188808Sgonzo 1198188808Sgonzostatic void 1199188808Sgonzoarge_start_locked(struct ifnet *ifp) 1200188808Sgonzo{ 1201188808Sgonzo struct arge_softc *sc; 1202188808Sgonzo struct mbuf *m_head; 1203220356Sadrian int enq = 0; 1204188808Sgonzo 1205188808Sgonzo sc = ifp->if_softc; 1206188808Sgonzo 1207188808Sgonzo ARGE_LOCK_ASSERT(sc); 1208188808Sgonzo 1209220356Sadrian ARGEDEBUG(sc, ARGE_DBG_TX, "%s: beginning\n", __func__); 1210220356Sadrian 1211188808Sgonzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1212188808Sgonzo IFF_DRV_RUNNING || sc->arge_link_status == 0 ) 1213188808Sgonzo return; 1214188808Sgonzo 1215220356Sadrian /* 1216220356Sadrian * Before we go any further, check whether we're already full. 1217220356Sadrian * The below check errors out immediately if the ring is full 1218220356Sadrian * and never gets a chance to set this flag. Although it's 1219220356Sadrian * likely never needed, this at least avoids an unexpected 1220220356Sadrian * situation. 1221220356Sadrian */ 1222220356Sadrian if (sc->arge_cdata.arge_tx_cnt >= ARGE_TX_RING_COUNT - 2) { 1223220356Sadrian ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1224232628Sray ARGEDEBUG(sc, ARGE_DBG_ERR, 1225232628Sray "%s: tx_cnt %d >= max %d; setting IFF_DRV_OACTIVE\n", 1226232628Sray __func__, sc->arge_cdata.arge_tx_cnt, 1227232628Sray ARGE_TX_RING_COUNT - 2); 1228220356Sadrian return; 1229220356Sadrian } 1230220356Sadrian 1231188808Sgonzo arge_flush_ddr(sc); 1232188808Sgonzo 1233188808Sgonzo for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 1234188808Sgonzo sc->arge_cdata.arge_tx_cnt < ARGE_TX_RING_COUNT - 2; ) { 1235188808Sgonzo IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1236188808Sgonzo if (m_head == NULL) 1237188808Sgonzo break; 1238188808Sgonzo 1239188808Sgonzo 1240188808Sgonzo /* 1241188808Sgonzo * Pack the data into the transmit ring. 1242188808Sgonzo */ 1243188808Sgonzo if (arge_encap(sc, &m_head)) { 1244188808Sgonzo if (m_head == NULL) 1245188808Sgonzo break; 1246188808Sgonzo IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1247188808Sgonzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1248188808Sgonzo break; 1249188808Sgonzo } 1250188808Sgonzo 1251188808Sgonzo enq++; 1252188808Sgonzo /* 1253188808Sgonzo * If there's a BPF listener, bounce a copy of this frame 1254188808Sgonzo * to him. 1255188808Sgonzo */ 1256188808Sgonzo ETHER_BPF_MTAP(ifp, m_head); 1257188808Sgonzo } 1258232628Sray ARGEDEBUG(sc, ARGE_DBG_TX, "%s: finished; queued %d packets\n", 1259232628Sray __func__, enq); 1260188808Sgonzo} 1261188808Sgonzo 1262188808Sgonzostatic void 1263188808Sgonzoarge_stop(struct arge_softc *sc) 1264188808Sgonzo{ 1265188808Sgonzo struct ifnet *ifp; 1266188808Sgonzo 1267188808Sgonzo ARGE_LOCK_ASSERT(sc); 1268188808Sgonzo 1269188808Sgonzo ifp = sc->arge_ifp; 1270188808Sgonzo ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1271199234Sgonzo if (sc->arge_miibus) 1272199234Sgonzo callout_stop(&sc->arge_stat_callout); 1273188808Sgonzo 1274188808Sgonzo /* mask out interrupts */ 1275188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); 1276188808Sgonzo 1277188808Sgonzo arge_reset_dma(sc); 1278232912Sadrian 1279232912Sadrian /* Flush FIFO and free any existing mbufs */ 1280232912Sadrian arge_flush_ddr(sc); 1281232912Sadrian arge_rx_ring_free(sc); 1282255300Sloos arge_tx_ring_free(sc); 1283188808Sgonzo} 1284188808Sgonzo 1285188808Sgonzo 1286188808Sgonzostatic int 1287188808Sgonzoarge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1288188808Sgonzo{ 1289188808Sgonzo struct arge_softc *sc = ifp->if_softc; 1290188808Sgonzo struct ifreq *ifr = (struct ifreq *) data; 1291188808Sgonzo struct mii_data *mii; 1292188808Sgonzo int error; 1293192783Sgonzo#ifdef DEVICE_POLLING 1294192783Sgonzo int mask; 1295192783Sgonzo#endif 1296188808Sgonzo 1297188808Sgonzo switch (command) { 1298188808Sgonzo case SIOCSIFFLAGS: 1299198932Sgonzo ARGE_LOCK(sc); 1300198932Sgonzo if ((ifp->if_flags & IFF_UP) != 0) { 1301198932Sgonzo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1302198932Sgonzo if (((ifp->if_flags ^ sc->arge_if_flags) 1303198939Sgonzo & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 1304198939Sgonzo /* XXX: handle promisc & multi flags */ 1305198939Sgonzo } 1306232627Sray 1307198932Sgonzo } else { 1308198932Sgonzo if (!sc->arge_detach) 1309198932Sgonzo arge_init_locked(sc); 1310198932Sgonzo } 1311198932Sgonzo } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1312198932Sgonzo ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1313198932Sgonzo arge_stop(sc); 1314198932Sgonzo } 1315198932Sgonzo sc->arge_if_flags = ifp->if_flags; 1316198932Sgonzo ARGE_UNLOCK(sc); 1317188808Sgonzo error = 0; 1318188808Sgonzo break; 1319188808Sgonzo case SIOCADDMULTI: 1320188808Sgonzo case SIOCDELMULTI: 1321198932Sgonzo /* XXX: implement SIOCDELMULTI */ 1322188808Sgonzo error = 0; 1323188808Sgonzo break; 1324188808Sgonzo case SIOCGIFMEDIA: 1325188808Sgonzo case SIOCSIFMEDIA: 1326199234Sgonzo if (sc->arge_miibus) { 1327199234Sgonzo mii = device_get_softc(sc->arge_miibus); 1328232628Sray error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 1329232628Sray command); 1330199234Sgonzo } 1331232627Sray else 1332232628Sray error = ifmedia_ioctl(ifp, ifr, &sc->arge_ifmedia, 1333232628Sray command); 1334188808Sgonzo break; 1335198933Sgonzo case SIOCSIFCAP: 1336198932Sgonzo /* XXX: Check other capabilities */ 1337192783Sgonzo#ifdef DEVICE_POLLING 1338198933Sgonzo mask = ifp->if_capenable ^ ifr->ifr_reqcap; 1339198933Sgonzo if (mask & IFCAP_POLLING) { 1340198933Sgonzo if (ifr->ifr_reqcap & IFCAP_POLLING) { 1341192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); 1342198933Sgonzo error = ether_poll_register(arge_poll, ifp); 1343198933Sgonzo if (error) 1344198933Sgonzo return error; 1345198933Sgonzo ARGE_LOCK(sc); 1346198933Sgonzo ifp->if_capenable |= IFCAP_POLLING; 1347198933Sgonzo ARGE_UNLOCK(sc); 1348198933Sgonzo } else { 1349192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); 1350198933Sgonzo error = ether_poll_deregister(ifp); 1351198933Sgonzo ARGE_LOCK(sc); 1352198933Sgonzo ifp->if_capenable &= ~IFCAP_POLLING; 1353198933Sgonzo ARGE_UNLOCK(sc); 1354198933Sgonzo } 1355198933Sgonzo } 1356198932Sgonzo error = 0; 1357198933Sgonzo break; 1358192783Sgonzo#endif 1359188808Sgonzo default: 1360188808Sgonzo error = ether_ioctl(ifp, command, data); 1361188808Sgonzo break; 1362188808Sgonzo } 1363188808Sgonzo 1364188808Sgonzo return (error); 1365188808Sgonzo} 1366188808Sgonzo 1367188808Sgonzo/* 1368188808Sgonzo * Set media options. 1369188808Sgonzo */ 1370188808Sgonzostatic int 1371188808Sgonzoarge_ifmedia_upd(struct ifnet *ifp) 1372188808Sgonzo{ 1373188808Sgonzo struct arge_softc *sc; 1374188808Sgonzo struct mii_data *mii; 1375188808Sgonzo struct mii_softc *miisc; 1376188808Sgonzo int error; 1377188808Sgonzo 1378188808Sgonzo sc = ifp->if_softc; 1379188808Sgonzo ARGE_LOCK(sc); 1380188808Sgonzo mii = device_get_softc(sc->arge_miibus); 1381221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1382221407Smarius PHY_RESET(miisc); 1383188808Sgonzo error = mii_mediachg(mii); 1384188808Sgonzo ARGE_UNLOCK(sc); 1385188808Sgonzo 1386188808Sgonzo return (error); 1387188808Sgonzo} 1388188808Sgonzo 1389188808Sgonzo/* 1390188808Sgonzo * Report current media status. 1391188808Sgonzo */ 1392188808Sgonzostatic void 1393188808Sgonzoarge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1394188808Sgonzo{ 1395188808Sgonzo struct arge_softc *sc = ifp->if_softc; 1396188808Sgonzo struct mii_data *mii; 1397188808Sgonzo 1398188808Sgonzo mii = device_get_softc(sc->arge_miibus); 1399188808Sgonzo ARGE_LOCK(sc); 1400188808Sgonzo mii_pollstat(mii); 1401188808Sgonzo ifmr->ifm_active = mii->mii_media_active; 1402188808Sgonzo ifmr->ifm_status = mii->mii_media_status; 1403226478Syongari ARGE_UNLOCK(sc); 1404188808Sgonzo} 1405188808Sgonzo 1406188808Sgonzostruct arge_dmamap_arg { 1407188808Sgonzo bus_addr_t arge_busaddr; 1408188808Sgonzo}; 1409188808Sgonzo 1410188808Sgonzostatic void 1411188808Sgonzoarge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1412188808Sgonzo{ 1413188808Sgonzo struct arge_dmamap_arg *ctx; 1414188808Sgonzo 1415188808Sgonzo if (error != 0) 1416188808Sgonzo return; 1417188808Sgonzo ctx = arg; 1418188808Sgonzo ctx->arge_busaddr = segs[0].ds_addr; 1419188808Sgonzo} 1420188808Sgonzo 1421188808Sgonzostatic int 1422188808Sgonzoarge_dma_alloc(struct arge_softc *sc) 1423188808Sgonzo{ 1424188808Sgonzo struct arge_dmamap_arg ctx; 1425188808Sgonzo struct arge_txdesc *txd; 1426188808Sgonzo struct arge_rxdesc *rxd; 1427188808Sgonzo int error, i; 1428188808Sgonzo 1429188808Sgonzo /* Create parent DMA tag. */ 1430188808Sgonzo error = bus_dma_tag_create( 1431188808Sgonzo bus_get_dma_tag(sc->arge_dev), /* parent */ 1432188808Sgonzo 1, 0, /* alignment, boundary */ 1433188808Sgonzo BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1434188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1435188808Sgonzo NULL, NULL, /* filter, filterarg */ 1436188808Sgonzo BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1437188808Sgonzo 0, /* nsegments */ 1438188808Sgonzo BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1439188808Sgonzo 0, /* flags */ 1440188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1441188808Sgonzo &sc->arge_cdata.arge_parent_tag); 1442188808Sgonzo if (error != 0) { 1443232628Sray device_printf(sc->arge_dev, 1444232628Sray "failed to create parent DMA tag\n"); 1445188808Sgonzo goto fail; 1446188808Sgonzo } 1447188808Sgonzo /* Create tag for Tx ring. */ 1448188808Sgonzo error = bus_dma_tag_create( 1449188808Sgonzo sc->arge_cdata.arge_parent_tag, /* parent */ 1450188808Sgonzo ARGE_RING_ALIGN, 0, /* alignment, boundary */ 1451188808Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1452188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1453188808Sgonzo NULL, NULL, /* filter, filterarg */ 1454188808Sgonzo ARGE_TX_DMA_SIZE, /* maxsize */ 1455188808Sgonzo 1, /* nsegments */ 1456188808Sgonzo ARGE_TX_DMA_SIZE, /* maxsegsize */ 1457188808Sgonzo 0, /* flags */ 1458188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1459188808Sgonzo &sc->arge_cdata.arge_tx_ring_tag); 1460188808Sgonzo if (error != 0) { 1461232628Sray device_printf(sc->arge_dev, 1462232628Sray "failed to create Tx ring DMA tag\n"); 1463188808Sgonzo goto fail; 1464188808Sgonzo } 1465188808Sgonzo 1466188808Sgonzo /* Create tag for Rx ring. */ 1467188808Sgonzo error = bus_dma_tag_create( 1468188808Sgonzo sc->arge_cdata.arge_parent_tag, /* parent */ 1469188808Sgonzo ARGE_RING_ALIGN, 0, /* alignment, boundary */ 1470188808Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1471188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1472188808Sgonzo NULL, NULL, /* filter, filterarg */ 1473188808Sgonzo ARGE_RX_DMA_SIZE, /* maxsize */ 1474188808Sgonzo 1, /* nsegments */ 1475188808Sgonzo ARGE_RX_DMA_SIZE, /* maxsegsize */ 1476188808Sgonzo 0, /* flags */ 1477188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1478188808Sgonzo &sc->arge_cdata.arge_rx_ring_tag); 1479188808Sgonzo if (error != 0) { 1480232628Sray device_printf(sc->arge_dev, 1481232628Sray "failed to create Rx ring DMA tag\n"); 1482188808Sgonzo goto fail; 1483188808Sgonzo } 1484188808Sgonzo 1485188808Sgonzo /* Create tag for Tx buffers. */ 1486188808Sgonzo error = bus_dma_tag_create( 1487188808Sgonzo sc->arge_cdata.arge_parent_tag, /* parent */ 1488188808Sgonzo sizeof(uint32_t), 0, /* alignment, boundary */ 1489188808Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1490188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1491188808Sgonzo NULL, NULL, /* filter, filterarg */ 1492188808Sgonzo MCLBYTES * ARGE_MAXFRAGS, /* maxsize */ 1493188808Sgonzo ARGE_MAXFRAGS, /* nsegments */ 1494188808Sgonzo MCLBYTES, /* maxsegsize */ 1495188808Sgonzo 0, /* flags */ 1496188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1497188808Sgonzo &sc->arge_cdata.arge_tx_tag); 1498188808Sgonzo if (error != 0) { 1499188808Sgonzo device_printf(sc->arge_dev, "failed to create Tx DMA tag\n"); 1500188808Sgonzo goto fail; 1501188808Sgonzo } 1502188808Sgonzo 1503188808Sgonzo /* Create tag for Rx buffers. */ 1504188808Sgonzo error = bus_dma_tag_create( 1505188808Sgonzo sc->arge_cdata.arge_parent_tag, /* parent */ 1506188808Sgonzo ARGE_RX_ALIGN, 0, /* alignment, boundary */ 1507188808Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1508188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1509188808Sgonzo NULL, NULL, /* filter, filterarg */ 1510188808Sgonzo MCLBYTES, /* maxsize */ 1511192821Sgonzo ARGE_MAXFRAGS, /* nsegments */ 1512188808Sgonzo MCLBYTES, /* maxsegsize */ 1513188808Sgonzo 0, /* flags */ 1514188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1515188808Sgonzo &sc->arge_cdata.arge_rx_tag); 1516188808Sgonzo if (error != 0) { 1517188808Sgonzo device_printf(sc->arge_dev, "failed to create Rx DMA tag\n"); 1518188808Sgonzo goto fail; 1519188808Sgonzo } 1520188808Sgonzo 1521188808Sgonzo /* Allocate DMA'able memory and load the DMA map for Tx ring. */ 1522188808Sgonzo error = bus_dmamem_alloc(sc->arge_cdata.arge_tx_ring_tag, 1523188808Sgonzo (void **)&sc->arge_rdata.arge_tx_ring, BUS_DMA_WAITOK | 1524232628Sray BUS_DMA_COHERENT | BUS_DMA_ZERO, 1525232628Sray &sc->arge_cdata.arge_tx_ring_map); 1526188808Sgonzo if (error != 0) { 1527188808Sgonzo device_printf(sc->arge_dev, 1528188808Sgonzo "failed to allocate DMA'able memory for Tx ring\n"); 1529188808Sgonzo goto fail; 1530188808Sgonzo } 1531188808Sgonzo 1532188808Sgonzo ctx.arge_busaddr = 0; 1533188808Sgonzo error = bus_dmamap_load(sc->arge_cdata.arge_tx_ring_tag, 1534188808Sgonzo sc->arge_cdata.arge_tx_ring_map, sc->arge_rdata.arge_tx_ring, 1535188808Sgonzo ARGE_TX_DMA_SIZE, arge_dmamap_cb, &ctx, 0); 1536188808Sgonzo if (error != 0 || ctx.arge_busaddr == 0) { 1537188808Sgonzo device_printf(sc->arge_dev, 1538188808Sgonzo "failed to load DMA'able memory for Tx ring\n"); 1539188808Sgonzo goto fail; 1540188808Sgonzo } 1541188808Sgonzo sc->arge_rdata.arge_tx_ring_paddr = ctx.arge_busaddr; 1542188808Sgonzo 1543188808Sgonzo /* Allocate DMA'able memory and load the DMA map for Rx ring. */ 1544188808Sgonzo error = bus_dmamem_alloc(sc->arge_cdata.arge_rx_ring_tag, 1545188808Sgonzo (void **)&sc->arge_rdata.arge_rx_ring, BUS_DMA_WAITOK | 1546232628Sray BUS_DMA_COHERENT | BUS_DMA_ZERO, 1547232628Sray &sc->arge_cdata.arge_rx_ring_map); 1548188808Sgonzo if (error != 0) { 1549188808Sgonzo device_printf(sc->arge_dev, 1550188808Sgonzo "failed to allocate DMA'able memory for Rx ring\n"); 1551188808Sgonzo goto fail; 1552188808Sgonzo } 1553188808Sgonzo 1554188808Sgonzo ctx.arge_busaddr = 0; 1555188808Sgonzo error = bus_dmamap_load(sc->arge_cdata.arge_rx_ring_tag, 1556188808Sgonzo sc->arge_cdata.arge_rx_ring_map, sc->arge_rdata.arge_rx_ring, 1557188808Sgonzo ARGE_RX_DMA_SIZE, arge_dmamap_cb, &ctx, 0); 1558188808Sgonzo if (error != 0 || ctx.arge_busaddr == 0) { 1559188808Sgonzo device_printf(sc->arge_dev, 1560188808Sgonzo "failed to load DMA'able memory for Rx ring\n"); 1561188808Sgonzo goto fail; 1562188808Sgonzo } 1563188808Sgonzo sc->arge_rdata.arge_rx_ring_paddr = ctx.arge_busaddr; 1564188808Sgonzo 1565188808Sgonzo /* Create DMA maps for Tx buffers. */ 1566188808Sgonzo for (i = 0; i < ARGE_TX_RING_COUNT; i++) { 1567188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[i]; 1568188808Sgonzo txd->tx_m = NULL; 1569188808Sgonzo txd->tx_dmamap = NULL; 1570188808Sgonzo error = bus_dmamap_create(sc->arge_cdata.arge_tx_tag, 0, 1571188808Sgonzo &txd->tx_dmamap); 1572188808Sgonzo if (error != 0) { 1573188808Sgonzo device_printf(sc->arge_dev, 1574188808Sgonzo "failed to create Tx dmamap\n"); 1575188808Sgonzo goto fail; 1576188808Sgonzo } 1577188808Sgonzo } 1578188808Sgonzo /* Create DMA maps for Rx buffers. */ 1579188808Sgonzo if ((error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0, 1580188808Sgonzo &sc->arge_cdata.arge_rx_sparemap)) != 0) { 1581188808Sgonzo device_printf(sc->arge_dev, 1582188808Sgonzo "failed to create spare Rx dmamap\n"); 1583188808Sgonzo goto fail; 1584188808Sgonzo } 1585188808Sgonzo for (i = 0; i < ARGE_RX_RING_COUNT; i++) { 1586188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[i]; 1587188808Sgonzo rxd->rx_m = NULL; 1588188808Sgonzo rxd->rx_dmamap = NULL; 1589188808Sgonzo error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0, 1590188808Sgonzo &rxd->rx_dmamap); 1591188808Sgonzo if (error != 0) { 1592188808Sgonzo device_printf(sc->arge_dev, 1593188808Sgonzo "failed to create Rx dmamap\n"); 1594188808Sgonzo goto fail; 1595188808Sgonzo } 1596188808Sgonzo } 1597188808Sgonzo 1598188808Sgonzofail: 1599188808Sgonzo return (error); 1600188808Sgonzo} 1601188808Sgonzo 1602188808Sgonzostatic void 1603188808Sgonzoarge_dma_free(struct arge_softc *sc) 1604188808Sgonzo{ 1605188808Sgonzo struct arge_txdesc *txd; 1606188808Sgonzo struct arge_rxdesc *rxd; 1607188808Sgonzo int i; 1608188808Sgonzo 1609188808Sgonzo /* Tx ring. */ 1610188808Sgonzo if (sc->arge_cdata.arge_tx_ring_tag) { 1611188808Sgonzo if (sc->arge_cdata.arge_tx_ring_map) 1612188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_tx_ring_tag, 1613188808Sgonzo sc->arge_cdata.arge_tx_ring_map); 1614188808Sgonzo if (sc->arge_cdata.arge_tx_ring_map && 1615188808Sgonzo sc->arge_rdata.arge_tx_ring) 1616188808Sgonzo bus_dmamem_free(sc->arge_cdata.arge_tx_ring_tag, 1617188808Sgonzo sc->arge_rdata.arge_tx_ring, 1618188808Sgonzo sc->arge_cdata.arge_tx_ring_map); 1619188808Sgonzo sc->arge_rdata.arge_tx_ring = NULL; 1620188808Sgonzo sc->arge_cdata.arge_tx_ring_map = NULL; 1621188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_tx_ring_tag); 1622188808Sgonzo sc->arge_cdata.arge_tx_ring_tag = NULL; 1623188808Sgonzo } 1624188808Sgonzo /* Rx ring. */ 1625188808Sgonzo if (sc->arge_cdata.arge_rx_ring_tag) { 1626188808Sgonzo if (sc->arge_cdata.arge_rx_ring_map) 1627188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_rx_ring_tag, 1628188808Sgonzo sc->arge_cdata.arge_rx_ring_map); 1629188808Sgonzo if (sc->arge_cdata.arge_rx_ring_map && 1630188808Sgonzo sc->arge_rdata.arge_rx_ring) 1631188808Sgonzo bus_dmamem_free(sc->arge_cdata.arge_rx_ring_tag, 1632188808Sgonzo sc->arge_rdata.arge_rx_ring, 1633188808Sgonzo sc->arge_cdata.arge_rx_ring_map); 1634188808Sgonzo sc->arge_rdata.arge_rx_ring = NULL; 1635188808Sgonzo sc->arge_cdata.arge_rx_ring_map = NULL; 1636188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_rx_ring_tag); 1637188808Sgonzo sc->arge_cdata.arge_rx_ring_tag = NULL; 1638188808Sgonzo } 1639188808Sgonzo /* Tx buffers. */ 1640188808Sgonzo if (sc->arge_cdata.arge_tx_tag) { 1641188808Sgonzo for (i = 0; i < ARGE_TX_RING_COUNT; i++) { 1642188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[i]; 1643188808Sgonzo if (txd->tx_dmamap) { 1644188808Sgonzo bus_dmamap_destroy(sc->arge_cdata.arge_tx_tag, 1645188808Sgonzo txd->tx_dmamap); 1646188808Sgonzo txd->tx_dmamap = NULL; 1647188808Sgonzo } 1648188808Sgonzo } 1649188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_tx_tag); 1650188808Sgonzo sc->arge_cdata.arge_tx_tag = NULL; 1651188808Sgonzo } 1652188808Sgonzo /* Rx buffers. */ 1653188808Sgonzo if (sc->arge_cdata.arge_rx_tag) { 1654188808Sgonzo for (i = 0; i < ARGE_RX_RING_COUNT; i++) { 1655188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[i]; 1656188808Sgonzo if (rxd->rx_dmamap) { 1657188808Sgonzo bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag, 1658188808Sgonzo rxd->rx_dmamap); 1659188808Sgonzo rxd->rx_dmamap = NULL; 1660188808Sgonzo } 1661188808Sgonzo } 1662188808Sgonzo if (sc->arge_cdata.arge_rx_sparemap) { 1663188808Sgonzo bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag, 1664188808Sgonzo sc->arge_cdata.arge_rx_sparemap); 1665188808Sgonzo sc->arge_cdata.arge_rx_sparemap = 0; 1666188808Sgonzo } 1667188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_rx_tag); 1668188808Sgonzo sc->arge_cdata.arge_rx_tag = NULL; 1669188808Sgonzo } 1670188808Sgonzo 1671188808Sgonzo if (sc->arge_cdata.arge_parent_tag) { 1672188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_parent_tag); 1673188808Sgonzo sc->arge_cdata.arge_parent_tag = NULL; 1674188808Sgonzo } 1675188808Sgonzo} 1676188808Sgonzo 1677188808Sgonzo/* 1678188808Sgonzo * Initialize the transmit descriptors. 1679188808Sgonzo */ 1680188808Sgonzostatic int 1681188808Sgonzoarge_tx_ring_init(struct arge_softc *sc) 1682188808Sgonzo{ 1683188808Sgonzo struct arge_ring_data *rd; 1684188808Sgonzo struct arge_txdesc *txd; 1685188808Sgonzo bus_addr_t addr; 1686188808Sgonzo int i; 1687188808Sgonzo 1688188808Sgonzo sc->arge_cdata.arge_tx_prod = 0; 1689188808Sgonzo sc->arge_cdata.arge_tx_cons = 0; 1690188808Sgonzo sc->arge_cdata.arge_tx_cnt = 0; 1691188808Sgonzo 1692188808Sgonzo rd = &sc->arge_rdata; 1693188808Sgonzo bzero(rd->arge_tx_ring, sizeof(rd->arge_tx_ring)); 1694188808Sgonzo for (i = 0; i < ARGE_TX_RING_COUNT; i++) { 1695188808Sgonzo if (i == ARGE_TX_RING_COUNT - 1) 1696188808Sgonzo addr = ARGE_TX_RING_ADDR(sc, 0); 1697188808Sgonzo else 1698188808Sgonzo addr = ARGE_TX_RING_ADDR(sc, i + 1); 1699188808Sgonzo rd->arge_tx_ring[i].packet_ctrl = ARGE_DESC_EMPTY; 1700188808Sgonzo rd->arge_tx_ring[i].next_desc = addr; 1701188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[i]; 1702188808Sgonzo txd->tx_m = NULL; 1703188808Sgonzo } 1704188808Sgonzo 1705188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, 1706188808Sgonzo sc->arge_cdata.arge_tx_ring_map, 1707188808Sgonzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1708188808Sgonzo 1709188808Sgonzo return (0); 1710188808Sgonzo} 1711188808Sgonzo 1712188808Sgonzo/* 1713255300Sloos * Free the Tx ring, unload any pending dma transaction and free the mbuf. 1714255300Sloos */ 1715255300Sloosstatic void 1716255300Sloosarge_tx_ring_free(struct arge_softc *sc) 1717255300Sloos{ 1718255300Sloos struct arge_txdesc *txd; 1719255300Sloos int i; 1720255300Sloos 1721255300Sloos /* Free the Tx buffers. */ 1722255300Sloos for (i = 0; i < ARGE_TX_RING_COUNT; i++) { 1723255300Sloos txd = &sc->arge_cdata.arge_txdesc[i]; 1724255300Sloos if (txd->tx_dmamap) { 1725255300Sloos bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, 1726255300Sloos txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 1727255300Sloos bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, 1728255300Sloos txd->tx_dmamap); 1729255300Sloos } 1730255300Sloos if (txd->tx_m) 1731255300Sloos m_freem(txd->tx_m); 1732255300Sloos txd->tx_m = NULL; 1733255300Sloos } 1734255300Sloos} 1735255300Sloos 1736255300Sloos/* 1737188808Sgonzo * Initialize the RX descriptors and allocate mbufs for them. Note that 1738188808Sgonzo * we arrange the descriptors in a closed ring, so that the last descriptor 1739188808Sgonzo * points back to the first. 1740188808Sgonzo */ 1741188808Sgonzostatic int 1742188808Sgonzoarge_rx_ring_init(struct arge_softc *sc) 1743188808Sgonzo{ 1744188808Sgonzo struct arge_ring_data *rd; 1745188808Sgonzo struct arge_rxdesc *rxd; 1746188808Sgonzo bus_addr_t addr; 1747188808Sgonzo int i; 1748188808Sgonzo 1749188808Sgonzo sc->arge_cdata.arge_rx_cons = 0; 1750188808Sgonzo 1751188808Sgonzo rd = &sc->arge_rdata; 1752188808Sgonzo bzero(rd->arge_rx_ring, sizeof(rd->arge_rx_ring)); 1753188808Sgonzo for (i = 0; i < ARGE_RX_RING_COUNT; i++) { 1754188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[i]; 1755232912Sadrian if (rxd->rx_m != NULL) { 1756232912Sadrian device_printf(sc->arge_dev, 1757232912Sadrian "%s: ring[%d] rx_m wasn't free?\n", 1758232912Sadrian __func__, 1759232912Sadrian i); 1760232912Sadrian } 1761188808Sgonzo rxd->rx_m = NULL; 1762188808Sgonzo rxd->desc = &rd->arge_rx_ring[i]; 1763188808Sgonzo if (i == ARGE_RX_RING_COUNT - 1) 1764188808Sgonzo addr = ARGE_RX_RING_ADDR(sc, 0); 1765188808Sgonzo else 1766188808Sgonzo addr = ARGE_RX_RING_ADDR(sc, i + 1); 1767188808Sgonzo rd->arge_rx_ring[i].next_desc = addr; 1768192783Sgonzo if (arge_newbuf(sc, i) != 0) { 1769188808Sgonzo return (ENOBUFS); 1770192783Sgonzo } 1771188808Sgonzo } 1772188808Sgonzo 1773188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, 1774188808Sgonzo sc->arge_cdata.arge_rx_ring_map, 1775195434Sgonzo BUS_DMASYNC_PREWRITE); 1776188808Sgonzo 1777188808Sgonzo return (0); 1778188808Sgonzo} 1779188808Sgonzo 1780188808Sgonzo/* 1781232912Sadrian * Free all the buffers in the RX ring. 1782232912Sadrian * 1783232912Sadrian * TODO: ensure that DMA is disabled and no pending DMA 1784232912Sadrian * is lurking in the FIFO. 1785232912Sadrian */ 1786232912Sadrianstatic void 1787232912Sadrianarge_rx_ring_free(struct arge_softc *sc) 1788232912Sadrian{ 1789232912Sadrian int i; 1790232912Sadrian struct arge_rxdesc *rxd; 1791232912Sadrian 1792232912Sadrian ARGE_LOCK_ASSERT(sc); 1793232912Sadrian 1794232912Sadrian for (i = 0; i < ARGE_RX_RING_COUNT; i++) { 1795232912Sadrian rxd = &sc->arge_cdata.arge_rxdesc[i]; 1796232912Sadrian /* Unmap the mbuf */ 1797232912Sadrian if (rxd->rx_m != NULL) { 1798232912Sadrian bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, 1799232912Sadrian rxd->rx_dmamap); 1800232912Sadrian m_free(rxd->rx_m); 1801232912Sadrian rxd->rx_m = NULL; 1802232912Sadrian } 1803232912Sadrian } 1804232912Sadrian} 1805232912Sadrian 1806232912Sadrian/* 1807188808Sgonzo * Initialize an RX descriptor and attach an MBUF cluster. 1808188808Sgonzo */ 1809188808Sgonzostatic int 1810188808Sgonzoarge_newbuf(struct arge_softc *sc, int idx) 1811188808Sgonzo{ 1812188808Sgonzo struct arge_desc *desc; 1813188808Sgonzo struct arge_rxdesc *rxd; 1814188808Sgonzo struct mbuf *m; 1815188808Sgonzo bus_dma_segment_t segs[1]; 1816188808Sgonzo bus_dmamap_t map; 1817188808Sgonzo int nsegs; 1818188808Sgonzo 1819243882Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1820188808Sgonzo if (m == NULL) 1821188808Sgonzo return (ENOBUFS); 1822188808Sgonzo m->m_len = m->m_pkthdr.len = MCLBYTES; 1823188808Sgonzo m_adj(m, sizeof(uint64_t)); 1824188808Sgonzo 1825188808Sgonzo if (bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_rx_tag, 1826188808Sgonzo sc->arge_cdata.arge_rx_sparemap, m, segs, &nsegs, 0) != 0) { 1827188808Sgonzo m_freem(m); 1828188808Sgonzo return (ENOBUFS); 1829188808Sgonzo } 1830188808Sgonzo KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1831188808Sgonzo 1832188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[idx]; 1833188808Sgonzo if (rxd->rx_m != NULL) { 1834188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap); 1835188808Sgonzo } 1836188808Sgonzo map = rxd->rx_dmamap; 1837188808Sgonzo rxd->rx_dmamap = sc->arge_cdata.arge_rx_sparemap; 1838188808Sgonzo sc->arge_cdata.arge_rx_sparemap = map; 1839188808Sgonzo rxd->rx_m = m; 1840188808Sgonzo desc = rxd->desc; 1841192783Sgonzo if (segs[0].ds_addr & 3) 1842192783Sgonzo panic("RX packet address unaligned"); 1843188808Sgonzo desc->packet_addr = segs[0].ds_addr; 1844192783Sgonzo desc->packet_ctrl = ARGE_DESC_EMPTY | ARGE_DMASIZE(segs[0].ds_len); 1845188808Sgonzo 1846195434Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, 1847195434Sgonzo sc->arge_cdata.arge_rx_ring_map, 1848195434Sgonzo BUS_DMASYNC_PREWRITE); 1849195434Sgonzo 1850188808Sgonzo return (0); 1851188808Sgonzo} 1852188808Sgonzo 1853188808Sgonzostatic __inline void 1854188808Sgonzoarge_fixup_rx(struct mbuf *m) 1855188808Sgonzo{ 1856198933Sgonzo int i; 1857198933Sgonzo uint16_t *src, *dst; 1858188808Sgonzo 1859188808Sgonzo src = mtod(m, uint16_t *); 1860188808Sgonzo dst = src - 1; 1861188808Sgonzo 1862195434Sgonzo for (i = 0; i < m->m_len / sizeof(uint16_t); i++) { 1863188808Sgonzo *dst++ = *src++; 1864195434Sgonzo } 1865188808Sgonzo 1866195434Sgonzo if (m->m_len % sizeof(uint16_t)) 1867195434Sgonzo *(uint8_t *)dst = *(uint8_t *)src; 1868195434Sgonzo 1869188808Sgonzo m->m_data -= ETHER_ALIGN; 1870188808Sgonzo} 1871188808Sgonzo 1872192783Sgonzo#ifdef DEVICE_POLLING 1873198667Sgonzostatic int 1874192783Sgonzoarge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1875192783Sgonzo{ 1876192783Sgonzo struct arge_softc *sc = ifp->if_softc; 1877198667Sgonzo int rx_npkts = 0; 1878188808Sgonzo 1879198933Sgonzo if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1880192783Sgonzo ARGE_LOCK(sc); 1881192783Sgonzo arge_tx_locked(sc); 1882198667Sgonzo rx_npkts = arge_rx_locked(sc); 1883192783Sgonzo ARGE_UNLOCK(sc); 1884198933Sgonzo } 1885198667Sgonzo 1886198667Sgonzo return (rx_npkts); 1887192783Sgonzo} 1888192783Sgonzo#endif /* DEVICE_POLLING */ 1889192783Sgonzo 1890192783Sgonzo 1891188808Sgonzostatic void 1892188808Sgonzoarge_tx_locked(struct arge_softc *sc) 1893188808Sgonzo{ 1894188808Sgonzo struct arge_txdesc *txd; 1895188808Sgonzo struct arge_desc *cur_tx; 1896188808Sgonzo struct ifnet *ifp; 1897188808Sgonzo uint32_t ctrl; 1898188808Sgonzo int cons, prod; 1899188808Sgonzo 1900188808Sgonzo ARGE_LOCK_ASSERT(sc); 1901188808Sgonzo 1902188808Sgonzo cons = sc->arge_cdata.arge_tx_cons; 1903188808Sgonzo prod = sc->arge_cdata.arge_tx_prod; 1904220356Sadrian 1905232628Sray ARGEDEBUG(sc, ARGE_DBG_TX, "%s: cons=%d, prod=%d\n", __func__, cons, 1906232628Sray prod); 1907220356Sadrian 1908188808Sgonzo if (cons == prod) 1909188808Sgonzo return; 1910188808Sgonzo 1911188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, 1912188808Sgonzo sc->arge_cdata.arge_tx_ring_map, 1913188808Sgonzo BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1914188808Sgonzo 1915188808Sgonzo ifp = sc->arge_ifp; 1916188808Sgonzo /* 1917188808Sgonzo * Go through our tx list and free mbufs for those 1918188808Sgonzo * frames that have been transmitted. 1919188808Sgonzo */ 1920188808Sgonzo for (; cons != prod; ARGE_INC(cons, ARGE_TX_RING_COUNT)) { 1921188808Sgonzo cur_tx = &sc->arge_rdata.arge_tx_ring[cons]; 1922188808Sgonzo ctrl = cur_tx->packet_ctrl; 1923188808Sgonzo /* Check if descriptor has "finished" flag */ 1924188808Sgonzo if ((ctrl & ARGE_DESC_EMPTY) == 0) 1925188808Sgonzo break; 1926188808Sgonzo 1927188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT); 1928188808Sgonzo 1929188808Sgonzo sc->arge_cdata.arge_tx_cnt--; 1930188808Sgonzo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1931188808Sgonzo 1932188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[cons]; 1933188808Sgonzo 1934188808Sgonzo ifp->if_opackets++; 1935188808Sgonzo 1936188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap, 1937188808Sgonzo BUS_DMASYNC_POSTWRITE); 1938188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap); 1939188808Sgonzo 1940188808Sgonzo /* Free only if it's first descriptor in list */ 1941188808Sgonzo if (txd->tx_m) 1942188808Sgonzo m_freem(txd->tx_m); 1943188808Sgonzo txd->tx_m = NULL; 1944188808Sgonzo 1945188808Sgonzo /* reset descriptor */ 1946188808Sgonzo cur_tx->packet_addr = 0; 1947188808Sgonzo } 1948188808Sgonzo 1949188808Sgonzo sc->arge_cdata.arge_tx_cons = cons; 1950188808Sgonzo 1951188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, 1952188808Sgonzo sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREWRITE); 1953188808Sgonzo} 1954188808Sgonzo 1955188808Sgonzo 1956198667Sgonzostatic int 1957188808Sgonzoarge_rx_locked(struct arge_softc *sc) 1958188808Sgonzo{ 1959188808Sgonzo struct arge_rxdesc *rxd; 1960188808Sgonzo struct ifnet *ifp = sc->arge_ifp; 1961192783Sgonzo int cons, prog, packet_len, i; 1962188808Sgonzo struct arge_desc *cur_rx; 1963188808Sgonzo struct mbuf *m; 1964198667Sgonzo int rx_npkts = 0; 1965188808Sgonzo 1966188808Sgonzo ARGE_LOCK_ASSERT(sc); 1967188808Sgonzo 1968188808Sgonzo cons = sc->arge_cdata.arge_rx_cons; 1969188808Sgonzo 1970188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, 1971188808Sgonzo sc->arge_cdata.arge_rx_ring_map, 1972188808Sgonzo BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1973188808Sgonzo 1974232627Sray for (prog = 0; prog < ARGE_RX_RING_COUNT; 1975188808Sgonzo ARGE_INC(cons, ARGE_RX_RING_COUNT)) { 1976188808Sgonzo cur_rx = &sc->arge_rdata.arge_rx_ring[cons]; 1977188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[cons]; 1978188808Sgonzo m = rxd->rx_m; 1979188808Sgonzo 1980188808Sgonzo if ((cur_rx->packet_ctrl & ARGE_DESC_EMPTY) != 0) 1981232627Sray break; 1982188808Sgonzo 1983188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD); 1984188808Sgonzo 1985188808Sgonzo prog++; 1986188808Sgonzo 1987188808Sgonzo packet_len = ARGE_DMASIZE(cur_rx->packet_ctrl); 1988188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap, 1989195434Sgonzo BUS_DMASYNC_POSTREAD); 1990188808Sgonzo m = rxd->rx_m; 1991188808Sgonzo 1992188808Sgonzo arge_fixup_rx(m); 1993188808Sgonzo m->m_pkthdr.rcvif = ifp; 1994188808Sgonzo /* Skip 4 bytes of CRC */ 1995188808Sgonzo m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN; 1996188808Sgonzo ifp->if_ipackets++; 1997198667Sgonzo rx_npkts++; 1998188808Sgonzo 1999188808Sgonzo ARGE_UNLOCK(sc); 2000188808Sgonzo (*ifp->if_input)(ifp, m); 2001188808Sgonzo ARGE_LOCK(sc); 2002192783Sgonzo cur_rx->packet_addr = 0; 2003192783Sgonzo } 2004188808Sgonzo 2005192783Sgonzo if (prog > 0) { 2006192783Sgonzo 2007192783Sgonzo i = sc->arge_cdata.arge_rx_cons; 2008192783Sgonzo for (; prog > 0 ; prog--) { 2009192783Sgonzo if (arge_newbuf(sc, i) != 0) { 2010232627Sray device_printf(sc->arge_dev, 2011192783Sgonzo "Failed to allocate buffer\n"); 2012192783Sgonzo break; 2013192783Sgonzo } 2014192783Sgonzo ARGE_INC(i, ARGE_RX_RING_COUNT); 2015188808Sgonzo } 2016188808Sgonzo 2017188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, 2018188808Sgonzo sc->arge_cdata.arge_rx_ring_map, 2019195434Sgonzo BUS_DMASYNC_PREWRITE); 2020188808Sgonzo 2021188808Sgonzo sc->arge_cdata.arge_rx_cons = cons; 2022188808Sgonzo } 2023198667Sgonzo 2024198667Sgonzo return (rx_npkts); 2025188808Sgonzo} 2026188808Sgonzo 2027188808Sgonzostatic int 2028188808Sgonzoarge_intr_filter(void *arg) 2029188808Sgonzo{ 2030188808Sgonzo struct arge_softc *sc = arg; 2031188808Sgonzo uint32_t status, ints; 2032188808Sgonzo 2033188808Sgonzo status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS); 2034188808Sgonzo ints = ARGE_READ(sc, AR71XX_DMA_INTR); 2035188808Sgonzo 2036220354Sadrian ARGEDEBUG(sc, ARGE_DBG_INTR, "int mask(filter) = %b\n", ints, 2037188808Sgonzo "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD" 2038188808Sgonzo "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); 2039232627Sray ARGEDEBUG(sc, ARGE_DBG_INTR, "status(filter) = %b\n", status, 2040188808Sgonzo "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD" 2041188808Sgonzo "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); 2042188808Sgonzo 2043188808Sgonzo if (status & DMA_INTR_ALL) { 2044191644Sgonzo sc->arge_intr_status |= status; 2045192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); 2046188808Sgonzo return (FILTER_SCHEDULE_THREAD); 2047232627Sray } 2048188808Sgonzo 2049188808Sgonzo sc->arge_intr_status = 0; 2050188808Sgonzo return (FILTER_STRAY); 2051188808Sgonzo} 2052188808Sgonzo 2053188808Sgonzostatic void 2054188808Sgonzoarge_intr(void *arg) 2055188808Sgonzo{ 2056188808Sgonzo struct arge_softc *sc = arg; 2057188808Sgonzo uint32_t status; 2058220356Sadrian struct ifnet *ifp = sc->arge_ifp; 2059188808Sgonzo 2060192783Sgonzo status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS); 2061192783Sgonzo status |= sc->arge_intr_status; 2062188808Sgonzo 2063232627Sray ARGEDEBUG(sc, ARGE_DBG_INTR, "int status(intr) = %b\n", status, 2064188808Sgonzo "\20\10\7RX_OVERFLOW\5RX_PKT_RCVD" 2065188808Sgonzo "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); 2066188808Sgonzo 2067232627Sray /* 2068232627Sray * Is it our interrupt at all? 2069188808Sgonzo */ 2070188808Sgonzo if (status == 0) 2071188808Sgonzo return; 2072188808Sgonzo 2073188808Sgonzo if (status & DMA_INTR_RX_BUS_ERROR) { 2074188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR); 2075188808Sgonzo device_printf(sc->arge_dev, "RX bus error"); 2076188808Sgonzo return; 2077188808Sgonzo } 2078188808Sgonzo 2079188808Sgonzo if (status & DMA_INTR_TX_BUS_ERROR) { 2080188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR); 2081188808Sgonzo device_printf(sc->arge_dev, "TX bus error"); 2082188808Sgonzo return; 2083188808Sgonzo } 2084188808Sgonzo 2085192783Sgonzo ARGE_LOCK(sc); 2086188808Sgonzo 2087192783Sgonzo if (status & DMA_INTR_RX_PKT_RCVD) 2088192783Sgonzo arge_rx_locked(sc); 2089188808Sgonzo 2090232627Sray /* 2091232627Sray * RX overrun disables the receiver. 2092232627Sray * Clear indication and re-enable rx. 2093192783Sgonzo */ 2094192783Sgonzo if ( status & DMA_INTR_RX_OVERFLOW) { 2095192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_OVERFLOW); 2096192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN); 2097220356Sadrian sc->stats.rx_overflow++; 2098192783Sgonzo } 2099188808Sgonzo 2100192783Sgonzo if (status & DMA_INTR_TX_PKT_SENT) 2101192783Sgonzo arge_tx_locked(sc); 2102232627Sray /* 2103232627Sray * Underrun turns off TX. Clear underrun indication. 2104232627Sray * If there's anything left in the ring, reactivate the tx. 2105192783Sgonzo */ 2106192569Sdwhite if (status & DMA_INTR_TX_UNDERRUN) { 2107192569Sdwhite ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_UNDERRUN); 2108220356Sadrian sc->stats.tx_underflow++; 2109232628Sray ARGEDEBUG(sc, ARGE_DBG_TX, "%s: TX underrun; tx_cnt=%d\n", 2110232628Sray __func__, sc->arge_cdata.arge_tx_cnt); 2111219590Sadrian if (sc->arge_cdata.arge_tx_cnt > 0 ) { 2112232627Sray ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 2113192783Sgonzo DMA_TX_CONTROL_EN); 2114192783Sgonzo } 2115192569Sdwhite } 2116192569Sdwhite 2117192946Sgonzo /* 2118220357Sadrian * If we've finished TXing and there's space for more packets 2119220357Sadrian * to be queued for TX, do so. Otherwise we may end up in a 2120220357Sadrian * situation where the interface send queue was filled 2121220357Sadrian * whilst the hardware queue was full, then the hardware 2122220357Sadrian * queue was drained by the interface send queue wasn't, 2123220357Sadrian * and thus if_start() is never called to kick-start 2124220357Sadrian * the send process (and all subsequent packets are simply 2125220357Sadrian * discarded. 2126220357Sadrian * 2127220357Sadrian * XXX TODO: make sure that the hardware deals nicely 2128220357Sadrian * with the possibility of the queue being enabled above 2129220357Sadrian * after a TX underrun, then having the hardware queue added 2130220357Sadrian * to below. 2131220357Sadrian */ 2132220357Sadrian if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN) && 2133220357Sadrian (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 2134220357Sadrian if (!IFQ_IS_EMPTY(&ifp->if_snd)) 2135220357Sadrian arge_start_locked(ifp); 2136220357Sadrian } 2137220357Sadrian 2138220357Sadrian /* 2139192946Sgonzo * We handled all bits, clear status 2140192946Sgonzo */ 2141192946Sgonzo sc->arge_intr_status = 0; 2142188808Sgonzo ARGE_UNLOCK(sc); 2143192783Sgonzo /* 2144232627Sray * re-enable all interrupts 2145192783Sgonzo */ 2146192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); 2147188808Sgonzo} 2148188808Sgonzo 2149192783Sgonzo 2150188808Sgonzostatic void 2151188808Sgonzoarge_tick(void *xsc) 2152188808Sgonzo{ 2153188808Sgonzo struct arge_softc *sc = xsc; 2154188808Sgonzo struct mii_data *mii; 2155188808Sgonzo 2156188808Sgonzo ARGE_LOCK_ASSERT(sc); 2157188808Sgonzo 2158199234Sgonzo if (sc->arge_miibus) { 2159199234Sgonzo mii = device_get_softc(sc->arge_miibus); 2160199234Sgonzo mii_tick(mii); 2161199234Sgonzo callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); 2162199234Sgonzo } 2163188808Sgonzo} 2164199234Sgonzo 2165199234Sgonzoint 2166199234Sgonzoarge_multiphy_mediachange(struct ifnet *ifp) 2167199234Sgonzo{ 2168199234Sgonzo struct arge_softc *sc = ifp->if_softc; 2169199234Sgonzo struct ifmedia *ifm = &sc->arge_ifmedia; 2170199234Sgonzo struct ifmedia_entry *ife = ifm->ifm_cur; 2171199234Sgonzo 2172199234Sgonzo if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 2173199234Sgonzo return (EINVAL); 2174199234Sgonzo 2175199234Sgonzo if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 2176232627Sray device_printf(sc->arge_dev, 2177199234Sgonzo "AUTO is not supported for multiphy MAC"); 2178199234Sgonzo return (EINVAL); 2179199234Sgonzo } 2180199234Sgonzo 2181199234Sgonzo /* 2182199234Sgonzo * Ignore everything 2183199234Sgonzo */ 2184199234Sgonzo return (0); 2185199234Sgonzo} 2186199234Sgonzo 2187199234Sgonzovoid 2188199234Sgonzoarge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 2189199234Sgonzo{ 2190199234Sgonzo struct arge_softc *sc = ifp->if_softc; 2191199234Sgonzo 2192199234Sgonzo ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 2193232627Sray ifmr->ifm_active = IFM_ETHER | sc->arge_media_type | 2194199234Sgonzo sc->arge_duplex_mode; 2195199234Sgonzo} 2196199234Sgonzo 2197234862Sadrian#if defined(ARGE_MDIO) 2198234862Sadrianstatic int 2199234862Sadrianargemdio_probe(device_t dev) 2200234862Sadrian{ 2201234862Sadrian device_set_desc(dev, "Atheros AR71xx built-in ethernet interface, MDIO controller"); 2202234862Sadrian return (0); 2203234862Sadrian} 2204234862Sadrian 2205234862Sadrianstatic int 2206234862Sadrianargemdio_attach(device_t dev) 2207234862Sadrian{ 2208234862Sadrian struct arge_softc *sc; 2209234862Sadrian int error = 0; 2210234862Sadrian 2211234862Sadrian sc = device_get_softc(dev); 2212234862Sadrian sc->arge_dev = dev; 2213234862Sadrian sc->arge_mac_unit = device_get_unit(dev); 2214234862Sadrian sc->arge_rid = 0; 2215234862Sadrian sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2216234862Sadrian &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE); 2217234862Sadrian if (sc->arge_res == NULL) { 2218234862Sadrian device_printf(dev, "couldn't map memory\n"); 2219234862Sadrian error = ENXIO; 2220234862Sadrian goto fail; 2221234862Sadrian } 2222234862Sadrian 2223234862Sadrian /* Reset MAC - required for AR71xx MDIO to successfully occur */ 2224234862Sadrian arge_reset_mac(sc); 2225234862Sadrian /* Reset MII bus */ 2226234862Sadrian arge_reset_miibus(sc); 2227234862Sadrian 2228234862Sadrian bus_generic_probe(dev); 2229234862Sadrian bus_enumerate_hinted_children(dev); 2230234862Sadrian error = bus_generic_attach(dev); 2231234862Sadrianfail: 2232234862Sadrian return (error); 2233234862Sadrian} 2234234862Sadrian 2235234862Sadrianstatic int 2236234862Sadrianargemdio_detach(device_t dev) 2237234862Sadrian{ 2238234862Sadrian return (0); 2239234862Sadrian} 2240234862Sadrian 2241234862Sadrian#endif 2242