1116743Ssam/*- 2178354Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3116743Ssam * All rights reserved. 4116743Ssam * 5116743Ssam * Redistribution and use in source and binary forms, with or without 6116743Ssam * modification, are permitted provided that the following conditions 7116743Ssam * are met: 8116743Ssam * 1. Redistributions of source code must retain the above copyright 9116743Ssam * notice, this list of conditions and the following disclaimer, 10116743Ssam * without modification. 11116743Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12116743Ssam * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13116743Ssam * redistribution must be conditioned upon including a substantially 14116743Ssam * similar Disclaimer requirement for further binary redistribution. 15116743Ssam * 16116743Ssam * NO WARRANTY 17116743Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18116743Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19116743Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20116743Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21116743Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22116743Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23116743Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24116743Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25116743Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26116743Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27116743Ssam * THE POSSIBILITY OF SUCH DAMAGES. 28116743Ssam */ 29116743Ssam 30116743Ssam#include <sys/cdefs.h> 31116743Ssam__FBSDID("$FreeBSD$"); 32116743Ssam 33116743Ssam/* 34116743Ssam * PCI/Cardbus front-end for the Atheros Wireless LAN controller driver. 35116743Ssam */ 36116743Ssam 37116743Ssam#include <sys/param.h> 38116743Ssam#include <sys/systm.h> 39116743Ssam#include <sys/module.h> 40116743Ssam#include <sys/kernel.h> 41116743Ssam#include <sys/lock.h> 42116743Ssam#include <sys/mutex.h> 43116743Ssam#include <sys/errno.h> 44116743Ssam 45116743Ssam#include <machine/bus.h> 46116743Ssam#include <machine/resource.h> 47116743Ssam#include <sys/bus.h> 48116743Ssam#include <sys/rman.h> 49138570Ssam 50138570Ssam#include <sys/socket.h> 51116743Ssam 52116743Ssam#include <net/if.h> 53116743Ssam#include <net/if_media.h> 54116743Ssam#include <net/if_arp.h> 55116743Ssam 56116743Ssam#include <net80211/ieee80211_var.h> 57116743Ssam 58116743Ssam#include <dev/ath/if_athvar.h> 59116743Ssam 60116743Ssam#include <dev/pci/pcivar.h> 61116743Ssam#include <dev/pci/pcireg.h> 62116743Ssam 63116743Ssam/* 64116743Ssam * PCI glue. 65116743Ssam */ 66116743Ssam 67116743Ssamstruct ath_pci_softc { 68116743Ssam struct ath_softc sc_sc; 69116743Ssam struct resource *sc_sr; /* memory resource */ 70116743Ssam struct resource *sc_irq; /* irq resource */ 71138570Ssam void *sc_ih; /* interrupt handler */ 72116743Ssam}; 73116743Ssam 74116743Ssam#define BS_BAR 0x10 75140427Ssam#define PCIR_RETRY_TIMEOUT 0x41 76116743Ssam 77116743Ssamstatic int 78116743Ssamath_pci_probe(device_t dev) 79116743Ssam{ 80116743Ssam const char* devname; 81116743Ssam 82116743Ssam devname = ath_hal_probe(pci_get_vendor(dev), pci_get_device(dev)); 83138570Ssam if (devname != NULL) { 84116743Ssam device_set_desc(dev, devname); 85143163Simp return BUS_PROBE_DEFAULT; 86116743Ssam } 87116743Ssam return ENXIO; 88116743Ssam} 89116743Ssam 90172900Skevlostatic int 91172900Skevloath_pci_attach(device_t dev) 92116743Ssam{ 93172900Skevlo struct ath_pci_softc *psc = device_get_softc(dev); 94172900Skevlo struct ath_softc *sc = &psc->sc_sc; 95172900Skevlo int error = ENXIO; 96172900Skevlo int rid; 97116743Ssam 98172900Skevlo sc->sc_dev = dev; 99172900Skevlo 100140427Ssam /* 101172900Skevlo * Enable bus mastering. 102140427Ssam */ 103172900Skevlo pci_enable_busmaster(dev); 104116743Ssam 105140427Ssam /* 106140427Ssam * Disable retry timeout to keep PCI Tx retries from 107140427Ssam * interfering with C3 CPU state. 108140427Ssam */ 109140427Ssam pci_write_config(dev, PCIR_RETRY_TIMEOUT, 0, 1); 110140427Ssam 111116743Ssam /* 112116743Ssam * Setup memory-mapping of PCI registers. 113116743Ssam */ 114116743Ssam rid = BS_BAR; 115127135Snjl psc->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 116127135Snjl RF_ACTIVE); 117116743Ssam if (psc->sc_sr == NULL) { 118116743Ssam device_printf(dev, "cannot map register space\n"); 119116743Ssam goto bad; 120116743Ssam } 121159383Ssam /* XXX uintptr_t is a bandaid for ia64; to be fixed */ 122159383Ssam sc->sc_st = (HAL_BUS_TAG)(uintptr_t) rman_get_bustag(psc->sc_sr); 123159290Ssam sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr); 124118884Ssam /* 125118884Ssam * Mark device invalid so any interrupts (shared or otherwise) 126118884Ssam * that arrive before the HAL is setup are discarded. 127118884Ssam */ 128118884Ssam sc->sc_invalid = 1; 129116743Ssam 130116743Ssam /* 131116743Ssam * Arrange interrupt line. 132116743Ssam */ 133116743Ssam rid = 0; 134127135Snjl psc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 135127135Snjl RF_SHAREABLE|RF_ACTIVE); 136116743Ssam if (psc->sc_irq == NULL) { 137116743Ssam device_printf(dev, "could not map interrupt\n"); 138116743Ssam goto bad1; 139116743Ssam } 140116743Ssam if (bus_setup_intr(dev, psc->sc_irq, 141116743Ssam INTR_TYPE_NET | INTR_MPSAFE, 142166901Spiso NULL, ath_intr, sc, &psc->sc_ih)) { 143116743Ssam device_printf(dev, "could not establish interrupt\n"); 144116743Ssam goto bad2; 145116743Ssam } 146116743Ssam 147116743Ssam /* 148116743Ssam * Setup DMA descriptor area. 149116743Ssam */ 150166165Smarius if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 151116743Ssam 1, 0, /* alignment, bounds */ 152116743Ssam BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 153116743Ssam BUS_SPACE_MAXADDR, /* highaddr */ 154116743Ssam NULL, NULL, /* filter, filterarg */ 155116743Ssam 0x3ffff, /* maxsize XXX */ 156116743Ssam ATH_MAX_SCATTER, /* nsegments */ 157158366Ssam 0x3ffff, /* maxsegsize XXX */ 158116743Ssam BUS_DMA_ALLOCNOW, /* flags */ 159117126Sscottl NULL, /* lockfunc */ 160117126Sscottl NULL, /* lockarg */ 161116743Ssam &sc->sc_dmat)) { 162116743Ssam device_printf(dev, "cannot allocate DMA tag\n"); 163116743Ssam goto bad3; 164116743Ssam } 165116743Ssam 166121100Ssam ATH_LOCK_INIT(sc); 167116743Ssam 168116743Ssam error = ath_attach(pci_get_device(dev), sc); 169164794Ssam if (error == 0) /* success */ 170164794Ssam return 0; 171116743Ssam 172121100Ssam ATH_LOCK_DESTROY(sc); 173116743Ssam bus_dma_tag_destroy(sc->sc_dmat); 174116743Ssambad3: 175116743Ssam bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih); 176116743Ssambad2: 177116743Ssam bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq); 178116743Ssambad1: 179116743Ssam bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr); 180116743Ssambad: 181116743Ssam return (error); 182116743Ssam} 183116743Ssam 184116743Ssamstatic int 185116743Ssamath_pci_detach(device_t dev) 186116743Ssam{ 187116743Ssam struct ath_pci_softc *psc = device_get_softc(dev); 188116743Ssam struct ath_softc *sc = &psc->sc_sc; 189116743Ssam 190116743Ssam /* check if device was removed */ 191116743Ssam sc->sc_invalid = !bus_child_present(dev); 192116743Ssam 193116743Ssam ath_detach(sc); 194116743Ssam 195116743Ssam bus_generic_detach(dev); 196116743Ssam bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih); 197116743Ssam bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq); 198116743Ssam 199116743Ssam bus_dma_tag_destroy(sc->sc_dmat); 200116743Ssam bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr); 201116743Ssam 202121100Ssam ATH_LOCK_DESTROY(sc); 203116743Ssam 204116743Ssam return (0); 205116743Ssam} 206116743Ssam 207116743Ssamstatic int 208116743Ssamath_pci_shutdown(device_t dev) 209116743Ssam{ 210116743Ssam struct ath_pci_softc *psc = device_get_softc(dev); 211116743Ssam 212116743Ssam ath_shutdown(&psc->sc_sc); 213116743Ssam return (0); 214116743Ssam} 215116743Ssam 216116743Ssamstatic int 217116743Ssamath_pci_suspend(device_t dev) 218116743Ssam{ 219116743Ssam struct ath_pci_softc *psc = device_get_softc(dev); 220116743Ssam 221116743Ssam ath_suspend(&psc->sc_sc); 222116743Ssam 223116743Ssam return (0); 224116743Ssam} 225116743Ssam 226116743Ssamstatic int 227116743Ssamath_pci_resume(device_t dev) 228116743Ssam{ 229116743Ssam struct ath_pci_softc *psc = device_get_softc(dev); 230116743Ssam 231116743Ssam ath_resume(&psc->sc_sc); 232116743Ssam 233116743Ssam return (0); 234116743Ssam} 235116743Ssam 236116743Ssamstatic device_method_t ath_pci_methods[] = { 237116743Ssam /* Device interface */ 238116743Ssam DEVMETHOD(device_probe, ath_pci_probe), 239116743Ssam DEVMETHOD(device_attach, ath_pci_attach), 240116743Ssam DEVMETHOD(device_detach, ath_pci_detach), 241116743Ssam DEVMETHOD(device_shutdown, ath_pci_shutdown), 242116743Ssam DEVMETHOD(device_suspend, ath_pci_suspend), 243116743Ssam DEVMETHOD(device_resume, ath_pci_resume), 244116743Ssam 245116743Ssam { 0,0 } 246116743Ssam}; 247116743Ssamstatic driver_t ath_pci_driver = { 248116743Ssam "ath", 249116743Ssam ath_pci_methods, 250116743Ssam sizeof (struct ath_pci_softc) 251116743Ssam}; 252116743Ssamstatic devclass_t ath_devclass; 253220185SadrianDRIVER_MODULE(ath_pci, pci, ath_pci_driver, ath_devclass, 0, 0); 254220185SadrianMODULE_VERSION(ath_pci, 1); 255220185SadrianMODULE_DEPEND(ath_pci, wlan, 1, 1, 1); /* 802.11 media layer */ 256220185SadrianMODULE_DEPEND(ath_pci, if_ath, 1, 1, 1); /* if_ath driver */ 257