if_gem.c revision 195049
1119418Sobrien/*- 291398Stmm * Copyright (C) 2001 Eduardo Horvath. 3108832Stmm * Copyright (c) 2001-2003 Thomas Moestl 4174987Smarius * Copyright (c) 2007 Marius Strobl <marius@FreeBSD.org> 591398Stmm * All rights reserved. 691398Stmm * 791398Stmm * Redistribution and use in source and binary forms, with or without 891398Stmm * modification, are permitted provided that the following conditions 991398Stmm * are met: 1091398Stmm * 1. Redistributions of source code must retain the above copyright 1191398Stmm * notice, this list of conditions and the following disclaimer. 1291398Stmm * 2. Redistributions in binary form must reproduce the above copyright 1391398Stmm * notice, this list of conditions and the following disclaimer in the 1491398Stmm * documentation and/or other materials provided with the distribution. 1591398Stmm * 1691398Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 1791398Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1891398Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1991398Stmm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 2091398Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2191398Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2291398Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2391398Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2491398Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2591398Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2691398Stmm * SUCH DAMAGE. 2791398Stmm * 2899726Sbenno * from: NetBSD: gem.c,v 1.21 2002/06/01 23:50:58 lukem Exp 2991398Stmm */ 3091398Stmm 31119418Sobrien#include <sys/cdefs.h> 32119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/gem/if_gem.c 195049 2009-06-26 11:45:06Z rwatson $"); 33119418Sobrien 3491398Stmm/* 35172334Smarius * Driver for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers 3691398Stmm */ 3791398Stmm 38115030Stmm#if 0 3991398Stmm#define GEM_DEBUG 40115030Stmm#endif 4191398Stmm 42148368Smarius#if 0 /* XXX: In case of emergency, re-enable this. */ 43148368Smarius#define GEM_RINT_TIMEOUT 44148368Smarius#endif 45148368Smarius 4691398Stmm#include <sys/param.h> 4791398Stmm#include <sys/systm.h> 4891398Stmm#include <sys/bus.h> 4991398Stmm#include <sys/callout.h> 5095533Smike#include <sys/endian.h> 5191398Stmm#include <sys/mbuf.h> 5291398Stmm#include <sys/malloc.h> 5391398Stmm#include <sys/kernel.h> 54148369Smarius#include <sys/lock.h> 55130026Sphk#include <sys/module.h> 56148369Smarius#include <sys/mutex.h> 5791398Stmm#include <sys/socket.h> 5891398Stmm#include <sys/sockio.h> 59169269Sphk#include <sys/rman.h> 6091398Stmm 61105982Stmm#include <net/bpf.h> 6291398Stmm#include <net/ethernet.h> 6391398Stmm#include <net/if.h> 6491398Stmm#include <net/if_arp.h> 6591398Stmm#include <net/if_dl.h> 6691398Stmm#include <net/if_media.h> 67147256Sbrooks#include <net/if_types.h> 68149552Smarius#include <net/if_vlan_var.h> 6991398Stmm 70170273Syongari#include <netinet/in.h> 71170273Syongari#include <netinet/in_systm.h> 72170273Syongari#include <netinet/ip.h> 73170273Syongari#include <netinet/tcp.h> 74170273Syongari#include <netinet/udp.h> 75170273Syongari 7691398Stmm#include <machine/bus.h> 7791398Stmm 7891398Stmm#include <dev/mii/mii.h> 7991398Stmm#include <dev/mii/miivar.h> 8091398Stmm 81119355Simp#include <dev/gem/if_gemreg.h> 82119355Simp#include <dev/gem/if_gemvar.h> 8391398Stmm 84172334SmariusCTASSERT(powerof2(GEM_NRXDESC) && GEM_NRXDESC >= 32 && GEM_NRXDESC <= 8192); 85172334SmariusCTASSERT(powerof2(GEM_NTXDESC) && GEM_NTXDESC >= 32 && GEM_NTXDESC <= 8192); 86172334Smarius 87194763Smarius#define GEM_TRIES 10000 88172334Smarius 89170273Syongari/* 90182060Smarius * The hardware supports basic TCP/UDP checksum offloading. However, 91170273Syongari * the hardware doesn't compensate the checksum for UDP datagram which 92174987Smarius * can yield to 0x0. As a safe guard, UDP checksum offload is disabled 93174987Smarius * by default. It can be reactivated by setting special link option 94170273Syongari * link0 with ifconfig(8). 95170273Syongari */ 96170273Syongari#define GEM_CSUM_FEATURES (CSUM_TCP) 9791398Stmm 98174987Smariusstatic int gem_add_rxbuf(struct gem_softc *sc, int idx); 99177560Smariusstatic int gem_bitwait(struct gem_softc *sc, u_int bank, bus_addr_t r, 100177560Smarius uint32_t clr, uint32_t set); 101174987Smariusstatic void gem_cddma_callback(void *xsc, bus_dma_segment_t *segs, 102174987Smarius int nsegs, int error); 103174987Smariusstatic int gem_disable_rx(struct gem_softc *sc); 104174987Smariusstatic int gem_disable_tx(struct gem_softc *sc); 105174987Smariusstatic void gem_eint(struct gem_softc *sc, u_int status); 106174987Smariusstatic void gem_init(void *xsc); 107174987Smariusstatic void gem_init_locked(struct gem_softc *sc); 108174987Smariusstatic void gem_init_regs(struct gem_softc *sc); 109174987Smariusstatic int gem_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 110174987Smariusstatic int gem_load_txmbuf(struct gem_softc *sc, struct mbuf **m_head); 111174987Smariusstatic int gem_meminit(struct gem_softc *sc); 112174987Smariusstatic void gem_mifinit(struct gem_softc *sc); 113174987Smariusstatic void gem_reset(struct gem_softc *sc); 114174987Smariusstatic int gem_reset_rx(struct gem_softc *sc); 115172334Smariusstatic void gem_reset_rxdma(struct gem_softc *sc); 116174987Smariusstatic int gem_reset_tx(struct gem_softc *sc); 117174987Smariusstatic u_int gem_ringsize(u_int sz); 118174987Smariusstatic void gem_rint(struct gem_softc *sc); 119148368Smarius#ifdef GEM_RINT_TIMEOUT 120174987Smariusstatic void gem_rint_timeout(void *arg); 121100587Sjake#endif 122194763Smariusstatic inline void gem_rxcksum(struct mbuf *m, uint64_t flags); 123174987Smariusstatic void gem_rxdrain(struct gem_softc *sc); 124174987Smariusstatic void gem_setladrf(struct gem_softc *sc); 125174987Smariusstatic void gem_start(struct ifnet *ifp); 126174987Smariusstatic void gem_start_locked(struct ifnet *ifp); 127174987Smariusstatic void gem_stop(struct ifnet *ifp, int disable); 128174987Smariusstatic void gem_tick(void *arg); 129174987Smariusstatic void gem_tint(struct gem_softc *sc); 130194763Smariusstatic inline void gem_txkick(struct gem_softc *sc); 131174987Smariusstatic int gem_watchdog(struct gem_softc *sc); 13291398Stmm 13391398Stmmdevclass_t gem_devclass; 13491398StmmDRIVER_MODULE(miibus, gem, miibus_driver, miibus_devclass, 0, 0); 13591398StmmMODULE_DEPEND(gem, miibus, 1, 1, 1); 13691398Stmm 13791398Stmm#ifdef GEM_DEBUG 13891398Stmm#include <sys/ktr.h> 13991398Stmm#define KTR_GEM KTR_CT2 14091398Stmm#endif 14191398Stmm 142177560Smarius#define GEM_BANK1_BITWAIT(sc, r, clr, set) \ 143177560Smarius gem_bitwait((sc), GEM_RES_BANK1, (r), (clr), (set)) 144177560Smarius#define GEM_BANK2_BITWAIT(sc, r, clr, set) \ 145177560Smarius gem_bitwait((sc), GEM_RES_BANK2, (r), (clr), (set)) 146177560Smarius 14791398Stmmint 148174987Smariusgem_attach(struct gem_softc *sc) 14991398Stmm{ 150174987Smarius struct gem_txsoft *txs; 151147256Sbrooks struct ifnet *ifp; 152174987Smarius int error, i; 153174987Smarius uint32_t v; 15491398Stmm 155194763Smarius if (bootverbose) 156194763Smarius device_printf(sc->sc_dev, "flags=0x%x\n", sc->sc_flags); 157194763Smarius 158194763Smarius /* Set up ifnet structure. */ 159147256Sbrooks ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 160147256Sbrooks if (ifp == NULL) 161147256Sbrooks return (ENOSPC); 162194763Smarius sc->sc_csum_features = GEM_CSUM_FEATURES; 163194763Smarius ifp->if_softc = sc; 164194763Smarius if_initname(ifp, device_get_name(sc->sc_dev), 165194763Smarius device_get_unit(sc->sc_dev)); 166194763Smarius ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 167194763Smarius ifp->if_start = gem_start; 168194763Smarius ifp->if_ioctl = gem_ioctl; 169194763Smarius ifp->if_init = gem_init; 170194763Smarius IFQ_SET_MAXLEN(&ifp->if_snd, GEM_TXQUEUELEN); 171194763Smarius ifp->if_snd.ifq_drv_maxlen = GEM_TXQUEUELEN; 172194763Smarius IFQ_SET_READY(&ifp->if_snd); 173147256Sbrooks 174150285Smarius callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0); 175150285Smarius#ifdef GEM_RINT_TIMEOUT 176150285Smarius callout_init_mtx(&sc->sc_rx_ch, &sc->sc_mtx, 0); 177150285Smarius#endif 178150285Smarius 17991398Stmm /* Make sure the chip is stopped. */ 18091398Stmm gem_reset(sc); 18191398Stmm 182161928Sjmg error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 183161928Sjmg BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 184174987Smarius BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, 185174987Smarius NULL, &sc->sc_pdmatag); 186194763Smarius if (error != 0) 187147256Sbrooks goto fail_ifnet; 18891398Stmm 18991398Stmm error = bus_dma_tag_create(sc->sc_pdmatag, 1, 0, 190170273Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 191170273Syongari 1, MCLBYTES, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_rdmatag); 192194763Smarius if (error != 0) 193108832Stmm goto fail_ptag; 19491398Stmm 195108832Stmm error = bus_dma_tag_create(sc->sc_pdmatag, 1, 0, 196170273Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 197170273Syongari MCLBYTES * GEM_NTXSEGS, GEM_NTXSEGS, MCLBYTES, 198117126Sscottl BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_tdmatag); 199194763Smarius if (error != 0) 200108832Stmm goto fail_rtag; 201108832Stmm 20291398Stmm error = bus_dma_tag_create(sc->sc_pdmatag, PAGE_SIZE, 0, 203170273Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 20491398Stmm sizeof(struct gem_control_data), 1, 205170273Syongari sizeof(struct gem_control_data), 0, 206170273Syongari NULL, NULL, &sc->sc_cdmatag); 207194763Smarius if (error != 0) 208108832Stmm goto fail_ttag; 20991398Stmm 21091398Stmm /* 211174987Smarius * Allocate the control data structures, create and load the 21291398Stmm * DMA map for it. 21391398Stmm */ 21491398Stmm if ((error = bus_dmamem_alloc(sc->sc_cdmatag, 215170273Syongari (void **)&sc->sc_control_data, 216170273Syongari BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 217194763Smarius &sc->sc_cddmamap)) != 0) { 218174987Smarius device_printf(sc->sc_dev, 219174987Smarius "unable to allocate control data, error = %d\n", error); 220108832Stmm goto fail_ctag; 22191398Stmm } 22291398Stmm 22391398Stmm sc->sc_cddma = 0; 22491398Stmm if ((error = bus_dmamap_load(sc->sc_cdmatag, sc->sc_cddmamap, 22591398Stmm sc->sc_control_data, sizeof(struct gem_control_data), 22691398Stmm gem_cddma_callback, sc, 0)) != 0 || sc->sc_cddma == 0) { 227174987Smarius device_printf(sc->sc_dev, 228174987Smarius "unable to load control data DMA map, error = %d\n", 229174987Smarius error); 230108832Stmm goto fail_cmem; 23191398Stmm } 23291398Stmm 23391398Stmm /* 23491398Stmm * Initialize the transmit job descriptors. 23591398Stmm */ 23691398Stmm STAILQ_INIT(&sc->sc_txfreeq); 23791398Stmm STAILQ_INIT(&sc->sc_txdirtyq); 23891398Stmm 23991398Stmm /* 24091398Stmm * Create the transmit buffer DMA maps. 24191398Stmm */ 24291398Stmm error = ENOMEM; 24391398Stmm for (i = 0; i < GEM_TXQUEUELEN; i++) { 24491398Stmm txs = &sc->sc_txsoft[i]; 24591398Stmm txs->txs_mbuf = NULL; 24691398Stmm txs->txs_ndescs = 0; 247108832Stmm if ((error = bus_dmamap_create(sc->sc_tdmatag, 0, 24891398Stmm &txs->txs_dmamap)) != 0) { 249174987Smarius device_printf(sc->sc_dev, 250174987Smarius "unable to create TX DMA map %d, error = %d\n", 251174987Smarius i, error); 252108832Stmm goto fail_txd; 25391398Stmm } 25491398Stmm STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); 25591398Stmm } 25691398Stmm 25791398Stmm /* 25891398Stmm * Create the receive buffer DMA maps. 25991398Stmm */ 26091398Stmm for (i = 0; i < GEM_NRXDESC; i++) { 261108832Stmm if ((error = bus_dmamap_create(sc->sc_rdmatag, 0, 26291398Stmm &sc->sc_rxsoft[i].rxs_dmamap)) != 0) { 263174987Smarius device_printf(sc->sc_dev, 264174987Smarius "unable to create RX DMA map %d, error = %d\n", 265174987Smarius i, error); 266108832Stmm goto fail_rxd; 26791398Stmm } 26891398Stmm sc->sc_rxsoft[i].rxs_mbuf = NULL; 26991398Stmm } 27091398Stmm 271172334Smarius /* Bad things will happen when touching this register on ERI. */ 272172334Smarius if (sc->sc_variant != GEM_SUN_ERI) 273177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_DATAPATH_MODE, 274172334Smarius GEM_MII_DATAPATH_MII); 275172334Smarius 27691398Stmm gem_mifinit(sc); 27791398Stmm 278172334Smarius /* 279172334Smarius * Look for an external PHY. 280172334Smarius */ 281172334Smarius error = ENXIO; 282177560Smarius v = GEM_BANK1_READ_4(sc, GEM_MIF_CONFIG); 283172334Smarius if ((v & GEM_MIF_CONFIG_MDI1) != 0) { 284172334Smarius v |= GEM_MIF_CONFIG_PHY_SEL; 285177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MIF_CONFIG, v); 286172334Smarius switch (sc->sc_variant) { 287172334Smarius case GEM_SUN_ERI: 288172334Smarius sc->sc_phyad = GEM_PHYAD_EXTERNAL; 289172334Smarius break; 290172334Smarius default: 291172334Smarius sc->sc_phyad = -1; 292172334Smarius break; 293172334Smarius } 294172334Smarius error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, 295172334Smarius gem_mediachange, gem_mediastatus); 296172334Smarius } 297172334Smarius 298172334Smarius /* 299172334Smarius * Fall back on an internal PHY if no external PHY was found. 300172334Smarius */ 301172334Smarius if (error != 0 && (v & GEM_MIF_CONFIG_MDI0) != 0) { 302172334Smarius v &= ~GEM_MIF_CONFIG_PHY_SEL; 303177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MIF_CONFIG, v); 304172334Smarius switch (sc->sc_variant) { 305172334Smarius case GEM_SUN_ERI: 306172334Smarius case GEM_APPLE_K2_GMAC: 307172334Smarius sc->sc_phyad = GEM_PHYAD_INTERNAL; 308172334Smarius break; 309172334Smarius case GEM_APPLE_GMAC: 310172334Smarius sc->sc_phyad = GEM_PHYAD_EXTERNAL; 311172334Smarius break; 312172334Smarius default: 313172334Smarius sc->sc_phyad = -1; 314172334Smarius break; 315172334Smarius } 316172334Smarius error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, 317172334Smarius gem_mediachange, gem_mediastatus); 318172334Smarius } 319172334Smarius 320172334Smarius /* 321172334Smarius * Try the external PCS SERDES if we didn't find any PHYs. 322172334Smarius */ 323172334Smarius if (error != 0 && sc->sc_variant == GEM_SUN_GEM) { 324177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_DATAPATH_MODE, 325172334Smarius GEM_MII_DATAPATH_SERDES); 326177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_SLINK_CONTROL, 327172334Smarius GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_EN_SYNC_D); 328177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_CONFIG, GEM_MII_CONFIG_ENABLE); 329172334Smarius sc->sc_flags |= GEM_SERDES; 330172334Smarius sc->sc_phyad = GEM_PHYAD_EXTERNAL; 331172334Smarius error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, 332172334Smarius gem_mediachange, gem_mediastatus); 333172334Smarius } 334172334Smarius 335172334Smarius if (error != 0) { 336172334Smarius device_printf(sc->sc_dev, "PHY probe failed: %d\n", error); 337108832Stmm goto fail_rxd; 33891398Stmm } 33991398Stmm sc->sc_mii = device_get_softc(sc->sc_miibus); 34091398Stmm 34191398Stmm /* 34291398Stmm * From this point forward, the attachment cannot fail. A failure 34391398Stmm * before this point releases all resources that may have been 34491398Stmm * allocated. 34591398Stmm */ 34691398Stmm 347176996Smarius /* Get RX FIFO size. */ 34899726Sbenno sc->sc_rxfifosize = 64 * 349177560Smarius GEM_BANK1_READ_4(sc, GEM_RX_FIFO_SIZE); 35099726Sbenno 351176996Smarius /* Get TX FIFO size. */ 352177560Smarius v = GEM_BANK1_READ_4(sc, GEM_TX_FIFO_SIZE); 353128588Stmm device_printf(sc->sc_dev, "%ukB RX FIFO, %ukB TX FIFO\n", 354128588Stmm sc->sc_rxfifosize / 1024, v / 16); 35599726Sbenno 35691398Stmm /* Attach the interface. */ 357147256Sbrooks ether_ifattach(ifp, sc->sc_enaddr); 35891398Stmm 35991398Stmm /* 360170273Syongari * Tell the upper layer(s) we support long frames/checksum offloads. 361149552Smarius */ 362149552Smarius ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 363170273Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_HWCSUM; 364170273Syongari ifp->if_hwassist |= sc->sc_csum_features; 365170273Syongari ifp->if_capenable |= IFCAP_VLAN_MTU | IFCAP_HWCSUM; 366149552Smarius 36791398Stmm return (0); 36891398Stmm 36991398Stmm /* 37091398Stmm * Free any resources we've allocated during the failed attach 37191398Stmm * attempt. Do this in reverse order and fall through. 37291398Stmm */ 373174987Smarius fail_rxd: 374174987Smarius for (i = 0; i < GEM_NRXDESC; i++) 37591398Stmm if (sc->sc_rxsoft[i].rxs_dmamap != NULL) 376108832Stmm bus_dmamap_destroy(sc->sc_rdmatag, 37791398Stmm sc->sc_rxsoft[i].rxs_dmamap); 378174987Smarius fail_txd: 379174987Smarius for (i = 0; i < GEM_TXQUEUELEN; i++) 38091398Stmm if (sc->sc_txsoft[i].txs_dmamap != NULL) 381108832Stmm bus_dmamap_destroy(sc->sc_tdmatag, 38291398Stmm sc->sc_txsoft[i].txs_dmamap); 383108832Stmm bus_dmamap_unload(sc->sc_cdmatag, sc->sc_cddmamap); 384174987Smarius fail_cmem: 38591398Stmm bus_dmamem_free(sc->sc_cdmatag, sc->sc_control_data, 38691398Stmm sc->sc_cddmamap); 387174987Smarius fail_ctag: 38891398Stmm bus_dma_tag_destroy(sc->sc_cdmatag); 389174987Smarius fail_ttag: 390108832Stmm bus_dma_tag_destroy(sc->sc_tdmatag); 391174987Smarius fail_rtag: 392108832Stmm bus_dma_tag_destroy(sc->sc_rdmatag); 393174987Smarius fail_ptag: 39491398Stmm bus_dma_tag_destroy(sc->sc_pdmatag); 395174987Smarius fail_ifnet: 396147256Sbrooks if_free(ifp); 39791398Stmm return (error); 39891398Stmm} 39991398Stmm 400108964Stmmvoid 401174987Smariusgem_detach(struct gem_softc *sc) 402108964Stmm{ 403147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 404108964Stmm int i; 405108964Stmm 406194886Smarius ether_ifdetach(ifp); 407148369Smarius GEM_LOCK(sc); 408147317Sbrooks gem_stop(ifp, 1); 409148369Smarius GEM_UNLOCK(sc); 410150285Smarius callout_drain(&sc->sc_tick_ch); 411150285Smarius#ifdef GEM_RINT_TIMEOUT 412150285Smarius callout_drain(&sc->sc_rx_ch); 413150285Smarius#endif 414147256Sbrooks if_free(ifp); 415108964Stmm device_delete_child(sc->sc_dev, sc->sc_miibus); 416108964Stmm 417174987Smarius for (i = 0; i < GEM_NRXDESC; i++) 418108964Stmm if (sc->sc_rxsoft[i].rxs_dmamap != NULL) 419108964Stmm bus_dmamap_destroy(sc->sc_rdmatag, 420108964Stmm sc->sc_rxsoft[i].rxs_dmamap); 421174987Smarius for (i = 0; i < GEM_TXQUEUELEN; i++) 422108964Stmm if (sc->sc_txsoft[i].txs_dmamap != NULL) 423108964Stmm bus_dmamap_destroy(sc->sc_tdmatag, 424108964Stmm sc->sc_txsoft[i].txs_dmamap); 425179925Smarius GEM_CDSYNC(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 426108964Stmm bus_dmamap_unload(sc->sc_cdmatag, sc->sc_cddmamap); 427108964Stmm bus_dmamem_free(sc->sc_cdmatag, sc->sc_control_data, 428108964Stmm sc->sc_cddmamap); 429108964Stmm bus_dma_tag_destroy(sc->sc_cdmatag); 430108964Stmm bus_dma_tag_destroy(sc->sc_tdmatag); 431108964Stmm bus_dma_tag_destroy(sc->sc_rdmatag); 432108964Stmm bus_dma_tag_destroy(sc->sc_pdmatag); 433108964Stmm} 434108964Stmm 435108964Stmmvoid 436174987Smariusgem_suspend(struct gem_softc *sc) 437108964Stmm{ 438147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 439108964Stmm 440148369Smarius GEM_LOCK(sc); 441108964Stmm gem_stop(ifp, 0); 442148369Smarius GEM_UNLOCK(sc); 443108964Stmm} 444108964Stmm 445108964Stmmvoid 446174987Smariusgem_resume(struct gem_softc *sc) 447108964Stmm{ 448147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 449108964Stmm 450148369Smarius GEM_LOCK(sc); 451149552Smarius /* 452149552Smarius * On resume all registers have to be initialized again like 453149552Smarius * after power-on. 454149552Smarius */ 455172334Smarius sc->sc_flags &= ~GEM_INITED; 456108964Stmm if (ifp->if_flags & IFF_UP) 457148369Smarius gem_init_locked(sc); 458148369Smarius GEM_UNLOCK(sc); 459108964Stmm} 460108964Stmm 461194763Smariusstatic inline void 462170273Syongarigem_rxcksum(struct mbuf *m, uint64_t flags) 463170273Syongari{ 464170273Syongari struct ether_header *eh; 465170273Syongari struct ip *ip; 466170273Syongari struct udphdr *uh; 467174987Smarius uint16_t *opts; 468170273Syongari int32_t hlen, len, pktlen; 469170273Syongari uint32_t temp32; 470174987Smarius uint16_t cksum; 471170273Syongari 472170273Syongari pktlen = m->m_pkthdr.len; 473170273Syongari if (pktlen < sizeof(struct ether_header) + sizeof(struct ip)) 474170273Syongari return; 475170273Syongari eh = mtod(m, struct ether_header *); 476170273Syongari if (eh->ether_type != htons(ETHERTYPE_IP)) 477170273Syongari return; 478170273Syongari ip = (struct ip *)(eh + 1); 479170273Syongari if (ip->ip_v != IPVERSION) 480170273Syongari return; 481170273Syongari 482170273Syongari hlen = ip->ip_hl << 2; 483170273Syongari pktlen -= sizeof(struct ether_header); 484170273Syongari if (hlen < sizeof(struct ip)) 485170273Syongari return; 486170273Syongari if (ntohs(ip->ip_len) < hlen) 487170273Syongari return; 488170273Syongari if (ntohs(ip->ip_len) != pktlen) 489170273Syongari return; 490170273Syongari if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) 491174987Smarius return; /* Cannot handle fragmented packet. */ 492170273Syongari 493170273Syongari switch (ip->ip_p) { 494170273Syongari case IPPROTO_TCP: 495170273Syongari if (pktlen < (hlen + sizeof(struct tcphdr))) 496170273Syongari return; 497170273Syongari break; 498170273Syongari case IPPROTO_UDP: 499170273Syongari if (pktlen < (hlen + sizeof(struct udphdr))) 500170273Syongari return; 501170273Syongari uh = (struct udphdr *)((uint8_t *)ip + hlen); 502170273Syongari if (uh->uh_sum == 0) 503170273Syongari return; /* no checksum */ 504170273Syongari break; 505170273Syongari default: 506170273Syongari return; 507170273Syongari } 508170273Syongari 509170273Syongari cksum = ~(flags & GEM_RD_CHECKSUM); 510170273Syongari /* checksum fixup for IP options */ 511170273Syongari len = hlen - sizeof(struct ip); 512170273Syongari if (len > 0) { 513170273Syongari opts = (uint16_t *)(ip + 1); 514170273Syongari for (; len > 0; len -= sizeof(uint16_t), opts++) { 515170273Syongari temp32 = cksum - *opts; 516170273Syongari temp32 = (temp32 >> 16) + (temp32 & 65535); 517170273Syongari cksum = temp32 & 65535; 518170273Syongari } 519170273Syongari } 520170273Syongari m->m_pkthdr.csum_flags |= CSUM_DATA_VALID; 521170273Syongari m->m_pkthdr.csum_data = cksum; 522170273Syongari} 523170273Syongari 52491398Stmmstatic void 525174987Smariusgem_cddma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) 52691398Stmm{ 527174987Smarius struct gem_softc *sc = xsc; 52891398Stmm 52991398Stmm if (error != 0) 53091398Stmm return; 531174987Smarius if (nsegs != 1) 532172334Smarius panic("%s: bad control buffer segment count", __func__); 53391398Stmm sc->sc_cddma = segs[0].ds_addr; 53491398Stmm} 53591398Stmm 53691398Stmmstatic void 537174987Smariusgem_tick(void *arg) 53891398Stmm{ 539170273Syongari struct gem_softc *sc = arg; 540194763Smarius struct ifnet *ifp = sc->sc_ifp; 541182060Smarius uint32_t v; 54291398Stmm 543170273Syongari GEM_LOCK_ASSERT(sc, MA_OWNED); 544170273Syongari 545108832Stmm /* 546182060Smarius * Unload collision and error counters. 547108832Stmm */ 548170273Syongari ifp->if_collisions += 549177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_NORM_COLL_CNT) + 550182060Smarius GEM_BANK1_READ_4(sc, GEM_MAC_FIRST_COLL_CNT); 551182060Smarius v = GEM_BANK1_READ_4(sc, GEM_MAC_EXCESS_COLL_CNT) + 552177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_LATE_COLL_CNT); 553182060Smarius ifp->if_collisions += v; 554182060Smarius ifp->if_oerrors += v; 555182060Smarius ifp->if_ierrors += 556182060Smarius GEM_BANK1_READ_4(sc, GEM_MAC_RX_LEN_ERR_CNT) + 557182060Smarius GEM_BANK1_READ_4(sc, GEM_MAC_RX_ALIGN_ERR) + 558182060Smarius GEM_BANK1_READ_4(sc, GEM_MAC_RX_CRC_ERR_CNT) + 559182060Smarius GEM_BANK1_READ_4(sc, GEM_MAC_RX_CODE_VIOL); 56091398Stmm 56191398Stmm /* 562176996Smarius * Then clear the hardware counters. 56391398Stmm */ 564177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_NORM_COLL_CNT, 0); 565177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_FIRST_COLL_CNT, 0); 566177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_EXCESS_COLL_CNT, 0); 567177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_LATE_COLL_CNT, 0); 568182060Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_LEN_ERR_CNT, 0); 569182060Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_ALIGN_ERR, 0); 570182060Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CRC_ERR_CNT, 0); 571182060Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CODE_VIOL, 0); 572108832Stmm 57391398Stmm mii_tick(sc->sc_mii); 57491398Stmm 575164931Smarius if (gem_watchdog(sc) == EJUSTRETURN) 576164931Smarius return; 577164931Smarius 57891398Stmm callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc); 57991398Stmm} 58091398Stmm 58191398Stmmstatic int 582177560Smariusgem_bitwait(struct gem_softc *sc, u_int bank, bus_addr_t r, uint32_t clr, 583177560Smarius uint32_t set) 58491398Stmm{ 58591398Stmm int i; 586174987Smarius uint32_t reg; 58791398Stmm 588194763Smarius for (i = GEM_TRIES; i--; DELAY(100)) { 589177560Smarius reg = GEM_BANKN_READ_M(bank, 4, sc, r); 590170847Smarius if ((reg & clr) == 0 && (reg & set) == set) 59191398Stmm return (1); 59291398Stmm } 59391398Stmm return (0); 59491398Stmm} 59591398Stmm 596172334Smariusstatic void 597194763Smariusgem_reset(struct gem_softc *sc) 59891398Stmm{ 59991398Stmm 600115030Stmm#ifdef GEM_DEBUG 601170273Syongari CTR2(KTR_GEM, "%s: %s", device_get_name(sc->sc_dev), __func__); 602115030Stmm#endif 60391398Stmm gem_reset_rx(sc); 60491398Stmm gem_reset_tx(sc); 60591398Stmm 606174987Smarius /* Do a full reset. */ 607177560Smarius GEM_BANK2_WRITE_4(sc, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX); 608179925Smarius GEM_BANK2_BARRIER(sc, GEM_RESET, 4, 609179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 610177560Smarius if (!GEM_BANK2_BITWAIT(sc, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX, 0)) 61191398Stmm device_printf(sc->sc_dev, "cannot reset device\n"); 61291398Stmm} 61391398Stmm 61491398Stmmstatic void 615174987Smariusgem_rxdrain(struct gem_softc *sc) 61691398Stmm{ 61791398Stmm struct gem_rxsoft *rxs; 61891398Stmm int i; 61991398Stmm 62091398Stmm for (i = 0; i < GEM_NRXDESC; i++) { 62191398Stmm rxs = &sc->sc_rxsoft[i]; 62291398Stmm if (rxs->rxs_mbuf != NULL) { 623109648Stmm bus_dmamap_sync(sc->sc_rdmatag, rxs->rxs_dmamap, 624109648Stmm BUS_DMASYNC_POSTREAD); 625108832Stmm bus_dmamap_unload(sc->sc_rdmatag, rxs->rxs_dmamap); 62691398Stmm m_freem(rxs->rxs_mbuf); 62791398Stmm rxs->rxs_mbuf = NULL; 62891398Stmm } 62991398Stmm } 63091398Stmm} 63191398Stmm 63291398Stmmstatic void 633174987Smariusgem_stop(struct ifnet *ifp, int disable) 63491398Stmm{ 635174987Smarius struct gem_softc *sc = ifp->if_softc; 63691398Stmm struct gem_txsoft *txs; 63791398Stmm 638115030Stmm#ifdef GEM_DEBUG 639170273Syongari CTR2(KTR_GEM, "%s: %s", device_get_name(sc->sc_dev), __func__); 640115030Stmm#endif 64191398Stmm 64291398Stmm callout_stop(&sc->sc_tick_ch); 643150285Smarius#ifdef GEM_RINT_TIMEOUT 644150285Smarius callout_stop(&sc->sc_rx_ch); 645172334Smarius#endif 64691398Stmm 647194763Smarius gem_reset_tx(sc); 648194763Smarius gem_reset_rx(sc); 64991398Stmm 65091398Stmm /* 65191398Stmm * Release any queued transmit buffers. 65291398Stmm */ 65391398Stmm while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) { 65491398Stmm STAILQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q); 65591398Stmm if (txs->txs_ndescs != 0) { 656109648Stmm bus_dmamap_sync(sc->sc_tdmatag, txs->txs_dmamap, 657109648Stmm BUS_DMASYNC_POSTWRITE); 658108832Stmm bus_dmamap_unload(sc->sc_tdmatag, txs->txs_dmamap); 65991398Stmm if (txs->txs_mbuf != NULL) { 66091398Stmm m_freem(txs->txs_mbuf); 66191398Stmm txs->txs_mbuf = NULL; 66291398Stmm } 66391398Stmm } 66491398Stmm STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); 66591398Stmm } 66691398Stmm 66791398Stmm if (disable) 66891398Stmm gem_rxdrain(sc); 66991398Stmm 67091398Stmm /* 67191398Stmm * Mark the interface down and cancel the watchdog timer. 67291398Stmm */ 673148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 674172334Smarius sc->sc_flags &= ~GEM_LINK; 675164931Smarius sc->sc_wdog_timer = 0; 67691398Stmm} 67791398Stmm 678172334Smariusstatic int 679174987Smariusgem_reset_rx(struct gem_softc *sc) 68091398Stmm{ 68191398Stmm 68291398Stmm /* 68391398Stmm * Resetting while DMA is in progress can cause a bus hang, so we 68491398Stmm * disable DMA first. 68591398Stmm */ 68691398Stmm gem_disable_rx(sc); 687177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_CONFIG, 0); 688179925Smarius GEM_BANK1_BARRIER(sc, GEM_RX_CONFIG, 4, 689179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 690177560Smarius if (!GEM_BANK1_BITWAIT(sc, GEM_RX_CONFIG, GEM_RX_CONFIG_RXDMA_EN, 0)) 691172334Smarius device_printf(sc->sc_dev, "cannot disable RX DMA\n"); 69291398Stmm 693176996Smarius /* Finally, reset the ERX. */ 694177560Smarius GEM_BANK2_WRITE_4(sc, GEM_RESET, GEM_RESET_RX); 695179925Smarius GEM_BANK2_BARRIER(sc, GEM_RESET, 4, 696179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 697177560Smarius if (!GEM_BANK2_BITWAIT(sc, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX, 698177560Smarius 0)) { 69991398Stmm device_printf(sc->sc_dev, "cannot reset receiver\n"); 70091398Stmm return (1); 70191398Stmm } 70291398Stmm return (0); 70391398Stmm} 70491398Stmm 705172334Smarius/* 706172334Smarius * Reset the receiver DMA engine. 707172334Smarius * 708172334Smarius * Intended to be used in case of GEM_INTR_RX_TAG_ERR, GEM_MAC_RX_OVERFLOW 709172334Smarius * etc in order to reset the receiver DMA engine only and not do a full 710172334Smarius * reset which amongst others also downs the link and clears the FIFOs. 711172334Smarius */ 712172334Smariusstatic void 713172334Smariusgem_reset_rxdma(struct gem_softc *sc) 714172334Smarius{ 715172334Smarius int i; 71691398Stmm 717172334Smarius if (gem_reset_rx(sc) != 0) 718172334Smarius return (gem_init_locked(sc)); 719172334Smarius for (i = 0; i < GEM_NRXDESC; i++) 720172334Smarius if (sc->sc_rxsoft[i].rxs_mbuf != NULL) 721172334Smarius GEM_UPDATE_RXDESC(sc, i); 722172334Smarius sc->sc_rxptr = 0; 723194763Smarius GEM_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 724172334Smarius 725172334Smarius /* NOTE: we use only 32-bit DMA addresses here. */ 726177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_RING_PTR_HI, 0); 727177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0)); 728177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_KICK, GEM_NRXDESC - 4); 729177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_CONFIG, 730174987Smarius gem_ringsize(GEM_NRXDESC /* XXX */) | 731172334Smarius ((ETHER_HDR_LEN + sizeof(struct ip)) << 732172334Smarius GEM_RX_CONFIG_CXM_START_SHFT) | 733172334Smarius (GEM_THRSH_1024 << GEM_RX_CONFIG_FIFO_THRS_SHIFT) | 734194763Smarius (ETHER_ALIGN << GEM_RX_CONFIG_FBOFF_SHFT)); 735194763Smarius /* Adjust for the SBus clock probably isn't worth the fuzz. */ 736177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_BLANKING, 737194763Smarius ((6 * (sc->sc_flags & GEM_PCI66) != 0 ? 2 : 1) << 738194763Smarius GEM_RX_BLANKING_TIME_SHIFT) | 6); 739177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_PAUSE_THRESH, 740174987Smarius (3 * sc->sc_rxfifosize / 256) | 741174987Smarius ((sc->sc_rxfifosize / 256) << 12)); 742177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_CONFIG, 743177560Smarius GEM_BANK1_READ_4(sc, GEM_RX_CONFIG) | GEM_RX_CONFIG_RXDMA_EN); 744177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_MASK, 745172334Smarius GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT); 746177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, 747177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG) | GEM_MAC_RX_ENABLE); 748172334Smarius} 749172334Smarius 75091398Stmmstatic int 751174987Smariusgem_reset_tx(struct gem_softc *sc) 75291398Stmm{ 75391398Stmm 75491398Stmm /* 75591398Stmm * Resetting while DMA is in progress can cause a bus hang, so we 75691398Stmm * disable DMA first. 75791398Stmm */ 75891398Stmm gem_disable_tx(sc); 759177560Smarius GEM_BANK1_WRITE_4(sc, GEM_TX_CONFIG, 0); 760179925Smarius GEM_BANK1_BARRIER(sc, GEM_TX_CONFIG, 4, 761179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 762177560Smarius if (!GEM_BANK1_BITWAIT(sc, GEM_TX_CONFIG, GEM_TX_CONFIG_TXDMA_EN, 0)) 763172334Smarius device_printf(sc->sc_dev, "cannot disable TX DMA\n"); 76491398Stmm 765176996Smarius /* Finally, reset the ETX. */ 766177560Smarius GEM_BANK2_WRITE_4(sc, GEM_RESET, GEM_RESET_TX); 767179925Smarius GEM_BANK2_BARRIER(sc, GEM_RESET, 4, 768179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 769177560Smarius if (!GEM_BANK2_BITWAIT(sc, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX, 770177560Smarius 0)) { 771172334Smarius device_printf(sc->sc_dev, "cannot reset transmitter\n"); 77291398Stmm return (1); 77391398Stmm } 77491398Stmm return (0); 77591398Stmm} 77691398Stmm 77791398Stmmstatic int 778174987Smariusgem_disable_rx(struct gem_softc *sc) 77991398Stmm{ 78091398Stmm 781177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, 782177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG) & ~GEM_MAC_RX_ENABLE); 783179925Smarius GEM_BANK1_BARRIER(sc, GEM_MAC_RX_CONFIG, 4, 784179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 785177560Smarius return (GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 786177560Smarius 0)); 78791398Stmm} 78891398Stmm 78991398Stmmstatic int 790174987Smariusgem_disable_tx(struct gem_softc *sc) 79191398Stmm{ 79291398Stmm 793177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, 794177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_TX_CONFIG) & ~GEM_MAC_TX_ENABLE); 795179925Smarius GEM_BANK1_BARRIER(sc, GEM_MAC_TX_CONFIG, 4, 796179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 797177560Smarius return (GEM_BANK1_BITWAIT(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 798177560Smarius 0)); 79991398Stmm} 80091398Stmm 80191398Stmmstatic int 802194763Smariusgem_meminit(struct gem_softc *sc) 80391398Stmm{ 80491398Stmm struct gem_rxsoft *rxs; 805174987Smarius int error, i; 80691398Stmm 807194763Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 808194763Smarius 80991398Stmm /* 81091398Stmm * Initialize the transmit descriptor ring. 81191398Stmm */ 81291398Stmm for (i = 0; i < GEM_NTXDESC; i++) { 81391398Stmm sc->sc_txdescs[i].gd_flags = 0; 81491398Stmm sc->sc_txdescs[i].gd_addr = 0; 81591398Stmm } 816108832Stmm sc->sc_txfree = GEM_MAXTXFREE; 81791398Stmm sc->sc_txnext = 0; 81899726Sbenno sc->sc_txwin = 0; 81991398Stmm 82091398Stmm /* 82191398Stmm * Initialize the receive descriptor and receive job 82291398Stmm * descriptor rings. 82391398Stmm */ 82491398Stmm for (i = 0; i < GEM_NRXDESC; i++) { 82591398Stmm rxs = &sc->sc_rxsoft[i]; 82691398Stmm if (rxs->rxs_mbuf == NULL) { 82791398Stmm if ((error = gem_add_rxbuf(sc, i)) != 0) { 828174987Smarius device_printf(sc->sc_dev, 829174987Smarius "unable to allocate or map RX buffer %d, " 830174987Smarius "error = %d\n", i, error); 83191398Stmm /* 832174987Smarius * XXX we should attempt to run with fewer 833174987Smarius * receive buffers instead of just failing. 83491398Stmm */ 83591398Stmm gem_rxdrain(sc); 83691398Stmm return (1); 83791398Stmm } 83891398Stmm } else 83991398Stmm GEM_INIT_RXDESC(sc, i); 84091398Stmm } 84191398Stmm sc->sc_rxptr = 0; 84291398Stmm 843194763Smarius GEM_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 844194763Smarius 84591398Stmm return (0); 84691398Stmm} 84791398Stmm 848172334Smariusstatic u_int 849174987Smariusgem_ringsize(u_int sz) 85091398Stmm{ 85191398Stmm 85291398Stmm switch (sz) { 85391398Stmm case 32: 854172334Smarius return (GEM_RING_SZ_32); 85591398Stmm case 64: 856172334Smarius return (GEM_RING_SZ_64); 85791398Stmm case 128: 858172334Smarius return (GEM_RING_SZ_128); 85991398Stmm case 256: 860172334Smarius return (GEM_RING_SZ_256); 86191398Stmm case 512: 862172334Smarius return (GEM_RING_SZ_512); 86391398Stmm case 1024: 864172334Smarius return (GEM_RING_SZ_1024); 86591398Stmm case 2048: 866172334Smarius return (GEM_RING_SZ_2048); 86791398Stmm case 4096: 868172334Smarius return (GEM_RING_SZ_4096); 86991398Stmm case 8192: 870172334Smarius return (GEM_RING_SZ_8192); 87191398Stmm default: 872172334Smarius printf("%s: invalid ring size %d\n", __func__, sz); 873172334Smarius return (GEM_RING_SZ_32); 87491398Stmm } 87591398Stmm} 87691398Stmm 877148369Smariusstatic void 878174987Smariusgem_init(void *xsc) 879148369Smarius{ 880174987Smarius struct gem_softc *sc = xsc; 881148369Smarius 882148369Smarius GEM_LOCK(sc); 883148369Smarius gem_init_locked(sc); 884148369Smarius GEM_UNLOCK(sc); 885148369Smarius} 886148369Smarius 88791398Stmm/* 88891398Stmm * Initialization of interface; set up initialization block 88991398Stmm * and transmit/receive descriptor rings. 89091398Stmm */ 89191398Stmmstatic void 892174987Smariusgem_init_locked(struct gem_softc *sc) 89391398Stmm{ 894147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 895174987Smarius uint32_t v; 89691398Stmm 897148369Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 89891398Stmm 899115030Stmm#ifdef GEM_DEBUG 900170273Syongari CTR2(KTR_GEM, "%s: %s: calling stop", device_get_name(sc->sc_dev), 901170273Syongari __func__); 902115030Stmm#endif 90391398Stmm /* 904174987Smarius * Initialization sequence. The numbered steps below correspond 90591398Stmm * to the sequence outlined in section 6.3.5.1 in the Ethernet 90691398Stmm * Channel Engine manual (part of the PCIO manual). 90791398Stmm * See also the STP2002-STQ document from Sun Microsystems. 90891398Stmm */ 90991398Stmm 910174987Smarius /* step 1 & 2. Reset the Ethernet Channel. */ 911179925Smarius gem_stop(ifp, 0); 91291398Stmm gem_reset(sc); 913115030Stmm#ifdef GEM_DEBUG 914170273Syongari CTR2(KTR_GEM, "%s: %s: restarting", device_get_name(sc->sc_dev), 915170273Syongari __func__); 916115030Stmm#endif 91791398Stmm 918174987Smarius /* Re-initialize the MIF. */ 91991398Stmm gem_mifinit(sc); 92091398Stmm 921174987Smarius /* step 3. Setup data structures in host memory. */ 922172334Smarius if (gem_meminit(sc) != 0) 923172334Smarius return; 92491398Stmm 925174987Smarius /* step 4. TX MAC registers & counters */ 92691398Stmm gem_init_regs(sc); 92791398Stmm 928174987Smarius /* step 5. RX MAC registers & counters */ 92991398Stmm gem_setladrf(sc); 93091398Stmm 931174987Smarius /* step 6 & 7. Program Descriptor Ring Base Addresses. */ 93291398Stmm /* NOTE: we use only 32-bit DMA addresses here. */ 933177560Smarius GEM_BANK1_WRITE_4(sc, GEM_TX_RING_PTR_HI, 0); 934177560Smarius GEM_BANK1_WRITE_4(sc, GEM_TX_RING_PTR_LO, GEM_CDTXADDR(sc, 0)); 93591398Stmm 936177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_RING_PTR_HI, 0); 937177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0)); 938115030Stmm#ifdef GEM_DEBUG 939174987Smarius CTR3(KTR_GEM, "loading RX ring %lx, TX ring %lx, cddma %lx", 94091398Stmm GEM_CDRXADDR(sc, 0), GEM_CDTXADDR(sc, 0), sc->sc_cddma); 941115030Stmm#endif 94291398Stmm 943174987Smarius /* step 8. Global Configuration & Interrupt Mask */ 944194763Smarius 945194763Smarius /* 946194763Smarius * Set the internal arbitration to "infinite" bursts of the 947194763Smarius * maximum length of 31 * 64 bytes so DMA transfers aren't 948194763Smarius * split up in cache line size chunks. This greatly improves 949194763Smarius * RX performance. 950194763Smarius * Enable silicon bug workarounds for the Apple variants. 951194763Smarius */ 952194763Smarius GEM_BANK1_WRITE_4(sc, GEM_CONFIG, 953194763Smarius GEM_CONFIG_TXDMA_LIMIT | GEM_CONFIG_RXDMA_LIMIT | 954194763Smarius ((sc->sc_flags & GEM_PCI) != 0 ? GEM_CONFIG_BURST_INF : 955194763Smarius GEM_CONFIG_BURST_64) | (GEM_IS_APPLE(sc) ? 956194763Smarius GEM_CONFIG_RONPAULBIT | GEM_CONFIG_BUG2FIX : 0)); 957194763Smarius 958177560Smarius GEM_BANK1_WRITE_4(sc, GEM_INTMASK, 959172334Smarius ~(GEM_INTR_TX_INTME | GEM_INTR_TX_EMPTY | GEM_INTR_RX_DONE | 960172334Smarius GEM_INTR_RX_NOBUF | GEM_INTR_RX_TAG_ERR | GEM_INTR_PERR | 961172334Smarius GEM_INTR_BERR 962172334Smarius#ifdef GEM_DEBUG 963172334Smarius | GEM_INTR_PCS | GEM_INTR_MIF 964172334Smarius#endif 965172334Smarius )); 966177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_MASK, 967172334Smarius GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT); 968177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_MASK, 969194763Smarius GEM_MAC_TX_XMIT_DONE | GEM_MAC_TX_DEFER_EXP | 970194763Smarius GEM_MAC_TX_PEAK_EXP); 971172334Smarius#ifdef GEM_DEBUG 972177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_MASK, 973172334Smarius ~(GEM_MAC_PAUSED | GEM_MAC_PAUSE | GEM_MAC_RESUME)); 974172334Smarius#else 975177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_MASK, 976172334Smarius GEM_MAC_PAUSED | GEM_MAC_PAUSE | GEM_MAC_RESUME); 977172334Smarius#endif 97891398Stmm 979174987Smarius /* step 9. ETX Configuration: use mostly default values. */ 98091398Stmm 981174987Smarius /* Enable DMA. */ 982194763Smarius v = gem_ringsize(GEM_NTXDESC); 983194763Smarius /* Set TX FIFO threshold and enable DMA. */ 984179925Smarius v |= ((sc->sc_variant == GEM_SUN_ERI ? 0x100 : 0x4ff) << 10) & 985179925Smarius GEM_TX_CONFIG_TXFIFO_TH; 986179925Smarius GEM_BANK1_WRITE_4(sc, GEM_TX_CONFIG, v | GEM_TX_CONFIG_TXDMA_EN); 98791398Stmm 988174987Smarius /* step 10. ERX Configuration */ 98991398Stmm 990172334Smarius /* Encode Receive Descriptor ring size. */ 991174987Smarius v = gem_ringsize(GEM_NRXDESC /* XXX */); 992174987Smarius /* RX TCP/UDP checksum offset */ 993170273Syongari v |= ((ETHER_HDR_LEN + sizeof(struct ip)) << 994170273Syongari GEM_RX_CONFIG_CXM_START_SHFT); 995194763Smarius /* Set RX FIFO threshold, set first byte offset and enable DMA. */ 996177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_CONFIG, 997174987Smarius v | (GEM_THRSH_1024 << GEM_RX_CONFIG_FIFO_THRS_SHIFT) | 998194763Smarius (ETHER_ALIGN << GEM_RX_CONFIG_FBOFF_SHFT) | 999194763Smarius GEM_RX_CONFIG_RXDMA_EN); 1000172334Smarius 1001194763Smarius /* Adjust for the SBus clock probably isn't worth the fuzz. */ 1002177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_BLANKING, 1003194763Smarius ((6 * (sc->sc_flags & GEM_PCI66) != 0 ? 2 : 1) << 1004194763Smarius GEM_RX_BLANKING_TIME_SHIFT) | 6); 1005172334Smarius 100691398Stmm /* 100799726Sbenno * The following value is for an OFF Threshold of about 3/4 full 100899726Sbenno * and an ON Threshold of 1/4 full. 100991398Stmm */ 1010177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_PAUSE_THRESH, 101199726Sbenno (3 * sc->sc_rxfifosize / 256) | 1012174987Smarius ((sc->sc_rxfifosize / 256) << 12)); 101391398Stmm 1014174987Smarius /* step 11. Configure Media. */ 101591398Stmm 1016174987Smarius /* step 12. RX_MAC Configuration Register */ 1017177560Smarius v = GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG); 1018179925Smarius v |= GEM_MAC_RX_ENABLE | GEM_MAC_RX_STRIP_CRC; 1019177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, 0); 1020179925Smarius GEM_BANK1_BARRIER(sc, GEM_MAC_RX_CONFIG, 4, 1021179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 1022177560Smarius if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)) 1023179925Smarius device_printf(sc->sc_dev, "cannot configure RX MAC\n"); 1024177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, v); 102591398Stmm 1026194763Smarius /* step 13. TX_MAC Configuration Register */ 1027179925Smarius v = GEM_BANK1_READ_4(sc, GEM_MAC_TX_CONFIG); 1028179925Smarius v |= GEM_MAC_TX_ENABLE; 1029179925Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, 0); 1030179925Smarius GEM_BANK1_BARRIER(sc, GEM_MAC_TX_CONFIG, 4, 1031179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 1032179925Smarius if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)) 1033179925Smarius device_printf(sc->sc_dev, "cannot configure TX MAC\n"); 1034179925Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, v); 1035179925Smarius 1036174987Smarius /* step 14. Issue Transmit Pending command. */ 103791398Stmm 1038174987Smarius /* step 15. Give the reciever a swift kick. */ 1039177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_KICK, GEM_NRXDESC - 4); 104091398Stmm 1041172334Smarius ifp->if_drv_flags |= IFF_DRV_RUNNING; 1042172334Smarius ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1043172334Smarius 1044172334Smarius mii_mediachg(sc->sc_mii); 1045172334Smarius 104691398Stmm /* Start the one second timer. */ 1047164931Smarius sc->sc_wdog_timer = 0; 104891398Stmm callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc); 104991398Stmm} 105091398Stmm 105191398Stmmstatic int 1052174987Smariusgem_load_txmbuf(struct gem_softc *sc, struct mbuf **m_head) 105391398Stmm{ 1054174987Smarius bus_dma_segment_t txsegs[GEM_NTXSEGS]; 105591398Stmm struct gem_txsoft *txs; 1056179925Smarius struct ip *ip; 1057170273Syongari struct mbuf *m; 1058174987Smarius uint64_t cflags, flags; 1059179925Smarius int error, nexttx, nsegs, offset, seg; 106091398Stmm 1061194763Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1062194763Smarius 1063108832Stmm /* Get a work queue entry. */ 1064108832Stmm if ((txs = STAILQ_FIRST(&sc->sc_txfreeq)) == NULL) { 1065108832Stmm /* Ran out of descriptors. */ 1066170273Syongari return (ENOBUFS); 1067108832Stmm } 1068179925Smarius 1069179925Smarius cflags = 0; 1070179925Smarius if (((*m_head)->m_pkthdr.csum_flags & sc->sc_csum_features) != 0) { 1071179925Smarius if (M_WRITABLE(*m_head) == 0) { 1072179925Smarius m = m_dup(*m_head, M_DONTWAIT); 1073179925Smarius m_freem(*m_head); 1074179925Smarius *m_head = m; 1075179925Smarius if (m == NULL) 1076179925Smarius return (ENOBUFS); 1077179925Smarius } 1078179925Smarius offset = sizeof(struct ether_header); 1079179925Smarius m = m_pullup(*m_head, offset + sizeof(struct ip)); 1080179925Smarius if (m == NULL) { 1081179925Smarius *m_head = NULL; 1082179925Smarius return (ENOBUFS); 1083179925Smarius } 1084179925Smarius ip = (struct ip *)(mtod(m, caddr_t) + offset); 1085179925Smarius offset += (ip->ip_hl << 2); 1086179925Smarius cflags = offset << GEM_TD_CXSUM_STARTSHFT | 1087179925Smarius ((offset + m->m_pkthdr.csum_data) << 1088179925Smarius GEM_TD_CXSUM_STUFFSHFT) | GEM_TD_CXSUM_ENABLE; 1089179925Smarius *m_head = m; 1090179925Smarius } 1091179925Smarius 1092170273Syongari error = bus_dmamap_load_mbuf_sg(sc->sc_tdmatag, txs->txs_dmamap, 1093170273Syongari *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); 1094170273Syongari if (error == EFBIG) { 1095175418Sjhb m = m_collapse(*m_head, M_DONTWAIT, GEM_NTXSEGS); 1096170273Syongari if (m == NULL) { 1097170273Syongari m_freem(*m_head); 1098170273Syongari *m_head = NULL; 1099170273Syongari return (ENOBUFS); 1100170273Syongari } 1101170273Syongari *m_head = m; 1102174987Smarius error = bus_dmamap_load_mbuf_sg(sc->sc_tdmatag, 1103174987Smarius txs->txs_dmamap, *m_head, txsegs, &nsegs, 1104174987Smarius BUS_DMA_NOWAIT); 1105170273Syongari if (error != 0) { 1106170273Syongari m_freem(*m_head); 1107170273Syongari *m_head = NULL; 1108170273Syongari return (error); 1109170273Syongari } 1110170273Syongari } else if (error != 0) 1111170273Syongari return (error); 1112176996Smarius /* If nsegs is wrong then the stack is corrupt. */ 1113176996Smarius KASSERT(nsegs <= GEM_NTXSEGS, 1114176996Smarius ("%s: too many DMA segments (%d)", __func__, nsegs)); 1115170273Syongari if (nsegs == 0) { 1116170273Syongari m_freem(*m_head); 1117170273Syongari *m_head = NULL; 1118170273Syongari return (EIO); 1119170273Syongari } 1120170273Syongari 1121170273Syongari /* 1122170273Syongari * Ensure we have enough descriptors free to describe 1123170273Syongari * the packet. Note, we always reserve one descriptor 1124174987Smarius * at the end of the ring as a termination point, in 1125174987Smarius * order to prevent wrap-around. 1126170273Syongari */ 1127170273Syongari if (nsegs > sc->sc_txfree - 1) { 1128170273Syongari txs->txs_ndescs = 0; 1129170273Syongari bus_dmamap_unload(sc->sc_tdmatag, txs->txs_dmamap); 1130170273Syongari return (ENOBUFS); 1131170273Syongari } 1132170273Syongari 1133170273Syongari txs->txs_ndescs = nsegs; 1134108832Stmm txs->txs_firstdesc = sc->sc_txnext; 1135170273Syongari nexttx = txs->txs_firstdesc; 1136170273Syongari for (seg = 0; seg < nsegs; seg++, nexttx = GEM_NEXTTX(nexttx)) { 1137172334Smarius#ifdef GEM_DEBUG 1138174987Smarius CTR6(KTR_GEM, 1139174987Smarius "%s: mapping seg %d (txd %d), len %lx, addr %#lx (%#lx)", 1140174987Smarius __func__, seg, nexttx, txsegs[seg].ds_len, 1141174987Smarius txsegs[seg].ds_addr, 1142170273Syongari GEM_DMA_WRITE(sc, txsegs[seg].ds_addr)); 1143170273Syongari#endif 1144170273Syongari sc->sc_txdescs[nexttx].gd_addr = 1145170273Syongari GEM_DMA_WRITE(sc, txsegs[seg].ds_addr); 1146170273Syongari KASSERT(txsegs[seg].ds_len < GEM_TD_BUFSIZE, 1147170273Syongari ("%s: segment size too large!", __func__)); 1148170273Syongari flags = txsegs[seg].ds_len & GEM_TD_BUFSIZE; 1149170273Syongari sc->sc_txdescs[nexttx].gd_flags = 1150170273Syongari GEM_DMA_WRITE(sc, flags | cflags); 1151170273Syongari txs->txs_lastdesc = nexttx; 115291398Stmm } 115391398Stmm 1154174987Smarius /* Set EOP on the last descriptor. */ 1155172334Smarius#ifdef GEM_DEBUG 1156174987Smarius CTR3(KTR_GEM, "%s: end of packet at segment %d, TX %d", 1157174987Smarius __func__, seg, nexttx); 1158170273Syongari#endif 1159170273Syongari sc->sc_txdescs[txs->txs_lastdesc].gd_flags |= 1160170273Syongari GEM_DMA_WRITE(sc, GEM_TD_END_OF_PACKET); 1161170273Syongari 1162174987Smarius /* Lastly set SOP on the first descriptor. */ 1163172334Smarius#ifdef GEM_DEBUG 1164174987Smarius CTR3(KTR_GEM, "%s: start of packet at segment %d, TX %d", 1165174987Smarius __func__, seg, nexttx); 1166170273Syongari#endif 1167170273Syongari if (++sc->sc_txwin > GEM_NTXSEGS * 2 / 3) { 1168170273Syongari sc->sc_txwin = 0; 1169170273Syongari sc->sc_txdescs[txs->txs_firstdesc].gd_flags |= 1170170273Syongari GEM_DMA_WRITE(sc, GEM_TD_INTERRUPT_ME | 1171170273Syongari GEM_TD_START_OF_PACKET); 1172170273Syongari } else 1173170273Syongari sc->sc_txdescs[txs->txs_firstdesc].gd_flags |= 1174170273Syongari GEM_DMA_WRITE(sc, GEM_TD_START_OF_PACKET); 1175170273Syongari 1176108832Stmm /* Sync the DMA map. */ 1177174987Smarius bus_dmamap_sync(sc->sc_tdmatag, txs->txs_dmamap, 1178174987Smarius BUS_DMASYNC_PREWRITE); 117991398Stmm 1180115030Stmm#ifdef GEM_DEBUG 1181170273Syongari CTR4(KTR_GEM, "%s: setting firstdesc=%d, lastdesc=%d, ndescs=%d", 1182174987Smarius __func__, txs->txs_firstdesc, txs->txs_lastdesc, 1183174987Smarius txs->txs_ndescs); 1184115030Stmm#endif 1185108832Stmm STAILQ_REMOVE_HEAD(&sc->sc_txfreeq, txs_q); 1186108832Stmm STAILQ_INSERT_TAIL(&sc->sc_txdirtyq, txs, txs_q); 1187170273Syongari txs->txs_mbuf = *m_head; 118891398Stmm 1189108832Stmm sc->sc_txnext = GEM_NEXTTX(txs->txs_lastdesc); 1190108832Stmm sc->sc_txfree -= txs->txs_ndescs; 1191170273Syongari 1192108832Stmm return (0); 119391398Stmm} 119491398Stmm 119591398Stmmstatic void 1196174987Smariusgem_init_regs(struct gem_softc *sc) 119791398Stmm{ 1198152315Sru const u_char *laddr = IF_LLADDR(sc->sc_ifp); 119991398Stmm 1200194763Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1201194763Smarius 1202174987Smarius /* These registers are not cleared on reset. */ 1203172334Smarius if ((sc->sc_flags & GEM_INITED) == 0) { 1204174987Smarius /* magic values */ 1205177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_IPG0, 0); 1206177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_IPG1, 8); 1207177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_IPG2, 4); 120891398Stmm 1209194763Smarius /* min frame length */ 1210177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN); 1211194763Smarius /* max frame length and max burst size */ 1212177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_MAC_MAX_FRAME, 1213172334Smarius (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) | (0x2000 << 16)); 121499726Sbenno 1215194763Smarius /* more magic values */ 1216177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_PREAMBLE_LEN, 0x7); 1217177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_JAM_SIZE, 0x4); 1218177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ATTEMPT_LIMIT, 0x10); 1219177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_TYPE, 0x8088); 1220194763Smarius 1221194763Smarius /* random number seed */ 1222177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RANDOM_SEED, 1223174987Smarius ((laddr[5] << 8) | laddr[4]) & 0x3ff); 122499726Sbenno 1225174987Smarius /* secondary MAC address: 0:0:0:0:0:0 */ 1226177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR3, 0); 1227177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR4, 0); 1228177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR5, 0); 122999726Sbenno 1230174987Smarius /* MAC control address: 01:80:c2:00:00:01 */ 1231177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR6, 0x0001); 1232177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR7, 0xc200); 1233177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR8, 0x0180); 123491398Stmm 1235174987Smarius /* MAC filter address: 0:0:0:0:0:0 */ 1236177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR_FILTER0, 0); 1237177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR_FILTER1, 0); 1238177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR_FILTER2, 0); 1239177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADR_FLT_MASK1_2, 0); 1240177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADR_FLT_MASK0, 0); 124191398Stmm 1242172334Smarius sc->sc_flags |= GEM_INITED; 124391398Stmm } 124491398Stmm 1245174987Smarius /* Counters need to be zeroed. */ 1246177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_NORM_COLL_CNT, 0); 1247177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_FIRST_COLL_CNT, 0); 1248177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_EXCESS_COLL_CNT, 0); 1249177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_LATE_COLL_CNT, 0); 1250177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_DEFER_TMR_CNT, 0); 1251177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_PEAK_ATTEMPTS, 0); 1252177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_FRAME_COUNT, 0); 1253177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_LEN_ERR_CNT, 0); 1254177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_ALIGN_ERR, 0); 1255177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CRC_ERR_CNT, 0); 1256177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CODE_VIOL, 0); 125791398Stmm 1258172334Smarius /* Set XOFF PAUSE time. */ 1259177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_SEND_PAUSE_CMD, 0x1BF0); 126091398Stmm 1261174987Smarius /* Set the station address. */ 1262177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR0, (laddr[4] << 8) | laddr[5]); 1263177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR1, (laddr[2] << 8) | laddr[3]); 1264177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_ADDR2, (laddr[0] << 8) | laddr[1]); 126599726Sbenno 1266172334Smarius /* Enable MII outputs. */ 1267177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_XIF_CONFIG, GEM_MAC_XIF_TX_MII_ENA); 126891398Stmm} 126991398Stmm 127091398Stmmstatic void 1271174987Smariusgem_start(struct ifnet *ifp) 127291398Stmm{ 1273174987Smarius struct gem_softc *sc = ifp->if_softc; 1274148369Smarius 1275148369Smarius GEM_LOCK(sc); 1276148369Smarius gem_start_locked(ifp); 1277148369Smarius GEM_UNLOCK(sc); 1278148369Smarius} 1279148369Smarius 1280194763Smariusstatic inline void 1281194763Smariusgem_txkick(struct gem_softc *sc) 1282194763Smarius{ 1283194763Smarius 1284194763Smarius /* 1285194763Smarius * Update the TX kick register. This register has to point to the 1286194763Smarius * descriptor after the last valid one and for optimum performance 1287194763Smarius * should be incremented in multiples of 4 (the DMA engine fetches/ 1288194763Smarius * updates descriptors in batches of 4). 1289194763Smarius */ 1290194763Smarius#ifdef GEM_DEBUG 1291194763Smarius CTR3(KTR_GEM, "%s: %s: kicking TX %d", 1292194763Smarius device_get_name(sc->sc_dev), __func__, sc->sc_txnext); 1293194763Smarius#endif 1294194763Smarius GEM_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1295194763Smarius GEM_BANK1_WRITE_4(sc, GEM_TX_KICK, sc->sc_txnext); 1296194763Smarius} 1297194763Smarius 1298148369Smariusstatic void 1299174987Smariusgem_start_locked(struct ifnet *ifp) 1300148369Smarius{ 1301174987Smarius struct gem_softc *sc = ifp->if_softc; 1302170273Syongari struct mbuf *m; 1303194763Smarius int kicked, ntx; 130491398Stmm 1305194763Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1306194763Smarius 1307148887Srwatson if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1308172334Smarius IFF_DRV_RUNNING || (sc->sc_flags & GEM_LINK) == 0) 130991398Stmm return; 131091398Stmm 1311115030Stmm#ifdef GEM_DEBUG 1312170273Syongari CTR4(KTR_GEM, "%s: %s: txfree %d, txnext %d", 1313172334Smarius device_get_name(sc->sc_dev), __func__, sc->sc_txfree, 1314172334Smarius sc->sc_txnext); 1315115030Stmm#endif 1316174987Smarius ntx = 0; 1317194763Smarius kicked = 0; 1318170273Syongari for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && sc->sc_txfree > 1;) { 1319170273Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1320170273Syongari if (m == NULL) 132191398Stmm break; 1322172334Smarius if (gem_load_txmbuf(sc, &m) != 0) { 1323170273Syongari if (m == NULL) 1324170273Syongari break; 1325170273Syongari ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1326170273Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m); 132791398Stmm break; 132891398Stmm } 1329194763Smarius if ((sc->sc_txnext % 4) == 0) { 1330194763Smarius gem_txkick(sc); 1331194763Smarius kicked = 1; 1332194763Smarius } else 1333194763Smarius kicked = 0; 1334115030Stmm ntx++; 1335170273Syongari BPF_MTAP(ifp, m); 133691398Stmm } 133791398Stmm 133891398Stmm if (ntx > 0) { 1339194763Smarius if (kicked == 0) 1340194763Smarius gem_txkick(sc); 1341115030Stmm#ifdef GEM_DEBUG 1342108832Stmm CTR2(KTR_GEM, "%s: packets enqueued, OWN on %d", 1343172334Smarius device_get_name(sc->sc_dev), sc->sc_txnext); 1344115030Stmm#endif 134591398Stmm 134691398Stmm /* Set a watchdog timer in case the chip flakes out. */ 1347164931Smarius sc->sc_wdog_timer = 5; 1348115030Stmm#ifdef GEM_DEBUG 1349170273Syongari CTR3(KTR_GEM, "%s: %s: watchdog %d", 1350174987Smarius device_get_name(sc->sc_dev), __func__, 1351174987Smarius sc->sc_wdog_timer); 1352115030Stmm#endif 135391398Stmm } 135491398Stmm} 135591398Stmm 135691398Stmmstatic void 1357174987Smariusgem_tint(struct gem_softc *sc) 135891398Stmm{ 1359147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 136091398Stmm struct gem_txsoft *txs; 1361194763Smarius int progress; 1362194763Smarius uint32_t txlast; 1363174987Smarius#ifdef GEM_DEBUG 1364174987Smarius int i; 136591398Stmm 1366194763Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1367194763Smarius 1368170273Syongari CTR2(KTR_GEM, "%s: %s", device_get_name(sc->sc_dev), __func__); 1369115030Stmm#endif 137091398Stmm 137191398Stmm /* 1372174987Smarius * Go through our TX list and free mbufs for those 137391398Stmm * frames that have been transmitted. 137491398Stmm */ 1375174987Smarius progress = 0; 1376109648Stmm GEM_CDSYNC(sc, BUS_DMASYNC_POSTREAD); 137791398Stmm while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) { 137891398Stmm#ifdef GEM_DEBUG 1379174987Smarius if ((ifp->if_flags & IFF_DEBUG) != 0) { 138091398Stmm printf(" txsoft %p transmit chain:\n", txs); 138191398Stmm for (i = txs->txs_firstdesc;; i = GEM_NEXTTX(i)) { 138291398Stmm printf("descriptor %d: ", i); 1383174987Smarius printf("gd_flags: 0x%016llx\t", 1384174987Smarius (long long)GEM_DMA_READ(sc, 1385174987Smarius sc->sc_txdescs[i].gd_flags)); 1386174987Smarius printf("gd_addr: 0x%016llx\n", 1387174987Smarius (long long)GEM_DMA_READ(sc, 1388174987Smarius sc->sc_txdescs[i].gd_addr)); 138991398Stmm if (i == txs->txs_lastdesc) 139091398Stmm break; 139191398Stmm } 139291398Stmm } 139391398Stmm#endif 139491398Stmm 139591398Stmm /* 1396172334Smarius * In theory, we could harvest some descriptors before 139791398Stmm * the ring is empty, but that's a bit complicated. 139891398Stmm * 139991398Stmm * GEM_TX_COMPLETION points to the last descriptor 1400174987Smarius * processed + 1. 140191398Stmm */ 1402177560Smarius txlast = GEM_BANK1_READ_4(sc, GEM_TX_COMPLETION); 1403115030Stmm#ifdef GEM_DEBUG 1404170273Syongari CTR4(KTR_GEM, "%s: txs->txs_firstdesc = %d, " 140591398Stmm "txs->txs_lastdesc = %d, txlast = %d", 1406170273Syongari __func__, txs->txs_firstdesc, txs->txs_lastdesc, txlast); 1407115030Stmm#endif 140891398Stmm if (txs->txs_firstdesc <= txs->txs_lastdesc) { 140991398Stmm if ((txlast >= txs->txs_firstdesc) && 1410174987Smarius (txlast <= txs->txs_lastdesc)) 141191398Stmm break; 141291398Stmm } else { 1413174987Smarius /* Ick -- this command wraps. */ 141491398Stmm if ((txlast >= txs->txs_firstdesc) || 1415174987Smarius (txlast <= txs->txs_lastdesc)) 141691398Stmm break; 141791398Stmm } 141891398Stmm 1419115030Stmm#ifdef GEM_DEBUG 1420174987Smarius CTR1(KTR_GEM, "%s: releasing a descriptor", __func__); 1421115030Stmm#endif 142291398Stmm STAILQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q); 142391398Stmm 142491398Stmm sc->sc_txfree += txs->txs_ndescs; 142591398Stmm 1426108832Stmm bus_dmamap_sync(sc->sc_tdmatag, txs->txs_dmamap, 142791398Stmm BUS_DMASYNC_POSTWRITE); 1428108832Stmm bus_dmamap_unload(sc->sc_tdmatag, txs->txs_dmamap); 142991398Stmm if (txs->txs_mbuf != NULL) { 143091398Stmm m_freem(txs->txs_mbuf); 143191398Stmm txs->txs_mbuf = NULL; 143291398Stmm } 143391398Stmm 143491398Stmm STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); 143591398Stmm 143691398Stmm ifp->if_opackets++; 143799726Sbenno progress = 1; 143891398Stmm } 143991398Stmm 1440115030Stmm#ifdef GEM_DEBUG 1441174987Smarius CTR4(KTR_GEM, "%s: GEM_TX_STATE_MACHINE %x GEM_TX_DATA_PTR %llx " 1442172334Smarius "GEM_TX_COMPLETION %x", 1443177560Smarius __func__, GEM_BANK1_READ_4(sc, GEM_TX_STATE_MACHINE), 1444177560Smarius ((long long)GEM_BANK1_READ_4(sc, GEM_TX_DATA_PTR_HI) << 32) | 1445177560Smarius GEM_BANK1_READ_4(sc, GEM_TX_DATA_PTR_LO), 1446177560Smarius GEM_BANK1_READ_4(sc, GEM_TX_COMPLETION)); 1447115030Stmm#endif 144891398Stmm 144999726Sbenno if (progress) { 145099726Sbenno if (sc->sc_txfree == GEM_NTXDESC - 1) 145199726Sbenno sc->sc_txwin = 0; 145291398Stmm 1453174987Smarius /* 1454174987Smarius * We freed some descriptors, so reset IFF_DRV_OACTIVE 1455174987Smarius * and restart. 1456174987Smarius */ 1457148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1458194763Smarius if (STAILQ_EMPTY(&sc->sc_txdirtyq)) 1459194763Smarius sc->sc_wdog_timer = 0; 1460179925Smarius gem_start_locked(ifp); 146199726Sbenno } 146299726Sbenno 1463115030Stmm#ifdef GEM_DEBUG 1464170273Syongari CTR3(KTR_GEM, "%s: %s: watchdog %d", 1465170273Syongari device_get_name(sc->sc_dev), __func__, sc->sc_wdog_timer); 1466115030Stmm#endif 146791398Stmm} 146891398Stmm 1469148368Smarius#ifdef GEM_RINT_TIMEOUT 147093045Stmmstatic void 1471174987Smariusgem_rint_timeout(void *arg) 147293045Stmm{ 1473174987Smarius struct gem_softc *sc = arg; 147493045Stmm 1475150285Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1476194763Smarius 1477148369Smarius gem_rint(sc); 147893045Stmm} 1479100587Sjake#endif 148093045Stmm 148191398Stmmstatic void 1482174987Smariusgem_rint(struct gem_softc *sc) 148391398Stmm{ 1484147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 148591398Stmm struct mbuf *m; 1486174987Smarius uint64_t rxstat; 1487174987Smarius uint32_t rxcomp; 148891398Stmm 1489194763Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1490194763Smarius 1491148368Smarius#ifdef GEM_RINT_TIMEOUT 149293045Stmm callout_stop(&sc->sc_rx_ch); 1493148368Smarius#endif 1494115030Stmm#ifdef GEM_DEBUG 1495170273Syongari CTR2(KTR_GEM, "%s: %s", device_get_name(sc->sc_dev), __func__); 1496115030Stmm#endif 149799726Sbenno 149891398Stmm /* 149999726Sbenno * Read the completion register once. This limits 150099726Sbenno * how long the following loop can execute. 150199726Sbenno */ 1502177560Smarius rxcomp = GEM_BANK1_READ_4(sc, GEM_RX_COMPLETION); 1503115030Stmm#ifdef GEM_DEBUG 1504194763Smarius CTR3(KTR_GEM, "%s: sc->sc_rxptr %d, complete %d", 1505170273Syongari __func__, sc->sc_rxptr, rxcomp); 1506115030Stmm#endif 1507194763Smarius GEM_CDSYNC(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1508172334Smarius for (; sc->sc_rxptr != rxcomp;) { 1509172334Smarius m = sc->sc_rxsoft[sc->sc_rxptr].rxs_mbuf; 1510172334Smarius rxstat = GEM_DMA_READ(sc, 1511172334Smarius sc->sc_rxdescs[sc->sc_rxptr].gd_flags); 151291398Stmm 151391398Stmm if (rxstat & GEM_RD_OWN) { 1514148368Smarius#ifdef GEM_RINT_TIMEOUT 151591398Stmm /* 151693045Stmm * The descriptor is still marked as owned, although 1517174987Smarius * it is supposed to have completed. This has been 1518174987Smarius * observed on some machines. Just exiting here 151993045Stmm * might leave the packet sitting around until another 152093045Stmm * one arrives to trigger a new interrupt, which is 152193045Stmm * generally undesirable, so set up a timeout. 152291398Stmm */ 152393045Stmm callout_reset(&sc->sc_rx_ch, GEM_RXOWN_TICKS, 152493045Stmm gem_rint_timeout, sc); 152599726Sbenno#endif 1526172334Smarius m = NULL; 1527172334Smarius goto kickit; 152891398Stmm } 152991398Stmm 153091398Stmm if (rxstat & GEM_RD_BAD_CRC) { 153199726Sbenno ifp->if_ierrors++; 153291398Stmm device_printf(sc->sc_dev, "receive error: CRC error\n"); 1533172334Smarius GEM_INIT_RXDESC(sc, sc->sc_rxptr); 1534172334Smarius m = NULL; 1535172334Smarius goto kickit; 153691398Stmm } 153791398Stmm 153891398Stmm#ifdef GEM_DEBUG 1539174987Smarius if ((ifp->if_flags & IFF_DEBUG) != 0) { 1540172334Smarius printf(" rxsoft %p descriptor %d: ", 1541172334Smarius &sc->sc_rxsoft[sc->sc_rxptr], sc->sc_rxptr); 1542174987Smarius printf("gd_flags: 0x%016llx\t", 1543174987Smarius (long long)GEM_DMA_READ(sc, 1544174987Smarius sc->sc_rxdescs[sc->sc_rxptr].gd_flags)); 1545174987Smarius printf("gd_addr: 0x%016llx\n", 1546174987Smarius (long long)GEM_DMA_READ(sc, 1547174987Smarius sc->sc_rxdescs[sc->sc_rxptr].gd_addr)); 154891398Stmm } 154991398Stmm#endif 155091398Stmm 155191398Stmm /* 155291398Stmm * Allocate a new mbuf cluster. If that fails, we are 155391398Stmm * out of memory, and must drop the packet and recycle 155491398Stmm * the buffer that's already attached to this descriptor. 155591398Stmm */ 1556172334Smarius if (gem_add_rxbuf(sc, sc->sc_rxptr) != 0) { 155791398Stmm ifp->if_ierrors++; 1558172334Smarius GEM_INIT_RXDESC(sc, sc->sc_rxptr); 1559172334Smarius m = NULL; 1560172334Smarius } 1561172334Smarius 1562174987Smarius kickit: 1563174987Smarius /* 1564174987Smarius * Update the RX kick register. This register has to point 1565172334Smarius * to the descriptor after the last valid one (before the 1566194763Smarius * current batch) and for optimum performance should be 1567194763Smarius * incremented in multiples of 4 (the DMA engine fetches/ 1568194763Smarius * updates descriptors in batches of 4). 1569172334Smarius */ 1570172334Smarius sc->sc_rxptr = GEM_NEXTRX(sc->sc_rxptr); 1571172334Smarius if ((sc->sc_rxptr % 4) == 0) { 1572179925Smarius GEM_CDSYNC(sc, 1573179925Smarius BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1574177560Smarius GEM_BANK1_WRITE_4(sc, GEM_RX_KICK, 1575172334Smarius (sc->sc_rxptr + GEM_NRXDESC - 4) & 1576172334Smarius GEM_NRXDESC_MASK); 1577172334Smarius } 1578172334Smarius 1579172334Smarius if (m == NULL) { 1580172334Smarius if (rxstat & GEM_RD_OWN) 1581172334Smarius break; 158291398Stmm continue; 158391398Stmm } 1584172334Smarius 1585172334Smarius ifp->if_ipackets++; 1586194763Smarius m->m_data += ETHER_ALIGN; /* first byte offset */ 158791398Stmm m->m_pkthdr.rcvif = ifp; 1588172334Smarius m->m_pkthdr.len = m->m_len = GEM_RD_BUFLEN(rxstat); 158991398Stmm 1590170273Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 1591170273Syongari gem_rxcksum(m, rxstat); 1592170273Syongari 159391398Stmm /* Pass it on. */ 1594148369Smarius GEM_UNLOCK(sc); 1595106937Ssam (*ifp->if_input)(ifp, m); 1596148369Smarius GEM_LOCK(sc); 159791398Stmm } 159891398Stmm 1599115030Stmm#ifdef GEM_DEBUG 1600194763Smarius CTR3(KTR_GEM, "%s: done sc->sc_rxptr %d, complete %d", __func__, 1601177560Smarius sc->sc_rxptr, GEM_BANK1_READ_4(sc, GEM_RX_COMPLETION)); 1602115030Stmm#endif 160391398Stmm} 160491398Stmm 160591398Stmmstatic int 1606174987Smariusgem_add_rxbuf(struct gem_softc *sc, int idx) 160791398Stmm{ 160891398Stmm struct gem_rxsoft *rxs = &sc->sc_rxsoft[idx]; 160991398Stmm struct mbuf *m; 1610148368Smarius bus_dma_segment_t segs[1]; 1611148368Smarius int error, nsegs; 161291398Stmm 1613194763Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1614194763Smarius 1615111119Simp m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 161691398Stmm if (m == NULL) 161791398Stmm return (ENOBUFS); 1618108832Stmm m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 161991398Stmm 162091398Stmm#ifdef GEM_DEBUG 1621174987Smarius /* Bzero the packet to check DMA. */ 162291398Stmm memset(m->m_ext.ext_buf, 0, m->m_ext.ext_size); 162391398Stmm#endif 162491398Stmm 1625109648Stmm if (rxs->rxs_mbuf != NULL) { 1626109648Stmm bus_dmamap_sync(sc->sc_rdmatag, rxs->rxs_dmamap, 1627109648Stmm BUS_DMASYNC_POSTREAD); 1628108832Stmm bus_dmamap_unload(sc->sc_rdmatag, rxs->rxs_dmamap); 1629109648Stmm } 163091398Stmm 1631148368Smarius error = bus_dmamap_load_mbuf_sg(sc->sc_rdmatag, rxs->rxs_dmamap, 1632148368Smarius m, segs, &nsegs, BUS_DMA_NOWAIT); 1633148368Smarius if (error != 0) { 1634174987Smarius device_printf(sc->sc_dev, 1635174987Smarius "cannot load RS DMA map %d, error = %d\n", idx, error); 1636148368Smarius m_freem(m); 1637172334Smarius return (error); 163891398Stmm } 1639174987Smarius /* If nsegs is wrong then the stack is corrupt. */ 1640176996Smarius KASSERT(nsegs == 1, 1641176996Smarius ("%s: too many DMA segments (%d)", __func__, nsegs)); 1642172334Smarius rxs->rxs_mbuf = m; 1643148368Smarius rxs->rxs_paddr = segs[0].ds_addr; 164491398Stmm 1645174987Smarius bus_dmamap_sync(sc->sc_rdmatag, rxs->rxs_dmamap, 1646174987Smarius BUS_DMASYNC_PREREAD); 164791398Stmm 164891398Stmm GEM_INIT_RXDESC(sc, idx); 164991398Stmm 165091398Stmm return (0); 165191398Stmm} 165291398Stmm 165391398Stmmstatic void 1654174987Smariusgem_eint(struct gem_softc *sc, u_int status) 165591398Stmm{ 165691398Stmm 1657172334Smarius sc->sc_ifp->if_ierrors++; 1658172334Smarius if ((status & GEM_INTR_RX_TAG_ERR) != 0) { 1659172334Smarius gem_reset_rxdma(sc); 166091398Stmm return; 166191398Stmm } 166291398Stmm 1663194763Smarius device_printf(sc->sc_dev, "%s: status 0x%x", __func__, status); 1664194763Smarius if ((status & GEM_INTR_BERR) != 0) { 1665194763Smarius if ((sc->sc_flags & GEM_PCI) != 0) 1666194763Smarius printf(", PCI bus error 0x%x\n", 1667194763Smarius GEM_BANK1_READ_4(sc, GEM_PCI_ERROR_STATUS)); 1668194763Smarius else 1669194763Smarius printf(", SBus error 0x%x\n", 1670194763Smarius GEM_BANK1_READ_4(sc, GEM_SBUS_STATUS)); 1671194763Smarius } 167291398Stmm} 167391398Stmm 167491398Stmmvoid 1675174987Smariusgem_intr(void *v) 167691398Stmm{ 1677174987Smarius struct gem_softc *sc = v; 1678172334Smarius uint32_t status, status2; 167991398Stmm 1680148369Smarius GEM_LOCK(sc); 1681177560Smarius status = GEM_BANK1_READ_4(sc, GEM_STATUS); 1682172334Smarius 1683115030Stmm#ifdef GEM_DEBUG 1684170273Syongari CTR4(KTR_GEM, "%s: %s: cplt %x, status %x", 1685194763Smarius device_get_name(sc->sc_dev), __func__, 1686194763Smarius (status >> GEM_STATUS_TX_COMPLETION_SHFT), (u_int)status); 1687172334Smarius 1688172334Smarius /* 1689172334Smarius * PCS interrupts must be cleared, otherwise no traffic is passed! 1690172334Smarius */ 1691172334Smarius if ((status & GEM_INTR_PCS) != 0) { 1692174987Smarius status2 = 1693177560Smarius GEM_BANK1_READ_4(sc, GEM_MII_INTERRUP_STATUS) | 1694177560Smarius GEM_BANK1_READ_4(sc, GEM_MII_INTERRUP_STATUS); 1695172334Smarius if ((status2 & GEM_MII_INTERRUP_LINK) != 0) 1696172334Smarius device_printf(sc->sc_dev, 1697172334Smarius "%s: PCS link status changed\n", __func__); 1698172334Smarius } 1699172334Smarius if ((status & GEM_MAC_CONTROL_STATUS) != 0) { 1700177560Smarius status2 = GEM_BANK1_READ_4(sc, GEM_MAC_CONTROL_STATUS); 1701172334Smarius if ((status2 & GEM_MAC_PAUSED) != 0) 1702172334Smarius device_printf(sc->sc_dev, 1703172334Smarius "%s: PAUSE received (PAUSE time %d slots)\n", 1704172334Smarius __func__, GEM_MAC_PAUSE_TIME(status2)); 1705172334Smarius if ((status2 & GEM_MAC_PAUSE) != 0) 1706172334Smarius device_printf(sc->sc_dev, 1707172334Smarius "%s: transited to PAUSE state\n", __func__); 1708172334Smarius if ((status2 & GEM_MAC_RESUME) != 0) 1709172334Smarius device_printf(sc->sc_dev, 1710172334Smarius "%s: transited to non-PAUSE state\n", __func__); 1711172334Smarius } 1712172334Smarius if ((status & GEM_INTR_MIF) != 0) 1713172334Smarius device_printf(sc->sc_dev, "%s: MIF interrupt\n", __func__); 1714115030Stmm#endif 171591398Stmm 1716194763Smarius if (__predict_false(status & 1717172334Smarius (GEM_INTR_RX_TAG_ERR | GEM_INTR_PERR | GEM_INTR_BERR)) != 0) 171891398Stmm gem_eint(sc, status); 171991398Stmm 1720172334Smarius if ((status & (GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF)) != 0) 1721172334Smarius gem_rint(sc); 1722172334Smarius 172391398Stmm if ((status & (GEM_INTR_TX_EMPTY | GEM_INTR_TX_INTME)) != 0) 172491398Stmm gem_tint(sc); 172591398Stmm 1726194763Smarius if (__predict_false((status & GEM_INTR_TX_MAC) != 0)) { 1727177560Smarius status2 = GEM_BANK1_READ_4(sc, GEM_MAC_TX_STATUS); 1728174987Smarius if ((status2 & 1729194763Smarius ~(GEM_MAC_TX_XMIT_DONE | GEM_MAC_TX_DEFER_EXP | 1730194763Smarius GEM_MAC_TX_PEAK_EXP)) != 0) 1731174987Smarius device_printf(sc->sc_dev, 1732174987Smarius "MAC TX fault, status %x\n", status2); 1733174987Smarius if ((status2 & 1734194763Smarius (GEM_MAC_TX_UNDERRUN | GEM_MAC_TX_PKT_TOO_LONG)) != 0) { 1735194763Smarius sc->sc_ifp->if_oerrors++; 1736148369Smarius gem_init_locked(sc); 1737194763Smarius } 173891398Stmm } 1739194763Smarius if (__predict_false((status & GEM_INTR_RX_MAC) != 0)) { 1740177560Smarius status2 = GEM_BANK1_READ_4(sc, GEM_MAC_RX_STATUS); 1741149552Smarius /* 1742172334Smarius * At least with GEM_SUN_GEM and some GEM_SUN_ERI 1743172334Smarius * revisions GEM_MAC_RX_OVERFLOW happen often due to a 1744174987Smarius * silicon bug so handle them silently. Moreover, it's 1745172334Smarius * likely that the receiver has hung so we reset it. 1746149552Smarius */ 1747174987Smarius if ((status2 & GEM_MAC_RX_OVERFLOW) != 0) { 1748172334Smarius sc->sc_ifp->if_ierrors++; 1749172334Smarius gem_reset_rxdma(sc); 1750174987Smarius } else if ((status2 & 1751174987Smarius ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT)) != 0) 1752174987Smarius device_printf(sc->sc_dev, 1753174987Smarius "MAC RX fault, status %x\n", status2); 175491398Stmm } 1755148369Smarius GEM_UNLOCK(sc); 175691398Stmm} 175791398Stmm 1758164931Smariusstatic int 1759174987Smariusgem_watchdog(struct gem_softc *sc) 176091398Stmm{ 1761179925Smarius struct ifnet *ifp = sc->sc_ifp; 176291398Stmm 1763164931Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1764164931Smarius 1765115030Stmm#ifdef GEM_DEBUG 1766174987Smarius CTR4(KTR_GEM, 1767174987Smarius "%s: GEM_RX_CONFIG %x GEM_MAC_RX_STATUS %x GEM_MAC_RX_CONFIG %x", 1768177560Smarius __func__, GEM_BANK1_READ_4(sc, GEM_RX_CONFIG), 1769177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_RX_STATUS), 1770177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG)); 1771174987Smarius CTR4(KTR_GEM, 1772174987Smarius "%s: GEM_TX_CONFIG %x GEM_MAC_TX_STATUS %x GEM_MAC_TX_CONFIG %x", 1773177560Smarius __func__, GEM_BANK1_READ_4(sc, GEM_TX_CONFIG), 1774177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_TX_STATUS), 1775177560Smarius GEM_BANK1_READ_4(sc, GEM_MAC_TX_CONFIG)); 1776115030Stmm#endif 177791398Stmm 1778164931Smarius if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) 1779164931Smarius return (0); 1780164931Smarius 1781172334Smarius if ((sc->sc_flags & GEM_LINK) != 0) 1782172334Smarius device_printf(sc->sc_dev, "device timeout\n"); 1783172334Smarius else if (bootverbose) 1784172334Smarius device_printf(sc->sc_dev, "device timeout (no link)\n"); 1785179925Smarius ++ifp->if_oerrors; 178691398Stmm 178791398Stmm /* Try to get more packets going. */ 1788148369Smarius gem_init_locked(sc); 1789179925Smarius gem_start_locked(ifp); 1790164931Smarius return (EJUSTRETURN); 179191398Stmm} 179291398Stmm 179391398Stmmstatic void 1794174987Smariusgem_mifinit(struct gem_softc *sc) 179591398Stmm{ 179691398Stmm 1797176996Smarius /* Configure the MIF in frame mode. */ 1798177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MIF_CONFIG, 1799177560Smarius GEM_BANK1_READ_4(sc, GEM_MIF_CONFIG) & ~GEM_MIF_CONFIG_BB_ENA); 180091398Stmm} 180191398Stmm 180291398Stmm/* 180391398Stmm * MII interface 180491398Stmm * 1805182060Smarius * The MII interface supports at least three different operating modes: 180691398Stmm * 180791398Stmm * Bitbang mode is implemented using data, clock and output enable registers. 180891398Stmm * 180991398Stmm * Frame mode is implemented by loading a complete frame into the frame 181091398Stmm * register and polling the valid bit for completion. 181191398Stmm * 181291398Stmm * Polling mode uses the frame register but completion is indicated by 181391398Stmm * an interrupt. 181491398Stmm * 181591398Stmm */ 181691398Stmmint 1817174987Smariusgem_mii_readreg(device_t dev, int phy, int reg) 181891398Stmm{ 1819174987Smarius struct gem_softc *sc; 182091398Stmm int n; 1821174987Smarius uint32_t v; 182291398Stmm 182391398Stmm#ifdef GEM_DEBUG_PHY 1824172334Smarius printf("%s: phy %d reg %d\n", __func__, phy, reg); 182591398Stmm#endif 182691398Stmm 1827174987Smarius sc = device_get_softc(dev); 1828172334Smarius if (sc->sc_phyad != -1 && phy != sc->sc_phyad) 1829172334Smarius return (0); 183091398Stmm 1831172334Smarius if ((sc->sc_flags & GEM_SERDES) != 0) { 1832172334Smarius switch (reg) { 1833172334Smarius case MII_BMCR: 1834172334Smarius reg = GEM_MII_CONTROL; 1835172334Smarius break; 1836172334Smarius case MII_BMSR: 1837172334Smarius reg = GEM_MII_STATUS; 1838172334Smarius break; 1839172334Smarius case MII_PHYIDR1: 1840172334Smarius case MII_PHYIDR2: 1841172334Smarius return (0); 1842172334Smarius case MII_ANAR: 1843172334Smarius reg = GEM_MII_ANAR; 1844172334Smarius break; 1845172334Smarius case MII_ANLPAR: 1846172334Smarius reg = GEM_MII_ANLPAR; 1847172334Smarius break; 1848172334Smarius case MII_EXTSR: 1849172334Smarius return (EXTSR_1000XFDX | EXTSR_1000XHDX); 1850172334Smarius default: 1851172334Smarius device_printf(sc->sc_dev, 1852172334Smarius "%s: unhandled register %d\n", __func__, reg); 1853172334Smarius return (0); 1854172334Smarius } 1855177560Smarius return (GEM_BANK1_READ_4(sc, reg)); 1856172334Smarius } 1857172334Smarius 1858174987Smarius /* Construct the frame command. */ 1859172334Smarius v = GEM_MIF_FRAME_READ | 1860172334Smarius (phy << GEM_MIF_PHY_SHIFT) | 1861172334Smarius (reg << GEM_MIF_REG_SHIFT); 186291398Stmm 1863177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MIF_FRAME, v); 1864179925Smarius GEM_BANK1_BARRIER(sc, GEM_MIF_FRAME, 4, 1865179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 186691398Stmm for (n = 0; n < 100; n++) { 186791398Stmm DELAY(1); 1868177560Smarius v = GEM_BANK1_READ_4(sc, GEM_MIF_FRAME); 1869150285Smarius if (v & GEM_MIF_FRAME_TA0) 187091398Stmm return (v & GEM_MIF_FRAME_DATA); 187191398Stmm } 187291398Stmm 1873174987Smarius device_printf(sc->sc_dev, "%s: timed out\n", __func__); 187491398Stmm return (0); 187591398Stmm} 187691398Stmm 187791398Stmmint 1878174987Smariusgem_mii_writereg(device_t dev, int phy, int reg, int val) 187991398Stmm{ 1880174987Smarius struct gem_softc *sc; 188191398Stmm int n; 1882174987Smarius uint32_t v; 188391398Stmm 188491398Stmm#ifdef GEM_DEBUG_PHY 1885172334Smarius printf("%s: phy %d reg %d val %x\n", phy, reg, val, __func__); 188691398Stmm#endif 188791398Stmm 1888174987Smarius sc = device_get_softc(dev); 1889172334Smarius if (sc->sc_phyad != -1 && phy != sc->sc_phyad) 1890172334Smarius return (0); 1891172334Smarius 1892172334Smarius if ((sc->sc_flags & GEM_SERDES) != 0) { 1893172334Smarius switch (reg) { 1894172334Smarius case MII_BMSR: 1895172334Smarius reg = GEM_MII_STATUS; 1896172334Smarius break; 1897179925Smarius case MII_BMCR: 1898179925Smarius reg = GEM_MII_CONTROL; 1899179925Smarius if ((val & GEM_MII_CONTROL_RESET) == 0) 1900179925Smarius break; 1901179925Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_CONTROL, val); 1902179925Smarius GEM_BANK1_BARRIER(sc, GEM_MII_CONTROL, 4, 1903179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 1904179925Smarius if (!GEM_BANK1_BITWAIT(sc, GEM_MII_CONTROL, 1905179925Smarius GEM_MII_CONTROL_RESET, 0)) 1906179925Smarius device_printf(sc->sc_dev, 1907179925Smarius "cannot reset PCS\n"); 1908179925Smarius /* FALLTHROUGH */ 1909172334Smarius case MII_ANAR: 1910177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_CONFIG, 0); 1911177560Smarius GEM_BANK1_BARRIER(sc, GEM_MII_CONFIG, 4, 1912172334Smarius BUS_SPACE_BARRIER_WRITE); 1913177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_ANAR, val); 1914177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_SLINK_CONTROL, 1915172334Smarius GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_EN_SYNC_D); 1916177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MII_CONFIG, 1917172334Smarius GEM_MII_CONFIG_ENABLE); 1918172334Smarius return (0); 1919172334Smarius case MII_ANLPAR: 1920172334Smarius reg = GEM_MII_ANLPAR; 1921172334Smarius break; 1922172334Smarius default: 1923172334Smarius device_printf(sc->sc_dev, 1924172334Smarius "%s: unhandled register %d\n", __func__, reg); 1925172334Smarius return (0); 1926172334Smarius } 1927177560Smarius GEM_BANK1_WRITE_4(sc, reg, val); 1928172334Smarius return (0); 1929172334Smarius } 1930172334Smarius 1931174987Smarius /* Construct the frame command. */ 1932172334Smarius v = GEM_MIF_FRAME_WRITE | 1933172334Smarius (phy << GEM_MIF_PHY_SHIFT) | 1934172334Smarius (reg << GEM_MIF_REG_SHIFT) | 193591398Stmm (val & GEM_MIF_FRAME_DATA); 193691398Stmm 1937177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MIF_FRAME, v); 1938179925Smarius GEM_BANK1_BARRIER(sc, GEM_MIF_FRAME, 4, 1939179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 194091398Stmm for (n = 0; n < 100; n++) { 194191398Stmm DELAY(1); 1942177560Smarius v = GEM_BANK1_READ_4(sc, GEM_MIF_FRAME); 1943150285Smarius if (v & GEM_MIF_FRAME_TA0) 194491398Stmm return (1); 194591398Stmm } 194691398Stmm 1947174987Smarius device_printf(sc->sc_dev, "%s: timed out\n", __func__); 194891398Stmm return (0); 194991398Stmm} 195091398Stmm 195191398Stmmvoid 1952174987Smariusgem_mii_statchg(device_t dev) 195391398Stmm{ 1954174987Smarius struct gem_softc *sc; 1955172334Smarius int gigabit; 1956172334Smarius uint32_t rxcfg, txcfg, v; 195791398Stmm 1958174987Smarius sc = device_get_softc(dev); 1959174987Smarius 1960194763Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 1961194763Smarius 196291398Stmm#ifdef GEM_DEBUG 1963174987Smarius if ((sc->sc_ifp->if_flags & IFF_DEBUG) != 0) 1964172334Smarius device_printf(sc->sc_dev, "%s: status change: PHY = %d\n", 1965172334Smarius __func__, sc->sc_phyad); 196691398Stmm#endif 196791398Stmm 1968172334Smarius if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) != 0 && 1969172334Smarius IFM_SUBTYPE(sc->sc_mii->mii_media_active) != IFM_NONE) 1970172334Smarius sc->sc_flags |= GEM_LINK; 1971172334Smarius else 1972172334Smarius sc->sc_flags &= ~GEM_LINK; 1973172334Smarius 1974172334Smarius switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) { 1975172334Smarius case IFM_1000_SX: 1976172334Smarius case IFM_1000_LX: 1977172334Smarius case IFM_1000_CX: 1978172334Smarius case IFM_1000_T: 1979172334Smarius gigabit = 1; 1980172334Smarius break; 1981172334Smarius default: 1982172334Smarius gigabit = 0; 198391398Stmm } 198491398Stmm 1985172334Smarius /* 1986172334Smarius * The configuration done here corresponds to the steps F) and 1987172334Smarius * G) and as far as enabling of RX and TX MAC goes also step H) 1988172334Smarius * of the initialization sequence outlined in section 3.2.1 of 1989172334Smarius * the GEM Gigabit Ethernet ASIC Specification. 1990172334Smarius */ 1991172334Smarius 1992177560Smarius rxcfg = GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG); 1993172334Smarius rxcfg &= ~(GEM_MAC_RX_CARR_EXTEND | GEM_MAC_RX_ENABLE); 1994172334Smarius txcfg = GEM_MAC_TX_ENA_IPG0 | GEM_MAC_TX_NGU | GEM_MAC_TX_NGU_LIMIT; 1995172334Smarius if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0) 1996172334Smarius txcfg |= GEM_MAC_TX_IGN_CARRIER | GEM_MAC_TX_IGN_COLLIS; 1997172334Smarius else if (gigabit != 0) { 1998172334Smarius rxcfg |= GEM_MAC_RX_CARR_EXTEND; 1999172334Smarius txcfg |= GEM_MAC_TX_CARR_EXTEND; 2000172334Smarius } 2001177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, 0); 2002179925Smarius GEM_BANK1_BARRIER(sc, GEM_MAC_TX_CONFIG, 4, 2003179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 2004177560Smarius if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)) 2005172334Smarius device_printf(sc->sc_dev, "cannot disable TX MAC\n"); 2006177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, txcfg); 2007177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, 0); 2008179925Smarius GEM_BANK1_BARRIER(sc, GEM_MAC_RX_CONFIG, 4, 2009179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 2010177560Smarius if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)) 2011172334Smarius device_printf(sc->sc_dev, "cannot disable RX MAC\n"); 2012177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, rxcfg); 2013172334Smarius 2014177560Smarius v = GEM_BANK1_READ_4(sc, GEM_MAC_CONTROL_CONFIG) & 2015172334Smarius ~(GEM_MAC_CC_RX_PAUSE | GEM_MAC_CC_TX_PAUSE); 2016172334Smarius#ifdef notyet 2017174987Smarius if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 2018174987Smarius IFM_ETH_RXPAUSE) != 0) 2019172334Smarius v |= GEM_MAC_CC_RX_PAUSE; 2020174987Smarius if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 2021174987Smarius IFM_ETH_TXPAUSE) != 0) 2022172334Smarius v |= GEM_MAC_CC_TX_PAUSE; 2023172334Smarius#endif 2024177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_CONFIG, v); 2025172334Smarius 2026172334Smarius if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) == 0 && 2027172334Smarius gigabit != 0) 2028177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_SLOT_TIME, 2029172334Smarius GEM_MAC_SLOT_TIME_CARR_EXTEND); 2030172334Smarius else 2031177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_SLOT_TIME, 2032172334Smarius GEM_MAC_SLOT_TIME_NORMAL); 2033172334Smarius 203491398Stmm /* XIF Configuration */ 203591398Stmm v = GEM_MAC_XIF_LINK_LED; 203691398Stmm v |= GEM_MAC_XIF_TX_MII_ENA; 2037172334Smarius if ((sc->sc_flags & GEM_SERDES) == 0) { 2038177560Smarius if ((GEM_BANK1_READ_4(sc, GEM_MIF_CONFIG) & 2039182060Smarius GEM_MIF_CONFIG_PHY_SEL) != 0) { 2040172334Smarius /* External MII needs echo disable if half duplex. */ 2041194763Smarius if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 2042182060Smarius IFM_FDX) == 0) 2043182060Smarius v |= GEM_MAC_XIF_ECHO_DISABL; 2044182060Smarius } else 2045172334Smarius /* 2046172334Smarius * Internal MII needs buffer enable. 2047172334Smarius * XXX buffer enable makes only sense for an 2048172334Smarius * external PHY. 2049172334Smarius */ 2050172334Smarius v |= GEM_MAC_XIF_MII_BUF_ENA; 2051172334Smarius } 2052172334Smarius if (gigabit != 0) 2053172334Smarius v |= GEM_MAC_XIF_GMII_MODE; 2054172334Smarius if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0) 2055172334Smarius v |= GEM_MAC_XIF_FDPLX_LED; 2056177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_XIF_CONFIG, v); 205799726Sbenno 2058172334Smarius if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 2059172334Smarius (sc->sc_flags & GEM_LINK) != 0) { 2060177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, 2061172334Smarius txcfg | GEM_MAC_TX_ENABLE); 2062177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, 2063172334Smarius rxcfg | GEM_MAC_RX_ENABLE); 206491398Stmm } 206591398Stmm} 206691398Stmm 206791398Stmmint 2068174987Smariusgem_mediachange(struct ifnet *ifp) 206991398Stmm{ 207091398Stmm struct gem_softc *sc = ifp->if_softc; 2071150285Smarius int error; 207291398Stmm 2073174987Smarius /* XXX add support for serial media. */ 207491398Stmm 2075150285Smarius GEM_LOCK(sc); 2076150285Smarius error = mii_mediachg(sc->sc_mii); 2077150285Smarius GEM_UNLOCK(sc); 2078150285Smarius return (error); 207991398Stmm} 208091398Stmm 208191398Stmmvoid 2082174987Smariusgem_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 208391398Stmm{ 208491398Stmm struct gem_softc *sc = ifp->if_softc; 208591398Stmm 2086148369Smarius GEM_LOCK(sc); 2087148369Smarius if ((ifp->if_flags & IFF_UP) == 0) { 2088148369Smarius GEM_UNLOCK(sc); 208991398Stmm return; 2090148369Smarius } 209191398Stmm 209291398Stmm mii_pollstat(sc->sc_mii); 209391398Stmm ifmr->ifm_active = sc->sc_mii->mii_media_active; 209491398Stmm ifmr->ifm_status = sc->sc_mii->mii_media_status; 2095148369Smarius GEM_UNLOCK(sc); 209691398Stmm} 209791398Stmm 209891398Stmmstatic int 2099174987Smariusgem_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 210091398Stmm{ 210191398Stmm struct gem_softc *sc = ifp->if_softc; 210291398Stmm struct ifreq *ifr = (struct ifreq *)data; 2103174987Smarius int error; 210491398Stmm 2105174987Smarius error = 0; 210691398Stmm switch (cmd) { 2107150285Smarius case SIOCSIFFLAGS: 2108148369Smarius GEM_LOCK(sc); 2109174987Smarius if ((ifp->if_flags & IFF_UP) != 0) { 2110172334Smarius if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 2111172334Smarius ((ifp->if_flags ^ sc->sc_ifflags) & 2112172334Smarius (IFF_ALLMULTI | IFF_PROMISC)) != 0) 211391398Stmm gem_setladrf(sc); 211491398Stmm else 2115148369Smarius gem_init_locked(sc); 2116174987Smarius } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 2117174987Smarius gem_stop(ifp, 0); 2118170273Syongari if ((ifp->if_flags & IFF_LINK0) != 0) 2119170273Syongari sc->sc_csum_features |= CSUM_UDP; 2120170273Syongari else 2121170273Syongari sc->sc_csum_features &= ~CSUM_UDP; 2122170273Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 2123170273Syongari ifp->if_hwassist = sc->sc_csum_features; 212499726Sbenno sc->sc_ifflags = ifp->if_flags; 2125150285Smarius GEM_UNLOCK(sc); 212691398Stmm break; 212791398Stmm case SIOCADDMULTI: 212891398Stmm case SIOCDELMULTI: 2129150285Smarius GEM_LOCK(sc); 213091398Stmm gem_setladrf(sc); 2131150285Smarius GEM_UNLOCK(sc); 213291398Stmm break; 213391398Stmm case SIOCGIFMEDIA: 213491398Stmm case SIOCSIFMEDIA: 213591398Stmm error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, cmd); 213691398Stmm break; 2137170273Syongari case SIOCSIFCAP: 2138170273Syongari GEM_LOCK(sc); 2139170273Syongari ifp->if_capenable = ifr->ifr_reqcap; 2140170273Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 2141170273Syongari ifp->if_hwassist = sc->sc_csum_features; 2142170273Syongari else 2143170273Syongari ifp->if_hwassist = 0; 2144170273Syongari GEM_UNLOCK(sc); 2145170273Syongari break; 214691398Stmm default: 2147150285Smarius error = ether_ioctl(ifp, cmd, data); 214891398Stmm break; 214991398Stmm } 215091398Stmm 215191398Stmm return (error); 215291398Stmm} 215391398Stmm 215491398Stmmstatic void 2155174987Smariusgem_setladrf(struct gem_softc *sc) 215691398Stmm{ 2157147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 215891398Stmm struct ifmultiaddr *inm; 215999726Sbenno int i; 2160174987Smarius uint32_t hash[16]; 2161174987Smarius uint32_t crc, v; 216291398Stmm 2163148369Smarius GEM_LOCK_ASSERT(sc, MA_OWNED); 2164148369Smarius 2165174987Smarius /* Get the current RX configuration. */ 2166177560Smarius v = GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG); 216791398Stmm 216899726Sbenno /* 216999726Sbenno * Turn off promiscuous mode, promiscuous group mode (all multicast), 217099726Sbenno * and hash filter. Depending on the case, the right bit will be 217199726Sbenno * enabled. 217299726Sbenno */ 2173174987Smarius v &= ~(GEM_MAC_RX_PROMISCUOUS | GEM_MAC_RX_HASH_FILTER | 217499726Sbenno GEM_MAC_RX_PROMISC_GRP); 217599726Sbenno 2176177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, v); 2177179925Smarius GEM_BANK1_BARRIER(sc, GEM_MAC_RX_CONFIG, 4, 2178179925Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 2179177560Smarius if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_HASH_FILTER, 2180177560Smarius 0)) 2181172334Smarius device_printf(sc->sc_dev, "cannot disable RX hash filter\n"); 2182172334Smarius 218391398Stmm if ((ifp->if_flags & IFF_PROMISC) != 0) { 218491398Stmm v |= GEM_MAC_RX_PROMISCUOUS; 218591398Stmm goto chipit; 218691398Stmm } 218791398Stmm if ((ifp->if_flags & IFF_ALLMULTI) != 0) { 218899726Sbenno v |= GEM_MAC_RX_PROMISC_GRP; 218991398Stmm goto chipit; 219091398Stmm } 219191398Stmm 219291398Stmm /* 2193174987Smarius * Set up multicast address filter by passing all multicast 2194174987Smarius * addresses through a crc generator, and then using the high 2195174987Smarius * order 8 bits as an index into the 256 bit logical address 2196174987Smarius * filter. The high order 4 bits selects the word, while the 2197174987Smarius * other 4 bits select the bit within the word (where bit 0 2198174987Smarius * is the MSB). 219991398Stmm */ 220091398Stmm 2201174987Smarius /* Clear the hash table. */ 220299726Sbenno memset(hash, 0, sizeof(hash)); 220399726Sbenno 2204195049Srwatson if_maddr_rlock(ifp); 2205147256Sbrooks TAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) { 220691398Stmm if (inm->ifma_addr->sa_family != AF_LINK) 220791398Stmm continue; 2208130288Smarius crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) 2209130288Smarius inm->ifma_addr), ETHER_ADDR_LEN); 221091398Stmm 2211174987Smarius /* We just want the 8 most significant bits. */ 221291398Stmm crc >>= 24; 221391398Stmm 221491398Stmm /* Set the corresponding bit in the filter. */ 221599726Sbenno hash[crc >> 4] |= 1 << (15 - (crc & 15)); 221691398Stmm } 2217195049Srwatson if_maddr_runlock(ifp); 221891398Stmm 221999726Sbenno v |= GEM_MAC_RX_HASH_FILTER; 222099726Sbenno 2221174987Smarius /* Now load the hash table into the chip (if we are using it). */ 2222174987Smarius for (i = 0; i < 16; i++) 2223177560Smarius GEM_BANK1_WRITE_4(sc, 2224174987Smarius GEM_MAC_HASH0 + i * (GEM_MAC_HASH1 - GEM_MAC_HASH0), 222599726Sbenno hash[i]); 222699726Sbenno 2227174987Smarius chipit: 2228177560Smarius GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, v); 222991398Stmm} 2230