1223927Sray/*- 2297646Ssgalabov * Copyright (c) 2015-2016, Stanislav Galabov 3292704Sadrian * Copyright (c) 2014, Aleksandr A. Mityaev 4223927Sray * Copyright (c) 2011, Aleksandr Rybalko 5223927Sray * based on hard work 6223927Sray * by Alexander Egorenkov <egorenar@gmail.com> 7223927Sray * and by Damien Bergamini <damien.bergamini@free.fr> 8223927Sray * All rights reserved. 9223927Sray * 10223927Sray * Redistribution and use in source and binary forms, with or without 11223927Sray * modification, are permitted provided that the following conditions 12223927Sray * are met: 13223927Sray * 1. Redistributions of source code must retain the above copyright 14223927Sray * notice unmodified, this list of conditions, and the following 15223927Sray * disclaimer. 16223927Sray * 2. Redistributions in binary form must reproduce the above copyright 17223927Sray * notice, this list of conditions and the following disclaimer in the 18223927Sray * documentation and/or other materials provided with the distribution. 19223927Sray * 20223927Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21223927Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22223927Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23223927Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24223927Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25223927Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26223927Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27223927Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28223927Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29223927Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30223927Sray * SUCH DAMAGE. 31223927Sray */ 32223927Sray 33223927Sray#include <sys/cdefs.h> 34223927Sray__FBSDID("$FreeBSD$"); 35223927Sray 36223927Sray#include "if_rtvar.h" 37223927Sray#include "if_rtreg.h" 38223927Sray 39223927Sray#include <net/if.h> 40257176Sglebius#include <net/if_var.h> 41223927Sray#include <net/if_arp.h> 42223927Sray#include <net/ethernet.h> 43223927Sray#include <net/if_dl.h> 44223927Sray#include <net/if_media.h> 45223927Sray#include <net/if_types.h> 46223927Sray#include <net/if_vlan_var.h> 47223927Sray 48223927Sray#include <net/bpf.h> 49223927Sray 50223927Sray#include <machine/bus.h> 51223927Sray#include <machine/cache.h> 52223927Sray#include <machine/cpufunc.h> 53223927Sray#include <machine/resource.h> 54223927Sray#include <vm/vm_param.h> 55223927Sray#include <vm/vm.h> 56223927Sray#include <vm/pmap.h> 57297646Ssgalabov#include <machine/pmap.h> 58223927Sray#include <sys/bus.h> 59223927Sray#include <sys/rman.h> 60223927Sray 61292704Sadrian#include "opt_platform.h" 62292704Sadrian#include "opt_rt305x.h" 63292704Sadrian 64292704Sadrian#ifdef FDT 65292704Sadrian#include <dev/ofw/openfirm.h> 66292704Sadrian#include <dev/ofw/ofw_bus.h> 67292704Sadrian#include <dev/ofw/ofw_bus_subr.h> 68292704Sadrian#endif 69292704Sadrian 70223927Sray#include <dev/mii/mii.h> 71223927Sray#include <dev/mii/miivar.h> 72223927Sray 73297646Ssgalabov#if 0 74223927Sray#include <mips/rt305x/rt305x_sysctlvar.h> 75223927Sray#include <mips/rt305x/rt305xreg.h> 76297646Ssgalabov#endif 77223927Sray 78223927Sray#ifdef IF_RT_PHY_SUPPORT 79223927Sray#include "miibus_if.h" 80223927Sray#endif 81223927Sray 82223927Sray/* 83223927Sray * Defines and macros 84223927Sray */ 85223927Sray#define RT_MAX_AGG_SIZE 3840 86223927Sray 87223927Sray#define RT_TX_DATA_SEG0_SIZE MJUMPAGESIZE 88223927Sray 89223927Sray#define RT_MS(_v, _f) (((_v) & _f) >> _f##_S) 90223927Sray#define RT_SM(_v, _f) (((_v) << _f##_S) & _f) 91223927Sray 92223927Sray#define RT_TX_WATCHDOG_TIMEOUT 5 93223927Sray 94292704Sadrian#define RT_CHIPID_RT3050 0x3050 95292704Sadrian#define RT_CHIPID_RT5350 0x5350 96292704Sadrian#define RT_CHIPID_MT7620 0x7620 97297646Ssgalabov#define RT_CHIPID_MT7621 0x7621 98292704Sadrian 99292704Sadrian#ifdef FDT 100292704Sadrian/* more specific and new models should go first */ 101292704Sadrianstatic const struct ofw_compat_data rt_compat_data[] = { 102298059Ssgalabov { "ralink,rt3050-eth", RT_CHIPID_RT3050 }, 103298059Ssgalabov { "ralink,rt3352-eth", RT_CHIPID_RT3050 }, 104298059Ssgalabov { "ralink,rt3883-eth", RT_CHIPID_RT3050 }, 105298059Ssgalabov { "ralink,rt5350-eth", RT_CHIPID_RT5350 }, 106298059Ssgalabov { "ralink,mt7620a-eth", RT_CHIPID_MT7620 }, 107298350Ssgalabov { "mediatek,mt7620-eth", RT_CHIPID_MT7620 }, 108298059Ssgalabov { "ralink,mt7621-eth", RT_CHIPID_MT7621 }, 109298059Ssgalabov { "mediatek,mt7621-eth", RT_CHIPID_MT7621 }, 110298059Ssgalabov { NULL, 0 } 111292704Sadrian}; 112292704Sadrian#endif 113292704Sadrian 114223927Sray/* 115223927Sray * Static function prototypes 116223927Sray */ 117223927Sraystatic int rt_probe(device_t dev); 118223927Sraystatic int rt_attach(device_t dev); 119223927Sraystatic int rt_detach(device_t dev); 120223927Sraystatic int rt_shutdown(device_t dev); 121223927Sraystatic int rt_suspend(device_t dev); 122223927Sraystatic int rt_resume(device_t dev); 123223927Sraystatic void rt_init_locked(void *priv); 124223927Sraystatic void rt_init(void *priv); 125223927Sraystatic void rt_stop_locked(void *priv); 126223927Sraystatic void rt_stop(void *priv); 127223927Sraystatic void rt_start(struct ifnet *ifp); 128223927Sraystatic int rt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 129223927Sraystatic void rt_periodic(void *arg); 130223927Sraystatic void rt_tx_watchdog(void *arg); 131223927Sraystatic void rt_intr(void *arg); 132292704Sadrianstatic void rt_rt5350_intr(void *arg); 133223927Sraystatic void rt_tx_coherent_intr(struct rt_softc *sc); 134223927Sraystatic void rt_rx_coherent_intr(struct rt_softc *sc); 135223927Sraystatic void rt_rx_delay_intr(struct rt_softc *sc); 136223927Sraystatic void rt_tx_delay_intr(struct rt_softc *sc); 137292704Sadrianstatic void rt_rx_intr(struct rt_softc *sc, int qid); 138223927Sraystatic void rt_tx_intr(struct rt_softc *sc, int qid); 139223927Sraystatic void rt_rx_done_task(void *context, int pending); 140223927Sraystatic void rt_tx_done_task(void *context, int pending); 141223927Sraystatic void rt_periodic_task(void *context, int pending); 142292704Sadrianstatic int rt_rx_eof(struct rt_softc *sc, 143292704Sadrian struct rt_softc_rx_ring *ring, int limit); 144223927Sraystatic void rt_tx_eof(struct rt_softc *sc, 145223927Sray struct rt_softc_tx_ring *ring); 146223927Sraystatic void rt_update_stats(struct rt_softc *sc); 147223927Sraystatic void rt_watchdog(struct rt_softc *sc); 148223927Sraystatic void rt_update_raw_counters(struct rt_softc *sc); 149223927Sraystatic void rt_intr_enable(struct rt_softc *sc, uint32_t intr_mask); 150223927Sraystatic void rt_intr_disable(struct rt_softc *sc, uint32_t intr_mask); 151223927Sraystatic int rt_txrx_enable(struct rt_softc *sc); 152223927Sraystatic int rt_alloc_rx_ring(struct rt_softc *sc, 153292704Sadrian struct rt_softc_rx_ring *ring, int qid); 154223927Sraystatic void rt_reset_rx_ring(struct rt_softc *sc, 155223927Sray struct rt_softc_rx_ring *ring); 156223927Sraystatic void rt_free_rx_ring(struct rt_softc *sc, 157223927Sray struct rt_softc_rx_ring *ring); 158223927Sraystatic int rt_alloc_tx_ring(struct rt_softc *sc, 159223927Sray struct rt_softc_tx_ring *ring, int qid); 160223927Sraystatic void rt_reset_tx_ring(struct rt_softc *sc, 161223927Sray struct rt_softc_tx_ring *ring); 162223927Sraystatic void rt_free_tx_ring(struct rt_softc *sc, 163223927Sray struct rt_softc_tx_ring *ring); 164223927Sraystatic void rt_dma_map_addr(void *arg, bus_dma_segment_t *segs, 165223927Sray int nseg, int error); 166223927Sraystatic void rt_sysctl_attach(struct rt_softc *sc); 167223927Sray#ifdef IF_RT_PHY_SUPPORT 168223927Srayvoid rt_miibus_statchg(device_t); 169223927Sraystatic int rt_miibus_readreg(device_t, int, int); 170223927Sraystatic int rt_miibus_writereg(device_t, int, int, int); 171223927Sray#endif 172223927Sraystatic int rt_ifmedia_upd(struct ifnet *); 173223927Sraystatic void rt_ifmedia_sts(struct ifnet *, struct ifmediareq *); 174223927Sray 175227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, rt, CTLFLAG_RD, 0, "RT driver parameters"); 176223927Sray#ifdef IF_RT_DEBUG 177223927Sraystatic int rt_debug = 0; 178267992ShselaskySYSCTL_INT(_hw_rt, OID_AUTO, debug, CTLFLAG_RWTUN, &rt_debug, 0, 179223927Sray "RT debug level"); 180223927Sray#endif 181223927Sray 182223927Sraystatic int 183223927Srayrt_probe(device_t dev) 184223927Sray{ 185292704Sadrian struct rt_softc *sc = device_get_softc(dev); 186292704Sadrian char buf[80]; 187292704Sadrian#ifdef FDT 188292704Sadrian const struct ofw_compat_data * cd; 189292704Sadrian 190292704Sadrian cd = ofw_bus_search_compatible(dev, rt_compat_data); 191297646Ssgalabov if (cd->ocd_data == 0) 192292704Sadrian return (ENXIO); 193292704Sadrian 194292704Sadrian sc->rt_chipid = (unsigned int)(cd->ocd_data); 195292704Sadrian#else 196292704Sadrian#if defined(MT7620) 197292704Sadrian sc->rt_chipid = RT_CHIPID_MT7620; 198297646Ssgalabov#elif defined(MT7621) 199297646Ssgalabov sc->rt_chipid = RT_CHIPID_MT7621; 200292704Sadrian#elif defined(RT5350) 201292704Sadrian sc->rt_chipid = RT_CHIPID_RT5350; 202292704Sadrian#else 203292704Sadrian sc->rt_chipid = RT_CHIPID_RT3050; 204292704Sadrian#endif 205292704Sadrian#endif 206297646Ssgalabov snprintf(buf, sizeof(buf), "Ralink %cT%x onChip Ethernet driver", 207297646Ssgalabov sc->rt_chipid >= 0x7600 ? 'M' : 'R', sc->rt_chipid); 208292704Sadrian device_set_desc_copy(dev, buf); 209292704Sadrian return (BUS_PROBE_GENERIC); 210223927Sray} 211223927Sray 212223927Sray/* 213223927Sray * macaddr_atoi - translate string MAC address to uint8_t array 214223927Sray */ 215223927Sraystatic int 216223927Sraymacaddr_atoi(const char *str, uint8_t *mac) 217223927Sray{ 218223927Sray int count, i; 219223927Sray unsigned int amac[ETHER_ADDR_LEN]; /* Aligned version */ 220223927Sray 221223927Sray count = sscanf(str, "%x%*c%x%*c%x%*c%x%*c%x%*c%x", 222223927Sray &amac[0], &amac[1], &amac[2], 223223927Sray &amac[3], &amac[4], &amac[5]); 224223927Sray if (count < ETHER_ADDR_LEN) { 225223927Sray memset(mac, 0, ETHER_ADDR_LEN); 226223927Sray return (1); 227223927Sray } 228223927Sray 229223927Sray /* Copy aligned to result */ 230223927Sray for (i = 0; i < ETHER_ADDR_LEN; i ++) 231223927Sray mac[i] = (amac[i] & 0xff); 232223927Sray 233223927Sray return (0); 234223927Sray} 235223927Sray 236223927Sray#ifdef USE_GENERATED_MAC_ADDRESS 237223927Sray/* 238223927Sray * generate_mac(uin8_t *mac) 239223927Sray * This is MAC address generator for cases when real device MAC address 240223927Sray * unknown or not yet accessible. 241223927Sray * Use 'b','s','d' signature and 3 octets from CRC32 on kenv. 242223927Sray * MAC = 'b', 's', 'd', CRC[3]^CRC[2], CRC[1], CRC[0] 243223927Sray * 244223927Sray * Output - MAC address, that do not change between reboots, if hints or 245223927Sray * bootloader info unchange. 246223927Sray */ 247223927Sraystatic void 248223927Sraygenerate_mac(uint8_t *mac) 249223927Sray{ 250223927Sray unsigned char *cp; 251223927Sray int i = 0; 252223927Sray uint32_t crc = 0xffffffff; 253223927Sray 254223927Sray /* Generate CRC32 on kenv */ 255293105Sian for (cp = kenvp[0]; cp != NULL; cp = kenvp[++i]) { 256293105Sian crc = calculate_crc32c(crc, cp, strlen(cp) + 1); 257223927Sray } 258223927Sray crc = ~crc; 259223927Sray 260223927Sray mac[0] = 'b'; 261223927Sray mac[1] = 's'; 262223927Sray mac[2] = 'd'; 263223927Sray mac[3] = (crc >> 24) ^ ((crc >> 16) & 0xff); 264223927Sray mac[4] = (crc >> 8) & 0xff; 265223927Sray mac[5] = crc & 0xff; 266223927Sray} 267223927Sray#endif 268223927Sray 269223927Sray/* 270223927Sray * ether_request_mac - try to find usable MAC address. 271223927Sray */ 272223927Sraystatic int 273223927Srayether_request_mac(device_t dev, uint8_t *mac) 274223927Sray{ 275223927Sray char *var; 276223927Sray 277223927Sray /* 278223927Sray * "ethaddr" is passed via envp on RedBoot platforms 279223927Sray * "kmac" is passed via argv on RouterBOOT platforms 280223927Sray */ 281292704Sadrian#if defined(RT305X_UBOOT) || defined(__REDBOOT__) || defined(__ROUTERBOOT__) 282273174Sdavide if ((var = kern_getenv("ethaddr")) != NULL || 283273174Sdavide (var = kern_getenv("kmac")) != NULL ) { 284223927Sray 285223927Sray if(!macaddr_atoi(var, mac)) { 286223927Sray printf("%s: use %s macaddr from KENV\n", 287223927Sray device_get_nameunit(dev), var); 288223927Sray freeenv(var); 289223927Sray return (0); 290223927Sray } 291223927Sray freeenv(var); 292223927Sray } 293223927Sray#endif 294223927Sray 295223927Sray /* 296223927Sray * Try from hints 297223927Sray * hint.[dev].[unit].macaddr 298223927Sray */ 299223927Sray if (!resource_string_value(device_get_name(dev), 300223927Sray device_get_unit(dev), "macaddr", (const char **)&var)) { 301223927Sray 302223927Sray if(!macaddr_atoi(var, mac)) { 303223927Sray printf("%s: use %s macaddr from hints\n", 304223927Sray device_get_nameunit(dev), var); 305223927Sray return (0); 306223927Sray } 307223927Sray } 308223927Sray 309223927Sray#ifdef USE_GENERATED_MAC_ADDRESS 310223927Sray generate_mac(mac); 311223927Sray 312223927Sray device_printf(dev, "use generated %02x:%02x:%02x:%02x:%02x:%02x " 313223927Sray "macaddr\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 314223927Sray#else 315223927Sray /* Hardcoded */ 316223927Sray mac[0] = 0x00; 317223927Sray mac[1] = 0x18; 318223927Sray mac[2] = 0xe7; 319223927Sray mac[3] = 0xd5; 320223927Sray mac[4] = 0x83; 321223927Sray mac[5] = 0x90; 322223927Sray 323223927Sray device_printf(dev, "use hardcoded 00:18:e7:d5:83:90 macaddr\n"); 324223927Sray#endif 325223927Sray 326223927Sray return (0); 327223927Sray} 328223927Sray 329292704Sadrian/* 330292704Sadrian * Reset hardware 331292704Sadrian */ 332292704Sadrianstatic void 333292704Sadrianreset_freng(struct rt_softc *sc) 334292704Sadrian{ 335292704Sadrian /* XXX hard reset kills everything so skip it ... */ 336292704Sadrian return; 337292704Sadrian} 338292704Sadrian 339223927Sraystatic int 340223927Srayrt_attach(device_t dev) 341223927Sray{ 342223927Sray struct rt_softc *sc; 343223927Sray struct ifnet *ifp; 344223927Sray int error, i; 345223927Sray 346223927Sray sc = device_get_softc(dev); 347223927Sray sc->dev = dev; 348223927Sray 349223927Sray mtx_init(&sc->lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, 350223927Sray MTX_DEF | MTX_RECURSE); 351223927Sray 352223927Sray sc->mem_rid = 0; 353223927Sray sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 354223927Sray RF_ACTIVE); 355223927Sray if (sc->mem == NULL) { 356223927Sray device_printf(dev, "could not allocate memory resource\n"); 357223927Sray error = ENXIO; 358223927Sray goto fail; 359223927Sray } 360223927Sray 361223927Sray sc->bst = rman_get_bustag(sc->mem); 362223927Sray sc->bsh = rman_get_bushandle(sc->mem); 363223927Sray 364223927Sray sc->irq_rid = 0; 365223927Sray sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 366223927Sray RF_ACTIVE); 367223927Sray if (sc->irq == NULL) { 368223927Sray device_printf(dev, 369223927Sray "could not allocate interrupt resource\n"); 370223927Sray error = ENXIO; 371223927Sray goto fail; 372223927Sray } 373223927Sray 374223927Sray#ifdef IF_RT_DEBUG 375223927Sray sc->debug = rt_debug; 376223927Sray 377223927Sray SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 378223927Sray SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 379223927Sray "debug", CTLFLAG_RW, &sc->debug, 0, "rt debug level"); 380223927Sray#endif 381223927Sray 382223927Sray /* Reset hardware */ 383292704Sadrian reset_freng(sc); 384297646Ssgalabov 385297646Ssgalabov 386297646Ssgalabov if (sc->rt_chipid == RT_CHIPID_MT7620) { 387297646Ssgalabov sc->csum_fail_ip = MT7620_RXD_SRC_IP_CSUM_FAIL; 388297646Ssgalabov sc->csum_fail_l4 = MT7620_RXD_SRC_L4_CSUM_FAIL; 389297646Ssgalabov } else if (sc->rt_chipid == RT_CHIPID_MT7621) { 390297646Ssgalabov sc->csum_fail_ip = MT7621_RXD_SRC_IP_CSUM_FAIL; 391297646Ssgalabov sc->csum_fail_l4 = MT7621_RXD_SRC_L4_CSUM_FAIL; 392297646Ssgalabov } else { 393297646Ssgalabov sc->csum_fail_ip = RT305X_RXD_SRC_IP_CSUM_FAIL; 394297646Ssgalabov sc->csum_fail_l4 = RT305X_RXD_SRC_L4_CSUM_FAIL; 395297646Ssgalabov } 396292704Sadrian 397292704Sadrian /* Fill in soc-specific registers map */ 398292704Sadrian switch(sc->rt_chipid) { 399292704Sadrian case RT_CHIPID_MT7620: 400297646Ssgalabov case RT_CHIPID_MT7621: 401292704Sadrian case RT_CHIPID_RT5350: 402297646Ssgalabov device_printf(dev, "%cT%x Ethernet MAC (rev 0x%08x)\n", 403297646Ssgalabov sc->rt_chipid >= 0x7600 ? 'M' : 'R', 404292704Sadrian sc->rt_chipid, sc->mac_rev); 405292704Sadrian /* RT5350: No GDMA, PSE, CDMA, PPE */ 406292704Sadrian RT_WRITE(sc, GE_PORT_BASE + 0x0C00, // UDPCS, TCPCS, IPCS=1 407292704Sadrian RT_READ(sc, GE_PORT_BASE + 0x0C00) | (0x7<<16)); 408292704Sadrian sc->delay_int_cfg=RT5350_PDMA_BASE+RT5350_DELAY_INT_CFG; 409292704Sadrian sc->fe_int_status=RT5350_FE_INT_STATUS; 410292704Sadrian sc->fe_int_enable=RT5350_FE_INT_ENABLE; 411292704Sadrian sc->pdma_glo_cfg=RT5350_PDMA_BASE+RT5350_PDMA_GLO_CFG; 412292704Sadrian sc->pdma_rst_idx=RT5350_PDMA_BASE+RT5350_PDMA_RST_IDX; 413292704Sadrian for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) { 414292704Sadrian sc->tx_base_ptr[i]=RT5350_PDMA_BASE+RT5350_TX_BASE_PTR(i); 415292704Sadrian sc->tx_max_cnt[i]=RT5350_PDMA_BASE+RT5350_TX_MAX_CNT(i); 416292704Sadrian sc->tx_ctx_idx[i]=RT5350_PDMA_BASE+RT5350_TX_CTX_IDX(i); 417292704Sadrian sc->tx_dtx_idx[i]=RT5350_PDMA_BASE+RT5350_TX_DTX_IDX(i); 418292704Sadrian } 419292704Sadrian sc->rx_ring_count=2; 420292704Sadrian sc->rx_base_ptr[0]=RT5350_PDMA_BASE+RT5350_RX_BASE_PTR0; 421292704Sadrian sc->rx_max_cnt[0]=RT5350_PDMA_BASE+RT5350_RX_MAX_CNT0; 422292704Sadrian sc->rx_calc_idx[0]=RT5350_PDMA_BASE+RT5350_RX_CALC_IDX0; 423292704Sadrian sc->rx_drx_idx[0]=RT5350_PDMA_BASE+RT5350_RX_DRX_IDX0; 424292704Sadrian sc->rx_base_ptr[1]=RT5350_PDMA_BASE+RT5350_RX_BASE_PTR1; 425292704Sadrian sc->rx_max_cnt[1]=RT5350_PDMA_BASE+RT5350_RX_MAX_CNT1; 426292704Sadrian sc->rx_calc_idx[1]=RT5350_PDMA_BASE+RT5350_RX_CALC_IDX1; 427292704Sadrian sc->rx_drx_idx[1]=RT5350_PDMA_BASE+RT5350_RX_DRX_IDX1; 428292704Sadrian sc->int_rx_done_mask=RT5350_INT_RXQ0_DONE; 429292704Sadrian sc->int_tx_done_mask=RT5350_INT_TXQ0_DONE; 430292704Sadrian break; 431292704Sadrian default: 432292704Sadrian device_printf(dev, "RT305XF Ethernet MAC (rev 0x%08x)\n", 433292704Sadrian sc->mac_rev); 434292704Sadrian RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG, 435292704Sadrian ( 436292704Sadrian GDM_ICS_EN | /* Enable IP Csum */ 437292704Sadrian GDM_TCS_EN | /* Enable TCP Csum */ 438292704Sadrian GDM_UCS_EN | /* Enable UDP Csum */ 439292704Sadrian GDM_STRPCRC | /* Strip CRC from packet */ 440292704Sadrian GDM_DST_PORT_CPU << GDM_UFRC_P_SHIFT | /* fwd UCast to CPU */ 441292704Sadrian GDM_DST_PORT_CPU << GDM_BFRC_P_SHIFT | /* fwd BCast to CPU */ 442292704Sadrian GDM_DST_PORT_CPU << GDM_MFRC_P_SHIFT | /* fwd MCast to CPU */ 443292704Sadrian GDM_DST_PORT_CPU << GDM_OFRC_P_SHIFT /* fwd Other to CPU */ 444292704Sadrian )); 445292704Sadrian 446292704Sadrian sc->delay_int_cfg=PDMA_BASE+DELAY_INT_CFG; 447292704Sadrian sc->fe_int_status=GE_PORT_BASE+FE_INT_STATUS; 448292704Sadrian sc->fe_int_enable=GE_PORT_BASE+FE_INT_ENABLE; 449292704Sadrian sc->pdma_glo_cfg=PDMA_BASE+PDMA_GLO_CFG; 450292704Sadrian sc->pdma_glo_cfg=PDMA_BASE+PDMA_GLO_CFG; 451292704Sadrian sc->pdma_rst_idx=PDMA_BASE+PDMA_RST_IDX; 452292704Sadrian for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) { 453292704Sadrian sc->tx_base_ptr[i]=PDMA_BASE+TX_BASE_PTR(i); 454292704Sadrian sc->tx_max_cnt[i]=PDMA_BASE+TX_MAX_CNT(i); 455292704Sadrian sc->tx_ctx_idx[i]=PDMA_BASE+TX_CTX_IDX(i); 456292704Sadrian sc->tx_dtx_idx[i]=PDMA_BASE+TX_DTX_IDX(i); 457292704Sadrian } 458292704Sadrian sc->rx_ring_count=1; 459292704Sadrian sc->rx_base_ptr[0]=PDMA_BASE+RX_BASE_PTR0; 460292704Sadrian sc->rx_max_cnt[0]=PDMA_BASE+RX_MAX_CNT0; 461292704Sadrian sc->rx_calc_idx[0]=PDMA_BASE+RX_CALC_IDX0; 462292704Sadrian sc->rx_drx_idx[0]=PDMA_BASE+RX_DRX_IDX0; 463292704Sadrian sc->int_rx_done_mask=INT_RX_DONE; 464292704Sadrian sc->int_tx_done_mask=INT_TXQ0_DONE; 465297793Spfg } 466223927Sray 467223927Sray /* allocate Tx and Rx rings */ 468223927Sray for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) { 469223927Sray error = rt_alloc_tx_ring(sc, &sc->tx_ring[i], i); 470223927Sray if (error != 0) { 471223927Sray device_printf(dev, "could not allocate Tx ring #%d\n", 472223927Sray i); 473223927Sray goto fail; 474223927Sray } 475223927Sray } 476223927Sray 477223927Sray sc->tx_ring_mgtqid = 5; 478292704Sadrian for (i = 0; i < sc->rx_ring_count; i++) { 479292704Sadrian error = rt_alloc_rx_ring(sc, &sc->rx_ring[i], i); 480292704Sadrian if (error != 0) { 481292704Sadrian device_printf(dev, "could not allocate Rx ring\n"); 482292704Sadrian goto fail; 483292704Sadrian } 484223927Sray } 485223927Sray 486223927Sray callout_init(&sc->periodic_ch, 0); 487223927Sray callout_init_mtx(&sc->tx_watchdog_ch, &sc->lock, 0); 488223927Sray 489223927Sray ifp = sc->ifp = if_alloc(IFT_ETHER); 490223927Sray if (ifp == NULL) { 491223927Sray device_printf(dev, "could not if_alloc()\n"); 492223927Sray error = ENOMEM; 493223927Sray goto fail; 494223927Sray } 495223927Sray 496223927Sray ifp->if_softc = sc; 497223927Sray if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev)); 498223927Sray ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 499223927Sray ifp->if_init = rt_init; 500223927Sray ifp->if_ioctl = rt_ioctl; 501223927Sray ifp->if_start = rt_start; 502223927Sray#define RT_TX_QLEN 256 503223927Sray 504223927Sray IFQ_SET_MAXLEN(&ifp->if_snd, RT_TX_QLEN); 505223927Sray ifp->if_snd.ifq_drv_maxlen = RT_TX_QLEN; 506223927Sray IFQ_SET_READY(&ifp->if_snd); 507223927Sray 508223927Sray#ifdef IF_RT_PHY_SUPPORT 509223927Sray error = mii_attach(dev, &sc->rt_miibus, ifp, rt_ifmedia_upd, 510223927Sray rt_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 511223927Sray if (error != 0) { 512223927Sray device_printf(dev, "attaching PHYs failed\n"); 513223927Sray error = ENXIO; 514223927Sray goto fail; 515223927Sray } 516223927Sray#else 517223927Sray ifmedia_init(&sc->rt_ifmedia, 0, rt_ifmedia_upd, rt_ifmedia_sts); 518223927Sray ifmedia_add(&sc->rt_ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, 519223927Sray NULL); 520223927Sray ifmedia_set(&sc->rt_ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX); 521223927Sray 522223927Sray#endif /* IF_RT_PHY_SUPPORT */ 523223927Sray 524223927Sray ether_request_mac(dev, sc->mac_addr); 525223927Sray ether_ifattach(ifp, sc->mac_addr); 526223927Sray 527223927Sray /* 528223927Sray * Tell the upper layer(s) we support long frames. 529223927Sray */ 530270856Sglebius ifp->if_hdrlen = sizeof(struct ether_vlan_header); 531223927Sray ifp->if_capabilities |= IFCAP_VLAN_MTU; 532223927Sray ifp->if_capenable |= IFCAP_VLAN_MTU; 533223927Sray ifp->if_capabilities |= IFCAP_RXCSUM|IFCAP_TXCSUM; 534223927Sray ifp->if_capenable |= IFCAP_RXCSUM|IFCAP_TXCSUM; 535223927Sray 536223927Sray /* init task queue */ 537223927Sray TASK_INIT(&sc->rx_done_task, 0, rt_rx_done_task, sc); 538223927Sray TASK_INIT(&sc->tx_done_task, 0, rt_tx_done_task, sc); 539223927Sray TASK_INIT(&sc->periodic_task, 0, rt_periodic_task, sc); 540223927Sray 541223927Sray sc->rx_process_limit = 100; 542223927Sray 543223927Sray sc->taskqueue = taskqueue_create("rt_taskq", M_NOWAIT, 544223927Sray taskqueue_thread_enqueue, &sc->taskqueue); 545223927Sray 546223927Sray taskqueue_start_threads(&sc->taskqueue, 1, PI_NET, "%s taskq", 547223927Sray device_get_nameunit(sc->dev)); 548223927Sray 549223927Sray rt_sysctl_attach(sc); 550223927Sray 551223927Sray /* set up interrupt */ 552223927Sray error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, 553292704Sadrian NULL, (sc->rt_chipid == RT_CHIPID_RT5350 || 554297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7620 || 555297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7621) ? rt_rt5350_intr : rt_intr, 556292704Sadrian sc, &sc->irqh); 557223927Sray if (error != 0) { 558223927Sray printf("%s: could not set up interrupt\n", 559223927Sray device_get_nameunit(dev)); 560223927Sray goto fail; 561223927Sray } 562223927Sray#ifdef IF_RT_DEBUG 563223927Sray device_printf(dev, "debug var at %#08x\n", (u_int)&(sc->debug)); 564223927Sray#endif 565223927Sray 566223927Sray return (0); 567223927Sray 568223927Srayfail: 569223927Sray /* free Tx and Rx rings */ 570223927Sray for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) 571223927Sray rt_free_tx_ring(sc, &sc->tx_ring[i]); 572223927Sray 573292704Sadrian for (i = 0; i < sc->rx_ring_count; i++) 574292704Sadrian rt_free_rx_ring(sc, &sc->rx_ring[i]); 575223927Sray 576223927Sray mtx_destroy(&sc->lock); 577223927Sray 578223927Sray if (sc->mem != NULL) 579223927Sray bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, 580223927Sray sc->mem); 581223927Sray 582223927Sray if (sc->irq != NULL) 583223927Sray bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 584223927Sray sc->irq); 585223927Sray 586223927Sray return (error); 587223927Sray} 588223927Sray 589223927Sray/* 590223927Sray * Set media options. 591223927Sray */ 592223927Sraystatic int 593223927Srayrt_ifmedia_upd(struct ifnet *ifp) 594223927Sray{ 595223927Sray struct rt_softc *sc; 596223927Sray#ifdef IF_RT_PHY_SUPPORT 597223927Sray struct mii_data *mii; 598251734Skevlo struct mii_softc *miisc; 599223927Sray int error = 0; 600223927Sray 601223927Sray sc = ifp->if_softc; 602223927Sray RT_SOFTC_LOCK(sc); 603223927Sray 604223927Sray mii = device_get_softc(sc->rt_miibus); 605251734Skevlo LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 606251734Skevlo PHY_RESET(miisc); 607251734Skevlo error = mii_mediachg(mii); 608223927Sray RT_SOFTC_UNLOCK(sc); 609223927Sray 610223927Sray return (error); 611223927Sray 612223927Sray#else /* !IF_RT_PHY_SUPPORT */ 613223927Sray 614223927Sray struct ifmedia *ifm; 615223927Sray struct ifmedia_entry *ife; 616223927Sray 617223927Sray sc = ifp->if_softc; 618223927Sray ifm = &sc->rt_ifmedia; 619223927Sray ife = ifm->ifm_cur; 620223927Sray 621223927Sray if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 622223927Sray return (EINVAL); 623223927Sray 624223927Sray if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 625223927Sray device_printf(sc->dev, 626223927Sray "AUTO is not supported for multiphy MAC"); 627223927Sray return (EINVAL); 628223927Sray } 629223927Sray 630223927Sray /* 631223927Sray * Ignore everything 632223927Sray */ 633223927Sray return (0); 634223927Sray#endif /* IF_RT_PHY_SUPPORT */ 635223927Sray} 636223927Sray 637223927Sray/* 638223927Sray * Report current media status. 639223927Sray */ 640223927Sraystatic void 641223927Srayrt_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 642223927Sray{ 643223927Sray#ifdef IF_RT_PHY_SUPPORT 644223927Sray struct rt_softc *sc; 645223927Sray struct mii_data *mii; 646223927Sray 647223927Sray sc = ifp->if_softc; 648223927Sray 649223927Sray RT_SOFTC_LOCK(sc); 650223927Sray mii = device_get_softc(sc->rt_miibus); 651223927Sray mii_pollstat(mii); 652223927Sray ifmr->ifm_active = mii->mii_media_active; 653223927Sray ifmr->ifm_status = mii->mii_media_status; 654223927Sray ifmr->ifm_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 655223927Sray ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 656223927Sray RT_SOFTC_UNLOCK(sc); 657223927Sray#else /* !IF_RT_PHY_SUPPORT */ 658223927Sray 659223927Sray ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 660223927Sray ifmr->ifm_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 661223927Sray#endif /* IF_RT_PHY_SUPPORT */ 662223927Sray} 663223927Sray 664223927Sraystatic int 665223927Srayrt_detach(device_t dev) 666223927Sray{ 667223927Sray struct rt_softc *sc; 668223927Sray struct ifnet *ifp; 669223927Sray int i; 670223927Sray 671223927Sray sc = device_get_softc(dev); 672223927Sray ifp = sc->ifp; 673223927Sray 674223927Sray RT_DPRINTF(sc, RT_DEBUG_ANY, "detaching\n"); 675223927Sray 676223927Sray RT_SOFTC_LOCK(sc); 677223927Sray 678223927Sray ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 679223927Sray 680223927Sray callout_stop(&sc->periodic_ch); 681223927Sray callout_stop(&sc->tx_watchdog_ch); 682223927Sray 683223927Sray taskqueue_drain(sc->taskqueue, &sc->rx_done_task); 684223927Sray taskqueue_drain(sc->taskqueue, &sc->tx_done_task); 685223927Sray taskqueue_drain(sc->taskqueue, &sc->periodic_task); 686223927Sray 687223927Sray /* free Tx and Rx rings */ 688223927Sray for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) 689223927Sray rt_free_tx_ring(sc, &sc->tx_ring[i]); 690292704Sadrian for (i = 0; i < sc->rx_ring_count; i++) 691292704Sadrian rt_free_rx_ring(sc, &sc->rx_ring[i]); 692223927Sray 693223927Sray RT_SOFTC_UNLOCK(sc); 694223927Sray 695223927Sray#ifdef IF_RT_PHY_SUPPORT 696223927Sray if (sc->rt_miibus != NULL) 697223927Sray device_delete_child(dev, sc->rt_miibus); 698223927Sray#endif 699223927Sray 700223927Sray ether_ifdetach(ifp); 701223927Sray if_free(ifp); 702223927Sray 703223927Sray taskqueue_free(sc->taskqueue); 704223927Sray 705223927Sray mtx_destroy(&sc->lock); 706223927Sray 707223927Sray bus_generic_detach(dev); 708223927Sray bus_teardown_intr(dev, sc->irq, sc->irqh); 709223927Sray bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 710223927Sray bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); 711223927Sray 712223927Sray return (0); 713223927Sray} 714223927Sray 715223927Sraystatic int 716223927Srayrt_shutdown(device_t dev) 717223927Sray{ 718223927Sray struct rt_softc *sc; 719223927Sray 720223927Sray sc = device_get_softc(dev); 721223927Sray RT_DPRINTF(sc, RT_DEBUG_ANY, "shutting down\n"); 722223927Sray rt_stop(sc); 723223927Sray 724223927Sray return (0); 725223927Sray} 726223927Sray 727223927Sraystatic int 728223927Srayrt_suspend(device_t dev) 729223927Sray{ 730223927Sray struct rt_softc *sc; 731223927Sray 732223927Sray sc = device_get_softc(dev); 733223927Sray RT_DPRINTF(sc, RT_DEBUG_ANY, "suspending\n"); 734223927Sray rt_stop(sc); 735223927Sray 736223927Sray return (0); 737223927Sray} 738223927Sray 739223927Sraystatic int 740223927Srayrt_resume(device_t dev) 741223927Sray{ 742223927Sray struct rt_softc *sc; 743223927Sray struct ifnet *ifp; 744223927Sray 745223927Sray sc = device_get_softc(dev); 746223927Sray ifp = sc->ifp; 747223927Sray 748223927Sray RT_DPRINTF(sc, RT_DEBUG_ANY, "resuming\n"); 749223927Sray 750223927Sray if (ifp->if_flags & IFF_UP) 751223927Sray rt_init(sc); 752223927Sray 753223927Sray return (0); 754223927Sray} 755223927Sray 756223927Sray/* 757223927Sray * rt_init_locked - Run initialization process having locked mtx. 758223927Sray */ 759223927Sraystatic void 760223927Srayrt_init_locked(void *priv) 761223927Sray{ 762223927Sray struct rt_softc *sc; 763223927Sray struct ifnet *ifp; 764223927Sray#ifdef IF_RT_PHY_SUPPORT 765223927Sray struct mii_data *mii; 766223927Sray#endif 767223927Sray int i, ntries; 768223927Sray uint32_t tmp; 769223927Sray 770223927Sray sc = priv; 771223927Sray ifp = sc->ifp; 772223927Sray#ifdef IF_RT_PHY_SUPPORT 773223927Sray mii = device_get_softc(sc->rt_miibus); 774223927Sray#endif 775223927Sray 776223927Sray RT_DPRINTF(sc, RT_DEBUG_ANY, "initializing\n"); 777223927Sray 778223927Sray RT_SOFTC_ASSERT_LOCKED(sc); 779223927Sray 780223927Sray /* hardware reset */ 781292704Sadrian //RT_WRITE(sc, GE_PORT_BASE + FE_RST_GLO, PSE_RESET); 782292704Sadrian //rt305x_sysctl_set(SYSCTL_RSTCTRL, SYSCTL_RSTCTRL_FRENG); 783223927Sray 784223927Sray /* Fwd to CPU (uni|broad|multi)cast and Unknown */ 785297646Ssgalabov if(sc->rt_chipid == RT_CHIPID_RT3050) 786292704Sadrian RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG, 787223927Sray ( 788223927Sray GDM_ICS_EN | /* Enable IP Csum */ 789223927Sray GDM_TCS_EN | /* Enable TCP Csum */ 790223927Sray GDM_UCS_EN | /* Enable UDP Csum */ 791223927Sray GDM_STRPCRC | /* Strip CRC from packet */ 792223927Sray GDM_DST_PORT_CPU << GDM_UFRC_P_SHIFT | /* Forward UCast to CPU */ 793223927Sray GDM_DST_PORT_CPU << GDM_BFRC_P_SHIFT | /* Forward BCast to CPU */ 794223927Sray GDM_DST_PORT_CPU << GDM_MFRC_P_SHIFT | /* Forward MCast to CPU */ 795223927Sray GDM_DST_PORT_CPU << GDM_OFRC_P_SHIFT /* Forward Other to CPU */ 796223927Sray )); 797223927Sray 798223927Sray /* disable DMA engine */ 799292704Sadrian RT_WRITE(sc, sc->pdma_glo_cfg, 0); 800292704Sadrian RT_WRITE(sc, sc->pdma_rst_idx, 0xffffffff); 801223927Sray 802223927Sray /* wait while DMA engine is busy */ 803223927Sray for (ntries = 0; ntries < 100; ntries++) { 804292704Sadrian tmp = RT_READ(sc, sc->pdma_glo_cfg); 805223927Sray if (!(tmp & (FE_TX_DMA_BUSY | FE_RX_DMA_BUSY))) 806223927Sray break; 807223927Sray DELAY(1000); 808223927Sray } 809223927Sray 810223927Sray if (ntries == 100) { 811223927Sray device_printf(sc->dev, "timeout waiting for DMA engine\n"); 812223927Sray goto fail; 813223927Sray } 814223927Sray 815223927Sray /* reset Rx and Tx rings */ 816223927Sray tmp = FE_RST_DRX_IDX0 | 817223927Sray FE_RST_DTX_IDX3 | 818223927Sray FE_RST_DTX_IDX2 | 819223927Sray FE_RST_DTX_IDX1 | 820223927Sray FE_RST_DTX_IDX0; 821223927Sray 822292704Sadrian RT_WRITE(sc, sc->pdma_rst_idx, tmp); 823223927Sray 824223927Sray /* XXX switch set mac address */ 825223927Sray for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) 826223927Sray rt_reset_tx_ring(sc, &sc->tx_ring[i]); 827223927Sray 828223927Sray for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) { 829223927Sray /* update TX_BASE_PTRx */ 830292704Sadrian RT_WRITE(sc, sc->tx_base_ptr[i], 831223927Sray sc->tx_ring[i].desc_phys_addr); 832292704Sadrian RT_WRITE(sc, sc->tx_max_cnt[i], 833223927Sray RT_SOFTC_TX_RING_DESC_COUNT); 834292704Sadrian RT_WRITE(sc, sc->tx_ctx_idx[i], 0); 835223927Sray } 836223927Sray 837223927Sray /* init Rx ring */ 838292704Sadrian for (i = 0; i < sc->rx_ring_count; i++) 839292704Sadrian rt_reset_rx_ring(sc, &sc->rx_ring[i]); 840223927Sray 841292704Sadrian /* update RX_BASE_PTRx */ 842292704Sadrian for (i = 0; i < sc->rx_ring_count; i++) { 843292704Sadrian RT_WRITE(sc, sc->rx_base_ptr[i], 844292704Sadrian sc->rx_ring[i].desc_phys_addr); 845292704Sadrian RT_WRITE(sc, sc->rx_max_cnt[i], 846292704Sadrian RT_SOFTC_RX_RING_DATA_COUNT); 847292704Sadrian RT_WRITE(sc, sc->rx_calc_idx[i], 848292704Sadrian RT_SOFTC_RX_RING_DATA_COUNT - 1); 849292704Sadrian } 850223927Sray 851223927Sray /* write back DDONE, 16byte burst enable RX/TX DMA */ 852292704Sadrian tmp = FE_TX_WB_DDONE | FE_DMA_BT_SIZE16 | FE_RX_DMA_EN | FE_TX_DMA_EN; 853297646Ssgalabov if (sc->rt_chipid == RT_CHIPID_MT7620 || 854297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7621) 855292704Sadrian tmp |= (1<<31); 856292704Sadrian RT_WRITE(sc, sc->pdma_glo_cfg, tmp); 857223927Sray 858223927Sray /* disable interrupts mitigation */ 859292704Sadrian RT_WRITE(sc, sc->delay_int_cfg, 0); 860223927Sray 861223927Sray /* clear pending interrupts */ 862292704Sadrian RT_WRITE(sc, sc->fe_int_status, 0xffffffff); 863223927Sray 864223927Sray /* enable interrupts */ 865292704Sadrian if (sc->rt_chipid == RT_CHIPID_RT5350 || 866297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7620 || 867297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7621) 868292704Sadrian tmp = RT5350_INT_TX_COHERENT | 869292704Sadrian RT5350_INT_RX_COHERENT | 870292704Sadrian RT5350_INT_TXQ3_DONE | 871292704Sadrian RT5350_INT_TXQ2_DONE | 872292704Sadrian RT5350_INT_TXQ1_DONE | 873292704Sadrian RT5350_INT_TXQ0_DONE | 874292704Sadrian RT5350_INT_RXQ1_DONE | 875292704Sadrian RT5350_INT_RXQ0_DONE; 876292704Sadrian else 877292704Sadrian tmp = CNT_PPE_AF | 878223927Sray CNT_GDM_AF | 879223927Sray PSE_P2_FC | 880223927Sray GDM_CRC_DROP | 881223927Sray PSE_BUF_DROP | 882223927Sray GDM_OTHER_DROP | 883223927Sray PSE_P1_FC | 884223927Sray PSE_P0_FC | 885223927Sray PSE_FQ_EMPTY | 886223927Sray INT_TX_COHERENT | 887223927Sray INT_RX_COHERENT | 888223927Sray INT_TXQ3_DONE | 889223927Sray INT_TXQ2_DONE | 890223927Sray INT_TXQ1_DONE | 891223927Sray INT_TXQ0_DONE | 892223927Sray INT_RX_DONE; 893223927Sray 894223927Sray sc->intr_enable_mask = tmp; 895223927Sray 896292704Sadrian RT_WRITE(sc, sc->fe_int_enable, tmp); 897223927Sray 898223927Sray if (rt_txrx_enable(sc) != 0) 899223927Sray goto fail; 900223927Sray 901223927Sray#ifdef IF_RT_PHY_SUPPORT 902223927Sray if (mii) mii_mediachg(mii); 903223927Sray#endif /* IF_RT_PHY_SUPPORT */ 904223927Sray 905223927Sray ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 906223927Sray ifp->if_drv_flags |= IFF_DRV_RUNNING; 907223927Sray 908223927Sray sc->periodic_round = 0; 909223927Sray 910223927Sray callout_reset(&sc->periodic_ch, hz / 10, rt_periodic, sc); 911223927Sray 912223927Sray return; 913223927Sray 914223927Srayfail: 915223927Sray rt_stop_locked(sc); 916223927Sray} 917223927Sray 918223927Sray/* 919223927Sray * rt_init - lock and initialize device. 920223927Sray */ 921223927Sraystatic void 922223927Srayrt_init(void *priv) 923223927Sray{ 924223927Sray struct rt_softc *sc; 925223927Sray 926223927Sray sc = priv; 927223927Sray RT_SOFTC_LOCK(sc); 928223927Sray rt_init_locked(sc); 929223927Sray RT_SOFTC_UNLOCK(sc); 930223927Sray} 931223927Sray 932223927Sray/* 933223927Sray * rt_stop_locked - stop TX/RX w/ lock 934223927Sray */ 935223927Sraystatic void 936223927Srayrt_stop_locked(void *priv) 937223927Sray{ 938223927Sray struct rt_softc *sc; 939223927Sray struct ifnet *ifp; 940223927Sray 941223927Sray sc = priv; 942223927Sray ifp = sc->ifp; 943223927Sray 944223927Sray RT_DPRINTF(sc, RT_DEBUG_ANY, "stopping\n"); 945223927Sray 946223927Sray RT_SOFTC_ASSERT_LOCKED(sc); 947223927Sray sc->tx_timer = 0; 948223927Sray ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 949223927Sray callout_stop(&sc->periodic_ch); 950223927Sray callout_stop(&sc->tx_watchdog_ch); 951223927Sray RT_SOFTC_UNLOCK(sc); 952223927Sray taskqueue_block(sc->taskqueue); 953223927Sray 954223927Sray /* 955223927Sray * Sometime rt_stop_locked called from isr and we get panic 956223927Sray * When found, I fix it 957223927Sray */ 958223927Sray#ifdef notyet 959223927Sray taskqueue_drain(sc->taskqueue, &sc->rx_done_task); 960223927Sray taskqueue_drain(sc->taskqueue, &sc->tx_done_task); 961223927Sray taskqueue_drain(sc->taskqueue, &sc->periodic_task); 962223927Sray#endif 963223927Sray RT_SOFTC_LOCK(sc); 964223927Sray 965223927Sray /* disable interrupts */ 966292704Sadrian RT_WRITE(sc, sc->fe_int_enable, 0); 967292704Sadrian 968292704Sadrian if(sc->rt_chipid == RT_CHIPID_RT5350 || 969297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7620 || 970297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7621) { 971292704Sadrian } else { 972292704Sadrian /* reset adapter */ 973292704Sadrian RT_WRITE(sc, GE_PORT_BASE + FE_RST_GLO, PSE_RESET); 974223927Sray 975292704Sadrian RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG, 976223927Sray ( 977223927Sray GDM_ICS_EN | /* Enable IP Csum */ 978223927Sray GDM_TCS_EN | /* Enable TCP Csum */ 979223927Sray GDM_UCS_EN | /* Enable UDP Csum */ 980223927Sray GDM_STRPCRC | /* Strip CRC from packet */ 981223927Sray GDM_DST_PORT_CPU << GDM_UFRC_P_SHIFT | /* Forward UCast to CPU */ 982223927Sray GDM_DST_PORT_CPU << GDM_BFRC_P_SHIFT | /* Forward BCast to CPU */ 983223927Sray GDM_DST_PORT_CPU << GDM_MFRC_P_SHIFT | /* Forward MCast to CPU */ 984223927Sray GDM_DST_PORT_CPU << GDM_OFRC_P_SHIFT /* Forward Other to CPU */ 985223927Sray )); 986292704Sadrian } 987223927Sray} 988223927Sray 989223927Sraystatic void 990223927Srayrt_stop(void *priv) 991223927Sray{ 992223927Sray struct rt_softc *sc; 993223927Sray 994223927Sray sc = priv; 995223927Sray RT_SOFTC_LOCK(sc); 996223927Sray rt_stop_locked(sc); 997223927Sray RT_SOFTC_UNLOCK(sc); 998223927Sray} 999223927Sray 1000223927Sray/* 1001223927Sray * rt_tx_data - transmit packet. 1002223927Sray */ 1003223927Sraystatic int 1004223927Srayrt_tx_data(struct rt_softc *sc, struct mbuf *m, int qid) 1005223927Sray{ 1006223927Sray struct ifnet *ifp; 1007223927Sray struct rt_softc_tx_ring *ring; 1008223927Sray struct rt_softc_tx_data *data; 1009223927Sray struct rt_txdesc *desc; 1010223927Sray struct mbuf *m_d; 1011223927Sray bus_dma_segment_t dma_seg[RT_SOFTC_MAX_SCATTER]; 1012223927Sray int error, ndmasegs, ndescs, i; 1013223927Sray 1014223927Sray KASSERT(qid >= 0 && qid < RT_SOFTC_TX_RING_COUNT, 1015223927Sray ("%s: Tx data: invalid qid=%d\n", 1016223927Sray device_get_nameunit(sc->dev), qid)); 1017223927Sray 1018223927Sray RT_SOFTC_TX_RING_ASSERT_LOCKED(&sc->tx_ring[qid]); 1019223927Sray 1020223927Sray ifp = sc->ifp; 1021223927Sray ring = &sc->tx_ring[qid]; 1022223927Sray desc = &ring->desc[ring->desc_cur]; 1023223927Sray data = &ring->data[ring->data_cur]; 1024223927Sray 1025223927Sray error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m, 1026223927Sray dma_seg, &ndmasegs, 0); 1027223927Sray if (error != 0) { 1028223927Sray /* too many fragments, linearize */ 1029223927Sray 1030223927Sray RT_DPRINTF(sc, RT_DEBUG_TX, 1031223927Sray "could not load mbuf DMA map, trying to linearize " 1032223927Sray "mbuf: ndmasegs=%d, len=%d, error=%d\n", 1033223927Sray ndmasegs, m->m_pkthdr.len, error); 1034223927Sray 1035243857Sglebius m_d = m_collapse(m, M_NOWAIT, 16); 1036223927Sray if (m_d == NULL) { 1037223927Sray m_freem(m); 1038223927Sray m = NULL; 1039223927Sray return (ENOMEM); 1040223927Sray } 1041223927Sray m = m_d; 1042223927Sray 1043223927Sray sc->tx_defrag_packets++; 1044223927Sray 1045223927Sray error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, 1046223927Sray data->dma_map, m, dma_seg, &ndmasegs, 0); 1047223927Sray if (error != 0) { 1048223927Sray device_printf(sc->dev, "could not load mbuf DMA map: " 1049223927Sray "ndmasegs=%d, len=%d, error=%d\n", 1050223927Sray ndmasegs, m->m_pkthdr.len, error); 1051223927Sray m_freem(m); 1052223927Sray return (error); 1053223927Sray } 1054223927Sray } 1055223927Sray 1056223927Sray if (m->m_pkthdr.len == 0) 1057223927Sray ndmasegs = 0; 1058223927Sray 1059223927Sray /* determine how many Tx descs are required */ 1060223927Sray ndescs = 1 + ndmasegs / 2; 1061223927Sray if ((ring->desc_queued + ndescs) > 1062223927Sray (RT_SOFTC_TX_RING_DESC_COUNT - 2)) { 1063223927Sray RT_DPRINTF(sc, RT_DEBUG_TX, 1064223927Sray "there are not enough Tx descs\n"); 1065223927Sray 1066223927Sray sc->no_tx_desc_avail++; 1067223927Sray 1068223927Sray bus_dmamap_unload(ring->data_dma_tag, data->dma_map); 1069223927Sray m_freem(m); 1070223927Sray return (EFBIG); 1071223927Sray } 1072223927Sray 1073223927Sray data->m = m; 1074223927Sray 1075223927Sray /* set up Tx descs */ 1076223927Sray for (i = 0; i < ndmasegs; i += 2) { 1077292704Sadrian 1078292704Sadrian /* TODO: this needs to be refined as MT7620 for example has 1079292704Sadrian * a different word3 layout than RT305x and RT5350 (the last 1080297646Ssgalabov * one doesn't use word3 at all). And so does MT7621... 1081292704Sadrian */ 1082292704Sadrian 1083297646Ssgalabov if (sc->rt_chipid != RT_CHIPID_MT7621) { 1084297646Ssgalabov /* Set destination */ 1085297646Ssgalabov if (sc->rt_chipid != RT_CHIPID_MT7620) 1086297646Ssgalabov desc->dst = (TXDSCR_DST_PORT_GDMA1); 1087292704Sadrian 1088297646Ssgalabov if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1089297646Ssgalabov desc->dst |= (TXDSCR_IP_CSUM_GEN | 1090297646Ssgalabov TXDSCR_UDP_CSUM_GEN | TXDSCR_TCP_CSUM_GEN); 1091297646Ssgalabov /* Set queue id */ 1092297646Ssgalabov desc->qn = qid; 1093297646Ssgalabov /* No PPPoE */ 1094297646Ssgalabov desc->pppoe = 0; 1095297646Ssgalabov /* No VLAN */ 1096297646Ssgalabov desc->vid = 0; 1097297646Ssgalabov } else { 1098297646Ssgalabov desc->vid = 0; 1099297646Ssgalabov desc->pppoe = 0; 1100297646Ssgalabov desc->qn = 0; 1101297646Ssgalabov desc->dst = 2; 1102297646Ssgalabov } 1103223927Sray 1104223927Sray desc->sdp0 = htole32(dma_seg[i].ds_addr); 1105223927Sray desc->sdl0 = htole16(dma_seg[i].ds_len | 1106223927Sray ( ((i+1) == ndmasegs )?RT_TXDESC_SDL0_LASTSEG:0 )); 1107223927Sray 1108223927Sray if ((i+1) < ndmasegs) { 1109223927Sray desc->sdp1 = htole32(dma_seg[i+1].ds_addr); 1110223927Sray desc->sdl1 = htole16(dma_seg[i+1].ds_len | 1111223927Sray ( ((i+2) == ndmasegs )?RT_TXDESC_SDL1_LASTSEG:0 )); 1112223927Sray } else { 1113223927Sray desc->sdp1 = 0; 1114223927Sray desc->sdl1 = 0; 1115223927Sray } 1116223927Sray 1117223927Sray if ((i+2) < ndmasegs) { 1118223927Sray ring->desc_queued++; 1119223927Sray ring->desc_cur = (ring->desc_cur + 1) % 1120223927Sray RT_SOFTC_TX_RING_DESC_COUNT; 1121223927Sray } 1122223927Sray desc = &ring->desc[ring->desc_cur]; 1123223927Sray } 1124223927Sray 1125223927Sray RT_DPRINTF(sc, RT_DEBUG_TX, "sending data: len=%d, ndmasegs=%d, " 1126223927Sray "DMA ds_len=%d/%d/%d/%d/%d\n", 1127223927Sray m->m_pkthdr.len, ndmasegs, 1128223927Sray (int) dma_seg[0].ds_len, 1129223927Sray (int) dma_seg[1].ds_len, 1130223927Sray (int) dma_seg[2].ds_len, 1131223927Sray (int) dma_seg[3].ds_len, 1132223927Sray (int) dma_seg[4].ds_len); 1133223927Sray 1134223927Sray bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map, 1135223927Sray BUS_DMASYNC_PREWRITE); 1136223927Sray bus_dmamap_sync(ring->data_dma_tag, data->dma_map, 1137223927Sray BUS_DMASYNC_PREWRITE); 1138223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 1139223927Sray BUS_DMASYNC_PREWRITE); 1140223927Sray 1141223927Sray ring->desc_queued++; 1142223927Sray ring->desc_cur = (ring->desc_cur + 1) % RT_SOFTC_TX_RING_DESC_COUNT; 1143223927Sray 1144223927Sray ring->data_queued++; 1145223927Sray ring->data_cur = (ring->data_cur + 1) % RT_SOFTC_TX_RING_DATA_COUNT; 1146223927Sray 1147223927Sray /* kick Tx */ 1148292704Sadrian RT_WRITE(sc, sc->tx_ctx_idx[qid], ring->desc_cur); 1149223927Sray 1150223927Sray return (0); 1151223927Sray} 1152223927Sray 1153223927Sray/* 1154223927Sray * rt_start - start Transmit/Receive 1155223927Sray */ 1156223927Sraystatic void 1157223927Srayrt_start(struct ifnet *ifp) 1158223927Sray{ 1159223927Sray struct rt_softc *sc; 1160223927Sray struct mbuf *m; 1161223927Sray int qid = 0 /* XXX must check QoS priority */; 1162223927Sray 1163223927Sray sc = ifp->if_softc; 1164223927Sray 1165223927Sray if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1166223927Sray return; 1167223927Sray 1168223927Sray for (;;) { 1169223927Sray IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1170223927Sray if (m == NULL) 1171223927Sray break; 1172223927Sray 1173223927Sray m->m_pkthdr.rcvif = NULL; 1174223927Sray 1175223927Sray RT_SOFTC_TX_RING_LOCK(&sc->tx_ring[qid]); 1176223927Sray 1177223927Sray if (sc->tx_ring[qid].data_queued >= 1178223927Sray RT_SOFTC_TX_RING_DATA_COUNT) { 1179223927Sray RT_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]); 1180223927Sray 1181223927Sray RT_DPRINTF(sc, RT_DEBUG_TX, 1182223927Sray "if_start: Tx ring with qid=%d is full\n", qid); 1183223927Sray 1184223927Sray m_freem(m); 1185223927Sray 1186223927Sray ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1187271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1188223927Sray 1189223927Sray sc->tx_data_queue_full[qid]++; 1190223927Sray 1191223927Sray break; 1192223927Sray } 1193223927Sray 1194223927Sray if (rt_tx_data(sc, m, qid) != 0) { 1195223927Sray RT_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]); 1196223927Sray 1197271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1198223927Sray 1199223927Sray break; 1200223927Sray } 1201223927Sray 1202223927Sray RT_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]); 1203223927Sray sc->tx_timer = RT_TX_WATCHDOG_TIMEOUT; 1204223927Sray callout_reset(&sc->tx_watchdog_ch, hz, rt_tx_watchdog, sc); 1205223927Sray } 1206223927Sray} 1207223927Sray 1208223927Sray/* 1209223927Sray * rt_update_promisc - set/clear promiscuous mode. Unused yet, because 1210223927Sray * filtering done by attached Ethernet switch. 1211223927Sray */ 1212223927Sraystatic void 1213223927Srayrt_update_promisc(struct ifnet *ifp) 1214223927Sray{ 1215223927Sray struct rt_softc *sc; 1216223927Sray 1217223927Sray sc = ifp->if_softc; 1218223927Sray printf("%s: %s promiscuous mode\n", 1219223927Sray device_get_nameunit(sc->dev), 1220223927Sray (ifp->if_flags & IFF_PROMISC) ? "entering" : "leaving"); 1221223927Sray} 1222223927Sray 1223223927Sray/* 1224223927Sray * rt_ioctl - ioctl handler. 1225223927Sray */ 1226223927Sraystatic int 1227223927Srayrt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1228223927Sray{ 1229223927Sray struct rt_softc *sc; 1230223927Sray struct ifreq *ifr; 1231223927Sray#ifdef IF_RT_PHY_SUPPORT 1232223927Sray struct mii_data *mii; 1233223927Sray#endif /* IF_RT_PHY_SUPPORT */ 1234223927Sray int error, startall; 1235223927Sray 1236223927Sray sc = ifp->if_softc; 1237223927Sray ifr = (struct ifreq *) data; 1238223927Sray 1239223927Sray error = 0; 1240223927Sray 1241223927Sray switch (cmd) { 1242223927Sray case SIOCSIFFLAGS: 1243223927Sray startall = 0; 1244223927Sray RT_SOFTC_LOCK(sc); 1245223927Sray if (ifp->if_flags & IFF_UP) { 1246223927Sray if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1247223927Sray if ((ifp->if_flags ^ sc->if_flags) & 1248223927Sray IFF_PROMISC) 1249223927Sray rt_update_promisc(ifp); 1250223927Sray } else { 1251223927Sray rt_init_locked(sc); 1252223927Sray startall = 1; 1253223927Sray } 1254223927Sray } else { 1255223927Sray if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1256223927Sray rt_stop_locked(sc); 1257223927Sray } 1258223927Sray sc->if_flags = ifp->if_flags; 1259223927Sray RT_SOFTC_UNLOCK(sc); 1260223927Sray break; 1261223927Sray case SIOCGIFMEDIA: 1262223927Sray case SIOCSIFMEDIA: 1263223927Sray#ifdef IF_RT_PHY_SUPPORT 1264223927Sray mii = device_get_softc(sc->rt_miibus); 1265223927Sray error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1266223927Sray#else 1267223927Sray error = ifmedia_ioctl(ifp, ifr, &sc->rt_ifmedia, cmd); 1268223927Sray#endif /* IF_RT_PHY_SUPPORT */ 1269223927Sray break; 1270223927Sray default: 1271223927Sray error = ether_ioctl(ifp, cmd, data); 1272223927Sray break; 1273223927Sray } 1274223927Sray return (error); 1275223927Sray} 1276223927Sray 1277223927Sray/* 1278223927Sray * rt_periodic - Handler of PERIODIC interrupt 1279223927Sray */ 1280223927Sraystatic void 1281223927Srayrt_periodic(void *arg) 1282223927Sray{ 1283223927Sray struct rt_softc *sc; 1284223927Sray 1285223927Sray sc = arg; 1286223927Sray RT_DPRINTF(sc, RT_DEBUG_PERIODIC, "periodic\n"); 1287223927Sray taskqueue_enqueue(sc->taskqueue, &sc->periodic_task); 1288223927Sray} 1289223927Sray 1290223927Sray/* 1291223927Sray * rt_tx_watchdog - Handler of TX Watchdog 1292223927Sray */ 1293223927Sraystatic void 1294223927Srayrt_tx_watchdog(void *arg) 1295223927Sray{ 1296223927Sray struct rt_softc *sc; 1297223927Sray struct ifnet *ifp; 1298223927Sray 1299223927Sray sc = arg; 1300223927Sray ifp = sc->ifp; 1301223927Sray 1302223927Sray if (sc->tx_timer == 0) 1303223927Sray return; 1304223927Sray 1305223927Sray if (--sc->tx_timer == 0) { 1306223927Sray device_printf(sc->dev, "Tx watchdog timeout: resetting\n"); 1307223927Sray#ifdef notyet 1308223927Sray /* 1309223927Sray * XXX: Commented out, because reset break input. 1310223927Sray */ 1311223927Sray rt_stop_locked(sc); 1312223927Sray rt_init_locked(sc); 1313223927Sray#endif 1314271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1315223927Sray sc->tx_watchdog_timeouts++; 1316223927Sray } 1317223927Sray callout_reset(&sc->tx_watchdog_ch, hz, rt_tx_watchdog, sc); 1318223927Sray} 1319223927Sray 1320223927Sray/* 1321223927Sray * rt_cnt_ppe_af - Handler of PPE Counter Table Almost Full interrupt 1322223927Sray */ 1323223927Sraystatic void 1324223927Srayrt_cnt_ppe_af(struct rt_softc *sc) 1325223927Sray{ 1326223927Sray 1327223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, "PPE Counter Table Almost Full\n"); 1328223927Sray} 1329223927Sray 1330223927Sray/* 1331223927Sray * rt_cnt_gdm_af - Handler of GDMA 1 & 2 Counter Table Almost Full interrupt 1332223927Sray */ 1333223927Sraystatic void 1334223927Srayrt_cnt_gdm_af(struct rt_softc *sc) 1335223927Sray{ 1336223927Sray 1337223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, 1338223927Sray "GDMA 1 & 2 Counter Table Almost Full\n"); 1339223927Sray} 1340223927Sray 1341223927Sray/* 1342223927Sray * rt_pse_p2_fc - Handler of PSE port2 (GDMA 2) flow control interrupt 1343223927Sray */ 1344223927Sraystatic void 1345223927Srayrt_pse_p2_fc(struct rt_softc *sc) 1346223927Sray{ 1347223927Sray 1348223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, 1349223927Sray "PSE port2 (GDMA 2) flow control asserted.\n"); 1350223927Sray} 1351223927Sray 1352223927Sray/* 1353223927Sray * rt_gdm_crc_drop - Handler of GDMA 1/2 discard a packet due to CRC error 1354223927Sray * interrupt 1355223927Sray */ 1356223927Sraystatic void 1357223927Srayrt_gdm_crc_drop(struct rt_softc *sc) 1358223927Sray{ 1359223927Sray 1360223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, 1361223927Sray "GDMA 1 & 2 discard a packet due to CRC error\n"); 1362223927Sray} 1363223927Sray 1364223927Sray/* 1365223927Sray * rt_pse_buf_drop - Handler of buffer sharing limitation interrupt 1366223927Sray */ 1367223927Sraystatic void 1368223927Srayrt_pse_buf_drop(struct rt_softc *sc) 1369223927Sray{ 1370223927Sray 1371223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, 1372223927Sray "PSE discards a packet due to buffer sharing limitation\n"); 1373223927Sray} 1374223927Sray 1375223927Sray/* 1376223927Sray * rt_gdm_other_drop - Handler of discard on other reason interrupt 1377223927Sray */ 1378223927Sraystatic void 1379223927Srayrt_gdm_other_drop(struct rt_softc *sc) 1380223927Sray{ 1381223927Sray 1382223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, 1383223927Sray "GDMA 1 & 2 discard a packet due to other reason\n"); 1384223927Sray} 1385223927Sray 1386223927Sray/* 1387223927Sray * rt_pse_p1_fc - Handler of PSE port1 (GDMA 1) flow control interrupt 1388223927Sray */ 1389223927Sraystatic void 1390223927Srayrt_pse_p1_fc(struct rt_softc *sc) 1391223927Sray{ 1392223927Sray 1393223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, 1394223927Sray "PSE port1 (GDMA 1) flow control asserted.\n"); 1395223927Sray} 1396223927Sray 1397223927Sray/* 1398223927Sray * rt_pse_p0_fc - Handler of PSE port0 (CDMA) flow control interrupt 1399223927Sray */ 1400223927Sraystatic void 1401223927Srayrt_pse_p0_fc(struct rt_softc *sc) 1402223927Sray{ 1403223927Sray 1404223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, 1405223927Sray "PSE port0 (CDMA) flow control asserted.\n"); 1406223927Sray} 1407223927Sray 1408223927Sray/* 1409223927Sray * rt_pse_fq_empty - Handler of PSE free Q empty threshold reached interrupt 1410223927Sray */ 1411223927Sraystatic void 1412223927Srayrt_pse_fq_empty(struct rt_softc *sc) 1413223927Sray{ 1414223927Sray 1415223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, 1416223927Sray "PSE free Q empty threshold reached & forced drop " 1417223927Sray "condition occurred.\n"); 1418223927Sray} 1419223927Sray 1420223927Sray/* 1421223927Sray * rt_intr - main ISR 1422223927Sray */ 1423223927Sraystatic void 1424223927Srayrt_intr(void *arg) 1425223927Sray{ 1426223927Sray struct rt_softc *sc; 1427223927Sray struct ifnet *ifp; 1428223927Sray uint32_t status; 1429223927Sray 1430223927Sray sc = arg; 1431223927Sray ifp = sc->ifp; 1432223927Sray 1433223927Sray /* acknowledge interrupts */ 1434292704Sadrian status = RT_READ(sc, sc->fe_int_status); 1435292704Sadrian RT_WRITE(sc, sc->fe_int_status, status); 1436223927Sray 1437223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, "interrupt: status=0x%08x\n", status); 1438223927Sray 1439223927Sray if (status == 0xffffffff || /* device likely went away */ 1440223927Sray status == 0) /* not for us */ 1441223927Sray return; 1442223927Sray 1443223927Sray sc->interrupts++; 1444223927Sray 1445223927Sray if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1446223927Sray return; 1447223927Sray 1448223927Sray if (status & CNT_PPE_AF) 1449223927Sray rt_cnt_ppe_af(sc); 1450223927Sray 1451223927Sray if (status & CNT_GDM_AF) 1452223927Sray rt_cnt_gdm_af(sc); 1453223927Sray 1454223927Sray if (status & PSE_P2_FC) 1455223927Sray rt_pse_p2_fc(sc); 1456223927Sray 1457223927Sray if (status & GDM_CRC_DROP) 1458223927Sray rt_gdm_crc_drop(sc); 1459223927Sray 1460223927Sray if (status & PSE_BUF_DROP) 1461223927Sray rt_pse_buf_drop(sc); 1462223927Sray 1463223927Sray if (status & GDM_OTHER_DROP) 1464223927Sray rt_gdm_other_drop(sc); 1465223927Sray 1466223927Sray if (status & PSE_P1_FC) 1467223927Sray rt_pse_p1_fc(sc); 1468223927Sray 1469223927Sray if (status & PSE_P0_FC) 1470223927Sray rt_pse_p0_fc(sc); 1471223927Sray 1472223927Sray if (status & PSE_FQ_EMPTY) 1473223927Sray rt_pse_fq_empty(sc); 1474223927Sray 1475223927Sray if (status & INT_TX_COHERENT) 1476223927Sray rt_tx_coherent_intr(sc); 1477223927Sray 1478223927Sray if (status & INT_RX_COHERENT) 1479223927Sray rt_rx_coherent_intr(sc); 1480223927Sray 1481223927Sray if (status & RX_DLY_INT) 1482223927Sray rt_rx_delay_intr(sc); 1483223927Sray 1484223927Sray if (status & TX_DLY_INT) 1485223927Sray rt_tx_delay_intr(sc); 1486223927Sray 1487223927Sray if (status & INT_RX_DONE) 1488292704Sadrian rt_rx_intr(sc, 0); 1489223927Sray 1490223927Sray if (status & INT_TXQ3_DONE) 1491223927Sray rt_tx_intr(sc, 3); 1492223927Sray 1493223927Sray if (status & INT_TXQ2_DONE) 1494223927Sray rt_tx_intr(sc, 2); 1495223927Sray 1496223927Sray if (status & INT_TXQ1_DONE) 1497223927Sray rt_tx_intr(sc, 1); 1498223927Sray 1499223927Sray if (status & INT_TXQ0_DONE) 1500223927Sray rt_tx_intr(sc, 0); 1501223927Sray} 1502223927Sray 1503292704Sadrian/* 1504292704Sadrian * rt_rt5350_intr - main ISR for Ralink 5350 SoC 1505292704Sadrian */ 1506223927Sraystatic void 1507292704Sadrianrt_rt5350_intr(void *arg) 1508292704Sadrian{ 1509292704Sadrian struct rt_softc *sc; 1510292704Sadrian struct ifnet *ifp; 1511292704Sadrian uint32_t status; 1512292704Sadrian 1513292704Sadrian sc = arg; 1514292704Sadrian ifp = sc->ifp; 1515292704Sadrian 1516292704Sadrian /* acknowledge interrupts */ 1517292704Sadrian status = RT_READ(sc, sc->fe_int_status); 1518292704Sadrian RT_WRITE(sc, sc->fe_int_status, status); 1519292704Sadrian 1520292704Sadrian RT_DPRINTF(sc, RT_DEBUG_INTR, "interrupt: status=0x%08x\n", status); 1521292704Sadrian 1522292704Sadrian if (status == 0xffffffff || /* device likely went away */ 1523292704Sadrian status == 0) /* not for us */ 1524292704Sadrian return; 1525292704Sadrian 1526292704Sadrian sc->interrupts++; 1527292704Sadrian 1528292704Sadrian if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1529292704Sadrian return; 1530292704Sadrian 1531292704Sadrian if (status & RT5350_INT_TX_COHERENT) 1532292704Sadrian rt_tx_coherent_intr(sc); 1533292704Sadrian if (status & RT5350_INT_RX_COHERENT) 1534292704Sadrian rt_rx_coherent_intr(sc); 1535292704Sadrian if (status & RT5350_RX_DLY_INT) 1536292704Sadrian rt_rx_delay_intr(sc); 1537292704Sadrian if (status & RT5350_TX_DLY_INT) 1538292704Sadrian rt_tx_delay_intr(sc); 1539292704Sadrian if (status & RT5350_INT_RXQ1_DONE) 1540292704Sadrian rt_rx_intr(sc, 1); 1541292704Sadrian if (status & RT5350_INT_RXQ0_DONE) 1542292704Sadrian rt_rx_intr(sc, 0); 1543292704Sadrian if (status & RT5350_INT_TXQ3_DONE) 1544292704Sadrian rt_tx_intr(sc, 3); 1545292704Sadrian if (status & RT5350_INT_TXQ2_DONE) 1546292704Sadrian rt_tx_intr(sc, 2); 1547292704Sadrian if (status & RT5350_INT_TXQ1_DONE) 1548292704Sadrian rt_tx_intr(sc, 1); 1549292704Sadrian if (status & RT5350_INT_TXQ0_DONE) 1550292704Sadrian rt_tx_intr(sc, 0); 1551292704Sadrian} 1552292704Sadrian 1553292704Sadrianstatic void 1554223927Srayrt_tx_coherent_intr(struct rt_softc *sc) 1555223927Sray{ 1556223927Sray uint32_t tmp; 1557223927Sray int i; 1558223927Sray 1559223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, "Tx coherent interrupt\n"); 1560223927Sray 1561223927Sray sc->tx_coherent_interrupts++; 1562223927Sray 1563223927Sray /* restart DMA engine */ 1564292704Sadrian tmp = RT_READ(sc, sc->pdma_glo_cfg); 1565223927Sray tmp &= ~(FE_TX_WB_DDONE | FE_TX_DMA_EN); 1566292704Sadrian RT_WRITE(sc, sc->pdma_glo_cfg, tmp); 1567223927Sray 1568223927Sray for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) 1569223927Sray rt_reset_tx_ring(sc, &sc->tx_ring[i]); 1570223927Sray 1571223927Sray for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) { 1572292704Sadrian RT_WRITE(sc, sc->tx_base_ptr[i], 1573223927Sray sc->tx_ring[i].desc_phys_addr); 1574292704Sadrian RT_WRITE(sc, sc->tx_max_cnt[i], 1575223927Sray RT_SOFTC_TX_RING_DESC_COUNT); 1576292704Sadrian RT_WRITE(sc, sc->tx_ctx_idx[i], 0); 1577223927Sray } 1578223927Sray 1579223927Sray rt_txrx_enable(sc); 1580223927Sray} 1581223927Sray 1582223927Sray/* 1583223927Sray * rt_rx_coherent_intr 1584223927Sray */ 1585223927Sraystatic void 1586223927Srayrt_rx_coherent_intr(struct rt_softc *sc) 1587223927Sray{ 1588223927Sray uint32_t tmp; 1589292704Sadrian int i; 1590223927Sray 1591223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, "Rx coherent interrupt\n"); 1592223927Sray 1593223927Sray sc->rx_coherent_interrupts++; 1594223927Sray 1595223927Sray /* restart DMA engine */ 1596292704Sadrian tmp = RT_READ(sc, sc->pdma_glo_cfg); 1597223927Sray tmp &= ~(FE_RX_DMA_EN); 1598292704Sadrian RT_WRITE(sc, sc->pdma_glo_cfg, tmp); 1599223927Sray 1600223927Sray /* init Rx ring */ 1601292704Sadrian for (i = 0; i < sc->rx_ring_count; i++) 1602292704Sadrian rt_reset_rx_ring(sc, &sc->rx_ring[i]); 1603223927Sray 1604292704Sadrian for (i = 0; i < sc->rx_ring_count; i++) { 1605292704Sadrian RT_WRITE(sc, sc->rx_base_ptr[i], 1606292704Sadrian sc->rx_ring[i].desc_phys_addr); 1607292704Sadrian RT_WRITE(sc, sc->rx_max_cnt[i], 1608292704Sadrian RT_SOFTC_RX_RING_DATA_COUNT); 1609292704Sadrian RT_WRITE(sc, sc->rx_calc_idx[i], 1610292704Sadrian RT_SOFTC_RX_RING_DATA_COUNT - 1); 1611292704Sadrian } 1612292704Sadrian 1613223927Sray rt_txrx_enable(sc); 1614223927Sray} 1615223927Sray 1616223927Sray/* 1617223927Sray * rt_rx_intr - a packet received 1618223927Sray */ 1619223927Sraystatic void 1620292704Sadrianrt_rx_intr(struct rt_softc *sc, int qid) 1621223927Sray{ 1622292704Sadrian KASSERT(qid >= 0 && qid < sc->rx_ring_count, 1623292704Sadrian ("%s: Rx interrupt: invalid qid=%d\n", 1624292704Sadrian device_get_nameunit(sc->dev), qid)); 1625223927Sray 1626223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, "Rx interrupt\n"); 1627292704Sadrian sc->rx_interrupts[qid]++; 1628223927Sray RT_SOFTC_LOCK(sc); 1629223927Sray 1630292704Sadrian if (!(sc->intr_disable_mask & (sc->int_rx_done_mask << qid))) { 1631292704Sadrian rt_intr_disable(sc, (sc->int_rx_done_mask << qid)); 1632223927Sray taskqueue_enqueue(sc->taskqueue, &sc->rx_done_task); 1633223927Sray } 1634223927Sray 1635292704Sadrian sc->intr_pending_mask |= (sc->int_rx_done_mask << qid); 1636223927Sray RT_SOFTC_UNLOCK(sc); 1637223927Sray} 1638223927Sray 1639223927Sraystatic void 1640223927Srayrt_rx_delay_intr(struct rt_softc *sc) 1641223927Sray{ 1642223927Sray 1643223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, "Rx delay interrupt\n"); 1644223927Sray sc->rx_delay_interrupts++; 1645223927Sray} 1646223927Sray 1647223927Sraystatic void 1648223927Srayrt_tx_delay_intr(struct rt_softc *sc) 1649223927Sray{ 1650223927Sray 1651223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, "Tx delay interrupt\n"); 1652223927Sray sc->tx_delay_interrupts++; 1653223927Sray} 1654223927Sray 1655223927Sray/* 1656223927Sray * rt_tx_intr - Transsmition of packet done 1657223927Sray */ 1658223927Sraystatic void 1659223927Srayrt_tx_intr(struct rt_softc *sc, int qid) 1660223927Sray{ 1661223927Sray 1662223927Sray KASSERT(qid >= 0 && qid < RT_SOFTC_TX_RING_COUNT, 1663223927Sray ("%s: Tx interrupt: invalid qid=%d\n", 1664223927Sray device_get_nameunit(sc->dev), qid)); 1665223927Sray 1666223927Sray RT_DPRINTF(sc, RT_DEBUG_INTR, "Tx interrupt: qid=%d\n", qid); 1667223927Sray 1668223927Sray sc->tx_interrupts[qid]++; 1669223927Sray RT_SOFTC_LOCK(sc); 1670223927Sray 1671292704Sadrian if (!(sc->intr_disable_mask & (sc->int_tx_done_mask << qid))) { 1672292704Sadrian rt_intr_disable(sc, (sc->int_tx_done_mask << qid)); 1673223927Sray taskqueue_enqueue(sc->taskqueue, &sc->tx_done_task); 1674223927Sray } 1675223927Sray 1676292704Sadrian sc->intr_pending_mask |= (sc->int_tx_done_mask << qid); 1677223927Sray RT_SOFTC_UNLOCK(sc); 1678223927Sray} 1679223927Sray 1680223927Sray/* 1681223927Sray * rt_rx_done_task - run RX task 1682223927Sray */ 1683223927Sraystatic void 1684223927Srayrt_rx_done_task(void *context, int pending) 1685223927Sray{ 1686223927Sray struct rt_softc *sc; 1687223927Sray struct ifnet *ifp; 1688223927Sray int again; 1689223927Sray 1690223927Sray sc = context; 1691223927Sray ifp = sc->ifp; 1692223927Sray 1693223927Sray RT_DPRINTF(sc, RT_DEBUG_RX, "Rx done task\n"); 1694223927Sray 1695223927Sray if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1696223927Sray return; 1697223927Sray 1698292704Sadrian sc->intr_pending_mask &= ~sc->int_rx_done_mask; 1699223927Sray 1700292704Sadrian again = rt_rx_eof(sc, &sc->rx_ring[0], sc->rx_process_limit); 1701223927Sray 1702223927Sray RT_SOFTC_LOCK(sc); 1703223927Sray 1704292704Sadrian if ((sc->intr_pending_mask & sc->int_rx_done_mask) || again) { 1705223927Sray RT_DPRINTF(sc, RT_DEBUG_RX, 1706223927Sray "Rx done task: scheduling again\n"); 1707223927Sray taskqueue_enqueue(sc->taskqueue, &sc->rx_done_task); 1708223927Sray } else { 1709292704Sadrian rt_intr_enable(sc, sc->int_rx_done_mask); 1710223927Sray } 1711223927Sray 1712223927Sray RT_SOFTC_UNLOCK(sc); 1713223927Sray} 1714223927Sray 1715223927Sray/* 1716223927Sray * rt_tx_done_task - check for pending TX task in all queues 1717223927Sray */ 1718223927Sraystatic void 1719223927Srayrt_tx_done_task(void *context, int pending) 1720223927Sray{ 1721223927Sray struct rt_softc *sc; 1722223927Sray struct ifnet *ifp; 1723223927Sray uint32_t intr_mask; 1724223927Sray int i; 1725223927Sray 1726223927Sray sc = context; 1727223927Sray ifp = sc->ifp; 1728223927Sray 1729223927Sray RT_DPRINTF(sc, RT_DEBUG_TX, "Tx done task\n"); 1730223927Sray 1731223927Sray if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1732223927Sray return; 1733223927Sray 1734223927Sray for (i = RT_SOFTC_TX_RING_COUNT - 1; i >= 0; i--) { 1735292704Sadrian if (sc->intr_pending_mask & (sc->int_tx_done_mask << i)) { 1736292704Sadrian sc->intr_pending_mask &= ~(sc->int_tx_done_mask << i); 1737223927Sray rt_tx_eof(sc, &sc->tx_ring[i]); 1738223927Sray } 1739223927Sray } 1740223927Sray 1741223927Sray sc->tx_timer = 0; 1742223927Sray 1743223927Sray ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1744223927Sray 1745292704Sadrian if(sc->rt_chipid == RT_CHIPID_RT5350 || 1746297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7620 || 1747297646Ssgalabov sc->rt_chipid == RT_CHIPID_MT7621) 1748292704Sadrian intr_mask = ( 1749292704Sadrian RT5350_INT_TXQ3_DONE | 1750292704Sadrian RT5350_INT_TXQ2_DONE | 1751292704Sadrian RT5350_INT_TXQ1_DONE | 1752292704Sadrian RT5350_INT_TXQ0_DONE); 1753292704Sadrian else 1754292704Sadrian intr_mask = ( 1755223927Sray INT_TXQ3_DONE | 1756223927Sray INT_TXQ2_DONE | 1757223927Sray INT_TXQ1_DONE | 1758223927Sray INT_TXQ0_DONE); 1759223927Sray 1760223927Sray RT_SOFTC_LOCK(sc); 1761223927Sray 1762223927Sray rt_intr_enable(sc, ~sc->intr_pending_mask & 1763223927Sray (sc->intr_disable_mask & intr_mask)); 1764223927Sray 1765223927Sray if (sc->intr_pending_mask & intr_mask) { 1766223927Sray RT_DPRINTF(sc, RT_DEBUG_TX, 1767223927Sray "Tx done task: scheduling again\n"); 1768223927Sray taskqueue_enqueue(sc->taskqueue, &sc->tx_done_task); 1769223927Sray } 1770223927Sray 1771223927Sray RT_SOFTC_UNLOCK(sc); 1772223927Sray 1773223927Sray if (!IFQ_IS_EMPTY(&ifp->if_snd)) 1774223927Sray rt_start(ifp); 1775223927Sray} 1776223927Sray 1777223927Sray/* 1778223927Sray * rt_periodic_task - run periodic task 1779223927Sray */ 1780223927Sraystatic void 1781223927Srayrt_periodic_task(void *context, int pending) 1782223927Sray{ 1783223927Sray struct rt_softc *sc; 1784223927Sray struct ifnet *ifp; 1785223927Sray 1786223927Sray sc = context; 1787223927Sray ifp = sc->ifp; 1788223927Sray 1789223927Sray RT_DPRINTF(sc, RT_DEBUG_PERIODIC, "periodic task: round=%lu\n", 1790223927Sray sc->periodic_round); 1791223927Sray 1792223927Sray if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1793223927Sray return; 1794223927Sray 1795223927Sray RT_SOFTC_LOCK(sc); 1796223927Sray sc->periodic_round++; 1797223927Sray rt_update_stats(sc); 1798223927Sray 1799223927Sray if ((sc->periodic_round % 10) == 0) { 1800223927Sray rt_update_raw_counters(sc); 1801223927Sray rt_watchdog(sc); 1802223927Sray } 1803223927Sray 1804223927Sray RT_SOFTC_UNLOCK(sc); 1805223927Sray callout_reset(&sc->periodic_ch, hz / 10, rt_periodic, sc); 1806223927Sray} 1807223927Sray 1808223927Sray/* 1809223927Sray * rt_rx_eof - check for frames that done by DMA engine and pass it into 1810223927Sray * network subsystem. 1811223927Sray */ 1812223927Sraystatic int 1813292704Sadrianrt_rx_eof(struct rt_softc *sc, struct rt_softc_rx_ring *ring, int limit) 1814223927Sray{ 1815223927Sray struct ifnet *ifp; 1816292704Sadrian/* struct rt_softc_rx_ring *ring; */ 1817223927Sray struct rt_rxdesc *desc; 1818223927Sray struct rt_softc_rx_data *data; 1819223927Sray struct mbuf *m, *mnew; 1820223927Sray bus_dma_segment_t segs[1]; 1821223927Sray bus_dmamap_t dma_map; 1822223927Sray uint32_t index, desc_flags; 1823223927Sray int error, nsegs, len, nframes; 1824223927Sray 1825223927Sray ifp = sc->ifp; 1826292704Sadrian/* ring = &sc->rx_ring[0]; */ 1827223927Sray 1828223927Sray nframes = 0; 1829223927Sray 1830223927Sray while (limit != 0) { 1831292704Sadrian index = RT_READ(sc, sc->rx_drx_idx[0]); 1832223927Sray if (ring->cur == index) 1833223927Sray break; 1834223927Sray 1835223927Sray desc = &ring->desc[ring->cur]; 1836223927Sray data = &ring->data[ring->cur]; 1837223927Sray 1838223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 1839223927Sray BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1840223927Sray 1841223927Sray#ifdef IF_RT_DEBUG 1842223927Sray if ( sc->debug & RT_DEBUG_RX ) { 1843223927Sray printf("\nRX Descriptor[%#08x] dump:\n", (u_int)desc); 1844223927Sray hexdump(desc, 16, 0, 0); 1845223927Sray printf("-----------------------------------\n"); 1846223927Sray } 1847223927Sray#endif 1848223927Sray 1849223927Sray /* XXX Sometime device don`t set DDONE bit */ 1850223927Sray#ifdef DDONE_FIXED 1851223927Sray if (!(desc->sdl0 & htole16(RT_RXDESC_SDL0_DDONE))) { 1852223927Sray RT_DPRINTF(sc, RT_DEBUG_RX, "DDONE=0, try next\n"); 1853223927Sray break; 1854223927Sray } 1855223927Sray#endif 1856223927Sray 1857223927Sray len = le16toh(desc->sdl0) & 0x3fff; 1858223927Sray RT_DPRINTF(sc, RT_DEBUG_RX, "new frame len=%d\n", len); 1859223927Sray 1860223927Sray nframes++; 1861223927Sray 1862243857Sglebius mnew = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 1863223927Sray MJUMPAGESIZE); 1864223927Sray if (mnew == NULL) { 1865223927Sray sc->rx_mbuf_alloc_errors++; 1866271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1867223927Sray goto skip; 1868223927Sray } 1869223927Sray 1870223927Sray mnew->m_len = mnew->m_pkthdr.len = MJUMPAGESIZE; 1871223927Sray 1872223927Sray error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, 1873223927Sray ring->spare_dma_map, mnew, segs, &nsegs, BUS_DMA_NOWAIT); 1874223927Sray if (error != 0) { 1875223927Sray RT_DPRINTF(sc, RT_DEBUG_RX, 1876223927Sray "could not load Rx mbuf DMA map: " 1877223927Sray "error=%d, nsegs=%d\n", 1878223927Sray error, nsegs); 1879223927Sray 1880223927Sray m_freem(mnew); 1881223927Sray 1882223927Sray sc->rx_mbuf_dmamap_errors++; 1883271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1884223927Sray 1885223927Sray goto skip; 1886223927Sray } 1887223927Sray 1888223927Sray KASSERT(nsegs == 1, ("%s: too many DMA segments", 1889223927Sray device_get_nameunit(sc->dev))); 1890223927Sray 1891223927Sray bus_dmamap_sync(ring->data_dma_tag, data->dma_map, 1892223927Sray BUS_DMASYNC_POSTREAD); 1893223927Sray bus_dmamap_unload(ring->data_dma_tag, data->dma_map); 1894223927Sray 1895223927Sray dma_map = data->dma_map; 1896223927Sray data->dma_map = ring->spare_dma_map; 1897223927Sray ring->spare_dma_map = dma_map; 1898223927Sray 1899223927Sray bus_dmamap_sync(ring->data_dma_tag, data->dma_map, 1900223927Sray BUS_DMASYNC_PREREAD); 1901223927Sray 1902223927Sray m = data->m; 1903297646Ssgalabov desc_flags = desc->word3; 1904223927Sray 1905223927Sray data->m = mnew; 1906223927Sray /* Add 2 for proper align of RX IP header */ 1907223927Sray desc->sdp0 = htole32(segs[0].ds_addr+2); 1908223927Sray desc->sdl0 = htole32(segs[0].ds_len-2); 1909297646Ssgalabov desc->word3 = 0; 1910223927Sray 1911223927Sray RT_DPRINTF(sc, RT_DEBUG_RX, 1912223927Sray "Rx frame: rxdesc flags=0x%08x\n", desc_flags); 1913223927Sray 1914223927Sray m->m_pkthdr.rcvif = ifp; 1915223927Sray /* Add 2 to fix data align, after sdp0 = addr + 2 */ 1916223927Sray m->m_data += 2; 1917223927Sray m->m_pkthdr.len = m->m_len = len; 1918223927Sray 1919223927Sray /* check for crc errors */ 1920223927Sray if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 1921223927Sray /*check for valid checksum*/ 1922297646Ssgalabov if (desc_flags & (sc->csum_fail_ip|sc->csum_fail_l4)) { 1923223927Sray RT_DPRINTF(sc, RT_DEBUG_RX, 1924223927Sray "rxdesc: crc error\n"); 1925223927Sray 1926271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1927223927Sray 1928223927Sray if (!(ifp->if_flags & IFF_PROMISC)) { 1929223927Sray m_freem(m); 1930223927Sray goto skip; 1931223927Sray } 1932223927Sray } 1933297646Ssgalabov if ((desc_flags & sc->csum_fail_ip) == 0) { 1934223927Sray m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 1935223927Sray m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1936223927Sray m->m_pkthdr.csum_data = 0xffff; 1937223927Sray } 1938223927Sray m->m_flags &= ~M_HASFCS; 1939223927Sray } 1940223927Sray 1941223927Sray (*ifp->if_input)(ifp, m); 1942223927Srayskip: 1943223927Sray desc->sdl0 &= ~htole16(RT_RXDESC_SDL0_DDONE); 1944223927Sray 1945223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 1946223927Sray BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1947223927Sray 1948223927Sray ring->cur = (ring->cur + 1) % RT_SOFTC_RX_RING_DATA_COUNT; 1949223927Sray 1950223927Sray limit--; 1951223927Sray } 1952223927Sray 1953223927Sray if (ring->cur == 0) 1954292704Sadrian RT_WRITE(sc, sc->rx_calc_idx[0], 1955223927Sray RT_SOFTC_RX_RING_DATA_COUNT - 1); 1956223927Sray else 1957292704Sadrian RT_WRITE(sc, sc->rx_calc_idx[0], 1958223927Sray ring->cur - 1); 1959223927Sray 1960223927Sray RT_DPRINTF(sc, RT_DEBUG_RX, "Rx eof: nframes=%d\n", nframes); 1961223927Sray 1962223927Sray sc->rx_packets += nframes; 1963223927Sray 1964223927Sray return (limit == 0); 1965223927Sray} 1966223927Sray 1967223927Sray/* 1968223927Sray * rt_tx_eof - check for successful transmitted frames and mark their 1969223927Sray * descriptor as free. 1970223927Sray */ 1971223927Sraystatic void 1972223927Srayrt_tx_eof(struct rt_softc *sc, struct rt_softc_tx_ring *ring) 1973223927Sray{ 1974223927Sray struct ifnet *ifp; 1975223927Sray struct rt_txdesc *desc; 1976223927Sray struct rt_softc_tx_data *data; 1977223927Sray uint32_t index; 1978223927Sray int ndescs, nframes; 1979223927Sray 1980223927Sray ifp = sc->ifp; 1981223927Sray 1982223927Sray ndescs = 0; 1983223927Sray nframes = 0; 1984223927Sray 1985223927Sray for (;;) { 1986292704Sadrian index = RT_READ(sc, sc->tx_dtx_idx[ring->qid]); 1987223927Sray if (ring->desc_next == index) 1988223927Sray break; 1989223927Sray 1990223927Sray ndescs++; 1991223927Sray 1992223927Sray desc = &ring->desc[ring->desc_next]; 1993223927Sray 1994223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 1995223927Sray BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1996223927Sray 1997223927Sray if (desc->sdl0 & htole16(RT_TXDESC_SDL0_LASTSEG) || 1998223927Sray desc->sdl1 & htole16(RT_TXDESC_SDL1_LASTSEG)) { 1999223927Sray nframes++; 2000223927Sray 2001223927Sray data = &ring->data[ring->data_next]; 2002223927Sray 2003223927Sray bus_dmamap_sync(ring->data_dma_tag, data->dma_map, 2004223927Sray BUS_DMASYNC_POSTWRITE); 2005223927Sray bus_dmamap_unload(ring->data_dma_tag, data->dma_map); 2006223927Sray 2007223927Sray m_freem(data->m); 2008223927Sray 2009223927Sray data->m = NULL; 2010223927Sray 2011271849Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 2012223927Sray 2013223927Sray RT_SOFTC_TX_RING_LOCK(ring); 2014223927Sray ring->data_queued--; 2015223927Sray ring->data_next = (ring->data_next + 1) % 2016223927Sray RT_SOFTC_TX_RING_DATA_COUNT; 2017223927Sray RT_SOFTC_TX_RING_UNLOCK(ring); 2018223927Sray } 2019223927Sray 2020223927Sray desc->sdl0 &= ~htole16(RT_TXDESC_SDL0_DDONE); 2021223927Sray 2022223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 2023223927Sray BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2024223927Sray 2025223927Sray RT_SOFTC_TX_RING_LOCK(ring); 2026223927Sray ring->desc_queued--; 2027223927Sray ring->desc_next = (ring->desc_next + 1) % 2028223927Sray RT_SOFTC_TX_RING_DESC_COUNT; 2029223927Sray RT_SOFTC_TX_RING_UNLOCK(ring); 2030223927Sray } 2031223927Sray 2032223927Sray RT_DPRINTF(sc, RT_DEBUG_TX, 2033223927Sray "Tx eof: qid=%d, ndescs=%d, nframes=%d\n", ring->qid, ndescs, 2034223927Sray nframes); 2035223927Sray} 2036223927Sray 2037223927Sray/* 2038223927Sray * rt_update_stats - query statistics counters and update related variables. 2039223927Sray */ 2040223927Sraystatic void 2041223927Srayrt_update_stats(struct rt_softc *sc) 2042223927Sray{ 2043223927Sray struct ifnet *ifp; 2044223927Sray 2045223927Sray ifp = sc->ifp; 2046223927Sray RT_DPRINTF(sc, RT_DEBUG_STATS, "update statistic: \n"); 2047223927Sray /* XXX do update stats here */ 2048223927Sray} 2049223927Sray 2050223927Sray/* 2051223927Sray * rt_watchdog - reinit device on watchdog event. 2052223927Sray */ 2053223927Sraystatic void 2054223927Srayrt_watchdog(struct rt_softc *sc) 2055223927Sray{ 2056223927Sray uint32_t tmp; 2057223927Sray#ifdef notyet 2058223927Sray int ntries; 2059223927Sray#endif 2060292704Sadrian if(sc->rt_chipid != RT_CHIPID_RT5350 && 2061297646Ssgalabov sc->rt_chipid != RT_CHIPID_MT7620 && 2062297646Ssgalabov sc->rt_chipid != RT_CHIPID_MT7621) { 2063292704Sadrian tmp = RT_READ(sc, PSE_BASE + CDMA_OQ_STA); 2064223927Sray 2065292704Sadrian RT_DPRINTF(sc, RT_DEBUG_WATCHDOG, 2066292704Sadrian "watchdog: PSE_IQ_STA=0x%08x\n", tmp); 2067292704Sadrian } 2068223927Sray /* XXX: do not reset */ 2069223927Sray#ifdef notyet 2070223927Sray if (((tmp >> P0_IQ_PCNT_SHIFT) & 0xff) != 0) { 2071223927Sray sc->tx_queue_not_empty[0]++; 2072223927Sray 2073223927Sray for (ntries = 0; ntries < 10; ntries++) { 2074223927Sray tmp = RT_READ(sc, PSE_BASE + PSE_IQ_STA); 2075223927Sray if (((tmp >> P0_IQ_PCNT_SHIFT) & 0xff) == 0) 2076223927Sray break; 2077223927Sray 2078223927Sray DELAY(1); 2079223927Sray } 2080223927Sray } 2081223927Sray 2082223927Sray if (((tmp >> P1_IQ_PCNT_SHIFT) & 0xff) != 0) { 2083223927Sray sc->tx_queue_not_empty[1]++; 2084223927Sray 2085223927Sray for (ntries = 0; ntries < 10; ntries++) { 2086223927Sray tmp = RT_READ(sc, PSE_BASE + PSE_IQ_STA); 2087223927Sray if (((tmp >> P1_IQ_PCNT_SHIFT) & 0xff) == 0) 2088223927Sray break; 2089223927Sray 2090223927Sray DELAY(1); 2091223927Sray } 2092223927Sray } 2093223927Sray#endif 2094223927Sray} 2095223927Sray 2096223927Sray/* 2097223927Sray * rt_update_raw_counters - update counters. 2098223927Sray */ 2099223927Sraystatic void 2100223927Srayrt_update_raw_counters(struct rt_softc *sc) 2101223927Sray{ 2102223927Sray 2103223927Sray sc->tx_bytes += RT_READ(sc, CNTR_BASE + GDMA_TX_GBCNT0); 2104223927Sray sc->tx_packets += RT_READ(sc, CNTR_BASE + GDMA_TX_GPCNT0); 2105223927Sray sc->tx_skip += RT_READ(sc, CNTR_BASE + GDMA_TX_SKIPCNT0); 2106223927Sray sc->tx_collision+= RT_READ(sc, CNTR_BASE + GDMA_TX_COLCNT0); 2107223927Sray 2108223927Sray sc->rx_bytes += RT_READ(sc, CNTR_BASE + GDMA_RX_GBCNT0); 2109223927Sray sc->rx_packets += RT_READ(sc, CNTR_BASE + GDMA_RX_GPCNT0); 2110223927Sray sc->rx_crc_err += RT_READ(sc, CNTR_BASE + GDMA_RX_CSUM_ERCNT0); 2111223927Sray sc->rx_short_err+= RT_READ(sc, CNTR_BASE + GDMA_RX_SHORT_ERCNT0); 2112223927Sray sc->rx_long_err += RT_READ(sc, CNTR_BASE + GDMA_RX_LONG_ERCNT0); 2113223927Sray sc->rx_phy_err += RT_READ(sc, CNTR_BASE + GDMA_RX_FERCNT0); 2114223927Sray sc->rx_fifo_overflows+= RT_READ(sc, CNTR_BASE + GDMA_RX_OERCNT0); 2115223927Sray} 2116223927Sray 2117223927Sraystatic void 2118223927Srayrt_intr_enable(struct rt_softc *sc, uint32_t intr_mask) 2119223927Sray{ 2120223927Sray uint32_t tmp; 2121223927Sray 2122223927Sray sc->intr_disable_mask &= ~intr_mask; 2123223927Sray tmp = sc->intr_enable_mask & ~sc->intr_disable_mask; 2124292704Sadrian RT_WRITE(sc, sc->fe_int_enable, tmp); 2125223927Sray} 2126223927Sray 2127223927Sraystatic void 2128223927Srayrt_intr_disable(struct rt_softc *sc, uint32_t intr_mask) 2129223927Sray{ 2130223927Sray uint32_t tmp; 2131223927Sray 2132223927Sray sc->intr_disable_mask |= intr_mask; 2133223927Sray tmp = sc->intr_enable_mask & ~sc->intr_disable_mask; 2134292704Sadrian RT_WRITE(sc, sc->fe_int_enable, tmp); 2135223927Sray} 2136223927Sray 2137223927Sray/* 2138223927Sray * rt_txrx_enable - enable TX/RX DMA 2139223927Sray */ 2140223927Sraystatic int 2141223927Srayrt_txrx_enable(struct rt_softc *sc) 2142223927Sray{ 2143223927Sray struct ifnet *ifp; 2144223927Sray uint32_t tmp; 2145223927Sray int ntries; 2146223927Sray 2147223927Sray ifp = sc->ifp; 2148223927Sray 2149223927Sray /* enable Tx/Rx DMA engine */ 2150223927Sray for (ntries = 0; ntries < 200; ntries++) { 2151292704Sadrian tmp = RT_READ(sc, sc->pdma_glo_cfg); 2152223927Sray if (!(tmp & (FE_TX_DMA_BUSY | FE_RX_DMA_BUSY))) 2153223927Sray break; 2154223927Sray 2155223927Sray DELAY(1000); 2156223927Sray } 2157223927Sray 2158223927Sray if (ntries == 200) { 2159223927Sray device_printf(sc->dev, "timeout waiting for DMA engine\n"); 2160223927Sray return (-1); 2161223927Sray } 2162223927Sray 2163223927Sray DELAY(50); 2164223927Sray 2165223927Sray tmp |= FE_TX_WB_DDONE | FE_RX_DMA_EN | FE_TX_DMA_EN; 2166292704Sadrian RT_WRITE(sc, sc->pdma_glo_cfg, tmp); 2167223927Sray 2168223927Sray /* XXX set Rx filter */ 2169223927Sray return (0); 2170223927Sray} 2171223927Sray 2172223927Sray/* 2173223927Sray * rt_alloc_rx_ring - allocate RX DMA ring buffer 2174223927Sray */ 2175223927Sraystatic int 2176292704Sadrianrt_alloc_rx_ring(struct rt_softc *sc, struct rt_softc_rx_ring *ring, int qid) 2177223927Sray{ 2178223927Sray struct rt_rxdesc *desc; 2179223927Sray struct rt_softc_rx_data *data; 2180223927Sray bus_dma_segment_t segs[1]; 2181223927Sray int i, nsegs, error; 2182223927Sray 2183223927Sray error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0, 2184223927Sray BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2185223927Sray RT_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt_rxdesc), 1, 2186223927Sray RT_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt_rxdesc), 2187223927Sray 0, NULL, NULL, &ring->desc_dma_tag); 2188223927Sray if (error != 0) { 2189223927Sray device_printf(sc->dev, 2190223927Sray "could not create Rx desc DMA tag\n"); 2191223927Sray goto fail; 2192223927Sray } 2193223927Sray 2194223927Sray error = bus_dmamem_alloc(ring->desc_dma_tag, (void **) &ring->desc, 2195223927Sray BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_dma_map); 2196223927Sray if (error != 0) { 2197223927Sray device_printf(sc->dev, 2198223927Sray "could not allocate Rx desc DMA memory\n"); 2199223927Sray goto fail; 2200223927Sray } 2201223927Sray 2202223927Sray error = bus_dmamap_load(ring->desc_dma_tag, ring->desc_dma_map, 2203223927Sray ring->desc, 2204223927Sray RT_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt_rxdesc), 2205223927Sray rt_dma_map_addr, &ring->desc_phys_addr, 0); 2206223927Sray if (error != 0) { 2207223927Sray device_printf(sc->dev, "could not load Rx desc DMA map\n"); 2208223927Sray goto fail; 2209223927Sray } 2210223927Sray 2211223927Sray error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0, 2212223927Sray BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2213223927Sray MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL, 2214223927Sray &ring->data_dma_tag); 2215223927Sray if (error != 0) { 2216223927Sray device_printf(sc->dev, 2217223927Sray "could not create Rx data DMA tag\n"); 2218223927Sray goto fail; 2219223927Sray } 2220223927Sray 2221223927Sray for (i = 0; i < RT_SOFTC_RX_RING_DATA_COUNT; i++) { 2222223927Sray desc = &ring->desc[i]; 2223223927Sray data = &ring->data[i]; 2224223927Sray 2225223927Sray error = bus_dmamap_create(ring->data_dma_tag, 0, 2226223927Sray &data->dma_map); 2227223927Sray if (error != 0) { 2228223927Sray device_printf(sc->dev, "could not create Rx data DMA " 2229223927Sray "map\n"); 2230223927Sray goto fail; 2231223927Sray } 2232223927Sray 2233243857Sglebius data->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 2234223927Sray MJUMPAGESIZE); 2235223927Sray if (data->m == NULL) { 2236223927Sray device_printf(sc->dev, "could not allocate Rx mbuf\n"); 2237223927Sray error = ENOMEM; 2238223927Sray goto fail; 2239223927Sray } 2240223927Sray 2241223927Sray data->m->m_len = data->m->m_pkthdr.len = MJUMPAGESIZE; 2242223927Sray 2243223927Sray error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, 2244223927Sray data->dma_map, data->m, segs, &nsegs, BUS_DMA_NOWAIT); 2245223927Sray if (error != 0) { 2246223927Sray device_printf(sc->dev, 2247223927Sray "could not load Rx mbuf DMA map\n"); 2248223927Sray goto fail; 2249223927Sray } 2250223927Sray 2251223927Sray KASSERT(nsegs == 1, ("%s: too many DMA segments", 2252223927Sray device_get_nameunit(sc->dev))); 2253223927Sray 2254223927Sray /* Add 2 for proper align of RX IP header */ 2255223927Sray desc->sdp0 = htole32(segs[0].ds_addr+2); 2256223927Sray desc->sdl0 = htole32(segs[0].ds_len-2); 2257223927Sray } 2258223927Sray 2259223927Sray error = bus_dmamap_create(ring->data_dma_tag, 0, 2260223927Sray &ring->spare_dma_map); 2261223927Sray if (error != 0) { 2262223927Sray device_printf(sc->dev, 2263223927Sray "could not create Rx spare DMA map\n"); 2264223927Sray goto fail; 2265223927Sray } 2266223927Sray 2267223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 2268223927Sray BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2269292704Sadrian ring->qid = qid; 2270223927Sray return (0); 2271223927Sray 2272223927Srayfail: 2273223927Sray rt_free_rx_ring(sc, ring); 2274223927Sray return (error); 2275223927Sray} 2276223927Sray 2277223927Sray/* 2278223927Sray * rt_reset_rx_ring - reset RX ring buffer 2279223927Sray */ 2280223927Sraystatic void 2281223927Srayrt_reset_rx_ring(struct rt_softc *sc, struct rt_softc_rx_ring *ring) 2282223927Sray{ 2283223927Sray struct rt_rxdesc *desc; 2284223927Sray int i; 2285223927Sray 2286223927Sray for (i = 0; i < RT_SOFTC_RX_RING_DATA_COUNT; i++) { 2287223927Sray desc = &ring->desc[i]; 2288223927Sray desc->sdl0 &= ~htole16(RT_RXDESC_SDL0_DDONE); 2289223927Sray } 2290223927Sray 2291223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 2292223927Sray BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2293223927Sray ring->cur = 0; 2294223927Sray} 2295223927Sray 2296223927Sray/* 2297223927Sray * rt_free_rx_ring - free memory used by RX ring buffer 2298223927Sray */ 2299223927Sraystatic void 2300223927Srayrt_free_rx_ring(struct rt_softc *sc, struct rt_softc_rx_ring *ring) 2301223927Sray{ 2302223927Sray struct rt_softc_rx_data *data; 2303223927Sray int i; 2304223927Sray 2305223927Sray if (ring->desc != NULL) { 2306223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 2307223927Sray BUS_DMASYNC_POSTWRITE); 2308223927Sray bus_dmamap_unload(ring->desc_dma_tag, ring->desc_dma_map); 2309223927Sray bus_dmamem_free(ring->desc_dma_tag, ring->desc, 2310223927Sray ring->desc_dma_map); 2311223927Sray } 2312223927Sray 2313223927Sray if (ring->desc_dma_tag != NULL) 2314223927Sray bus_dma_tag_destroy(ring->desc_dma_tag); 2315223927Sray 2316223927Sray for (i = 0; i < RT_SOFTC_RX_RING_DATA_COUNT; i++) { 2317223927Sray data = &ring->data[i]; 2318223927Sray 2319223927Sray if (data->m != NULL) { 2320223927Sray bus_dmamap_sync(ring->data_dma_tag, data->dma_map, 2321223927Sray BUS_DMASYNC_POSTREAD); 2322223927Sray bus_dmamap_unload(ring->data_dma_tag, data->dma_map); 2323223927Sray m_freem(data->m); 2324223927Sray } 2325223927Sray 2326223927Sray if (data->dma_map != NULL) 2327223927Sray bus_dmamap_destroy(ring->data_dma_tag, data->dma_map); 2328223927Sray } 2329223927Sray 2330223927Sray if (ring->spare_dma_map != NULL) 2331223927Sray bus_dmamap_destroy(ring->data_dma_tag, ring->spare_dma_map); 2332223927Sray 2333223927Sray if (ring->data_dma_tag != NULL) 2334223927Sray bus_dma_tag_destroy(ring->data_dma_tag); 2335223927Sray} 2336223927Sray 2337223927Sray/* 2338223927Sray * rt_alloc_tx_ring - allocate TX ring buffer 2339223927Sray */ 2340223927Sraystatic int 2341223927Srayrt_alloc_tx_ring(struct rt_softc *sc, struct rt_softc_tx_ring *ring, int qid) 2342223927Sray{ 2343223927Sray struct rt_softc_tx_data *data; 2344223927Sray int error, i; 2345223927Sray 2346223927Sray mtx_init(&ring->lock, device_get_nameunit(sc->dev), NULL, MTX_DEF); 2347223927Sray 2348223927Sray error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0, 2349223927Sray BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2350223927Sray RT_SOFTC_TX_RING_DESC_COUNT * sizeof(struct rt_txdesc), 1, 2351223927Sray RT_SOFTC_TX_RING_DESC_COUNT * sizeof(struct rt_txdesc), 2352223927Sray 0, NULL, NULL, &ring->desc_dma_tag); 2353223927Sray if (error != 0) { 2354223927Sray device_printf(sc->dev, 2355223927Sray "could not create Tx desc DMA tag\n"); 2356223927Sray goto fail; 2357223927Sray } 2358223927Sray 2359223927Sray error = bus_dmamem_alloc(ring->desc_dma_tag, (void **) &ring->desc, 2360223927Sray BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_dma_map); 2361223927Sray if (error != 0) { 2362223927Sray device_printf(sc->dev, 2363223927Sray "could not allocate Tx desc DMA memory\n"); 2364223927Sray goto fail; 2365223927Sray } 2366223927Sray 2367223927Sray error = bus_dmamap_load(ring->desc_dma_tag, ring->desc_dma_map, 2368223927Sray ring->desc, (RT_SOFTC_TX_RING_DESC_COUNT * 2369223927Sray sizeof(struct rt_txdesc)), rt_dma_map_addr, 2370223927Sray &ring->desc_phys_addr, 0); 2371223927Sray if (error != 0) { 2372223927Sray device_printf(sc->dev, "could not load Tx desc DMA map\n"); 2373223927Sray goto fail; 2374223927Sray } 2375223927Sray 2376223927Sray ring->desc_queued = 0; 2377223927Sray ring->desc_cur = 0; 2378223927Sray ring->desc_next = 0; 2379223927Sray 2380223927Sray error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0, 2381223927Sray BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2382223927Sray RT_SOFTC_TX_RING_DATA_COUNT * RT_TX_DATA_SEG0_SIZE, 1, 2383223927Sray RT_SOFTC_TX_RING_DATA_COUNT * RT_TX_DATA_SEG0_SIZE, 2384223927Sray 0, NULL, NULL, &ring->seg0_dma_tag); 2385223927Sray if (error != 0) { 2386223927Sray device_printf(sc->dev, 2387223927Sray "could not create Tx seg0 DMA tag\n"); 2388223927Sray goto fail; 2389223927Sray } 2390223927Sray 2391223927Sray error = bus_dmamem_alloc(ring->seg0_dma_tag, (void **) &ring->seg0, 2392223927Sray BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->seg0_dma_map); 2393223927Sray if (error != 0) { 2394223927Sray device_printf(sc->dev, 2395223927Sray "could not allocate Tx seg0 DMA memory\n"); 2396223927Sray goto fail; 2397223927Sray } 2398223927Sray 2399223927Sray error = bus_dmamap_load(ring->seg0_dma_tag, ring->seg0_dma_map, 2400223927Sray ring->seg0, 2401223927Sray RT_SOFTC_TX_RING_DATA_COUNT * RT_TX_DATA_SEG0_SIZE, 2402223927Sray rt_dma_map_addr, &ring->seg0_phys_addr, 0); 2403223927Sray if (error != 0) { 2404223927Sray device_printf(sc->dev, "could not load Tx seg0 DMA map\n"); 2405223927Sray goto fail; 2406223927Sray } 2407223927Sray 2408223927Sray error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0, 2409223927Sray BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2410223927Sray MJUMPAGESIZE, RT_SOFTC_MAX_SCATTER, MJUMPAGESIZE, 0, NULL, NULL, 2411223927Sray &ring->data_dma_tag); 2412223927Sray if (error != 0) { 2413223927Sray device_printf(sc->dev, 2414223927Sray "could not create Tx data DMA tag\n"); 2415223927Sray goto fail; 2416223927Sray } 2417223927Sray 2418223927Sray for (i = 0; i < RT_SOFTC_TX_RING_DATA_COUNT; i++) { 2419223927Sray data = &ring->data[i]; 2420223927Sray 2421223927Sray error = bus_dmamap_create(ring->data_dma_tag, 0, 2422223927Sray &data->dma_map); 2423223927Sray if (error != 0) { 2424223927Sray device_printf(sc->dev, "could not create Tx data DMA " 2425223927Sray "map\n"); 2426223927Sray goto fail; 2427223927Sray } 2428223927Sray } 2429223927Sray 2430223927Sray ring->data_queued = 0; 2431223927Sray ring->data_cur = 0; 2432223927Sray ring->data_next = 0; 2433223927Sray 2434223927Sray ring->qid = qid; 2435223927Sray return (0); 2436223927Sray 2437223927Srayfail: 2438223927Sray rt_free_tx_ring(sc, ring); 2439223927Sray return (error); 2440223927Sray} 2441223927Sray 2442223927Sray/* 2443223927Sray * rt_reset_tx_ring - reset TX ring buffer to empty state 2444223927Sray */ 2445223927Sraystatic void 2446223927Srayrt_reset_tx_ring(struct rt_softc *sc, struct rt_softc_tx_ring *ring) 2447223927Sray{ 2448223927Sray struct rt_softc_tx_data *data; 2449223927Sray struct rt_txdesc *desc; 2450223927Sray int i; 2451223927Sray 2452223927Sray for (i = 0; i < RT_SOFTC_TX_RING_DESC_COUNT; i++) { 2453223927Sray desc = &ring->desc[i]; 2454223927Sray 2455223927Sray desc->sdl0 = 0; 2456223927Sray desc->sdl1 = 0; 2457223927Sray } 2458223927Sray 2459223927Sray ring->desc_queued = 0; 2460223927Sray ring->desc_cur = 0; 2461223927Sray ring->desc_next = 0; 2462223927Sray 2463223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 2464223927Sray BUS_DMASYNC_PREWRITE); 2465223927Sray 2466223927Sray bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map, 2467223927Sray BUS_DMASYNC_PREWRITE); 2468223927Sray 2469223927Sray for (i = 0; i < RT_SOFTC_TX_RING_DATA_COUNT; i++) { 2470223927Sray data = &ring->data[i]; 2471223927Sray 2472223927Sray if (data->m != NULL) { 2473223927Sray bus_dmamap_sync(ring->data_dma_tag, data->dma_map, 2474223927Sray BUS_DMASYNC_POSTWRITE); 2475223927Sray bus_dmamap_unload(ring->data_dma_tag, data->dma_map); 2476223927Sray m_freem(data->m); 2477223927Sray data->m = NULL; 2478223927Sray } 2479223927Sray } 2480223927Sray 2481223927Sray ring->data_queued = 0; 2482223927Sray ring->data_cur = 0; 2483223927Sray ring->data_next = 0; 2484223927Sray} 2485223927Sray 2486223927Sray/* 2487223927Sray * rt_free_tx_ring - free RX ring buffer 2488223927Sray */ 2489223927Sraystatic void 2490223927Srayrt_free_tx_ring(struct rt_softc *sc, struct rt_softc_tx_ring *ring) 2491223927Sray{ 2492223927Sray struct rt_softc_tx_data *data; 2493223927Sray int i; 2494223927Sray 2495223927Sray if (ring->desc != NULL) { 2496223927Sray bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, 2497223927Sray BUS_DMASYNC_POSTWRITE); 2498223927Sray bus_dmamap_unload(ring->desc_dma_tag, ring->desc_dma_map); 2499223927Sray bus_dmamem_free(ring->desc_dma_tag, ring->desc, 2500223927Sray ring->desc_dma_map); 2501223927Sray } 2502223927Sray 2503223927Sray if (ring->desc_dma_tag != NULL) 2504223927Sray bus_dma_tag_destroy(ring->desc_dma_tag); 2505223927Sray 2506223927Sray if (ring->seg0 != NULL) { 2507223927Sray bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map, 2508223927Sray BUS_DMASYNC_POSTWRITE); 2509223927Sray bus_dmamap_unload(ring->seg0_dma_tag, ring->seg0_dma_map); 2510223927Sray bus_dmamem_free(ring->seg0_dma_tag, ring->seg0, 2511223927Sray ring->seg0_dma_map); 2512223927Sray } 2513223927Sray 2514223927Sray if (ring->seg0_dma_tag != NULL) 2515223927Sray bus_dma_tag_destroy(ring->seg0_dma_tag); 2516223927Sray 2517223927Sray for (i = 0; i < RT_SOFTC_TX_RING_DATA_COUNT; i++) { 2518223927Sray data = &ring->data[i]; 2519223927Sray 2520223927Sray if (data->m != NULL) { 2521223927Sray bus_dmamap_sync(ring->data_dma_tag, data->dma_map, 2522223927Sray BUS_DMASYNC_POSTWRITE); 2523223927Sray bus_dmamap_unload(ring->data_dma_tag, data->dma_map); 2524223927Sray m_freem(data->m); 2525223927Sray } 2526223927Sray 2527223927Sray if (data->dma_map != NULL) 2528223927Sray bus_dmamap_destroy(ring->data_dma_tag, data->dma_map); 2529223927Sray } 2530223927Sray 2531223927Sray if (ring->data_dma_tag != NULL) 2532223927Sray bus_dma_tag_destroy(ring->data_dma_tag); 2533223927Sray 2534223927Sray mtx_destroy(&ring->lock); 2535223927Sray} 2536223927Sray 2537223927Sray/* 2538223927Sray * rt_dma_map_addr - get address of busdma segment 2539223927Sray */ 2540223927Sraystatic void 2541223927Srayrt_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2542223927Sray{ 2543223927Sray if (error != 0) 2544223927Sray return; 2545223927Sray 2546223927Sray KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 2547223927Sray 2548223927Sray *(bus_addr_t *) arg = segs[0].ds_addr; 2549223927Sray} 2550223927Sray 2551223927Sray/* 2552223927Sray * rt_sysctl_attach - attach sysctl nodes for NIC counters. 2553223927Sray */ 2554223927Sraystatic void 2555223927Srayrt_sysctl_attach(struct rt_softc *sc) 2556223927Sray{ 2557223927Sray struct sysctl_ctx_list *ctx; 2558223927Sray struct sysctl_oid *tree; 2559223927Sray struct sysctl_oid *stats; 2560223927Sray 2561223927Sray ctx = device_get_sysctl_ctx(sc->dev); 2562223927Sray tree = device_get_sysctl_tree(sc->dev); 2563223927Sray 2564223927Sray /* statistic counters */ 2565223927Sray stats = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 2566223927Sray "stats", CTLFLAG_RD, 0, "statistic"); 2567223927Sray 2568273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2569273377Shselasky "interrupts", CTLFLAG_RD, &sc->interrupts, 2570223927Sray "all interrupts"); 2571223927Sray 2572273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2573223927Sray "tx_coherent_interrupts", CTLFLAG_RD, &sc->tx_coherent_interrupts, 2574273377Shselasky "Tx coherent interrupts"); 2575223927Sray 2576273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2577223927Sray "rx_coherent_interrupts", CTLFLAG_RD, &sc->rx_coherent_interrupts, 2578273377Shselasky "Rx coherent interrupts"); 2579223927Sray 2580273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2581292704Sadrian "rx_interrupts", CTLFLAG_RD, &sc->rx_interrupts[0], 2582223927Sray "Rx interrupts"); 2583223927Sray 2584273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2585273377Shselasky "rx_delay_interrupts", CTLFLAG_RD, &sc->rx_delay_interrupts, 2586223927Sray "Rx delay interrupts"); 2587223927Sray 2588273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2589273377Shselasky "TXQ3_interrupts", CTLFLAG_RD, &sc->tx_interrupts[3], 2590223927Sray "Tx AC3 interrupts"); 2591223927Sray 2592273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2593273377Shselasky "TXQ2_interrupts", CTLFLAG_RD, &sc->tx_interrupts[2], 2594223927Sray "Tx AC2 interrupts"); 2595223927Sray 2596273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2597273377Shselasky "TXQ1_interrupts", CTLFLAG_RD, &sc->tx_interrupts[1], 2598223927Sray "Tx AC1 interrupts"); 2599223927Sray 2600273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2601273377Shselasky "TXQ0_interrupts", CTLFLAG_RD, &sc->tx_interrupts[0], 2602223927Sray "Tx AC0 interrupts"); 2603223927Sray 2604273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2605223927Sray "tx_delay_interrupts", CTLFLAG_RD, &sc->tx_delay_interrupts, 2606273377Shselasky "Tx delay interrupts"); 2607223927Sray 2608223927Sray SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2609223927Sray "TXQ3_desc_queued", CTLFLAG_RD, &sc->tx_ring[3].desc_queued, 2610223927Sray 0, "Tx AC3 descriptors queued"); 2611223927Sray 2612223927Sray SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2613223927Sray "TXQ3_data_queued", CTLFLAG_RD, &sc->tx_ring[3].data_queued, 2614223929Sray 0, "Tx AC3 data queued"); 2615223927Sray 2616223927Sray SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2617223927Sray "TXQ2_desc_queued", CTLFLAG_RD, &sc->tx_ring[2].desc_queued, 2618223927Sray 0, "Tx AC2 descriptors queued"); 2619223927Sray 2620223927Sray SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2621223927Sray "TXQ2_data_queued", CTLFLAG_RD, &sc->tx_ring[2].data_queued, 2622223927Sray 0, "Tx AC2 data queued"); 2623223927Sray 2624223927Sray SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2625223927Sray "TXQ1_desc_queued", CTLFLAG_RD, &sc->tx_ring[1].desc_queued, 2626223927Sray 0, "Tx AC1 descriptors queued"); 2627223927Sray 2628223927Sray SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2629223927Sray "TXQ1_data_queued", CTLFLAG_RD, &sc->tx_ring[1].data_queued, 2630223927Sray 0, "Tx AC1 data queued"); 2631223927Sray 2632223927Sray SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2633223927Sray "TXQ0_desc_queued", CTLFLAG_RD, &sc->tx_ring[0].desc_queued, 2634223927Sray 0, "Tx AC0 descriptors queued"); 2635223927Sray 2636223927Sray SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2637223927Sray "TXQ0_data_queued", CTLFLAG_RD, &sc->tx_ring[0].data_queued, 2638223927Sray 0, "Tx AC0 data queued"); 2639223927Sray 2640273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2641223927Sray "TXQ3_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[3], 2642273377Shselasky "Tx AC3 data queue full"); 2643223927Sray 2644273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2645223927Sray "TXQ2_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[2], 2646273377Shselasky "Tx AC2 data queue full"); 2647223927Sray 2648273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2649223927Sray "TXQ1_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[1], 2650273377Shselasky "Tx AC1 data queue full"); 2651223927Sray 2652273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2653223927Sray "TXQ0_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[0], 2654273377Shselasky "Tx AC0 data queue full"); 2655223927Sray 2656273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2657223927Sray "tx_watchdog_timeouts", CTLFLAG_RD, &sc->tx_watchdog_timeouts, 2658273377Shselasky "Tx watchdog timeouts"); 2659223927Sray 2660273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2661273377Shselasky "tx_defrag_packets", CTLFLAG_RD, &sc->tx_defrag_packets, 2662223927Sray "Tx defragmented packets"); 2663223927Sray 2664273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2665273377Shselasky "no_tx_desc_avail", CTLFLAG_RD, &sc->no_tx_desc_avail, 2666223927Sray "no Tx descriptors available"); 2667223927Sray 2668273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2669223927Sray "rx_mbuf_alloc_errors", CTLFLAG_RD, &sc->rx_mbuf_alloc_errors, 2670273377Shselasky "Rx mbuf allocation errors"); 2671223927Sray 2672273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2673223927Sray "rx_mbuf_dmamap_errors", CTLFLAG_RD, &sc->rx_mbuf_dmamap_errors, 2674273377Shselasky "Rx mbuf DMA mapping errors"); 2675223927Sray 2676273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2677223927Sray "tx_queue_0_not_empty", CTLFLAG_RD, &sc->tx_queue_not_empty[0], 2678273377Shselasky "Tx queue 0 not empty"); 2679223927Sray 2680273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2681223927Sray "tx_queue_1_not_empty", CTLFLAG_RD, &sc->tx_queue_not_empty[1], 2682273377Shselasky "Tx queue 1 not empty"); 2683223927Sray 2684273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2685273377Shselasky "rx_packets", CTLFLAG_RD, &sc->rx_packets, 2686223927Sray "Rx packets"); 2687223927Sray 2688273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2689273377Shselasky "rx_crc_errors", CTLFLAG_RD, &sc->rx_crc_err, 2690223927Sray "Rx CRC errors"); 2691223927Sray 2692273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2693273377Shselasky "rx_phy_errors", CTLFLAG_RD, &sc->rx_phy_err, 2694223927Sray "Rx PHY errors"); 2695223927Sray 2696273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2697273377Shselasky "rx_dup_packets", CTLFLAG_RD, &sc->rx_dup_packets, 2698223927Sray "Rx duplicate packets"); 2699223927Sray 2700273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2701273377Shselasky "rx_fifo_overflows", CTLFLAG_RD, &sc->rx_fifo_overflows, 2702223927Sray "Rx FIFO overflows"); 2703223927Sray 2704273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2705273377Shselasky "rx_bytes", CTLFLAG_RD, &sc->rx_bytes, 2706223927Sray "Rx bytes"); 2707223927Sray 2708273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2709273377Shselasky "rx_long_err", CTLFLAG_RD, &sc->rx_long_err, 2710223927Sray "Rx too long frame errors"); 2711223927Sray 2712273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2713273377Shselasky "rx_short_err", CTLFLAG_RD, &sc->rx_short_err, 2714223927Sray "Rx too short frame errors"); 2715223927Sray 2716273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2717273377Shselasky "tx_bytes", CTLFLAG_RD, &sc->tx_bytes, 2718223927Sray "Tx bytes"); 2719273377Shselasky 2720273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2721273377Shselasky "tx_packets", CTLFLAG_RD, &sc->tx_packets, 2722223927Sray "Tx packets"); 2723273377Shselasky 2724273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2725273377Shselasky "tx_skip", CTLFLAG_RD, &sc->tx_skip, 2726223927Sray "Tx skip count for GDMA ports"); 2727273377Shselasky 2728273377Shselasky SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, 2729273377Shselasky "tx_collision", CTLFLAG_RD, &sc->tx_collision, 2730223927Sray "Tx collision count for GDMA ports"); 2731223927Sray} 2732223927Sray 2733223927Sray#ifdef IF_RT_PHY_SUPPORT 2734223927Sraystatic int 2735223927Srayrt_miibus_readreg(device_t dev, int phy, int reg) 2736223927Sray{ 2737223927Sray struct rt_softc *sc = device_get_softc(dev); 2738223927Sray 2739223927Sray /* 2740223927Sray * PSEUDO_PHYAD is a special value for indicate switch attached. 2741223927Sray * No one PHY use PSEUDO_PHYAD (0x1e) address. 2742223927Sray */ 2743223927Sray if (phy == 31) { 2744223927Sray /* Fake PHY ID for bfeswitch attach */ 2745223927Sray switch (reg) { 2746223927Sray case MII_BMSR: 2747223927Sray return (BMSR_EXTSTAT|BMSR_MEDIAMASK); 2748223927Sray case MII_PHYIDR1: 2749223927Sray return (0x40); /* As result of faking */ 2750223927Sray case MII_PHYIDR2: /* PHY will detect as */ 2751223927Sray return (0x6250); /* bfeswitch */ 2752223927Sray } 2753223927Sray } 2754223927Sray 2755223927Sray /* Wait prev command done if any */ 2756223927Sray while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); 2757223927Sray RT_WRITE(sc, MDIO_ACCESS, 2758223927Sray MDIO_CMD_ONGO || 2759223927Sray ((phy << MDIO_PHY_ADDR_SHIFT) & MDIO_PHY_ADDR_MASK) || 2760223927Sray ((reg << MDIO_PHYREG_ADDR_SHIFT) & MDIO_PHYREG_ADDR_MASK)); 2761223927Sray while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); 2762223927Sray 2763223927Sray return (RT_READ(sc, MDIO_ACCESS) & MDIO_PHY_DATA_MASK); 2764223927Sray} 2765223927Sray 2766223927Sraystatic int 2767223927Srayrt_miibus_writereg(device_t dev, int phy, int reg, int val) 2768223927Sray{ 2769223927Sray struct rt_softc *sc = device_get_softc(dev); 2770223927Sray 2771223927Sray /* Wait prev command done if any */ 2772223927Sray while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); 2773223927Sray RT_WRITE(sc, MDIO_ACCESS, 2774223927Sray MDIO_CMD_ONGO || MDIO_CMD_WR || 2775223927Sray ((phy << MDIO_PHY_ADDR_SHIFT) & MDIO_PHY_ADDR_MASK) || 2776223927Sray ((reg << MDIO_PHYREG_ADDR_SHIFT) & MDIO_PHYREG_ADDR_MASK) || 2777223927Sray (val & MDIO_PHY_DATA_MASK)); 2778223927Sray while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); 2779223927Sray 2780223927Sray return (0); 2781223927Sray} 2782223927Sray 2783223927Srayvoid 2784223927Srayrt_miibus_statchg(device_t dev) 2785223927Sray{ 2786223927Sray struct rt_softc *sc = device_get_softc(dev); 2787223927Sray struct mii_data *mii; 2788223927Sray 2789223927Sray mii = device_get_softc(sc->rt_miibus); 2790223927Sray 2791223927Sray if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 2792223927Sray (IFM_ACTIVE | IFM_AVALID)) { 2793223927Sray switch (IFM_SUBTYPE(mii->mii_media_active)) { 2794223927Sray case IFM_10_T: 2795223927Sray case IFM_100_TX: 2796223927Sray /* XXX check link here */ 2797223927Sray sc->flags |= 1; 2798223927Sray break; 2799223927Sray default: 2800223927Sray break; 2801223927Sray } 2802223927Sray } 2803223927Sray} 2804223927Sray#endif /* IF_RT_PHY_SUPPORT */ 2805223927Sray 2806223927Sraystatic device_method_t rt_dev_methods[] = 2807223927Sray{ 2808223927Sray DEVMETHOD(device_probe, rt_probe), 2809223927Sray DEVMETHOD(device_attach, rt_attach), 2810223927Sray DEVMETHOD(device_detach, rt_detach), 2811223927Sray DEVMETHOD(device_shutdown, rt_shutdown), 2812223927Sray DEVMETHOD(device_suspend, rt_suspend), 2813223927Sray DEVMETHOD(device_resume, rt_resume), 2814223927Sray 2815223927Sray#ifdef IF_RT_PHY_SUPPORT 2816223927Sray /* MII interface */ 2817223927Sray DEVMETHOD(miibus_readreg, rt_miibus_readreg), 2818223927Sray DEVMETHOD(miibus_writereg, rt_miibus_writereg), 2819223927Sray DEVMETHOD(miibus_statchg, rt_miibus_statchg), 2820223927Sray#endif 2821227843Smarius 2822227843Smarius DEVMETHOD_END 2823223927Sray}; 2824223927Sray 2825223927Sraystatic driver_t rt_driver = 2826223927Sray{ 2827223927Sray "rt", 2828223927Sray rt_dev_methods, 2829223927Sray sizeof(struct rt_softc) 2830223927Sray}; 2831223927Sray 2832223927Sraystatic devclass_t rt_dev_class; 2833223927Sray 2834223927SrayDRIVER_MODULE(rt, nexus, rt_driver, rt_dev_class, 0, 0); 2835292704Sadrian#ifdef FDT 2836292704SadrianDRIVER_MODULE(rt, simplebus, rt_driver, rt_dev_class, 0, 0); 2837292704Sadrian#endif 2838292704Sadrian 2839223927SrayMODULE_DEPEND(rt, ether, 1, 1, 1); 2840223927SrayMODULE_DEPEND(rt, miibus, 1, 1, 1); 2841223927Sray 2842