if_ath_pci.c revision 185522
1234353Sdim/*- 2193323Sed * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer, 10193323Sed * without modification. 11193323Sed * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12193323Sed * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13193323Sed * redistribution must be conditioned upon including a substantially 14193323Sed * similar Disclaimer requirement for further binary redistribution. 15193323Sed * 16234353Sdim * NO WARRANTY 17193323Sed * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18249423Sdim * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19193323Sed * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20193323Sed * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21193323Sed * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22249423Sdim * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23249423Sdim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24249423Sdim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25249423Sdim * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26193323Sed * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27193323Sed * THE POSSIBILITY OF SUCH DAMAGES. 28193323Sed */ 29193323Sed 30249423Sdim#include <sys/cdefs.h> 31249423Sdim__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_pci.c 185522 2008-12-01 16:53:01Z sam $"); 32249423Sdim 33249423Sdim/* 34249423Sdim * PCI/Cardbus front-end for the Atheros Wireless LAN controller driver. 35193323Sed */ 36193323Sed 37198090Srdivacky#include <sys/param.h> 38193323Sed#include <sys/systm.h> 39198090Srdivacky#include <sys/module.h> 40249423Sdim#include <sys/kernel.h> 41249423Sdim#include <sys/lock.h> 42249423Sdim#include <sys/mutex.h> 43249423Sdim#include <sys/errno.h> 44193323Sed 45193323Sed#include <machine/bus.h> 46224145Sdim#include <machine/resource.h> 47224145Sdim#include <sys/bus.h> 48224145Sdim#include <sys/rman.h> 49207618Srdivacky 50207618Srdivacky#include <sys/socket.h> 51193323Sed 52193323Sed#include <net/if.h> 53226633Sdim#include <net/if_media.h> 54226633Sdim#include <net/if_arp.h> 55226633Sdim 56249423Sdim#include <net80211/ieee80211_var.h> 57193323Sed 58193323Sed#include <dev/ath/if_athvar.h> 59193323Sed 60193323Sed#include <dev/pci/pcivar.h> 61193323Sed#include <dev/pci/pcireg.h> 62193323Sed 63193323Sed/* 64193323Sed * PCI glue. 65193323Sed */ 66193323Sed 67193323Sedstruct ath_pci_softc { 68193323Sed struct ath_softc sc_sc; 69193323Sed struct resource *sc_sr; /* memory resource */ 70193323Sed struct resource *sc_irq; /* irq resource */ 71249423Sdim void *sc_ih; /* interrupt handler */ 72193323Sed}; 73193323Sed 74193323Sed#define BS_BAR 0x10 75193323Sed#define PCIR_RETRY_TIMEOUT 0x41 76198090Srdivacky 77239462Sdimstatic int 78239462Sdimath_pci_probe(device_t dev) 79251662Sdim{ 80251662Sdim const char* devname; 81249423Sdim 82249423Sdim devname = ath_hal_probe(pci_get_vendor(dev), pci_get_device(dev)); 83249423Sdim if (devname != NULL) { 84249423Sdim device_set_desc(dev, devname); 85249423Sdim return BUS_PROBE_DEFAULT; 86249423Sdim } 87193323Sed return ENXIO; 88193323Sed} 89198090Srdivacky 90193323Sedstatic int 91193323Sedath_pci_attach(device_t dev) 92234353Sdim{ 93193323Sed struct ath_pci_softc *psc = device_get_softc(dev); 94234353Sdim struct ath_softc *sc = &psc->sc_sc; 95234353Sdim int error = ENXIO; 96234353Sdim int rid; 97193323Sed 98234353Sdim sc->sc_dev = dev; 99234353Sdim 100198090Srdivacky /* 101243830Sdim * Enable bus mastering. 102234353Sdim */ 103195340Sed pci_enable_busmaster(dev); 104234353Sdim 105234353Sdim /* 106198090Srdivacky * Disable retry timeout to keep PCI Tx retries from 107234353Sdim * interfering with C3 CPU state. 108193323Sed */ 109193323Sed pci_write_config(dev, PCIR_RETRY_TIMEOUT, 0, 1); 110249423Sdim 111249423Sdim /* 112249423Sdim * Setup memory-mapping of PCI registers. 113249423Sdim */ 114249423Sdim rid = BS_BAR; 115249423Sdim psc->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 116249423Sdim RF_ACTIVE); 117249423Sdim if (psc->sc_sr == NULL) { 118249423Sdim device_printf(dev, "cannot map register space\n"); 119249423Sdim goto bad; 120249423Sdim } 121249423Sdim /* XXX uintptr_t is a bandaid for ia64; to be fixed */ 122249423Sdim sc->sc_st = (HAL_BUS_TAG)(uintptr_t) rman_get_bustag(psc->sc_sr); 123249423Sdim sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr); 124193323Sed /* 125193323Sed * Mark device invalid so any interrupts (shared or otherwise) 126218893Sdim * that arrive before the HAL is setup are discarded. 127218893Sdim */ 128218893Sdim sc->sc_invalid = 1; 129249423Sdim 130249423Sdim /* 131249423Sdim * Arrange interrupt line. 132249423Sdim */ 133249423Sdim rid = 0; 134249423Sdim psc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 135249423Sdim RF_SHAREABLE|RF_ACTIVE); 136249423Sdim if (psc->sc_irq == NULL) { 137249423Sdim device_printf(dev, "could not map interrupt\n"); 138249423Sdim goto bad1; 139193323Sed } 140193323Sed if (bus_setup_intr(dev, psc->sc_irq, 141193323Sed INTR_TYPE_NET | INTR_MPSAFE, 142193323Sed NULL, ath_intr, sc, &psc->sc_ih)) { 143193323Sed device_printf(dev, "could not establish interrupt\n"); 144195340Sed goto bad2; 145195340Sed } 146195340Sed 147195340Sed /* 148195340Sed * Setup DMA descriptor area. 149195340Sed */ 150198090Srdivacky if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 151193323Sed 1, 0, /* alignment, bounds */ 152193323Sed BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 153193323Sed BUS_SPACE_MAXADDR, /* highaddr */ 154193323Sed NULL, NULL, /* filter, filterarg */ 155193323Sed 0x3ffff, /* maxsize XXX */ 156198090Srdivacky ATH_MAX_SCATTER, /* nsegments */ 157249423Sdim 0x3ffff, /* maxsegsize XXX */ 158249423Sdim BUS_DMA_ALLOCNOW, /* flags */ 159249423Sdim NULL, /* lockfunc */ 160198090Srdivacky NULL, /* lockarg */ 161198090Srdivacky &sc->sc_dmat)) { 162198090Srdivacky device_printf(dev, "cannot allocate DMA tag\n"); 163198090Srdivacky goto bad3; 164193323Sed } 165193323Sed 166218893Sdim ATH_LOCK_INIT(sc); 167193323Sed 168193323Sed error = ath_attach(pci_get_device(dev), sc); 169193323Sed if (error == 0) /* success */ 170193323Sed return 0; 171193323Sed 172234353Sdim ATH_LOCK_DESTROY(sc); 173234353Sdim bus_dma_tag_destroy(sc->sc_dmat); 174234353Sdimbad3: 175234353Sdim bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih); 176234353Sdimbad2: 177234353Sdim bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq); 178234353Sdimbad1: 179234353Sdim bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr); 180234353Sdimbad: 181249423Sdim return (error); 182249423Sdim} 183234353Sdim 184234353Sdimstatic int 185234353Sdimath_pci_detach(device_t dev) 186234353Sdim{ 187234353Sdim struct ath_pci_softc *psc = device_get_softc(dev); 188234353Sdim struct ath_softc *sc = &psc->sc_sc; 189234353Sdim 190234353Sdim /* check if device was removed */ 191234353Sdim sc->sc_invalid = !bus_child_present(dev); 192234353Sdim 193234353Sdim ath_detach(sc); 194234353Sdim 195234353Sdim bus_generic_detach(dev); 196234353Sdim bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih); 197193323Sed bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq); 198193323Sed 199193323Sed bus_dma_tag_destroy(sc->sc_dmat); 200193323Sed bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr); 201193323Sed 202193323Sed ATH_LOCK_DESTROY(sc); 203193323Sed 204193323Sed return (0); 205193323Sed} 206193323Sed 207193323Sedstatic int 208249423Sdimath_pci_shutdown(device_t dev) 209193323Sed{ 210193323Sed struct ath_pci_softc *psc = device_get_softc(dev); 211193323Sed 212193323Sed ath_shutdown(&psc->sc_sc); 213193323Sed return (0); 214193323Sed} 215193323Sed 216193323Sedstatic int 217193323Sedath_pci_suspend(device_t dev) 218193323Sed{ 219193323Sed struct ath_pci_softc *psc = device_get_softc(dev); 220193323Sed 221193323Sed ath_suspend(&psc->sc_sc); 222193323Sed 223193323Sed return (0); 224193323Sed} 225193323Sed 226193323Sedstatic int 227218893Sdimath_pci_resume(device_t dev) 228193323Sed{ 229212904Sdim struct ath_pci_softc *psc = device_get_softc(dev); 230212904Sdim 231193323Sed ath_resume(&psc->sc_sc); 232193323Sed 233193323Sed return (0); 234193323Sed} 235193323Sed 236193323Sedstatic device_method_t ath_pci_methods[] = { 237193323Sed /* Device interface */ 238193323Sed DEVMETHOD(device_probe, ath_pci_probe), 239193323Sed DEVMETHOD(device_attach, ath_pci_attach), 240249423Sdim DEVMETHOD(device_detach, ath_pci_detach), 241193323Sed DEVMETHOD(device_shutdown, ath_pci_shutdown), 242206083Srdivacky DEVMETHOD(device_suspend, ath_pci_suspend), 243193323Sed DEVMETHOD(device_resume, ath_pci_resume), 244193323Sed 245193323Sed { 0,0 } 246193323Sed}; 247249423Sdimstatic driver_t ath_pci_driver = { 248249423Sdim "ath", 249249423Sdim ath_pci_methods, 250193323Sed sizeof (struct ath_pci_softc) 251193323Sed}; 252193323Sedstatic devclass_t ath_devclass; 253193323SedDRIVER_MODULE(if_ath, pci, ath_pci_driver, ath_devclass, 0, 0); 254193323SedDRIVER_MODULE(if_ath, cardbus, ath_pci_driver, ath_devclass, 0, 0); 255193323SedMODULE_VERSION(if_ath, 1); 256193323SedMODULE_DEPEND(if_ath, wlan, 1, 1, 1); /* 802.11 media layer */ 257193323SedMODULE_DEPEND(if_ath, ath_rate, 1, 1, 1); /* rate control algorithm */ 258193323Sed