1220185Sadrian/*- 2220185Sadrian * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3220185Sadrian * Copyright (c) 2010-2011 Adrian Chadd, Xenion Pty Ltd 4220185Sadrian * All rights reserved. 5220185Sadrian * 6220185Sadrian * Redistribution and use in source and binary forms, with or without 7220185Sadrian * modification, are permitted provided that the following conditions 8220185Sadrian * are met: 9220185Sadrian * 1. Redistributions of source code must retain the above copyright 10220185Sadrian * notice, this list of conditions and the following disclaimer, 11220185Sadrian * without modification. 12220185Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 13220185Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 14220185Sadrian * redistribution must be conditioned upon including a substantially 15220185Sadrian * similar Disclaimer requirement for further binary redistribution. 16220185Sadrian * 17220185Sadrian * NO WARRANTY 18220185Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19220185Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20220185Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 21220185Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22220185Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 23220185Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24220185Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25220185Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26220185Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27220185Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28220185Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 29220185Sadrian */ 30220185Sadrian 31220185Sadrian#include <sys/cdefs.h> 32220185Sadrian__FBSDID("$FreeBSD$"); 33220185Sadrian 34220185Sadrian/* 35220185Sadrian * AHB bus front-end for the Atheros Wireless LAN controller driver. 36220185Sadrian */ 37220185Sadrian 38237529Sadrian#include "opt_ath.h" 39237529Sadrian 40220185Sadrian#include <sys/param.h> 41220185Sadrian#include <sys/systm.h> 42257284Sglebius#include <sys/malloc.h> 43220185Sadrian#include <sys/module.h> 44220185Sadrian#include <sys/kernel.h> 45220185Sadrian#include <sys/lock.h> 46220185Sadrian#include <sys/mutex.h> 47220185Sadrian#include <sys/errno.h> 48220185Sadrian 49220185Sadrian#include <machine/bus.h> 50220185Sadrian#include <machine/resource.h> 51220185Sadrian#include <sys/bus.h> 52220185Sadrian#include <sys/rman.h> 53220185Sadrian 54220185Sadrian#include <sys/socket.h> 55220185Sadrian 56220185Sadrian#include <net/if.h> 57220185Sadrian#include <net/if_media.h> 58220185Sadrian#include <net/if_arp.h> 59257284Sglebius#include <net/ethernet.h> 60220185Sadrian 61220185Sadrian#include <net80211/ieee80211_var.h> 62220185Sadrian 63220185Sadrian#include <dev/ath/if_athvar.h> 64220185Sadrian 65220185Sadrian#include <mips/atheros/ar71xxreg.h> 66220185Sadrian#include <mips/atheros/ar91xxreg.h> 67220185Sadrian#include <mips/atheros/ar71xx_cpudef.h> 68220185Sadrian 69220185Sadrian/* 70220185Sadrian * bus glue. 71220185Sadrian */ 72220185Sadrian 73220185Sadrian/* number of 16 bit words */ 74220185Sadrian#define ATH_EEPROM_DATA_SIZE 2048 75220185Sadrian 76220185Sadrianstruct ath_ahb_softc { 77220185Sadrian struct ath_softc sc_sc; 78220185Sadrian struct resource *sc_sr; /* memory resource */ 79220185Sadrian struct resource *sc_irq; /* irq resource */ 80220185Sadrian struct resource *sc_eeprom; /* eeprom location */ 81220185Sadrian void *sc_ih; /* interrupt handler */ 82220185Sadrian}; 83220185Sadrian 84220185Sadrian#define VENDOR_ATHEROS 0x168c 85221163Sadrian#define AR9130_DEVID 0x000b 86220185Sadrian 87220185Sadrianstatic int 88220185Sadrianath_ahb_probe(device_t dev) 89220185Sadrian{ 90252239Sadrian int vendor_id, device_id; 91220185Sadrian const char* devname; 92220185Sadrian 93252239Sadrian /* 94252239Sadrian * Check if a device/vendor ID is provided in hints. 95252239Sadrian */ 96252239Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 97252239Sadrian "vendor_id", &vendor_id) != 0) { 98252239Sadrian vendor_id = VENDOR_ATHEROS; 99252239Sadrian } 100220185Sadrian 101252239Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 102252239Sadrian "device_id", &device_id) != 0) { 103252239Sadrian device_id = AR9130_DEVID; 104252239Sadrian } 105252239Sadrian 106252239Sadrian device_printf(dev, "Vendor=0x%04x, Device=0x%04x\n", 107252239Sadrian vendor_id & 0xffff, 108252239Sadrian device_id & 0xffff); 109252239Sadrian 110252239Sadrian /* Attempt to probe */ 111252239Sadrian devname = ath_hal_probe(vendor_id, device_id); 112252239Sadrian 113220185Sadrian if (devname != NULL) { 114220185Sadrian device_set_desc(dev, devname); 115220185Sadrian return BUS_PROBE_DEFAULT; 116220185Sadrian } 117220185Sadrian return ENXIO; 118220185Sadrian} 119220185Sadrian 120285122Sadrianstatic void 121285122Sadrianath_ahb_intr(void *arg) 122285122Sadrian{ 123285122Sadrian /* XXX TODO: check if its ours! */ 124285122Sadrian ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_WMAC); 125285122Sadrian ath_intr(arg); 126285122Sadrian} 127285122Sadrian 128220185Sadrianstatic int 129220185Sadrianath_ahb_attach(device_t dev) 130220185Sadrian{ 131220185Sadrian struct ath_ahb_softc *psc = device_get_softc(dev); 132220185Sadrian struct ath_softc *sc = &psc->sc_sc; 133220185Sadrian int error = ENXIO; 134220185Sadrian int rid; 135220185Sadrian long eepromaddr; 136252239Sadrian int eepromsize; 137220185Sadrian uint8_t *p; 138252239Sadrian int device_id, vendor_id; 139220185Sadrian 140220185Sadrian sc->sc_dev = dev; 141220185Sadrian 142220185Sadrian rid = 0; 143220185Sadrian psc->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 144220185Sadrian if (psc->sc_sr == NULL) { 145220185Sadrian device_printf(dev, "cannot map register space\n"); 146220185Sadrian goto bad; 147220185Sadrian } 148220185Sadrian 149252239Sadrian if (resource_long_value(device_get_name(dev), device_get_unit(dev), 150252239Sadrian "eepromaddr", &eepromaddr) != 0) { 151220185Sadrian device_printf(dev, "cannot fetch 'eepromaddr' from hints\n"); 152220185Sadrian goto bad0; 153252239Sadrian } 154252239Sadrian 155252239Sadrian /* 156252239Sadrian * The default EEPROM size is 2048 * 16 bit words. 157252239Sadrian * Later EEPROM/OTP/flash regions may be quite a bit bigger. 158252239Sadrian */ 159252239Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 160252239Sadrian "eepromsize", &eepromsize) != 0) { 161252239Sadrian eepromsize = ATH_EEPROM_DATA_SIZE * 2; 162252239Sadrian } 163252239Sadrian 164220185Sadrian rid = 0; 165252239Sadrian device_printf(sc->sc_dev, "eeprom @ %p (%d bytes)\n", 166252239Sadrian (void *) eepromaddr, eepromsize); 167279512Sadrian /* 168279512Sadrian * XXX this assumes that the parent device is the nexus 169279512Sadrian * and will just pass through requests for all of memory. 170279512Sadrian * 171279512Sadrian * Later on, when this has to attach off of the actual 172279512Sadrian * AHB, this won't work. 173279512Sadrian * 174279512Sadrian * Ideally this would be done in machdep code in mips/atheros/ 175279512Sadrian * and it'd expose the EEPROM via the firmware interface, 176279512Sadrian * so the ath/ath_ahb drivers can be loaded as modules 177279512Sadrian * after boot-time. 178279512Sadrian */ 179279512Sadrian psc->sc_eeprom = bus_alloc_resource(dev, SYS_RES_MEMORY, 180279512Sadrian &rid, (uintptr_t) eepromaddr, 181279512Sadrian (uintptr_t) eepromaddr + (uintptr_t) (eepromsize - 1), 0, RF_ACTIVE); 182223032Sadrian if (psc->sc_eeprom == NULL) { 183220185Sadrian device_printf(dev, "cannot map eeprom space\n"); 184220185Sadrian goto bad0; 185220185Sadrian } 186220185Sadrian 187268351Smarcel sc->sc_st = (HAL_BUS_TAG) rman_get_bustag(psc->sc_sr); 188220185Sadrian sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr); 189220185Sadrian /* 190220185Sadrian * Mark device invalid so any interrupts (shared or otherwise) 191220185Sadrian * that arrive before the HAL is setup are discarded. 192220185Sadrian */ 193220185Sadrian sc->sc_invalid = 1; 194220185Sadrian 195220185Sadrian /* Copy the EEPROM data out */ 196252239Sadrian sc->sc_eepromdata = malloc(eepromsize, M_TEMP, M_NOWAIT | M_ZERO); 197223032Sadrian if (sc->sc_eepromdata == NULL) { 198223032Sadrian device_printf(dev, "cannot allocate memory for eeprom data\n"); 199223032Sadrian goto bad1; 200223032Sadrian } 201220185Sadrian device_printf(sc->sc_dev, "eeprom data @ %p\n", (void *) rman_get_bushandle(psc->sc_eeprom)); 202220185Sadrian /* XXX why doesn't this work? -adrian */ 203220185Sadrian#if 0 204220185Sadrian bus_space_read_multi_1( 205220185Sadrian rman_get_bustag(psc->sc_eeprom), 206220185Sadrian rman_get_bushandle(psc->sc_eeprom), 207252239Sadrian 0, (u_int8_t *) sc->sc_eepromdata, eepromsize); 208220185Sadrian#endif 209220185Sadrian p = (void *) rman_get_bushandle(psc->sc_eeprom); 210252239Sadrian memcpy(sc->sc_eepromdata, p, eepromsize); 211220185Sadrian 212220185Sadrian /* 213220185Sadrian * Arrange interrupt line. 214220185Sadrian */ 215220185Sadrian rid = 0; 216220185Sadrian psc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE|RF_ACTIVE); 217220185Sadrian if (psc->sc_irq == NULL) { 218220185Sadrian device_printf(dev, "could not map interrupt\n"); 219220185Sadrian goto bad1; 220220185Sadrian } 221220185Sadrian if (bus_setup_intr(dev, psc->sc_irq, 222220185Sadrian INTR_TYPE_NET | INTR_MPSAFE, 223285122Sadrian NULL, ath_ahb_intr, sc, &psc->sc_ih)) { 224220185Sadrian device_printf(dev, "could not establish interrupt\n"); 225220185Sadrian goto bad2; 226220185Sadrian } 227220185Sadrian 228220185Sadrian /* 229220185Sadrian * Setup DMA descriptor area. 230220185Sadrian */ 231220185Sadrian if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 232220185Sadrian 1, 0, /* alignment, bounds */ 233220185Sadrian BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 234220185Sadrian BUS_SPACE_MAXADDR, /* highaddr */ 235220185Sadrian NULL, NULL, /* filter, filterarg */ 236220185Sadrian 0x3ffff, /* maxsize XXX */ 237220185Sadrian ATH_MAX_SCATTER, /* nsegments */ 238220185Sadrian 0x3ffff, /* maxsegsize XXX */ 239220185Sadrian BUS_DMA_ALLOCNOW, /* flags */ 240220185Sadrian NULL, /* lockfunc */ 241220185Sadrian NULL, /* lockarg */ 242220185Sadrian &sc->sc_dmat)) { 243220185Sadrian device_printf(dev, "cannot allocate DMA tag\n"); 244220185Sadrian goto bad3; 245220185Sadrian } 246220185Sadrian 247252239Sadrian /* 248252239Sadrian * Check if a device/vendor ID is provided in hints. 249252239Sadrian */ 250252239Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 251252239Sadrian "vendor_id", &vendor_id) != 0) { 252252239Sadrian vendor_id = VENDOR_ATHEROS; 253252239Sadrian } 254252239Sadrian 255252239Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 256252239Sadrian "device_id", &device_id) != 0) { 257252239Sadrian device_id = AR9130_DEVID; 258252239Sadrian } 259252239Sadrian 260220185Sadrian ATH_LOCK_INIT(sc); 261227328Sadrian ATH_PCU_LOCK_INIT(sc); 262238433Sadrian ATH_RX_LOCK_INIT(sc); 263242391Sadrian ATH_TX_LOCK_INIT(sc); 264238709Sadrian ATH_TXSTATUS_LOCK_INIT(sc); 265220185Sadrian 266252239Sadrian error = ath_attach(device_id, sc); 267220185Sadrian if (error == 0) /* success */ 268220185Sadrian return 0; 269220185Sadrian 270238709Sadrian ATH_TXSTATUS_LOCK_DESTROY(sc); 271238433Sadrian ATH_RX_LOCK_DESTROY(sc); 272242391Sadrian ATH_TX_LOCK_DESTROY(sc); 273227328Sadrian ATH_PCU_LOCK_DESTROY(sc); 274220185Sadrian ATH_LOCK_DESTROY(sc); 275220185Sadrian bus_dma_tag_destroy(sc->sc_dmat); 276220185Sadrianbad3: 277220185Sadrian bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih); 278220185Sadrianbad2: 279220185Sadrian bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq); 280220185Sadrianbad1: 281220185Sadrian bus_release_resource(dev, SYS_RES_MEMORY, 0, psc->sc_eeprom); 282220185Sadrianbad0: 283220185Sadrian bus_release_resource(dev, SYS_RES_MEMORY, 0, psc->sc_sr); 284220185Sadrianbad: 285220185Sadrian /* XXX?! */ 286220185Sadrian if (sc->sc_eepromdata) 287220185Sadrian free(sc->sc_eepromdata, M_TEMP); 288220185Sadrian return (error); 289220185Sadrian} 290220185Sadrian 291220185Sadrianstatic int 292220185Sadrianath_ahb_detach(device_t dev) 293220185Sadrian{ 294220185Sadrian struct ath_ahb_softc *psc = device_get_softc(dev); 295220185Sadrian struct ath_softc *sc = &psc->sc_sc; 296220185Sadrian 297220185Sadrian /* check if device was removed */ 298220185Sadrian sc->sc_invalid = !bus_child_present(dev); 299220185Sadrian 300220185Sadrian ath_detach(sc); 301220185Sadrian 302220185Sadrian bus_generic_detach(dev); 303220185Sadrian bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih); 304220185Sadrian bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq); 305220185Sadrian 306220185Sadrian bus_dma_tag_destroy(sc->sc_dmat); 307220185Sadrian bus_release_resource(dev, SYS_RES_MEMORY, 0, psc->sc_sr); 308220185Sadrian bus_release_resource(dev, SYS_RES_MEMORY, 0, psc->sc_eeprom); 309220185Sadrian /* XXX?! */ 310220185Sadrian if (sc->sc_eepromdata) 311220185Sadrian free(sc->sc_eepromdata, M_TEMP); 312220185Sadrian 313238709Sadrian ATH_TXSTATUS_LOCK_DESTROY(sc); 314238433Sadrian ATH_RX_LOCK_DESTROY(sc); 315242391Sadrian ATH_TX_LOCK_DESTROY(sc); 316227328Sadrian ATH_PCU_LOCK_DESTROY(sc); 317220185Sadrian ATH_LOCK_DESTROY(sc); 318220185Sadrian 319220185Sadrian return (0); 320220185Sadrian} 321220185Sadrian 322220185Sadrianstatic int 323220185Sadrianath_ahb_shutdown(device_t dev) 324220185Sadrian{ 325220185Sadrian struct ath_ahb_softc *psc = device_get_softc(dev); 326220185Sadrian 327220185Sadrian ath_shutdown(&psc->sc_sc); 328220185Sadrian return (0); 329220185Sadrian} 330220185Sadrian 331220185Sadrianstatic int 332220185Sadrianath_ahb_suspend(device_t dev) 333220185Sadrian{ 334220185Sadrian struct ath_ahb_softc *psc = device_get_softc(dev); 335220185Sadrian 336220185Sadrian ath_suspend(&psc->sc_sc); 337220185Sadrian 338220185Sadrian return (0); 339220185Sadrian} 340220185Sadrian 341220185Sadrianstatic int 342220185Sadrianath_ahb_resume(device_t dev) 343220185Sadrian{ 344220185Sadrian struct ath_ahb_softc *psc = device_get_softc(dev); 345220185Sadrian 346220185Sadrian ath_resume(&psc->sc_sc); 347220185Sadrian 348220185Sadrian return (0); 349220185Sadrian} 350220185Sadrian 351220185Sadrianstatic device_method_t ath_ahb_methods[] = { 352220185Sadrian /* Device interface */ 353220185Sadrian DEVMETHOD(device_probe, ath_ahb_probe), 354220185Sadrian DEVMETHOD(device_attach, ath_ahb_attach), 355220185Sadrian DEVMETHOD(device_detach, ath_ahb_detach), 356220185Sadrian DEVMETHOD(device_shutdown, ath_ahb_shutdown), 357220185Sadrian DEVMETHOD(device_suspend, ath_ahb_suspend), 358220185Sadrian DEVMETHOD(device_resume, ath_ahb_resume), 359220185Sadrian 360220185Sadrian { 0,0 } 361220185Sadrian}; 362220185Sadrianstatic driver_t ath_ahb_driver = { 363220185Sadrian "ath", 364220185Sadrian ath_ahb_methods, 365220185Sadrian sizeof (struct ath_ahb_softc) 366220185Sadrian}; 367220185Sadrianstatic devclass_t ath_devclass; 368220185SadrianDRIVER_MODULE(ath, nexus, ath_ahb_driver, ath_devclass, 0, 0); 369279512SadrianDRIVER_MODULE(ath, apb, ath_ahb_driver, ath_devclass, 0, 0); 370220185SadrianMODULE_VERSION(ath, 1); 371220185SadrianMODULE_DEPEND(ath, wlan, 1, 1, 1); /* 802.11 media layer */ 372220185SadrianMODULE_DEPEND(ath, if_ath, 1, 1, 1); /* if_ath driver */ 373