if_an_pci.c revision 119418
1284285Sjkim/*- 2238405Sjkim * Copyright (c) 1997, 1998, 1999 3238405Sjkim * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4238405Sjkim * 5238405Sjkim * Redistribution and use in source and binary forms, with or without 6238405Sjkim * modification, are permitted provided that the following conditions 7238405Sjkim * are met: 8238405Sjkim * 1. Redistributions of source code must retain the above copyright 9238405Sjkim * notice, this list of conditions and the following disclaimer. 10238405Sjkim * 2. Redistributions in binary form must reproduce the above copyright 11238405Sjkim * notice, this list of conditions and the following disclaimer in the 12238405Sjkim * documentation and/or other materials provided with the distribution. 13238405Sjkim * 3. All advertising materials mentioning features or use of this software 14238405Sjkim * must display the following acknowledgement: 15238405Sjkim * This product includes software developed by Bill Paul. 16238405Sjkim * 4. Neither the name of the author nor the names of any co-contributors 17238405Sjkim * may be used to endorse or promote products derived from this software 18238405Sjkim * without specific prior written permission. 19238405Sjkim * 20238405Sjkim * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21238405Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22238405Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23238405Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24238405Sjkim * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25238405Sjkim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26238405Sjkim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27238405Sjkim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28238405Sjkim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29238405Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30238405Sjkim * THE POSSIBILITY OF SUCH DAMAGE. 31238405Sjkim */ 32238405Sjkim 33238405Sjkim#include <sys/cdefs.h> 34238405Sjkim__FBSDID("$FreeBSD: head/sys/dev/an/if_an_pci.c 119418 2003-08-24 17:55:58Z obrien $"); 35238405Sjkim 36238405Sjkim/* 37238405Sjkim * This is a PCI shim for the Aironet PC4500/4800 wireless network 38238405Sjkim * driver. Aironet makes PCMCIA, ISA and PCI versions of these devices, 39238405Sjkim * which all have basically the same interface. The ISA and PCI cards 40238405Sjkim * are actually bridge adapters with PCMCIA cards inserted into them, 41276864Sjkim * however they appear as normal PCI or ISA devices to the host. 42276864Sjkim * 43238405Sjkim * All we do here is handle the PCI probe and attach and set up an 44238405Sjkim * interrupt handler entry point. The PCI version of the card uses 45238405Sjkim * a PLX 9050 PCI to "dumb bus" bridge chip, which provides us with 46238405Sjkim * multiple PCI address space mappings. The primary mapping at PCI 47238405Sjkim * register 0x14 is for the PLX chip itself, *NOT* the Aironet card. 48238405Sjkim * The I/O address of the Aironet is actually at register 0x18, which 49238405Sjkim * is the local bus mapping register for bus space 0. There are also 50238405Sjkim * registers for additional register spaces at registers 0x1C and 51238405Sjkim * 0x20, but these are unused in the Aironet devices. To find out 52238405Sjkim * more, you need a datasheet for the 9050 from PLX, but you have 53276864Sjkim * to go through their sales office to get it. Bleh. 54276864Sjkim */ 55276864Sjkim 56238405Sjkim#include "opt_inet.h" 57276864Sjkim 58276864Sjkim#ifdef INET 59276864Sjkim#define ANCACHE 60276864Sjkim#endif 61276864Sjkim 62276864Sjkim#include <sys/param.h> 63238405Sjkim#include <sys/systm.h> 64276864Sjkim#include <sys/sockio.h> 65276864Sjkim#include <sys/mbuf.h> 66276864Sjkim#include <sys/kernel.h> 67276864Sjkim#include <sys/socket.h> 68276864Sjkim 69238405Sjkim#include <sys/module.h> 70276864Sjkim#include <sys/bus.h> 71238405Sjkim#include <machine/bus.h> 72238405Sjkim#include <sys/rman.h> 73238405Sjkim#include <sys/lock.h> 74238405Sjkim#include <sys/mutex.h> 75238405Sjkim#include <machine/resource.h> 76238405Sjkim 77238405Sjkim#include <net/if.h> 78238405Sjkim#include <net/if_arp.h> 79238405Sjkim#include <net/ethernet.h> 80238405Sjkim#include <net/if_dl.h> 81238405Sjkim#include <net/if_media.h> 82238405Sjkim 83238405Sjkim#include <dev/pci/pcireg.h> 84238405Sjkim#include <dev/pci/pcivar.h> 85238405Sjkim 86238405Sjkim#include <dev/an/if_aironet_ieee.h> 87238405Sjkim#include <dev/an/if_anreg.h> 88238405Sjkim 89238405Sjkimstruct an_type { 90238405Sjkim u_int16_t an_vid; 91238405Sjkim u_int16_t an_did; 92238405Sjkim char *an_name; 93238405Sjkim}; 94238405Sjkim 95238405Sjkim#define AIRONET_VENDORID 0x14B9 96238405Sjkim#define AIRONET_DEVICEID_35x 0x0350 97238405Sjkim#define AIRONET_DEVICEID_4500 0x4500 98238405Sjkim#define AIRONET_DEVICEID_4800 0x4800 99238405Sjkim#define AIRONET_DEVICEID_4xxx 0x0001 100238405Sjkim#define AIRONET_DEVICEID_MPI350 0xA504 101238405Sjkim#define AN_PCI_PLX_LOIO 0x14 /* PLX chip iobase */ 102238405Sjkim#define AN_PCI_LOIO 0x18 /* Aironet iobase */ 103238405Sjkim 104238405Sjkimstatic struct an_type an_devs[] = { 105238405Sjkim { AIRONET_VENDORID, AIRONET_DEVICEID_35x, "Cisco Aironet 350 Series" }, 106238405Sjkim { AIRONET_VENDORID, AIRONET_DEVICEID_4500, "Aironet PCI4500" }, 107238405Sjkim { AIRONET_VENDORID, AIRONET_DEVICEID_4800, "Aironet PCI4800" }, 108238405Sjkim { AIRONET_VENDORID, AIRONET_DEVICEID_4xxx, "Aironet PCI4500/PCI4800" }, 109238405Sjkim { 0, 0, NULL } 110238405Sjkim}; 111238405Sjkim 112238405Sjkimstatic int an_probe_pci (device_t); 113238405Sjkimstatic int an_attach_pci (device_t); 114238405Sjkimstatic int an_detach_pci (device_t); 115238405Sjkimstatic int an_suspend_pci (device_t); 116238405Sjkimstatic int an_resume_pci (device_t); 117238405Sjkim 118238405Sjkimstatic int 119238405Sjkiman_probe_pci(device_t dev) 120238405Sjkim{ 121238405Sjkim struct an_type *t; 122238405Sjkim 123238405Sjkim t = an_devs; 124238405Sjkim 125238405Sjkim while (t->an_name != NULL) { 126238405Sjkim if (pci_get_vendor(dev) == t->an_vid && 127238405Sjkim pci_get_device(dev) == t->an_did) { 128238405Sjkim device_set_desc(dev, t->an_name); 129238405Sjkim return(0); 130238405Sjkim } 131238405Sjkim t++; 132238405Sjkim } 133238405Sjkim 134238405Sjkim if (pci_get_vendor(dev) == AIRONET_VENDORID && 135238405Sjkim pci_get_device(dev) == AIRONET_DEVICEID_MPI350) { 136285330Sjkim device_set_desc(dev, "Cisco Aironet MPI350"); 137238405Sjkim return(0); 138238405Sjkim } 139238405Sjkim 140238405Sjkim return(ENXIO); 141238405Sjkim} 142238405Sjkim 143238405Sjkimstatic int 144238405Sjkiman_attach_pci(dev) 145238405Sjkim device_t dev; 146238405Sjkim{ 147238405Sjkim u_int32_t command; 148238405Sjkim struct an_softc *sc; 149238405Sjkim int unit, flags, error = 0; 150238405Sjkim 151238405Sjkim sc = device_get_softc(dev); 152238405Sjkim unit = device_get_unit(dev); 153238405Sjkim flags = device_get_flags(dev); 154238405Sjkim bzero(sc, sizeof(struct an_softc)); 155238405Sjkim 156238405Sjkim if (pci_get_vendor(dev) == AIRONET_VENDORID && 157238405Sjkim pci_get_device(dev) == AIRONET_DEVICEID_MPI350) { 158238405Sjkim sc->mpi350 = 1; 159238405Sjkim sc->port_rid = PCIR_MAPS; 160238405Sjkim } else { 161238405Sjkim /* 162238405Sjkim * Map control/status registers. 163238405Sjkim */ 164238405Sjkim command = pci_read_config(dev, PCIR_COMMAND, 4); 165238405Sjkim command |= PCIM_CMD_PORTEN; 166238405Sjkim pci_write_config(dev, PCIR_COMMAND, command, 4); 167276864Sjkim command = pci_read_config(dev, PCIR_COMMAND, 4); 168238405Sjkim 169238405Sjkim if (!(command & PCIM_CMD_PORTEN)) { 170238405Sjkim printf("an%d: failed to enable I/O ports!\n", unit); 171238405Sjkim error = ENXIO; 172238405Sjkim goto fail; 173238405Sjkim } 174238405Sjkim sc->port_rid = AN_PCI_LOIO; 175238405Sjkim } 176238405Sjkim error = an_alloc_port(dev, sc->port_rid, 1); 177238405Sjkim 178238405Sjkim if (error) { 179238405Sjkim printf("an%d: couldn't map ports\n", unit); 180276864Sjkim goto fail; 181238405Sjkim } 182238405Sjkim 183238405Sjkim sc->an_btag = rman_get_bustag(sc->port_res); 184238405Sjkim sc->an_bhandle = rman_get_bushandle(sc->port_res); 185238405Sjkim 186238405Sjkim /* Allocate memory for MPI350 */ 187238405Sjkim if (sc->mpi350) { 188238405Sjkim /* Allocate memory */ 189238405Sjkim sc->mem_rid = PCIR_MAPS + 4; 190276864Sjkim error = an_alloc_memory(dev, sc->mem_rid, 1); 191238405Sjkim if (error) { 192238405Sjkim printf("an%d: couldn't map memory\n", unit); 193238405Sjkim goto fail; 194238405Sjkim } 195238405Sjkim sc->an_mem_btag = rman_get_bustag(sc->mem_res); 196238405Sjkim sc->an_mem_bhandle = rman_get_bushandle(sc->mem_res); 197238405Sjkim 198238405Sjkim /* Allocate aux. memory */ 199238405Sjkim sc->mem_aux_rid = PCIR_MAPS + 8; 200238405Sjkim error = an_alloc_aux_memory(dev, sc->mem_aux_rid, 201238405Sjkim AN_AUX_MEM_SIZE); 202238405Sjkim if (error) { 203238405Sjkim printf("an%d: couldn't map aux memory\n", unit); 204238405Sjkim goto fail; 205238405Sjkim } 206238405Sjkim sc->an_mem_aux_btag = rman_get_bustag(sc->mem_aux_res); 207238405Sjkim sc->an_mem_aux_bhandle = rman_get_bushandle(sc->mem_aux_res); 208238405Sjkim 209238405Sjkim /* Allocate DMA region */ 210238405Sjkim error = bus_dma_tag_create(NULL, /* parent */ 211238405Sjkim 1, 0, /* alignment, bounds */ 212238405Sjkim BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 213238405Sjkim BUS_SPACE_MAXADDR, /* highaddr */ 214238405Sjkim NULL, NULL, /* filter, filterarg */ 215238405Sjkim 0x3ffff, /* maxsize XXX */ 216238405Sjkim 1, /* nsegments */ 217238405Sjkim 0xffff, /* maxsegsize XXX */ 218238405Sjkim BUS_DMA_ALLOCNOW, /* flags */ 219238405Sjkim NULL, /* lockfunc */ 220238405Sjkim NULL, /* lockarg */ 221238405Sjkim &sc->an_dtag); 222238405Sjkim if (error) { 223238405Sjkim printf("an%d: couldn't get DMA region\n", unit); 224238405Sjkim goto fail; 225238405Sjkim } 226238405Sjkim } 227238405Sjkim 228238405Sjkim /* Allocate interrupt */ 229238405Sjkim error = an_alloc_irq(dev, 0, RF_SHAREABLE); 230238405Sjkim if (error) { 231238405Sjkim goto fail; 232238405Sjkim } 233238405Sjkim 234238405Sjkim sc->an_dev = dev; 235238405Sjkim error = an_attach(sc, device_get_unit(dev), flags); 236238405Sjkim if (error) { 237238405Sjkim goto fail; 238238405Sjkim } 239238405Sjkim 240238405Sjkim /* 241238405Sjkim * Must setup the interrupt after the an_attach to prevent racing. 242238405Sjkim */ 243238405Sjkim error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, 244238405Sjkim an_intr, sc, &sc->irq_handle); 245238405Sjkim 246238405Sjkimfail: 247238405Sjkim if (error) 248238405Sjkim an_release_resources(dev); 249238405Sjkim return(error); 250238405Sjkim} 251238405Sjkim 252238405Sjkimstatic int 253238405Sjkiman_detach_pci(device_t dev) 254238405Sjkim{ 255238405Sjkim struct an_softc *sc = device_get_softc(dev); 256238405Sjkim struct ifnet *ifp = &sc->arpcom.ac_if; 257238405Sjkim 258238405Sjkim an_stop(sc); 259238405Sjkim ifmedia_removeall(&sc->an_ifmedia); 260238405Sjkim ether_ifdetach(ifp); 261 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 262 an_release_resources(dev); 263 264 return (0); 265} 266 267static int 268an_suspend_pci(device_t dev) 269{ 270 an_shutdown(dev); 271 272 return (0); 273} 274 275static int 276an_resume_pci(device_t dev) 277{ 278 an_resume(dev); 279 280 return (0); 281} 282 283static device_method_t an_pci_methods[] = { 284 /* Device interface */ 285 DEVMETHOD(device_probe, an_probe_pci), 286 DEVMETHOD(device_attach, an_attach_pci), 287 DEVMETHOD(device_detach, an_detach_pci), 288 DEVMETHOD(device_shutdown, an_shutdown), 289 DEVMETHOD(device_suspend, an_suspend_pci), 290 DEVMETHOD(device_resume, an_resume_pci), 291 { 0, 0 } 292}; 293 294static driver_t an_pci_driver = { 295 "an", 296 an_pci_methods, 297 sizeof(struct an_softc), 298}; 299 300static devclass_t an_devclass; 301 302DRIVER_MODULE(an, pci, an_pci_driver, an_devclass, 0, 0); 303MODULE_DEPEND(an, pci, 1, 1, 1); 304MODULE_DEPEND(an, wlan, 1, 1, 1); 305