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 38188808Sgonzo#include <sys/param.h> 39188808Sgonzo#include <sys/endian.h> 40188808Sgonzo#include <sys/systm.h> 41188808Sgonzo#include <sys/sockio.h> 42188808Sgonzo#include <sys/mbuf.h> 43188808Sgonzo#include <sys/malloc.h> 44188808Sgonzo#include <sys/kernel.h> 45188808Sgonzo#include <sys/module.h> 46188808Sgonzo#include <sys/socket.h> 47188808Sgonzo#include <sys/taskqueue.h> 48209802Sadrian#include <sys/sysctl.h> 49188808Sgonzo 50188808Sgonzo#include <net/if.h> 51188808Sgonzo#include <net/if_arp.h> 52188808Sgonzo#include <net/ethernet.h> 53188808Sgonzo#include <net/if_dl.h> 54188808Sgonzo#include <net/if_media.h> 55188808Sgonzo#include <net/if_types.h> 56188808Sgonzo 57188808Sgonzo#include <net/bpf.h> 58188808Sgonzo 59188808Sgonzo#include <machine/bus.h> 60188808Sgonzo#include <machine/cache.h> 61188808Sgonzo#include <machine/resource.h> 62188808Sgonzo#include <vm/vm_param.h> 63188808Sgonzo#include <vm/vm.h> 64188808Sgonzo#include <vm/pmap.h> 65188808Sgonzo#include <machine/pmap.h> 66188808Sgonzo#include <sys/bus.h> 67188808Sgonzo#include <sys/rman.h> 68188808Sgonzo 69188808Sgonzo#include <dev/mii/mii.h> 70188808Sgonzo#include <dev/mii/miivar.h> 71188808Sgonzo 72188808Sgonzo#include <dev/pci/pcireg.h> 73188808Sgonzo#include <dev/pci/pcivar.h> 74188808Sgonzo 75188808SgonzoMODULE_DEPEND(arge, ether, 1, 1, 1); 76188808SgonzoMODULE_DEPEND(arge, miibus, 1, 1, 1); 77188808Sgonzo 78188808Sgonzo#include "miibus_if.h" 79188808Sgonzo 80188808Sgonzo#include <mips/atheros/ar71xxreg.h> 81188808Sgonzo#include <mips/atheros/if_argevar.h> 82219589Sadrian#include <mips/atheros/ar71xx_setup.h> 83211477Sadrian#include <mips/atheros/ar71xx_cpudef.h> 84188808Sgonzo 85220354Sadriantypedef enum { 86220354Sadrian ARGE_DBG_MII = 0x00000001, 87220356Sadrian ARGE_DBG_INTR = 0x00000002, 88220356Sadrian ARGE_DBG_TX = 0x00000004, 89220356Sadrian ARGE_DBG_RX = 0x00000008, 90220356Sadrian ARGE_DBG_ERR = 0x00000010, 91220356Sadrian ARGE_DBG_RESET = 0x00000020, 92220354Sadrian} arge_debug_flags; 93220354Sadrian 94188808Sgonzo#ifdef ARGE_DEBUG 95220354Sadrian#define ARGEDEBUG(_sc, _m, ...) \ 96220354Sadrian do { \ 97220354Sadrian if ((_m) & (_sc)->arge_debug) \ 98220354Sadrian device_printf((_sc)->arge_dev, __VA_ARGS__); \ 99220354Sadrian } while (0) 100188808Sgonzo#else 101220354Sadrian#define ARGEDEBUG(_sc, _m, ...) 102188808Sgonzo#endif 103188808Sgonzo 104188808Sgonzostatic int arge_attach(device_t); 105188808Sgonzostatic int arge_detach(device_t); 106188808Sgonzostatic void arge_flush_ddr(struct arge_softc *); 107188808Sgonzostatic int arge_ifmedia_upd(struct ifnet *); 108188808Sgonzostatic void arge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 109188808Sgonzostatic int arge_ioctl(struct ifnet *, u_long, caddr_t); 110188808Sgonzostatic void arge_init(void *); 111188808Sgonzostatic void arge_init_locked(struct arge_softc *); 112188808Sgonzostatic void arge_link_task(void *, int); 113199234Sgonzostatic void arge_set_pll(struct arge_softc *, int, int); 114188808Sgonzostatic int arge_miibus_readreg(device_t, int, int); 115188808Sgonzostatic void arge_miibus_statchg(device_t); 116188808Sgonzostatic int arge_miibus_writereg(device_t, int, int, int); 117188808Sgonzostatic int arge_probe(device_t); 118188808Sgonzostatic void arge_reset_dma(struct arge_softc *); 119188808Sgonzostatic int arge_resume(device_t); 120188808Sgonzostatic int arge_rx_ring_init(struct arge_softc *); 121188808Sgonzostatic int arge_tx_ring_init(struct arge_softc *); 122192821Sgonzo#ifdef DEVICE_POLLING 123198667Sgonzostatic int arge_poll(struct ifnet *, enum poll_cmd, int); 124192821Sgonzo#endif 125194059Sgonzostatic int arge_shutdown(device_t); 126188808Sgonzostatic void arge_start(struct ifnet *); 127188808Sgonzostatic void arge_start_locked(struct ifnet *); 128188808Sgonzostatic void arge_stop(struct arge_softc *); 129188808Sgonzostatic int arge_suspend(device_t); 130188808Sgonzo 131198667Sgonzostatic int arge_rx_locked(struct arge_softc *); 132188808Sgonzostatic void arge_tx_locked(struct arge_softc *); 133188808Sgonzostatic void arge_intr(void *); 134188808Sgonzostatic int arge_intr_filter(void *); 135188808Sgonzostatic void arge_tick(void *); 136188808Sgonzo 137199234Sgonzo/* 138199234Sgonzo * ifmedia callbacks for multiPHY MAC 139199234Sgonzo */ 140199234Sgonzovoid arge_multiphy_mediastatus(struct ifnet *, struct ifmediareq *); 141199234Sgonzoint arge_multiphy_mediachange(struct ifnet *); 142199234Sgonzo 143188808Sgonzostatic void arge_dmamap_cb(void *, bus_dma_segment_t *, int, int); 144188808Sgonzostatic int arge_dma_alloc(struct arge_softc *); 145188808Sgonzostatic void arge_dma_free(struct arge_softc *); 146188808Sgonzostatic int arge_newbuf(struct arge_softc *, int); 147188808Sgonzostatic __inline void arge_fixup_rx(struct mbuf *); 148188808Sgonzo 149188808Sgonzostatic device_method_t arge_methods[] = { 150188808Sgonzo /* Device interface */ 151188808Sgonzo DEVMETHOD(device_probe, arge_probe), 152188808Sgonzo DEVMETHOD(device_attach, arge_attach), 153188808Sgonzo DEVMETHOD(device_detach, arge_detach), 154188808Sgonzo DEVMETHOD(device_suspend, arge_suspend), 155188808Sgonzo DEVMETHOD(device_resume, arge_resume), 156188808Sgonzo DEVMETHOD(device_shutdown, arge_shutdown), 157188808Sgonzo 158188808Sgonzo /* MII interface */ 159188808Sgonzo DEVMETHOD(miibus_readreg, arge_miibus_readreg), 160188808Sgonzo DEVMETHOD(miibus_writereg, arge_miibus_writereg), 161188808Sgonzo DEVMETHOD(miibus_statchg, arge_miibus_statchg), 162188808Sgonzo 163229093Shselasky DEVMETHOD_END 164188808Sgonzo}; 165188808Sgonzo 166188808Sgonzostatic driver_t arge_driver = { 167188808Sgonzo "arge", 168188808Sgonzo arge_methods, 169188808Sgonzo sizeof(struct arge_softc) 170188808Sgonzo}; 171188808Sgonzo 172188808Sgonzostatic devclass_t arge_devclass; 173188808Sgonzo 174188808SgonzoDRIVER_MODULE(arge, nexus, arge_driver, arge_devclass, 0, 0); 175188808SgonzoDRIVER_MODULE(miibus, arge, miibus_driver, miibus_devclass, 0, 0); 176188808Sgonzo 177188808Sgonzo/* 178192179Sgonzo * RedBoot passes MAC address to entry point as environment 179192179Sgonzo * variable. platfrom_start parses it and stores in this variable 180192179Sgonzo */ 181192179Sgonzoextern uint32_t ar711_base_mac[ETHER_ADDR_LEN]; 182192179Sgonzo 183199038Sgonzostatic struct mtx miibus_mtx; 184199038Sgonzo 185206400SgonzoMTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_DEF); 186199038Sgonzo 187199038Sgonzo 188192179Sgonzo/* 189188808Sgonzo * Flushes all 190188808Sgonzo */ 191188808Sgonzostatic void 192188808Sgonzoarge_flush_ddr(struct arge_softc *sc) 193188808Sgonzo{ 194211497Sadrian if (sc->arge_mac_unit == 0) 195211477Sadrian ar71xx_device_flush_ddr_ge0(); 196211497Sadrian else 197211477Sadrian ar71xx_device_flush_ddr_ge1(); 198188808Sgonzo} 199188808Sgonzo 200188808Sgonzostatic int 201188808Sgonzoarge_probe(device_t dev) 202188808Sgonzo{ 203188808Sgonzo 204188808Sgonzo device_set_desc(dev, "Atheros AR71xx built-in ethernet interface"); 205188808Sgonzo return (0); 206188808Sgonzo} 207188808Sgonzo 208209802Sadrianstatic void 209209802Sadrianarge_attach_sysctl(device_t dev) 210209802Sadrian{ 211209802Sadrian struct arge_softc *sc = device_get_softc(dev); 212209802Sadrian struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 213209802Sadrian struct sysctl_oid *tree = device_get_sysctl_tree(dev); 214209802Sadrian 215220355Sadrian#ifdef ARGE_DEBUG 216209802Sadrian SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 217209802Sadrian "debug", CTLFLAG_RW, &sc->arge_debug, 0, 218209802Sadrian "arge interface debugging flags"); 219220355Sadrian#endif 220209809Sadrian 221209809Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 222209809Sadrian "tx_pkts_aligned", CTLFLAG_RW, &sc->stats.tx_pkts_aligned, 0, 223209809Sadrian "number of TX aligned packets"); 224209809Sadrian 225209809Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 226209809Sadrian "tx_pkts_unaligned", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned, 0, 227209809Sadrian "number of TX unaligned packets"); 228220354Sadrian 229220355Sadrian#ifdef ARGE_DEBUG 230220355Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_prod", 231220355Sadrian CTLFLAG_RW, &sc->arge_cdata.arge_tx_prod, 0, ""); 232220355Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cons", 233220355Sadrian CTLFLAG_RW, &sc->arge_cdata.arge_tx_cons, 0, ""); 234220355Sadrian SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cnt", 235220355Sadrian CTLFLAG_RW, &sc->arge_cdata.arge_tx_cnt, 0, ""); 236220355Sadrian#endif 237209802Sadrian} 238209802Sadrian 239188808Sgonzostatic int 240188808Sgonzoarge_attach(device_t dev) 241188808Sgonzo{ 242188808Sgonzo uint8_t eaddr[ETHER_ADDR_LEN]; 243188808Sgonzo struct ifnet *ifp; 244188808Sgonzo struct arge_softc *sc; 245199234Sgonzo int error = 0, rid, phymask; 246192179Sgonzo uint32_t reg, rnd; 247199234Sgonzo int is_base_mac_empty, i, phys_total; 248199234Sgonzo uint32_t hint; 249220260Sadrian long eeprom_mac_addr = 0; 250188808Sgonzo 251188808Sgonzo sc = device_get_softc(dev); 252188808Sgonzo sc->arge_dev = dev; 253188808Sgonzo sc->arge_mac_unit = device_get_unit(dev); 254188808Sgonzo 255220260Sadrian /* 256220260Sadrian * Some units (eg the TP-Link WR-1043ND) do not have a convenient 257220260Sadrian * EEPROM location to read the ethernet MAC address from. 258220260Sadrian * OpenWRT simply snaffles it from a fixed location. 259220260Sadrian * 260220260Sadrian * Since multiple units seem to use this feature, include 261220260Sadrian * a method of setting the MAC address based on an flash location 262220260Sadrian * in CPU address space. 263220260Sadrian */ 264220260Sadrian if (sc->arge_mac_unit == 0 && 265220260Sadrian resource_long_value(device_get_name(dev), device_get_unit(dev), 266220260Sadrian "eeprommac", &eeprom_mac_addr) == 0) { 267220260Sadrian int i; 268220260Sadrian const char *mac = (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr); 269220260Sadrian device_printf(dev, "Overriding MAC from EEPROM\n"); 270220260Sadrian for (i = 0; i < 6; i++) { 271220260Sadrian ar711_base_mac[i] = mac[i]; 272220260Sadrian } 273220260Sadrian } 274220260Sadrian 275188808Sgonzo KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)), 276188808Sgonzo ("if_arge: Only MAC0 and MAC1 supported")); 277188808Sgonzo 278188808Sgonzo /* 279188808Sgonzo * Get which PHY of 5 available we should use for this unit 280188808Sgonzo */ 281188808Sgonzo if (resource_int_value(device_get_name(dev), device_get_unit(dev), 282199234Sgonzo "phymask", &phymask) != 0) { 283188808Sgonzo /* 284188808Sgonzo * Use port 4 (WAN) for GE0. For any other port use 285188808Sgonzo * its PHY the same as its unit number 286188808Sgonzo */ 287188808Sgonzo if (sc->arge_mac_unit == 0) 288199234Sgonzo phymask = (1 << 4); 289188808Sgonzo else 290199234Sgonzo /* Use all phys up to 4 */ 291199234Sgonzo phymask = (1 << 4) - 1; 292188808Sgonzo 293199234Sgonzo device_printf(dev, "No PHY specified, using mask %d\n", phymask); 294188808Sgonzo } 295188808Sgonzo 296199234Sgonzo /* 297199234Sgonzo * Get default media & duplex mode, by default its Base100T 298199234Sgonzo * and full duplex 299199234Sgonzo */ 300199234Sgonzo if (resource_int_value(device_get_name(dev), device_get_unit(dev), 301199234Sgonzo "media", &hint) != 0) 302199234Sgonzo hint = 0; 303188808Sgonzo 304199234Sgonzo if (hint == 1000) 305199234Sgonzo sc->arge_media_type = IFM_1000_T; 306199234Sgonzo else 307199234Sgonzo sc->arge_media_type = IFM_100_TX; 308199234Sgonzo 309199234Sgonzo if (resource_int_value(device_get_name(dev), device_get_unit(dev), 310199234Sgonzo "fduplex", &hint) != 0) 311199234Sgonzo hint = 1; 312199234Sgonzo 313199234Sgonzo if (hint) 314199234Sgonzo sc->arge_duplex_mode = IFM_FDX; 315199234Sgonzo else 316199234Sgonzo sc->arge_duplex_mode = 0; 317199234Sgonzo 318199234Sgonzo sc->arge_phymask = phymask; 319199234Sgonzo 320188808Sgonzo mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 321188808Sgonzo MTX_DEF); 322188808Sgonzo callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0); 323188808Sgonzo TASK_INIT(&sc->arge_link_task, 0, arge_link_task, sc); 324188808Sgonzo 325188808Sgonzo /* Map control/status registers. */ 326188808Sgonzo sc->arge_rid = 0; 327188808Sgonzo sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 328188808Sgonzo &sc->arge_rid, RF_ACTIVE); 329188808Sgonzo 330188808Sgonzo if (sc->arge_res == NULL) { 331188808Sgonzo device_printf(dev, "couldn't map memory\n"); 332188808Sgonzo error = ENXIO; 333188808Sgonzo goto fail; 334188808Sgonzo } 335188808Sgonzo 336188808Sgonzo /* Allocate interrupts */ 337188808Sgonzo rid = 0; 338188808Sgonzo sc->arge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 339188808Sgonzo RF_SHAREABLE | RF_ACTIVE); 340188808Sgonzo 341188808Sgonzo if (sc->arge_irq == NULL) { 342188808Sgonzo device_printf(dev, "couldn't map interrupt\n"); 343188808Sgonzo error = ENXIO; 344188808Sgonzo goto fail; 345188808Sgonzo } 346188808Sgonzo 347188808Sgonzo /* Allocate ifnet structure. */ 348188808Sgonzo ifp = sc->arge_ifp = if_alloc(IFT_ETHER); 349188808Sgonzo 350188808Sgonzo if (ifp == NULL) { 351188808Sgonzo device_printf(dev, "couldn't allocate ifnet structure\n"); 352188808Sgonzo error = ENOSPC; 353188808Sgonzo goto fail; 354188808Sgonzo } 355188808Sgonzo 356188808Sgonzo ifp->if_softc = sc; 357188808Sgonzo if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 358188808Sgonzo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 359188808Sgonzo ifp->if_ioctl = arge_ioctl; 360188808Sgonzo ifp->if_start = arge_start; 361188808Sgonzo ifp->if_init = arge_init; 362198932Sgonzo sc->arge_if_flags = ifp->if_flags; 363188808Sgonzo 364188808Sgonzo /* XXX: add real size */ 365207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 366207554Ssobomax ifp->if_snd.ifq_maxlen = ifqmaxlen; 367188808Sgonzo IFQ_SET_READY(&ifp->if_snd); 368188808Sgonzo 369188808Sgonzo ifp->if_capenable = ifp->if_capabilities; 370192783Sgonzo#ifdef DEVICE_POLLING 371192783Sgonzo ifp->if_capabilities |= IFCAP_POLLING; 372192783Sgonzo#endif 373188808Sgonzo 374192179Sgonzo is_base_mac_empty = 1; 375192179Sgonzo for (i = 0; i < ETHER_ADDR_LEN; i++) { 376192179Sgonzo eaddr[i] = ar711_base_mac[i] & 0xff; 377192179Sgonzo if (eaddr[i] != 0) 378192179Sgonzo is_base_mac_empty = 0; 379192179Sgonzo } 380188808Sgonzo 381192179Sgonzo if (is_base_mac_empty) { 382192179Sgonzo /* 383192179Sgonzo * No MAC address configured. Generate the random one. 384192179Sgonzo */ 385198933Sgonzo if (bootverbose) 386192179Sgonzo device_printf(dev, 387192179Sgonzo "Generating random ethernet address.\n"); 388192179Sgonzo 389192179Sgonzo rnd = arc4random(); 390192179Sgonzo eaddr[0] = 'b'; 391192179Sgonzo eaddr[1] = 's'; 392192179Sgonzo eaddr[2] = 'd'; 393192179Sgonzo eaddr[3] = (rnd >> 24) & 0xff; 394192179Sgonzo eaddr[4] = (rnd >> 16) & 0xff; 395192179Sgonzo eaddr[5] = (rnd >> 8) & 0xff; 396192179Sgonzo } 397192179Sgonzo 398198970Sgonzo if (sc->arge_mac_unit != 0) 399198970Sgonzo eaddr[5] += sc->arge_mac_unit; 400198970Sgonzo 401188808Sgonzo if (arge_dma_alloc(sc) != 0) { 402188808Sgonzo error = ENXIO; 403188808Sgonzo goto fail; 404188808Sgonzo } 405188808Sgonzo 406192569Sdwhite /* Initialize the MAC block */ 407192569Sdwhite 408192569Sdwhite /* Step 1. Soft-reset MAC */ 409192569Sdwhite ARGE_SET_BITS(sc, AR71XX_MAC_CFG1, MAC_CFG1_SOFT_RESET); 410192569Sdwhite DELAY(20); 411192569Sdwhite 412192569Sdwhite /* Step 2. Punt the MAC core from the central reset register */ 413211477Sadrian ar71xx_device_stop(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC : RST_RESET_GE1_MAC); 414192569Sdwhite DELAY(100); 415211477Sadrian ar71xx_device_start(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC : RST_RESET_GE1_MAC); 416192569Sdwhite 417192569Sdwhite /* Step 3. Reconfigure MAC block */ 418188808Sgonzo ARGE_WRITE(sc, AR71XX_MAC_CFG1, 419188808Sgonzo MAC_CFG1_SYNC_RX | MAC_CFG1_RX_ENABLE | 420188808Sgonzo MAC_CFG1_SYNC_TX | MAC_CFG1_TX_ENABLE); 421188808Sgonzo 422188808Sgonzo reg = ARGE_READ(sc, AR71XX_MAC_CFG2); 423188808Sgonzo reg |= MAC_CFG2_ENABLE_PADCRC | MAC_CFG2_LENGTH_FIELD ; 424188808Sgonzo ARGE_WRITE(sc, AR71XX_MAC_CFG2, reg); 425188808Sgonzo 426188808Sgonzo ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536); 427188808Sgonzo 428188808Sgonzo /* Reset MII bus */ 429188808Sgonzo ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET); 430188808Sgonzo DELAY(100); 431188808Sgonzo ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_CLOCK_DIV_28); 432188808Sgonzo DELAY(100); 433188808Sgonzo 434188808Sgonzo /* 435188808Sgonzo * Set all Ethernet address registers to the same initial values 436188808Sgonzo * set all four addresses to 66-88-aa-cc-dd-ee 437188808Sgonzo */ 438192783Sgonzo ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, 439192783Sgonzo (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]); 440192783Sgonzo ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (eaddr[0] << 8) | eaddr[1]); 441188808Sgonzo 442188808Sgonzo ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0, 443188808Sgonzo FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT); 444188808Sgonzo 445219589Sadrian switch (ar71xx_soc) { 446219589Sadrian case AR71XX_SOC_AR7240: 447219589Sadrian case AR71XX_SOC_AR7241: 448219589Sadrian case AR71XX_SOC_AR7242: 449219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0010ffff); 450219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x015500aa); 451219589Sadrian break; 452219589Sadrian default: 453219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0fff0000); 454219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff); 455219589Sadrian } 456219589Sadrian 457192783Sgonzo ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH, 458192783Sgonzo FIFO_RX_FILTMATCH_DEFAULT); 459188808Sgonzo 460192783Sgonzo ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, 461192783Sgonzo FIFO_RX_FILTMASK_DEFAULT); 462188808Sgonzo 463199234Sgonzo /* 464199234Sgonzo * Check if we have single-PHY MAC or multi-PHY 465199234Sgonzo */ 466199234Sgonzo phys_total = 0; 467199234Sgonzo for (i = 0; i < ARGE_NPHY; i++) 468199234Sgonzo if (phymask & (1 << i)) 469199234Sgonzo phys_total ++; 470199234Sgonzo 471199234Sgonzo if (phys_total == 0) { 472199234Sgonzo error = EINVAL; 473188808Sgonzo goto fail; 474188808Sgonzo } 475188808Sgonzo 476199234Sgonzo if (phys_total == 1) { 477199234Sgonzo /* Do MII setup. */ 478213894Smarius error = mii_attach(dev, &sc->arge_miibus, ifp, 479213894Smarius arge_ifmedia_upd, arge_ifmedia_sts, BMSR_DEFCAPMASK, 480213894Smarius MII_PHY_ANY, MII_OFFSET_ANY, 0); 481213894Smarius if (error != 0) { 482213894Smarius device_printf(dev, "attaching PHYs failed\n"); 483199234Sgonzo goto fail; 484199234Sgonzo } 485199234Sgonzo } 486199234Sgonzo else { 487199234Sgonzo ifmedia_init(&sc->arge_ifmedia, 0, 488199234Sgonzo arge_multiphy_mediachange, 489199234Sgonzo arge_multiphy_mediastatus); 490199234Sgonzo ifmedia_add(&sc->arge_ifmedia, 491199234Sgonzo IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode, 492199234Sgonzo 0, NULL); 493199234Sgonzo ifmedia_set(&sc->arge_ifmedia, 494199234Sgonzo IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode); 495199234Sgonzo arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode); 496199234Sgonzo } 497199234Sgonzo 498188808Sgonzo /* Call MI attach routine. */ 499188808Sgonzo ether_ifattach(ifp, eaddr); 500188808Sgonzo 501188808Sgonzo /* Hook interrupt last to avoid having to lock softc */ 502188808Sgonzo error = bus_setup_intr(dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE, 503188808Sgonzo arge_intr_filter, arge_intr, sc, &sc->arge_intrhand); 504188808Sgonzo 505188808Sgonzo if (error) { 506188808Sgonzo device_printf(dev, "couldn't set up irq\n"); 507188808Sgonzo ether_ifdetach(ifp); 508188808Sgonzo goto fail; 509188808Sgonzo } 510188808Sgonzo 511209802Sadrian /* setup sysctl variables */ 512209802Sadrian arge_attach_sysctl(dev); 513209802Sadrian 514188808Sgonzofail: 515188808Sgonzo if (error) 516188808Sgonzo arge_detach(dev); 517188808Sgonzo 518188808Sgonzo return (error); 519188808Sgonzo} 520188808Sgonzo 521188808Sgonzostatic int 522188808Sgonzoarge_detach(device_t dev) 523188808Sgonzo{ 524192783Sgonzo struct arge_softc *sc = device_get_softc(dev); 525188808Sgonzo struct ifnet *ifp = sc->arge_ifp; 526188808Sgonzo 527188808Sgonzo KASSERT(mtx_initialized(&sc->arge_mtx), ("arge mutex not initialized")); 528188808Sgonzo 529188808Sgonzo /* These should only be active if attach succeeded */ 530188808Sgonzo if (device_is_attached(dev)) { 531188808Sgonzo ARGE_LOCK(sc); 532188808Sgonzo sc->arge_detach = 1; 533192783Sgonzo#ifdef DEVICE_POLLING 534192783Sgonzo if (ifp->if_capenable & IFCAP_POLLING) 535192783Sgonzo ether_poll_deregister(ifp); 536192783Sgonzo#endif 537192783Sgonzo 538188808Sgonzo arge_stop(sc); 539188808Sgonzo ARGE_UNLOCK(sc); 540188808Sgonzo taskqueue_drain(taskqueue_swi, &sc->arge_link_task); 541188808Sgonzo ether_ifdetach(ifp); 542188808Sgonzo } 543188808Sgonzo 544188808Sgonzo if (sc->arge_miibus) 545188808Sgonzo device_delete_child(dev, sc->arge_miibus); 546199234Sgonzo 547188808Sgonzo bus_generic_detach(dev); 548188808Sgonzo 549188808Sgonzo if (sc->arge_intrhand) 550188808Sgonzo bus_teardown_intr(dev, sc->arge_irq, sc->arge_intrhand); 551188808Sgonzo 552188808Sgonzo if (sc->arge_res) 553188808Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, sc->arge_rid, 554188808Sgonzo sc->arge_res); 555188808Sgonzo 556188808Sgonzo if (ifp) 557188808Sgonzo if_free(ifp); 558188808Sgonzo 559188808Sgonzo arge_dma_free(sc); 560188808Sgonzo 561188808Sgonzo mtx_destroy(&sc->arge_mtx); 562188808Sgonzo 563188808Sgonzo return (0); 564188808Sgonzo 565188808Sgonzo} 566188808Sgonzo 567188808Sgonzostatic int 568188808Sgonzoarge_suspend(device_t dev) 569188808Sgonzo{ 570188808Sgonzo 571188808Sgonzo panic("%s", __func__); 572188808Sgonzo return 0; 573188808Sgonzo} 574188808Sgonzo 575188808Sgonzostatic int 576188808Sgonzoarge_resume(device_t dev) 577188808Sgonzo{ 578188808Sgonzo 579188808Sgonzo panic("%s", __func__); 580188808Sgonzo return 0; 581188808Sgonzo} 582188808Sgonzo 583194059Sgonzostatic int 584188808Sgonzoarge_shutdown(device_t dev) 585188808Sgonzo{ 586188808Sgonzo struct arge_softc *sc; 587188808Sgonzo 588188808Sgonzo sc = device_get_softc(dev); 589188808Sgonzo 590188808Sgonzo ARGE_LOCK(sc); 591188808Sgonzo arge_stop(sc); 592188808Sgonzo ARGE_UNLOCK(sc); 593194059Sgonzo 594194059Sgonzo return (0); 595188808Sgonzo} 596188808Sgonzo 597188808Sgonzostatic int 598188808Sgonzoarge_miibus_readreg(device_t dev, int phy, int reg) 599188808Sgonzo{ 600188808Sgonzo struct arge_softc * sc = device_get_softc(dev); 601188808Sgonzo int i, result; 602196794Sgonzo uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT) 603188808Sgonzo | (reg & MAC_MII_REG_MASK); 604188808Sgonzo 605199234Sgonzo if ((sc->arge_phymask & (1 << phy)) == 0) 606188808Sgonzo return (0); 607188808Sgonzo 608199038Sgonzo mtx_lock(&miibus_mtx); 609199038Sgonzo ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE); 610199038Sgonzo ARGE_MII_WRITE(AR71XX_MAC_MII_ADDR, addr); 611199038Sgonzo ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ); 612188808Sgonzo 613188808Sgonzo i = ARGE_MII_TIMEOUT; 614199038Sgonzo while ((ARGE_MII_READ(AR71XX_MAC_MII_INDICATOR) & 615188808Sgonzo MAC_MII_INDICATOR_BUSY) && (i--)) 616188808Sgonzo DELAY(5); 617188808Sgonzo 618188808Sgonzo if (i < 0) { 619199038Sgonzo mtx_unlock(&miibus_mtx); 620220354Sadrian ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__); 621188808Sgonzo /* XXX: return ERRNO istead? */ 622188808Sgonzo return (-1); 623188808Sgonzo } 624188808Sgonzo 625199038Sgonzo result = ARGE_MII_READ(AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK; 626199038Sgonzo ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE); 627199038Sgonzo mtx_unlock(&miibus_mtx); 628199038Sgonzo 629220354Sadrian ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value[%08x]=%04x\n", __func__, 630188808Sgonzo phy, reg, addr, result); 631188808Sgonzo 632188808Sgonzo return (result); 633188808Sgonzo} 634188808Sgonzo 635188808Sgonzostatic int 636188808Sgonzoarge_miibus_writereg(device_t dev, int phy, int reg, int data) 637188808Sgonzo{ 638188808Sgonzo struct arge_softc * sc = device_get_softc(dev); 639188808Sgonzo int i; 640196794Sgonzo uint32_t addr = 641196794Sgonzo (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK); 642188808Sgonzo 643199038Sgonzo 644199234Sgonzo if ((sc->arge_phymask & (1 << phy)) == 0) 645199038Sgonzo return (-1); 646199038Sgonzo 647220354Sadrian ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value=%04x\n", __func__, 648188808Sgonzo phy, reg, data); 649188808Sgonzo 650199038Sgonzo mtx_lock(&miibus_mtx); 651199038Sgonzo ARGE_MII_WRITE(AR71XX_MAC_MII_ADDR, addr); 652199038Sgonzo ARGE_MII_WRITE(AR71XX_MAC_MII_CONTROL, data); 653188808Sgonzo 654188808Sgonzo i = ARGE_MII_TIMEOUT; 655199038Sgonzo while ((ARGE_MII_READ(AR71XX_MAC_MII_INDICATOR) & 656188808Sgonzo MAC_MII_INDICATOR_BUSY) && (i--)) 657188808Sgonzo DELAY(5); 658188808Sgonzo 659199038Sgonzo mtx_unlock(&miibus_mtx); 660199038Sgonzo 661188808Sgonzo if (i < 0) { 662220354Sadrian ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__); 663188808Sgonzo /* XXX: return ERRNO istead? */ 664188808Sgonzo return (-1); 665188808Sgonzo } 666188808Sgonzo 667188808Sgonzo return (0); 668188808Sgonzo} 669188808Sgonzo 670188808Sgonzostatic void 671188808Sgonzoarge_miibus_statchg(device_t dev) 672188808Sgonzo{ 673188808Sgonzo struct arge_softc *sc; 674188808Sgonzo 675188808Sgonzo sc = device_get_softc(dev); 676188808Sgonzo taskqueue_enqueue(taskqueue_swi, &sc->arge_link_task); 677188808Sgonzo} 678188808Sgonzo 679188808Sgonzostatic void 680188808Sgonzoarge_link_task(void *arg, int pending) 681188808Sgonzo{ 682188808Sgonzo struct arge_softc *sc; 683188808Sgonzo struct mii_data *mii; 684188808Sgonzo struct ifnet *ifp; 685199234Sgonzo uint32_t media, duplex; 686188808Sgonzo 687188808Sgonzo sc = (struct arge_softc *)arg; 688188808Sgonzo 689188808Sgonzo ARGE_LOCK(sc); 690188808Sgonzo mii = device_get_softc(sc->arge_miibus); 691188808Sgonzo ifp = sc->arge_ifp; 692188808Sgonzo if (mii == NULL || ifp == NULL || 693188808Sgonzo (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 694188808Sgonzo ARGE_UNLOCK(sc); 695188808Sgonzo return; 696188808Sgonzo } 697188808Sgonzo 698188808Sgonzo if (mii->mii_media_status & IFM_ACTIVE) { 699188808Sgonzo 700188808Sgonzo media = IFM_SUBTYPE(mii->mii_media_active); 701188808Sgonzo 702188808Sgonzo if (media != IFM_NONE) { 703188808Sgonzo sc->arge_link_status = 1; 704199234Sgonzo duplex = mii->mii_media_active & IFM_GMASK; 705199234Sgonzo arge_set_pll(sc, media, duplex); 706199234Sgonzo } 707199234Sgonzo } else 708199234Sgonzo sc->arge_link_status = 0; 709188808Sgonzo 710199234Sgonzo ARGE_UNLOCK(sc); 711199234Sgonzo} 712192783Sgonzo 713199234Sgonzostatic void 714199234Sgonzoarge_set_pll(struct arge_softc *sc, int media, int duplex) 715199234Sgonzo{ 716211511Sadrian uint32_t cfg, ifcontrol, rx_filtmask; 717219589Sadrian uint32_t fifo_tx; 718211511Sadrian int if_speed; 719192783Sgonzo 720199234Sgonzo cfg = ARGE_READ(sc, AR71XX_MAC_CFG2); 721199234Sgonzo cfg &= ~(MAC_CFG2_IFACE_MODE_1000 722199234Sgonzo | MAC_CFG2_IFACE_MODE_10_100 723199234Sgonzo | MAC_CFG2_FULL_DUPLEX); 724188808Sgonzo 725199234Sgonzo if (duplex == IFM_FDX) 726199234Sgonzo cfg |= MAC_CFG2_FULL_DUPLEX; 727188808Sgonzo 728199234Sgonzo ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL); 729199234Sgonzo ifcontrol &= ~MAC_IFCONTROL_SPEED; 730199234Sgonzo rx_filtmask = 731199234Sgonzo ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK); 732199234Sgonzo rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE; 733188808Sgonzo 734199234Sgonzo switch(media) { 735199234Sgonzo case IFM_10_T: 736199234Sgonzo cfg |= MAC_CFG2_IFACE_MODE_10_100; 737211511Sadrian if_speed = 10; 738199234Sgonzo break; 739199234Sgonzo case IFM_100_TX: 740199234Sgonzo cfg |= MAC_CFG2_IFACE_MODE_10_100; 741199234Sgonzo ifcontrol |= MAC_IFCONTROL_SPEED; 742211511Sadrian if_speed = 100; 743199234Sgonzo break; 744199234Sgonzo case IFM_1000_T: 745199234Sgonzo case IFM_1000_SX: 746199234Sgonzo cfg |= MAC_CFG2_IFACE_MODE_1000; 747199234Sgonzo rx_filtmask |= FIFO_RX_MASK_BYTE_MODE; 748211511Sadrian if_speed = 1000; 749199234Sgonzo break; 750199234Sgonzo default: 751211511Sadrian if_speed = 100; 752199234Sgonzo device_printf(sc->arge_dev, 753199234Sgonzo "Unknown media %d\n", media); 754199234Sgonzo } 755188808Sgonzo 756219589Sadrian switch (ar71xx_soc) { 757219589Sadrian case AR71XX_SOC_AR7240: 758219589Sadrian case AR71XX_SOC_AR7241: 759219589Sadrian case AR71XX_SOC_AR7242: 760219589Sadrian fifo_tx = 0x01f00140; 761219589Sadrian break; 762219589Sadrian case AR71XX_SOC_AR9130: 763219589Sadrian case AR71XX_SOC_AR9132: 764219589Sadrian fifo_tx = 0x00780fff; 765219589Sadrian break; 766219589Sadrian default: 767219589Sadrian fifo_tx = 0x008001ff; 768219589Sadrian } 769188808Sgonzo 770199234Sgonzo ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg); 771199234Sgonzo ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol); 772199234Sgonzo ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, 773199234Sgonzo rx_filtmask); 774219589Sadrian ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD, fifo_tx); 775188808Sgonzo 776199234Sgonzo /* set PLL registers */ 777211511Sadrian if (sc->arge_mac_unit == 0) 778211511Sadrian ar71xx_device_set_pll_ge0(if_speed); 779211511Sadrian else 780211511Sadrian ar71xx_device_set_pll_ge1(if_speed); 781188808Sgonzo} 782188808Sgonzo 783199234Sgonzo 784188808Sgonzostatic void 785188808Sgonzoarge_reset_dma(struct arge_softc *sc) 786188808Sgonzo{ 787188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0); 788188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 0); 789188808Sgonzo 790188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, 0); 791188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, 0); 792188808Sgonzo 793188808Sgonzo /* Clear all possible RX interrupts */ 794192569Sdwhite while(ARGE_READ(sc, AR71XX_DMA_RX_STATUS) & DMA_RX_STATUS_PKT_RECVD) 795188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD); 796188808Sgonzo 797188808Sgonzo /* 798188808Sgonzo * Clear all possible TX interrupts 799188808Sgonzo */ 800192569Sdwhite while(ARGE_READ(sc, AR71XX_DMA_TX_STATUS) & DMA_TX_STATUS_PKT_SENT) 801188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT); 802188808Sgonzo 803188808Sgonzo /* 804188808Sgonzo * Now Rx/Tx errors 805188808Sgonzo */ 806188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, 807188808Sgonzo DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW); 808188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, 809188808Sgonzo DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN); 810188808Sgonzo} 811188808Sgonzo 812188808Sgonzo 813188808Sgonzo 814188808Sgonzostatic void 815188808Sgonzoarge_init(void *xsc) 816188808Sgonzo{ 817188808Sgonzo struct arge_softc *sc = xsc; 818188808Sgonzo 819188808Sgonzo ARGE_LOCK(sc); 820188808Sgonzo arge_init_locked(sc); 821188808Sgonzo ARGE_UNLOCK(sc); 822188808Sgonzo} 823188808Sgonzo 824188808Sgonzostatic void 825188808Sgonzoarge_init_locked(struct arge_softc *sc) 826188808Sgonzo{ 827188808Sgonzo struct ifnet *ifp = sc->arge_ifp; 828188808Sgonzo struct mii_data *mii; 829188808Sgonzo 830188808Sgonzo ARGE_LOCK_ASSERT(sc); 831188808Sgonzo 832188808Sgonzo arge_stop(sc); 833188808Sgonzo 834188808Sgonzo /* Init circular RX list. */ 835188808Sgonzo if (arge_rx_ring_init(sc) != 0) { 836188808Sgonzo device_printf(sc->arge_dev, 837188808Sgonzo "initialization failed: no memory for rx buffers\n"); 838188808Sgonzo arge_stop(sc); 839188808Sgonzo return; 840188808Sgonzo } 841188808Sgonzo 842188808Sgonzo /* Init tx descriptors. */ 843188808Sgonzo arge_tx_ring_init(sc); 844188808Sgonzo 845188808Sgonzo arge_reset_dma(sc); 846188808Sgonzo 847188808Sgonzo 848199234Sgonzo if (sc->arge_miibus) { 849199234Sgonzo sc->arge_link_status = 0; 850199234Sgonzo mii = device_get_softc(sc->arge_miibus); 851199234Sgonzo mii_mediachg(mii); 852199234Sgonzo } 853199234Sgonzo else { 854199234Sgonzo /* 855199234Sgonzo * Sun always shines over multiPHY interface 856199234Sgonzo */ 857199234Sgonzo sc->arge_link_status = 1; 858199234Sgonzo } 859199234Sgonzo 860188808Sgonzo ifp->if_drv_flags |= IFF_DRV_RUNNING; 861188808Sgonzo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 862188808Sgonzo 863199234Sgonzo if (sc->arge_miibus) 864199234Sgonzo callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); 865192783Sgonzo 866188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0)); 867188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0)); 868188808Sgonzo 869188808Sgonzo /* Start listening */ 870188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN); 871188808Sgonzo 872188808Sgonzo /* Enable interrupts */ 873188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); 874188808Sgonzo} 875188808Sgonzo 876188808Sgonzo/* 877209807Sadrian * Return whether the mbuf chain is correctly aligned 878209807Sadrian * for the arge TX engine. 879209807Sadrian * 880209807Sadrian * The TX engine requires each fragment to be aligned to a 881209807Sadrian * 4 byte boundary and the size of each fragment except 882209807Sadrian * the last to be a multiple of 4 bytes. 883209807Sadrian */ 884209807Sadrianstatic int 885209807Sadrianarge_mbuf_chain_is_tx_aligned(struct mbuf *m0) 886209807Sadrian{ 887209807Sadrian struct mbuf *m; 888209807Sadrian 889209807Sadrian for (m = m0; m != NULL; m = m->m_next) { 890209807Sadrian if((mtod(m, intptr_t) & 3) != 0) 891209807Sadrian return 0; 892209807Sadrian if ((m->m_next != NULL) && ((m->m_len & 0x03) != 0)) 893209807Sadrian return 0; 894209807Sadrian } 895209807Sadrian return 1; 896209807Sadrian} 897209807Sadrian 898209807Sadrian/* 899188808Sgonzo * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 900188808Sgonzo * pointers to the fragment pointers. 901188808Sgonzo */ 902188808Sgonzostatic int 903188808Sgonzoarge_encap(struct arge_softc *sc, struct mbuf **m_head) 904188808Sgonzo{ 905188808Sgonzo struct arge_txdesc *txd; 906188808Sgonzo struct arge_desc *desc, *prev_desc; 907188808Sgonzo bus_dma_segment_t txsegs[ARGE_MAXFRAGS]; 908192569Sdwhite int error, i, nsegs, prod, prev_prod; 909192783Sgonzo struct mbuf *m; 910188808Sgonzo 911188808Sgonzo ARGE_LOCK_ASSERT(sc); 912188808Sgonzo 913192783Sgonzo /* 914192783Sgonzo * Fix mbuf chain, all fragments should be 4 bytes aligned and 915192783Sgonzo * even 4 bytes 916192783Sgonzo */ 917192783Sgonzo m = *m_head; 918209807Sadrian if (! arge_mbuf_chain_is_tx_aligned(m)) { 919209809Sadrian sc->stats.tx_pkts_unaligned++; 920192783Sgonzo m = m_defrag(*m_head, M_DONTWAIT); 921192783Sgonzo if (m == NULL) { 922192783Sgonzo *m_head = NULL; 923192783Sgonzo return (ENOBUFS); 924192783Sgonzo } 925192783Sgonzo *m_head = m; 926209809Sadrian } else 927209809Sadrian sc->stats.tx_pkts_aligned++; 928192783Sgonzo 929188808Sgonzo prod = sc->arge_cdata.arge_tx_prod; 930188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[prod]; 931188808Sgonzo error = bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_tx_tag, 932188808Sgonzo txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); 933188808Sgonzo 934188808Sgonzo if (error == EFBIG) { 935188808Sgonzo panic("EFBIG"); 936188808Sgonzo } else if (error != 0) 937188808Sgonzo return (error); 938188808Sgonzo 939188808Sgonzo if (nsegs == 0) { 940188808Sgonzo m_freem(*m_head); 941188808Sgonzo *m_head = NULL; 942188808Sgonzo return (EIO); 943188808Sgonzo } 944188808Sgonzo 945188808Sgonzo /* Check number of available descriptors. */ 946188808Sgonzo if (sc->arge_cdata.arge_tx_cnt + nsegs >= (ARGE_TX_RING_COUNT - 1)) { 947188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap); 948188808Sgonzo return (ENOBUFS); 949188808Sgonzo } 950188808Sgonzo 951188808Sgonzo txd->tx_m = *m_head; 952188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap, 953188808Sgonzo BUS_DMASYNC_PREWRITE); 954188808Sgonzo 955188808Sgonzo /* 956188808Sgonzo * Make a list of descriptors for this packet. DMA controller will 957188808Sgonzo * walk through it while arge_link is not zero. 958188808Sgonzo */ 959188808Sgonzo prev_prod = prod; 960188808Sgonzo desc = prev_desc = NULL; 961188808Sgonzo for (i = 0; i < nsegs; i++) { 962188808Sgonzo desc = &sc->arge_rdata.arge_tx_ring[prod]; 963188808Sgonzo desc->packet_ctrl = ARGE_DMASIZE(txsegs[i].ds_len); 964188808Sgonzo 965192783Sgonzo if (txsegs[i].ds_addr & 3) 966192783Sgonzo panic("TX packet address unaligned\n"); 967192783Sgonzo 968188808Sgonzo desc->packet_addr = txsegs[i].ds_addr; 969192783Sgonzo 970188808Sgonzo /* link with previous descriptor */ 971188808Sgonzo if (prev_desc) 972188808Sgonzo prev_desc->packet_ctrl |= ARGE_DESC_MORE; 973188808Sgonzo 974188808Sgonzo sc->arge_cdata.arge_tx_cnt++; 975188808Sgonzo prev_desc = desc; 976188808Sgonzo ARGE_INC(prod, ARGE_TX_RING_COUNT); 977188808Sgonzo } 978188808Sgonzo 979188808Sgonzo /* Update producer index. */ 980188808Sgonzo sc->arge_cdata.arge_tx_prod = prod; 981188808Sgonzo 982188808Sgonzo /* Sync descriptors. */ 983188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, 984188808Sgonzo sc->arge_cdata.arge_tx_ring_map, 985188808Sgonzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 986188808Sgonzo 987188808Sgonzo /* Start transmitting */ 988220356Sadrian ARGEDEBUG(sc, ARGE_DBG_TX, "%s: setting DMA_TX_CONTROL_EN\n", __func__); 989188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN); 990188808Sgonzo return (0); 991188808Sgonzo} 992188808Sgonzo 993188808Sgonzostatic void 994188808Sgonzoarge_start(struct ifnet *ifp) 995188808Sgonzo{ 996188808Sgonzo struct arge_softc *sc; 997188808Sgonzo 998188808Sgonzo sc = ifp->if_softc; 999188808Sgonzo 1000188808Sgonzo ARGE_LOCK(sc); 1001188808Sgonzo arge_start_locked(ifp); 1002188808Sgonzo ARGE_UNLOCK(sc); 1003188808Sgonzo} 1004188808Sgonzo 1005188808Sgonzostatic void 1006188808Sgonzoarge_start_locked(struct ifnet *ifp) 1007188808Sgonzo{ 1008188808Sgonzo struct arge_softc *sc; 1009188808Sgonzo struct mbuf *m_head; 1010220356Sadrian int enq = 0; 1011188808Sgonzo 1012188808Sgonzo sc = ifp->if_softc; 1013188808Sgonzo 1014188808Sgonzo ARGE_LOCK_ASSERT(sc); 1015188808Sgonzo 1016220356Sadrian ARGEDEBUG(sc, ARGE_DBG_TX, "%s: beginning\n", __func__); 1017220356Sadrian 1018188808Sgonzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1019188808Sgonzo IFF_DRV_RUNNING || sc->arge_link_status == 0 ) 1020188808Sgonzo return; 1021188808Sgonzo 1022220356Sadrian /* 1023220356Sadrian * Before we go any further, check whether we're already full. 1024220356Sadrian * The below check errors out immediately if the ring is full 1025220356Sadrian * and never gets a chance to set this flag. Although it's 1026220356Sadrian * likely never needed, this at least avoids an unexpected 1027220356Sadrian * situation. 1028220356Sadrian */ 1029220356Sadrian if (sc->arge_cdata.arge_tx_cnt >= ARGE_TX_RING_COUNT - 2) { 1030220356Sadrian ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1031220356Sadrian ARGEDEBUG(sc, ARGE_DBG_ERR, "%s: tx_cnt %d >= max %d; setting IFF_DRV_OACTIVE\n", 1032220356Sadrian __func__, sc->arge_cdata.arge_tx_cnt, ARGE_TX_RING_COUNT - 2); 1033220356Sadrian return; 1034220356Sadrian } 1035220356Sadrian 1036188808Sgonzo arge_flush_ddr(sc); 1037188808Sgonzo 1038188808Sgonzo for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 1039188808Sgonzo sc->arge_cdata.arge_tx_cnt < ARGE_TX_RING_COUNT - 2; ) { 1040188808Sgonzo IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1041188808Sgonzo if (m_head == NULL) 1042188808Sgonzo break; 1043188808Sgonzo 1044188808Sgonzo 1045188808Sgonzo /* 1046188808Sgonzo * Pack the data into the transmit ring. 1047188808Sgonzo */ 1048188808Sgonzo if (arge_encap(sc, &m_head)) { 1049188808Sgonzo if (m_head == NULL) 1050188808Sgonzo break; 1051188808Sgonzo IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1052188808Sgonzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1053188808Sgonzo break; 1054188808Sgonzo } 1055188808Sgonzo 1056188808Sgonzo enq++; 1057188808Sgonzo /* 1058188808Sgonzo * If there's a BPF listener, bounce a copy of this frame 1059188808Sgonzo * to him. 1060188808Sgonzo */ 1061188808Sgonzo ETHER_BPF_MTAP(ifp, m_head); 1062188808Sgonzo } 1063220356Sadrian ARGEDEBUG(sc, ARGE_DBG_TX, "%s: finished; queued %d packets\n", __func__, enq); 1064188808Sgonzo} 1065188808Sgonzo 1066188808Sgonzostatic void 1067188808Sgonzoarge_stop(struct arge_softc *sc) 1068188808Sgonzo{ 1069188808Sgonzo struct ifnet *ifp; 1070188808Sgonzo 1071188808Sgonzo ARGE_LOCK_ASSERT(sc); 1072188808Sgonzo 1073188808Sgonzo ifp = sc->arge_ifp; 1074188808Sgonzo ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1075199234Sgonzo if (sc->arge_miibus) 1076199234Sgonzo callout_stop(&sc->arge_stat_callout); 1077188808Sgonzo 1078188808Sgonzo /* mask out interrupts */ 1079188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); 1080188808Sgonzo 1081188808Sgonzo arge_reset_dma(sc); 1082188808Sgonzo} 1083188808Sgonzo 1084188808Sgonzo 1085188808Sgonzostatic int 1086188808Sgonzoarge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1087188808Sgonzo{ 1088188808Sgonzo struct arge_softc *sc = ifp->if_softc; 1089188808Sgonzo struct ifreq *ifr = (struct ifreq *) data; 1090188808Sgonzo struct mii_data *mii; 1091188808Sgonzo int error; 1092192783Sgonzo#ifdef DEVICE_POLLING 1093192783Sgonzo int mask; 1094192783Sgonzo#endif 1095188808Sgonzo 1096188808Sgonzo switch (command) { 1097188808Sgonzo case SIOCSIFFLAGS: 1098198932Sgonzo ARGE_LOCK(sc); 1099198932Sgonzo if ((ifp->if_flags & IFF_UP) != 0) { 1100198932Sgonzo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1101198932Sgonzo if (((ifp->if_flags ^ sc->arge_if_flags) 1102198939Sgonzo & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 1103198939Sgonzo /* XXX: handle promisc & multi flags */ 1104198939Sgonzo } 1105198939Sgonzo 1106198932Sgonzo } else { 1107198932Sgonzo if (!sc->arge_detach) 1108198932Sgonzo arge_init_locked(sc); 1109198932Sgonzo } 1110198932Sgonzo } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1111198932Sgonzo ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1112198932Sgonzo arge_stop(sc); 1113198932Sgonzo } 1114198932Sgonzo sc->arge_if_flags = ifp->if_flags; 1115198932Sgonzo ARGE_UNLOCK(sc); 1116188808Sgonzo error = 0; 1117188808Sgonzo break; 1118188808Sgonzo case SIOCADDMULTI: 1119188808Sgonzo case SIOCDELMULTI: 1120198932Sgonzo /* XXX: implement SIOCDELMULTI */ 1121188808Sgonzo error = 0; 1122188808Sgonzo break; 1123188808Sgonzo case SIOCGIFMEDIA: 1124188808Sgonzo case SIOCSIFMEDIA: 1125199234Sgonzo if (sc->arge_miibus) { 1126199234Sgonzo mii = device_get_softc(sc->arge_miibus); 1127199234Sgonzo error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1128199234Sgonzo } 1129199234Sgonzo else 1130199234Sgonzo error = ifmedia_ioctl(ifp, ifr, &sc->arge_ifmedia, command); 1131188808Sgonzo break; 1132198933Sgonzo case SIOCSIFCAP: 1133198932Sgonzo /* XXX: Check other capabilities */ 1134192783Sgonzo#ifdef DEVICE_POLLING 1135198933Sgonzo mask = ifp->if_capenable ^ ifr->ifr_reqcap; 1136198933Sgonzo if (mask & IFCAP_POLLING) { 1137198933Sgonzo if (ifr->ifr_reqcap & IFCAP_POLLING) { 1138192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); 1139198933Sgonzo error = ether_poll_register(arge_poll, ifp); 1140198933Sgonzo if (error) 1141198933Sgonzo return error; 1142198933Sgonzo ARGE_LOCK(sc); 1143198933Sgonzo ifp->if_capenable |= IFCAP_POLLING; 1144198933Sgonzo ARGE_UNLOCK(sc); 1145198933Sgonzo } else { 1146192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); 1147198933Sgonzo error = ether_poll_deregister(ifp); 1148198933Sgonzo ARGE_LOCK(sc); 1149198933Sgonzo ifp->if_capenable &= ~IFCAP_POLLING; 1150198933Sgonzo ARGE_UNLOCK(sc); 1151198933Sgonzo } 1152198933Sgonzo } 1153198932Sgonzo error = 0; 1154198933Sgonzo break; 1155192783Sgonzo#endif 1156188808Sgonzo default: 1157188808Sgonzo error = ether_ioctl(ifp, command, data); 1158188808Sgonzo break; 1159188808Sgonzo } 1160188808Sgonzo 1161188808Sgonzo return (error); 1162188808Sgonzo} 1163188808Sgonzo 1164188808Sgonzo/* 1165188808Sgonzo * Set media options. 1166188808Sgonzo */ 1167188808Sgonzostatic int 1168188808Sgonzoarge_ifmedia_upd(struct ifnet *ifp) 1169188808Sgonzo{ 1170188808Sgonzo struct arge_softc *sc; 1171188808Sgonzo struct mii_data *mii; 1172188808Sgonzo struct mii_softc *miisc; 1173188808Sgonzo int error; 1174188808Sgonzo 1175188808Sgonzo sc = ifp->if_softc; 1176188808Sgonzo ARGE_LOCK(sc); 1177188808Sgonzo mii = device_get_softc(sc->arge_miibus); 1178221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1179221407Smarius PHY_RESET(miisc); 1180188808Sgonzo error = mii_mediachg(mii); 1181188808Sgonzo ARGE_UNLOCK(sc); 1182188808Sgonzo 1183188808Sgonzo return (error); 1184188808Sgonzo} 1185188808Sgonzo 1186188808Sgonzo/* 1187188808Sgonzo * Report current media status. 1188188808Sgonzo */ 1189188808Sgonzostatic void 1190188808Sgonzoarge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1191188808Sgonzo{ 1192188808Sgonzo struct arge_softc *sc = ifp->if_softc; 1193188808Sgonzo struct mii_data *mii; 1194188808Sgonzo 1195188808Sgonzo mii = device_get_softc(sc->arge_miibus); 1196188808Sgonzo ARGE_LOCK(sc); 1197188808Sgonzo mii_pollstat(mii); 1198188808Sgonzo ifmr->ifm_active = mii->mii_media_active; 1199188808Sgonzo ifmr->ifm_status = mii->mii_media_status; 1200229057Syongari ARGE_UNLOCK(sc); 1201188808Sgonzo} 1202188808Sgonzo 1203188808Sgonzostruct arge_dmamap_arg { 1204188808Sgonzo bus_addr_t arge_busaddr; 1205188808Sgonzo}; 1206188808Sgonzo 1207188808Sgonzostatic void 1208188808Sgonzoarge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1209188808Sgonzo{ 1210188808Sgonzo struct arge_dmamap_arg *ctx; 1211188808Sgonzo 1212188808Sgonzo if (error != 0) 1213188808Sgonzo return; 1214188808Sgonzo ctx = arg; 1215188808Sgonzo ctx->arge_busaddr = segs[0].ds_addr; 1216188808Sgonzo} 1217188808Sgonzo 1218188808Sgonzostatic int 1219188808Sgonzoarge_dma_alloc(struct arge_softc *sc) 1220188808Sgonzo{ 1221188808Sgonzo struct arge_dmamap_arg ctx; 1222188808Sgonzo struct arge_txdesc *txd; 1223188808Sgonzo struct arge_rxdesc *rxd; 1224188808Sgonzo int error, i; 1225188808Sgonzo 1226188808Sgonzo /* Create parent DMA tag. */ 1227188808Sgonzo error = bus_dma_tag_create( 1228188808Sgonzo bus_get_dma_tag(sc->arge_dev), /* parent */ 1229188808Sgonzo 1, 0, /* alignment, boundary */ 1230188808Sgonzo BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1231188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1232188808Sgonzo NULL, NULL, /* filter, filterarg */ 1233188808Sgonzo BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1234188808Sgonzo 0, /* nsegments */ 1235188808Sgonzo BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1236188808Sgonzo 0, /* flags */ 1237188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1238188808Sgonzo &sc->arge_cdata.arge_parent_tag); 1239188808Sgonzo if (error != 0) { 1240188808Sgonzo device_printf(sc->arge_dev, "failed to create parent DMA tag\n"); 1241188808Sgonzo goto fail; 1242188808Sgonzo } 1243188808Sgonzo /* Create tag for Tx ring. */ 1244188808Sgonzo error = bus_dma_tag_create( 1245188808Sgonzo sc->arge_cdata.arge_parent_tag, /* parent */ 1246188808Sgonzo ARGE_RING_ALIGN, 0, /* alignment, boundary */ 1247188808Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1248188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1249188808Sgonzo NULL, NULL, /* filter, filterarg */ 1250188808Sgonzo ARGE_TX_DMA_SIZE, /* maxsize */ 1251188808Sgonzo 1, /* nsegments */ 1252188808Sgonzo ARGE_TX_DMA_SIZE, /* maxsegsize */ 1253188808Sgonzo 0, /* flags */ 1254188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1255188808Sgonzo &sc->arge_cdata.arge_tx_ring_tag); 1256188808Sgonzo if (error != 0) { 1257188808Sgonzo device_printf(sc->arge_dev, "failed to create Tx ring DMA tag\n"); 1258188808Sgonzo goto fail; 1259188808Sgonzo } 1260188808Sgonzo 1261188808Sgonzo /* Create tag for Rx ring. */ 1262188808Sgonzo error = bus_dma_tag_create( 1263188808Sgonzo sc->arge_cdata.arge_parent_tag, /* parent */ 1264188808Sgonzo ARGE_RING_ALIGN, 0, /* alignment, boundary */ 1265188808Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1266188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1267188808Sgonzo NULL, NULL, /* filter, filterarg */ 1268188808Sgonzo ARGE_RX_DMA_SIZE, /* maxsize */ 1269188808Sgonzo 1, /* nsegments */ 1270188808Sgonzo ARGE_RX_DMA_SIZE, /* maxsegsize */ 1271188808Sgonzo 0, /* flags */ 1272188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1273188808Sgonzo &sc->arge_cdata.arge_rx_ring_tag); 1274188808Sgonzo if (error != 0) { 1275188808Sgonzo device_printf(sc->arge_dev, "failed to create Rx ring DMA tag\n"); 1276188808Sgonzo goto fail; 1277188808Sgonzo } 1278188808Sgonzo 1279188808Sgonzo /* Create tag for Tx buffers. */ 1280188808Sgonzo error = bus_dma_tag_create( 1281188808Sgonzo sc->arge_cdata.arge_parent_tag, /* parent */ 1282188808Sgonzo sizeof(uint32_t), 0, /* alignment, boundary */ 1283188808Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1284188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1285188808Sgonzo NULL, NULL, /* filter, filterarg */ 1286188808Sgonzo MCLBYTES * ARGE_MAXFRAGS, /* maxsize */ 1287188808Sgonzo ARGE_MAXFRAGS, /* nsegments */ 1288188808Sgonzo MCLBYTES, /* maxsegsize */ 1289188808Sgonzo 0, /* flags */ 1290188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1291188808Sgonzo &sc->arge_cdata.arge_tx_tag); 1292188808Sgonzo if (error != 0) { 1293188808Sgonzo device_printf(sc->arge_dev, "failed to create Tx DMA tag\n"); 1294188808Sgonzo goto fail; 1295188808Sgonzo } 1296188808Sgonzo 1297188808Sgonzo /* Create tag for Rx buffers. */ 1298188808Sgonzo error = bus_dma_tag_create( 1299188808Sgonzo sc->arge_cdata.arge_parent_tag, /* parent */ 1300188808Sgonzo ARGE_RX_ALIGN, 0, /* alignment, boundary */ 1301188808Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1302188808Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1303188808Sgonzo NULL, NULL, /* filter, filterarg */ 1304188808Sgonzo MCLBYTES, /* maxsize */ 1305192821Sgonzo ARGE_MAXFRAGS, /* nsegments */ 1306188808Sgonzo MCLBYTES, /* maxsegsize */ 1307188808Sgonzo 0, /* flags */ 1308188808Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1309188808Sgonzo &sc->arge_cdata.arge_rx_tag); 1310188808Sgonzo if (error != 0) { 1311188808Sgonzo device_printf(sc->arge_dev, "failed to create Rx DMA tag\n"); 1312188808Sgonzo goto fail; 1313188808Sgonzo } 1314188808Sgonzo 1315188808Sgonzo /* Allocate DMA'able memory and load the DMA map for Tx ring. */ 1316188808Sgonzo error = bus_dmamem_alloc(sc->arge_cdata.arge_tx_ring_tag, 1317188808Sgonzo (void **)&sc->arge_rdata.arge_tx_ring, BUS_DMA_WAITOK | 1318188808Sgonzo BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->arge_cdata.arge_tx_ring_map); 1319188808Sgonzo if (error != 0) { 1320188808Sgonzo device_printf(sc->arge_dev, 1321188808Sgonzo "failed to allocate DMA'able memory for Tx ring\n"); 1322188808Sgonzo goto fail; 1323188808Sgonzo } 1324188808Sgonzo 1325188808Sgonzo ctx.arge_busaddr = 0; 1326188808Sgonzo error = bus_dmamap_load(sc->arge_cdata.arge_tx_ring_tag, 1327188808Sgonzo sc->arge_cdata.arge_tx_ring_map, sc->arge_rdata.arge_tx_ring, 1328188808Sgonzo ARGE_TX_DMA_SIZE, arge_dmamap_cb, &ctx, 0); 1329188808Sgonzo if (error != 0 || ctx.arge_busaddr == 0) { 1330188808Sgonzo device_printf(sc->arge_dev, 1331188808Sgonzo "failed to load DMA'able memory for Tx ring\n"); 1332188808Sgonzo goto fail; 1333188808Sgonzo } 1334188808Sgonzo sc->arge_rdata.arge_tx_ring_paddr = ctx.arge_busaddr; 1335188808Sgonzo 1336188808Sgonzo /* Allocate DMA'able memory and load the DMA map for Rx ring. */ 1337188808Sgonzo error = bus_dmamem_alloc(sc->arge_cdata.arge_rx_ring_tag, 1338188808Sgonzo (void **)&sc->arge_rdata.arge_rx_ring, BUS_DMA_WAITOK | 1339188808Sgonzo BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->arge_cdata.arge_rx_ring_map); 1340188808Sgonzo if (error != 0) { 1341188808Sgonzo device_printf(sc->arge_dev, 1342188808Sgonzo "failed to allocate DMA'able memory for Rx ring\n"); 1343188808Sgonzo goto fail; 1344188808Sgonzo } 1345188808Sgonzo 1346188808Sgonzo ctx.arge_busaddr = 0; 1347188808Sgonzo error = bus_dmamap_load(sc->arge_cdata.arge_rx_ring_tag, 1348188808Sgonzo sc->arge_cdata.arge_rx_ring_map, sc->arge_rdata.arge_rx_ring, 1349188808Sgonzo ARGE_RX_DMA_SIZE, arge_dmamap_cb, &ctx, 0); 1350188808Sgonzo if (error != 0 || ctx.arge_busaddr == 0) { 1351188808Sgonzo device_printf(sc->arge_dev, 1352188808Sgonzo "failed to load DMA'able memory for Rx ring\n"); 1353188808Sgonzo goto fail; 1354188808Sgonzo } 1355188808Sgonzo sc->arge_rdata.arge_rx_ring_paddr = ctx.arge_busaddr; 1356188808Sgonzo 1357188808Sgonzo /* Create DMA maps for Tx buffers. */ 1358188808Sgonzo for (i = 0; i < ARGE_TX_RING_COUNT; i++) { 1359188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[i]; 1360188808Sgonzo txd->tx_m = NULL; 1361188808Sgonzo txd->tx_dmamap = NULL; 1362188808Sgonzo error = bus_dmamap_create(sc->arge_cdata.arge_tx_tag, 0, 1363188808Sgonzo &txd->tx_dmamap); 1364188808Sgonzo if (error != 0) { 1365188808Sgonzo device_printf(sc->arge_dev, 1366188808Sgonzo "failed to create Tx dmamap\n"); 1367188808Sgonzo goto fail; 1368188808Sgonzo } 1369188808Sgonzo } 1370188808Sgonzo /* Create DMA maps for Rx buffers. */ 1371188808Sgonzo if ((error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0, 1372188808Sgonzo &sc->arge_cdata.arge_rx_sparemap)) != 0) { 1373188808Sgonzo device_printf(sc->arge_dev, 1374188808Sgonzo "failed to create spare Rx dmamap\n"); 1375188808Sgonzo goto fail; 1376188808Sgonzo } 1377188808Sgonzo for (i = 0; i < ARGE_RX_RING_COUNT; i++) { 1378188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[i]; 1379188808Sgonzo rxd->rx_m = NULL; 1380188808Sgonzo rxd->rx_dmamap = NULL; 1381188808Sgonzo error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0, 1382188808Sgonzo &rxd->rx_dmamap); 1383188808Sgonzo if (error != 0) { 1384188808Sgonzo device_printf(sc->arge_dev, 1385188808Sgonzo "failed to create Rx dmamap\n"); 1386188808Sgonzo goto fail; 1387188808Sgonzo } 1388188808Sgonzo } 1389188808Sgonzo 1390188808Sgonzofail: 1391188808Sgonzo return (error); 1392188808Sgonzo} 1393188808Sgonzo 1394188808Sgonzostatic void 1395188808Sgonzoarge_dma_free(struct arge_softc *sc) 1396188808Sgonzo{ 1397188808Sgonzo struct arge_txdesc *txd; 1398188808Sgonzo struct arge_rxdesc *rxd; 1399188808Sgonzo int i; 1400188808Sgonzo 1401188808Sgonzo /* Tx ring. */ 1402188808Sgonzo if (sc->arge_cdata.arge_tx_ring_tag) { 1403188808Sgonzo if (sc->arge_cdata.arge_tx_ring_map) 1404188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_tx_ring_tag, 1405188808Sgonzo sc->arge_cdata.arge_tx_ring_map); 1406188808Sgonzo if (sc->arge_cdata.arge_tx_ring_map && 1407188808Sgonzo sc->arge_rdata.arge_tx_ring) 1408188808Sgonzo bus_dmamem_free(sc->arge_cdata.arge_tx_ring_tag, 1409188808Sgonzo sc->arge_rdata.arge_tx_ring, 1410188808Sgonzo sc->arge_cdata.arge_tx_ring_map); 1411188808Sgonzo sc->arge_rdata.arge_tx_ring = NULL; 1412188808Sgonzo sc->arge_cdata.arge_tx_ring_map = NULL; 1413188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_tx_ring_tag); 1414188808Sgonzo sc->arge_cdata.arge_tx_ring_tag = NULL; 1415188808Sgonzo } 1416188808Sgonzo /* Rx ring. */ 1417188808Sgonzo if (sc->arge_cdata.arge_rx_ring_tag) { 1418188808Sgonzo if (sc->arge_cdata.arge_rx_ring_map) 1419188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_rx_ring_tag, 1420188808Sgonzo sc->arge_cdata.arge_rx_ring_map); 1421188808Sgonzo if (sc->arge_cdata.arge_rx_ring_map && 1422188808Sgonzo sc->arge_rdata.arge_rx_ring) 1423188808Sgonzo bus_dmamem_free(sc->arge_cdata.arge_rx_ring_tag, 1424188808Sgonzo sc->arge_rdata.arge_rx_ring, 1425188808Sgonzo sc->arge_cdata.arge_rx_ring_map); 1426188808Sgonzo sc->arge_rdata.arge_rx_ring = NULL; 1427188808Sgonzo sc->arge_cdata.arge_rx_ring_map = NULL; 1428188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_rx_ring_tag); 1429188808Sgonzo sc->arge_cdata.arge_rx_ring_tag = NULL; 1430188808Sgonzo } 1431188808Sgonzo /* Tx buffers. */ 1432188808Sgonzo if (sc->arge_cdata.arge_tx_tag) { 1433188808Sgonzo for (i = 0; i < ARGE_TX_RING_COUNT; i++) { 1434188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[i]; 1435188808Sgonzo if (txd->tx_dmamap) { 1436188808Sgonzo bus_dmamap_destroy(sc->arge_cdata.arge_tx_tag, 1437188808Sgonzo txd->tx_dmamap); 1438188808Sgonzo txd->tx_dmamap = NULL; 1439188808Sgonzo } 1440188808Sgonzo } 1441188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_tx_tag); 1442188808Sgonzo sc->arge_cdata.arge_tx_tag = NULL; 1443188808Sgonzo } 1444188808Sgonzo /* Rx buffers. */ 1445188808Sgonzo if (sc->arge_cdata.arge_rx_tag) { 1446188808Sgonzo for (i = 0; i < ARGE_RX_RING_COUNT; i++) { 1447188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[i]; 1448188808Sgonzo if (rxd->rx_dmamap) { 1449188808Sgonzo bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag, 1450188808Sgonzo rxd->rx_dmamap); 1451188808Sgonzo rxd->rx_dmamap = NULL; 1452188808Sgonzo } 1453188808Sgonzo } 1454188808Sgonzo if (sc->arge_cdata.arge_rx_sparemap) { 1455188808Sgonzo bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag, 1456188808Sgonzo sc->arge_cdata.arge_rx_sparemap); 1457188808Sgonzo sc->arge_cdata.arge_rx_sparemap = 0; 1458188808Sgonzo } 1459188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_rx_tag); 1460188808Sgonzo sc->arge_cdata.arge_rx_tag = NULL; 1461188808Sgonzo } 1462188808Sgonzo 1463188808Sgonzo if (sc->arge_cdata.arge_parent_tag) { 1464188808Sgonzo bus_dma_tag_destroy(sc->arge_cdata.arge_parent_tag); 1465188808Sgonzo sc->arge_cdata.arge_parent_tag = NULL; 1466188808Sgonzo } 1467188808Sgonzo} 1468188808Sgonzo 1469188808Sgonzo/* 1470188808Sgonzo * Initialize the transmit descriptors. 1471188808Sgonzo */ 1472188808Sgonzostatic int 1473188808Sgonzoarge_tx_ring_init(struct arge_softc *sc) 1474188808Sgonzo{ 1475188808Sgonzo struct arge_ring_data *rd; 1476188808Sgonzo struct arge_txdesc *txd; 1477188808Sgonzo bus_addr_t addr; 1478188808Sgonzo int i; 1479188808Sgonzo 1480188808Sgonzo sc->arge_cdata.arge_tx_prod = 0; 1481188808Sgonzo sc->arge_cdata.arge_tx_cons = 0; 1482188808Sgonzo sc->arge_cdata.arge_tx_cnt = 0; 1483188808Sgonzo 1484188808Sgonzo rd = &sc->arge_rdata; 1485188808Sgonzo bzero(rd->arge_tx_ring, sizeof(rd->arge_tx_ring)); 1486188808Sgonzo for (i = 0; i < ARGE_TX_RING_COUNT; i++) { 1487188808Sgonzo if (i == ARGE_TX_RING_COUNT - 1) 1488188808Sgonzo addr = ARGE_TX_RING_ADDR(sc, 0); 1489188808Sgonzo else 1490188808Sgonzo addr = ARGE_TX_RING_ADDR(sc, i + 1); 1491188808Sgonzo rd->arge_tx_ring[i].packet_ctrl = ARGE_DESC_EMPTY; 1492188808Sgonzo rd->arge_tx_ring[i].next_desc = addr; 1493188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[i]; 1494188808Sgonzo txd->tx_m = NULL; 1495188808Sgonzo } 1496188808Sgonzo 1497188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, 1498188808Sgonzo sc->arge_cdata.arge_tx_ring_map, 1499188808Sgonzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1500188808Sgonzo 1501188808Sgonzo return (0); 1502188808Sgonzo} 1503188808Sgonzo 1504188808Sgonzo/* 1505188808Sgonzo * Initialize the RX descriptors and allocate mbufs for them. Note that 1506188808Sgonzo * we arrange the descriptors in a closed ring, so that the last descriptor 1507188808Sgonzo * points back to the first. 1508188808Sgonzo */ 1509188808Sgonzostatic int 1510188808Sgonzoarge_rx_ring_init(struct arge_softc *sc) 1511188808Sgonzo{ 1512188808Sgonzo struct arge_ring_data *rd; 1513188808Sgonzo struct arge_rxdesc *rxd; 1514188808Sgonzo bus_addr_t addr; 1515188808Sgonzo int i; 1516188808Sgonzo 1517188808Sgonzo sc->arge_cdata.arge_rx_cons = 0; 1518188808Sgonzo 1519188808Sgonzo rd = &sc->arge_rdata; 1520188808Sgonzo bzero(rd->arge_rx_ring, sizeof(rd->arge_rx_ring)); 1521188808Sgonzo for (i = 0; i < ARGE_RX_RING_COUNT; i++) { 1522188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[i]; 1523188808Sgonzo rxd->rx_m = NULL; 1524188808Sgonzo rxd->desc = &rd->arge_rx_ring[i]; 1525188808Sgonzo if (i == ARGE_RX_RING_COUNT - 1) 1526188808Sgonzo addr = ARGE_RX_RING_ADDR(sc, 0); 1527188808Sgonzo else 1528188808Sgonzo addr = ARGE_RX_RING_ADDR(sc, i + 1); 1529188808Sgonzo rd->arge_rx_ring[i].next_desc = addr; 1530192783Sgonzo if (arge_newbuf(sc, i) != 0) { 1531188808Sgonzo return (ENOBUFS); 1532192783Sgonzo } 1533188808Sgonzo } 1534188808Sgonzo 1535188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, 1536188808Sgonzo sc->arge_cdata.arge_rx_ring_map, 1537195434Sgonzo BUS_DMASYNC_PREWRITE); 1538188808Sgonzo 1539188808Sgonzo return (0); 1540188808Sgonzo} 1541188808Sgonzo 1542188808Sgonzo/* 1543188808Sgonzo * Initialize an RX descriptor and attach an MBUF cluster. 1544188808Sgonzo */ 1545188808Sgonzostatic int 1546188808Sgonzoarge_newbuf(struct arge_softc *sc, int idx) 1547188808Sgonzo{ 1548188808Sgonzo struct arge_desc *desc; 1549188808Sgonzo struct arge_rxdesc *rxd; 1550188808Sgonzo struct mbuf *m; 1551188808Sgonzo bus_dma_segment_t segs[1]; 1552188808Sgonzo bus_dmamap_t map; 1553188808Sgonzo int nsegs; 1554188808Sgonzo 1555188808Sgonzo m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1556188808Sgonzo if (m == NULL) 1557188808Sgonzo return (ENOBUFS); 1558188808Sgonzo m->m_len = m->m_pkthdr.len = MCLBYTES; 1559188808Sgonzo m_adj(m, sizeof(uint64_t)); 1560188808Sgonzo 1561188808Sgonzo if (bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_rx_tag, 1562188808Sgonzo sc->arge_cdata.arge_rx_sparemap, m, segs, &nsegs, 0) != 0) { 1563188808Sgonzo m_freem(m); 1564188808Sgonzo return (ENOBUFS); 1565188808Sgonzo } 1566188808Sgonzo KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1567188808Sgonzo 1568188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[idx]; 1569188808Sgonzo if (rxd->rx_m != NULL) { 1570188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap); 1571188808Sgonzo } 1572188808Sgonzo map = rxd->rx_dmamap; 1573188808Sgonzo rxd->rx_dmamap = sc->arge_cdata.arge_rx_sparemap; 1574188808Sgonzo sc->arge_cdata.arge_rx_sparemap = map; 1575188808Sgonzo rxd->rx_m = m; 1576188808Sgonzo desc = rxd->desc; 1577192783Sgonzo if (segs[0].ds_addr & 3) 1578192783Sgonzo panic("RX packet address unaligned"); 1579188808Sgonzo desc->packet_addr = segs[0].ds_addr; 1580192783Sgonzo desc->packet_ctrl = ARGE_DESC_EMPTY | ARGE_DMASIZE(segs[0].ds_len); 1581188808Sgonzo 1582195434Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, 1583195434Sgonzo sc->arge_cdata.arge_rx_ring_map, 1584195434Sgonzo BUS_DMASYNC_PREWRITE); 1585195434Sgonzo 1586188808Sgonzo return (0); 1587188808Sgonzo} 1588188808Sgonzo 1589188808Sgonzostatic __inline void 1590188808Sgonzoarge_fixup_rx(struct mbuf *m) 1591188808Sgonzo{ 1592198933Sgonzo int i; 1593198933Sgonzo uint16_t *src, *dst; 1594188808Sgonzo 1595188808Sgonzo src = mtod(m, uint16_t *); 1596188808Sgonzo dst = src - 1; 1597188808Sgonzo 1598195434Sgonzo for (i = 0; i < m->m_len / sizeof(uint16_t); i++) { 1599188808Sgonzo *dst++ = *src++; 1600195434Sgonzo } 1601188808Sgonzo 1602195434Sgonzo if (m->m_len % sizeof(uint16_t)) 1603195434Sgonzo *(uint8_t *)dst = *(uint8_t *)src; 1604195434Sgonzo 1605188808Sgonzo m->m_data -= ETHER_ALIGN; 1606188808Sgonzo} 1607188808Sgonzo 1608192783Sgonzo#ifdef DEVICE_POLLING 1609198667Sgonzostatic int 1610192783Sgonzoarge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1611192783Sgonzo{ 1612192783Sgonzo struct arge_softc *sc = ifp->if_softc; 1613198667Sgonzo int rx_npkts = 0; 1614188808Sgonzo 1615198933Sgonzo if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1616192783Sgonzo ARGE_LOCK(sc); 1617192783Sgonzo arge_tx_locked(sc); 1618198667Sgonzo rx_npkts = arge_rx_locked(sc); 1619192783Sgonzo ARGE_UNLOCK(sc); 1620198933Sgonzo } 1621198667Sgonzo 1622198667Sgonzo return (rx_npkts); 1623192783Sgonzo} 1624192783Sgonzo#endif /* DEVICE_POLLING */ 1625192783Sgonzo 1626192783Sgonzo 1627188808Sgonzostatic void 1628188808Sgonzoarge_tx_locked(struct arge_softc *sc) 1629188808Sgonzo{ 1630188808Sgonzo struct arge_txdesc *txd; 1631188808Sgonzo struct arge_desc *cur_tx; 1632188808Sgonzo struct ifnet *ifp; 1633188808Sgonzo uint32_t ctrl; 1634188808Sgonzo int cons, prod; 1635188808Sgonzo 1636188808Sgonzo ARGE_LOCK_ASSERT(sc); 1637188808Sgonzo 1638188808Sgonzo cons = sc->arge_cdata.arge_tx_cons; 1639188808Sgonzo prod = sc->arge_cdata.arge_tx_prod; 1640220356Sadrian 1641220356Sadrian ARGEDEBUG(sc, ARGE_DBG_TX, "%s: cons=%d, prod=%d\n", __func__, cons, prod); 1642220356Sadrian 1643188808Sgonzo if (cons == prod) 1644188808Sgonzo return; 1645188808Sgonzo 1646188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, 1647188808Sgonzo sc->arge_cdata.arge_tx_ring_map, 1648188808Sgonzo BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1649188808Sgonzo 1650188808Sgonzo ifp = sc->arge_ifp; 1651188808Sgonzo /* 1652188808Sgonzo * Go through our tx list and free mbufs for those 1653188808Sgonzo * frames that have been transmitted. 1654188808Sgonzo */ 1655188808Sgonzo for (; cons != prod; ARGE_INC(cons, ARGE_TX_RING_COUNT)) { 1656188808Sgonzo cur_tx = &sc->arge_rdata.arge_tx_ring[cons]; 1657188808Sgonzo ctrl = cur_tx->packet_ctrl; 1658188808Sgonzo /* Check if descriptor has "finished" flag */ 1659188808Sgonzo if ((ctrl & ARGE_DESC_EMPTY) == 0) 1660188808Sgonzo break; 1661188808Sgonzo 1662188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT); 1663188808Sgonzo 1664188808Sgonzo sc->arge_cdata.arge_tx_cnt--; 1665188808Sgonzo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1666188808Sgonzo 1667188808Sgonzo txd = &sc->arge_cdata.arge_txdesc[cons]; 1668188808Sgonzo 1669188808Sgonzo ifp->if_opackets++; 1670188808Sgonzo 1671188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap, 1672188808Sgonzo BUS_DMASYNC_POSTWRITE); 1673188808Sgonzo bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap); 1674188808Sgonzo 1675188808Sgonzo /* Free only if it's first descriptor in list */ 1676188808Sgonzo if (txd->tx_m) 1677188808Sgonzo m_freem(txd->tx_m); 1678188808Sgonzo txd->tx_m = NULL; 1679188808Sgonzo 1680188808Sgonzo /* reset descriptor */ 1681188808Sgonzo cur_tx->packet_addr = 0; 1682188808Sgonzo } 1683188808Sgonzo 1684188808Sgonzo sc->arge_cdata.arge_tx_cons = cons; 1685188808Sgonzo 1686188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, 1687188808Sgonzo sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREWRITE); 1688188808Sgonzo} 1689188808Sgonzo 1690188808Sgonzo 1691198667Sgonzostatic int 1692188808Sgonzoarge_rx_locked(struct arge_softc *sc) 1693188808Sgonzo{ 1694188808Sgonzo struct arge_rxdesc *rxd; 1695188808Sgonzo struct ifnet *ifp = sc->arge_ifp; 1696192783Sgonzo int cons, prog, packet_len, i; 1697188808Sgonzo struct arge_desc *cur_rx; 1698188808Sgonzo struct mbuf *m; 1699198667Sgonzo int rx_npkts = 0; 1700188808Sgonzo 1701188808Sgonzo ARGE_LOCK_ASSERT(sc); 1702188808Sgonzo 1703188808Sgonzo cons = sc->arge_cdata.arge_rx_cons; 1704188808Sgonzo 1705188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, 1706188808Sgonzo sc->arge_cdata.arge_rx_ring_map, 1707188808Sgonzo BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1708188808Sgonzo 1709188808Sgonzo for (prog = 0; prog < ARGE_RX_RING_COUNT; 1710188808Sgonzo ARGE_INC(cons, ARGE_RX_RING_COUNT)) { 1711188808Sgonzo cur_rx = &sc->arge_rdata.arge_rx_ring[cons]; 1712188808Sgonzo rxd = &sc->arge_cdata.arge_rxdesc[cons]; 1713188808Sgonzo m = rxd->rx_m; 1714188808Sgonzo 1715188808Sgonzo if ((cur_rx->packet_ctrl & ARGE_DESC_EMPTY) != 0) 1716188808Sgonzo break; 1717188808Sgonzo 1718188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD); 1719188808Sgonzo 1720188808Sgonzo prog++; 1721188808Sgonzo 1722188808Sgonzo packet_len = ARGE_DMASIZE(cur_rx->packet_ctrl); 1723188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap, 1724195434Sgonzo BUS_DMASYNC_POSTREAD); 1725188808Sgonzo m = rxd->rx_m; 1726188808Sgonzo 1727188808Sgonzo arge_fixup_rx(m); 1728188808Sgonzo m->m_pkthdr.rcvif = ifp; 1729188808Sgonzo /* Skip 4 bytes of CRC */ 1730188808Sgonzo m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN; 1731188808Sgonzo ifp->if_ipackets++; 1732198667Sgonzo rx_npkts++; 1733188808Sgonzo 1734188808Sgonzo ARGE_UNLOCK(sc); 1735188808Sgonzo (*ifp->if_input)(ifp, m); 1736188808Sgonzo ARGE_LOCK(sc); 1737192783Sgonzo cur_rx->packet_addr = 0; 1738192783Sgonzo } 1739188808Sgonzo 1740192783Sgonzo if (prog > 0) { 1741192783Sgonzo 1742192783Sgonzo i = sc->arge_cdata.arge_rx_cons; 1743192783Sgonzo for (; prog > 0 ; prog--) { 1744192783Sgonzo if (arge_newbuf(sc, i) != 0) { 1745192783Sgonzo device_printf(sc->arge_dev, 1746192783Sgonzo "Failed to allocate buffer\n"); 1747192783Sgonzo break; 1748192783Sgonzo } 1749192783Sgonzo ARGE_INC(i, ARGE_RX_RING_COUNT); 1750188808Sgonzo } 1751188808Sgonzo 1752188808Sgonzo bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, 1753188808Sgonzo sc->arge_cdata.arge_rx_ring_map, 1754195434Sgonzo BUS_DMASYNC_PREWRITE); 1755188808Sgonzo 1756188808Sgonzo sc->arge_cdata.arge_rx_cons = cons; 1757188808Sgonzo } 1758198667Sgonzo 1759198667Sgonzo return (rx_npkts); 1760188808Sgonzo} 1761188808Sgonzo 1762188808Sgonzostatic int 1763188808Sgonzoarge_intr_filter(void *arg) 1764188808Sgonzo{ 1765188808Sgonzo struct arge_softc *sc = arg; 1766188808Sgonzo uint32_t status, ints; 1767188808Sgonzo 1768188808Sgonzo status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS); 1769188808Sgonzo ints = ARGE_READ(sc, AR71XX_DMA_INTR); 1770188808Sgonzo 1771220354Sadrian ARGEDEBUG(sc, ARGE_DBG_INTR, "int mask(filter) = %b\n", ints, 1772188808Sgonzo "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD" 1773188808Sgonzo "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); 1774220354Sadrian ARGEDEBUG(sc, ARGE_DBG_INTR, "status(filter) = %b\n", status, 1775188808Sgonzo "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD" 1776188808Sgonzo "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); 1777188808Sgonzo 1778188808Sgonzo if (status & DMA_INTR_ALL) { 1779191644Sgonzo sc->arge_intr_status |= status; 1780192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); 1781188808Sgonzo return (FILTER_SCHEDULE_THREAD); 1782192783Sgonzo } 1783188808Sgonzo 1784188808Sgonzo sc->arge_intr_status = 0; 1785188808Sgonzo return (FILTER_STRAY); 1786188808Sgonzo} 1787188808Sgonzo 1788188808Sgonzostatic void 1789188808Sgonzoarge_intr(void *arg) 1790188808Sgonzo{ 1791188808Sgonzo struct arge_softc *sc = arg; 1792188808Sgonzo uint32_t status; 1793220356Sadrian struct ifnet *ifp = sc->arge_ifp; 1794188808Sgonzo 1795192783Sgonzo status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS); 1796192783Sgonzo status |= sc->arge_intr_status; 1797188808Sgonzo 1798220354Sadrian ARGEDEBUG(sc, ARGE_DBG_INTR, "int status(intr) = %b\n", status, 1799188808Sgonzo "\20\10\7RX_OVERFLOW\5RX_PKT_RCVD" 1800188808Sgonzo "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); 1801188808Sgonzo 1802188808Sgonzo /* 1803188808Sgonzo * Is it our interrupt at all? 1804188808Sgonzo */ 1805188808Sgonzo if (status == 0) 1806188808Sgonzo return; 1807188808Sgonzo 1808188808Sgonzo if (status & DMA_INTR_RX_BUS_ERROR) { 1809188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR); 1810188808Sgonzo device_printf(sc->arge_dev, "RX bus error"); 1811188808Sgonzo return; 1812188808Sgonzo } 1813188808Sgonzo 1814188808Sgonzo if (status & DMA_INTR_TX_BUS_ERROR) { 1815188808Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR); 1816188808Sgonzo device_printf(sc->arge_dev, "TX bus error"); 1817188808Sgonzo return; 1818188808Sgonzo } 1819188808Sgonzo 1820192783Sgonzo ARGE_LOCK(sc); 1821188808Sgonzo 1822192783Sgonzo if (status & DMA_INTR_RX_PKT_RCVD) 1823192783Sgonzo arge_rx_locked(sc); 1824188808Sgonzo 1825192783Sgonzo /* 1826192783Sgonzo * RX overrun disables the receiver. 1827192783Sgonzo * Clear indication and re-enable rx. 1828192783Sgonzo */ 1829192783Sgonzo if ( status & DMA_INTR_RX_OVERFLOW) { 1830192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_OVERFLOW); 1831192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN); 1832220356Sadrian sc->stats.rx_overflow++; 1833192783Sgonzo } 1834188808Sgonzo 1835192783Sgonzo if (status & DMA_INTR_TX_PKT_SENT) 1836192783Sgonzo arge_tx_locked(sc); 1837192783Sgonzo /* 1838192783Sgonzo * Underrun turns off TX. Clear underrun indication. 1839192783Sgonzo * If there's anything left in the ring, reactivate the tx. 1840192783Sgonzo */ 1841192569Sdwhite if (status & DMA_INTR_TX_UNDERRUN) { 1842192569Sdwhite ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_UNDERRUN); 1843220356Sadrian sc->stats.tx_underflow++; 1844220356Sadrian ARGEDEBUG(sc, ARGE_DBG_TX, "%s: TX underrun; tx_cnt=%d\n", __func__, sc->arge_cdata.arge_tx_cnt); 1845219590Sadrian if (sc->arge_cdata.arge_tx_cnt > 0 ) { 1846192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 1847192783Sgonzo DMA_TX_CONTROL_EN); 1848192783Sgonzo } 1849192569Sdwhite } 1850192569Sdwhite 1851192946Sgonzo /* 1852220357Sadrian * If we've finished TXing and there's space for more packets 1853220357Sadrian * to be queued for TX, do so. Otherwise we may end up in a 1854220357Sadrian * situation where the interface send queue was filled 1855220357Sadrian * whilst the hardware queue was full, then the hardware 1856220357Sadrian * queue was drained by the interface send queue wasn't, 1857220357Sadrian * and thus if_start() is never called to kick-start 1858220357Sadrian * the send process (and all subsequent packets are simply 1859220357Sadrian * discarded. 1860220357Sadrian * 1861220357Sadrian * XXX TODO: make sure that the hardware deals nicely 1862220357Sadrian * with the possibility of the queue being enabled above 1863220357Sadrian * after a TX underrun, then having the hardware queue added 1864220357Sadrian * to below. 1865220357Sadrian */ 1866220357Sadrian if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN) && 1867220357Sadrian (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 1868220357Sadrian if (!IFQ_IS_EMPTY(&ifp->if_snd)) 1869220357Sadrian arge_start_locked(ifp); 1870220357Sadrian } 1871220357Sadrian 1872220357Sadrian /* 1873192946Sgonzo * We handled all bits, clear status 1874192946Sgonzo */ 1875192946Sgonzo sc->arge_intr_status = 0; 1876188808Sgonzo ARGE_UNLOCK(sc); 1877192783Sgonzo /* 1878192783Sgonzo * re-enable all interrupts 1879192783Sgonzo */ 1880192783Sgonzo ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); 1881188808Sgonzo} 1882188808Sgonzo 1883192783Sgonzo 1884188808Sgonzostatic void 1885188808Sgonzoarge_tick(void *xsc) 1886188808Sgonzo{ 1887188808Sgonzo struct arge_softc *sc = xsc; 1888188808Sgonzo struct mii_data *mii; 1889188808Sgonzo 1890188808Sgonzo ARGE_LOCK_ASSERT(sc); 1891188808Sgonzo 1892199234Sgonzo if (sc->arge_miibus) { 1893199234Sgonzo mii = device_get_softc(sc->arge_miibus); 1894199234Sgonzo mii_tick(mii); 1895199234Sgonzo callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); 1896199234Sgonzo } 1897188808Sgonzo} 1898199234Sgonzo 1899199234Sgonzoint 1900199234Sgonzoarge_multiphy_mediachange(struct ifnet *ifp) 1901199234Sgonzo{ 1902199234Sgonzo struct arge_softc *sc = ifp->if_softc; 1903199234Sgonzo struct ifmedia *ifm = &sc->arge_ifmedia; 1904199234Sgonzo struct ifmedia_entry *ife = ifm->ifm_cur; 1905199234Sgonzo 1906199234Sgonzo if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1907199234Sgonzo return (EINVAL); 1908199234Sgonzo 1909199234Sgonzo if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 1910199234Sgonzo device_printf(sc->arge_dev, 1911199234Sgonzo "AUTO is not supported for multiphy MAC"); 1912199234Sgonzo return (EINVAL); 1913199234Sgonzo } 1914199234Sgonzo 1915199234Sgonzo /* 1916199234Sgonzo * Ignore everything 1917199234Sgonzo */ 1918199234Sgonzo return (0); 1919199234Sgonzo} 1920199234Sgonzo 1921199234Sgonzovoid 1922199234Sgonzoarge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1923199234Sgonzo{ 1924199234Sgonzo struct arge_softc *sc = ifp->if_softc; 1925199234Sgonzo 1926199234Sgonzo ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 1927199234Sgonzo ifmr->ifm_active = IFM_ETHER | sc->arge_media_type | 1928199234Sgonzo sc->arge_duplex_mode; 1929199234Sgonzo} 1930199234Sgonzo 1931