if_ndis_pci.c revision 131953
120253Sjoerg/* 220302Sjoerg * Copyright (c) 2003 320302Sjoerg * Bill Paul <wpaul@windriver.com>. All rights reserved. 420253Sjoerg * 520253Sjoerg * Redistribution and use in source and binary forms, with or without 620253Sjoerg * modification, are permitted provided that the following conditions 720253Sjoerg * are met: 820253Sjoerg * 1. Redistributions of source code must retain the above copyright 920302Sjoerg * notice, this list of conditions and the following disclaimer. 1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1120253Sjoerg * notice, this list of conditions and the following disclaimer in the 1220253Sjoerg * documentation and/or other materials provided with the distribution. 1320253Sjoerg * 3. All advertising materials mentioning features or use of this software 1420302Sjoerg * must display the following acknowledgement: 1520253Sjoerg * This product includes software developed by Bill Paul. 1620253Sjoerg * 4. Neither the name of the author nor the names of any co-contributors 1720302Sjoerg * may be used to endorse or promote products derived from this software 1820253Sjoerg * without specific prior written permission. 1920253Sjoerg * 2020253Sjoerg * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2120253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2220253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2320253Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2420253Sjoerg * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2544229Sdavidn * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2620253Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2720253Sjoerg * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2830259Scharnier * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2930259Scharnier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3050479Speter * THE POSSIBILITY OF SUCH DAMAGE. 3130259Scharnier */ 3230259Scharnier 3330259Scharnier#include <sys/cdefs.h> 3430259Scharnier__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_pci.c 131953 2004-07-11 00:19:30Z wpaul $"); 3520253Sjoerg 3620253Sjoerg#include <sys/param.h> 3720253Sjoerg#include <sys/systm.h> 3830259Scharnier#include <sys/kernel.h> 3920253Sjoerg#include <sys/module.h> 4020555Sdavidn#include <sys/socket.h> 4120555Sdavidn#include <sys/queue.h> 4220555Sdavidn#include <sys/sysctl.h> 4364918Sgreen 44242349Sbapt#include <net/if.h> 45242349Sbapt#include <net/if_arp.h> 46242349Sbapt#include <net/if_media.h> 4720253Sjoerg 4820253Sjoerg#include <machine/bus.h> 4920253Sjoerg#include <machine/resource.h> 5023318Sache#include <sys/bus.h> 5122394Sdavidn#include <sys/rman.h> 5252512Sdavidn 5324214Sache#include <net80211/ieee80211_var.h> 54284111Sbapt 55284128Sbapt#include <dev/pci/pcireg.h> 56284124Sbapt#include <dev/pci/pcivar.h> 57284133Sbapt 58284118Sbapt#include <compat/ndis/pe_var.h> 5920253Sjoerg#include <compat/ndis/resource_var.h> 6020253Sjoerg#include <compat/ndis/ntoskrnl_var.h> 6120253Sjoerg#include <compat/ndis/ndis_var.h> 6220253Sjoerg#include <compat/ndis/cfg_var.h> 6320253Sjoerg#include <dev/if_ndis/if_ndisvar.h> 6420253Sjoerg 6520253Sjoerg#include "ndis_driver_data.h" 6685145Sache 6720253Sjoerg#ifdef NDIS_PCI_DEV_TABLE 68283961Sbapt 69284118SbaptMODULE_DEPEND(ndis, pci, 1, 1, 1); 70283961SbaptMODULE_DEPEND(ndis, ether, 1, 1, 1); 71283961SbaptMODULE_DEPEND(ndis, wlan, 1, 1, 1); 72284118SbaptMODULE_DEPEND(ndis, ndisapi, 1, 1, 1); 73283961Sbapt 74283961Sbapt/* 75283961Sbapt * Various supported device vendors/types and their names. 76284118Sbapt * These are defined in the ndis_driver_data.h file. 77284118Sbapt */ 78283961Sbaptstatic struct ndis_pci_type ndis_devs[] = { 79283961Sbapt#ifdef NDIS_PCI_DEV_TABLE 80284118Sbapt NDIS_PCI_DEV_TABLE 81283961Sbapt#endif 82283961Sbapt { 0, 0, 0, NULL } 83283961Sbapt}; 84283961Sbapt 85283961Sbaptstatic int ndis_probe_pci (device_t); 86283961Sbaptstatic int ndis_attach_pci (device_t); 87283961Sbaptstatic struct resource_list *ndis_get_resource_list 88283961Sbapt (device_t, device_t); 89285133Sbaptextern int ndis_attach (device_t); 90285137Sbaptextern int ndis_shutdown (device_t); 91285133Sbaptextern int ndis_detach (device_t); 92285133Sbaptextern int ndis_suspend (device_t); 93285133Sbaptextern int ndis_resume (device_t); 94285133Sbapt 95285133Sbaptextern struct mtx_pool *ndis_mtxpool; 96285133Sbapt 97285133Sbaptstatic device_method_t ndis_methods[] = { 98285133Sbapt /* Device interface */ 99285133Sbapt DEVMETHOD(device_probe, ndis_probe_pci), 100285133Sbapt DEVMETHOD(device_attach, ndis_attach_pci), 101285133Sbapt DEVMETHOD(device_detach, ndis_detach), 102285133Sbapt DEVMETHOD(device_shutdown, ndis_shutdown), 103285133Sbapt DEVMETHOD(device_suspend, ndis_suspend), 104285133Sbapt DEVMETHOD(device_resume, ndis_resume), 105285133Sbapt 106285133Sbapt /* Bus interface */ 107285133Sbapt DEVMETHOD(bus_get_resource_list, ndis_get_resource_list), 108285133Sbapt 109285133Sbapt { 0, 0 } 110285137Sbapt}; 111285133Sbapt 112285133Sbaptstatic driver_t ndis_driver = { 113285133Sbapt#ifdef NDIS_DEVNAME 114285133Sbapt NDIS_DEVNAME, 115285133Sbapt#else 116285133Sbapt "ndis", 117285133Sbapt#endif 118285133Sbapt ndis_methods, 119285133Sbapt sizeof(struct ndis_softc) 120285133Sbapt}; 121285133Sbapt 122285133Sbaptstatic devclass_t ndis_devclass; 123285133Sbapt 124285133Sbapt#ifdef NDIS_MODNAME 125285133Sbapt#define NDIS_MODNAME_OVERRIDE_PCI(x) \ 126285133Sbapt DRIVER_MODULE(x, pci, ndis_driver, ndis_devclass, 0, 0) 127285133Sbapt#define NDIS_MODNAME_OVERRIDE_CARDBUS(x) \ 128285133Sbapt DRIVER_MODULE(x, cardbus, ndis_driver, ndis_devclass, 0, 0) 129285133SbaptNDIS_MODNAME_OVERRIDE_PCI(NDIS_MODNAME); 130285133SbaptNDIS_MODNAME_OVERRIDE_CARDBUS(NDIS_MODNAME); 131285133Sbapt#else 132285133SbaptDRIVER_MODULE(ndis, pci, ndis_driver, ndis_devclass, 0, 0); 133285133SbaptDRIVER_MODULE(ndis, cardbus, ndis_driver, ndis_devclass, 0, 0); 134285133Sbapt#endif 135285133Sbapt 136285133Sbapt/* 137285133Sbapt * Probe for an NDIS device. Check the PCI vendor and device 138285137Sbapt * IDs against our list and return a device name if we find a match. 139285133Sbapt */ 140285133Sbaptstatic int 141285133Sbaptndis_probe_pci(dev) 142285133Sbapt device_t dev; 143285133Sbapt{ 144285133Sbapt struct ndis_pci_type *t; 145285133Sbapt 146285133Sbapt t = ndis_devs; 147285133Sbapt 148285133Sbapt while(t->ndis_name != NULL) { 149285133Sbapt if ((pci_get_vendor(dev) == t->ndis_vid) && 150285133Sbapt (pci_get_device(dev) == t->ndis_did) && 151285395Sbapt ((pci_read_config(dev, PCIR_SUBVEND_0, 4) == 152285395Sbapt t->ndis_subsys) || t->ndis_subsys == 0)) { 153285395Sbapt device_set_desc(dev, t->ndis_name); 154285395Sbapt return(0); 155285395Sbapt } 156285395Sbapt t++; 157285395Sbapt } 158285395Sbapt 159285395Sbapt return(ENXIO); 160285395Sbapt} 161285395Sbapt 162285395Sbapt/* 163285395Sbapt * Attach the interface. Allocate softc structures, do ifmedia 164285395Sbapt * setup and ethernet/BPF attach. 16520253Sjoerg */ 16620253Sjoergstatic int 16720253Sjoergndis_attach_pci(dev) 16820253Sjoerg device_t dev; 16920253Sjoerg{ 17020253Sjoerg struct ndis_softc *sc; 17120253Sjoerg int unit, error = 0, rid; 17220253Sjoerg struct ndis_pci_type *t; 17320253Sjoerg int devidx = 0, defidx = 0; 17420253Sjoerg struct resource_list *rl; 17520253Sjoerg struct resource_list_entry *rle; 17620253Sjoerg 17720253Sjoerg sc = device_get_softc(dev); 17820253Sjoerg unit = device_get_unit(dev); 17920253Sjoerg sc->ndis_dev = dev; 18020253Sjoerg 18120253Sjoerg /* 182124382Siedowse * Map control/status registers. 18320253Sjoerg */ 18420253Sjoerg 18520253Sjoerg pci_enable_busmaster(dev); 18620253Sjoerg 18720253Sjoerg rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 18820253Sjoerg if (rl != NULL) { 18920253Sjoerg SLIST_FOREACH(rle, rl, link) { 19020253Sjoerg switch (rle->type) { 19120253Sjoerg case SYS_RES_IOPORT: 19220253Sjoerg sc->ndis_io_rid = rle->rid; 19320253Sjoerg sc->ndis_res_io = bus_alloc_resource(dev, 19420253Sjoerg SYS_RES_IOPORT, &sc->ndis_io_rid, 19520253Sjoerg 0, ~0, 1, RF_ACTIVE); 19620253Sjoerg if (sc->ndis_res_io == NULL) { 19720253Sjoerg device_printf(dev, 198284128Sbapt "couldn't map iospace\n"); 19920253Sjoerg error = ENXIO; 20052527Sdavidn goto fail; 20120253Sjoerg } 20252512Sdavidn break; 20320253Sjoerg case SYS_RES_MEMORY: 20420253Sjoerg if (sc->ndis_res_altmem != NULL && 20520253Sjoerg sc->ndis_res_mem != NULL) { 20620253Sjoerg device_printf(dev, 207284118Sbapt "too many memory resources\n"); 20820747Sdavidn error = ENXIO; 209283961Sbapt goto fail; 21082868Sdd } 211167919Sle if (rle->rid == PCIR_BAR(2)) { 212167919Sle sc->ndis_altmem_rid = rle->rid; 21320253Sjoerg sc->ndis_res_altmem = 21420253Sjoerg bus_alloc_resource(dev, 21520253Sjoerg SYS_RES_MEMORY, 21620253Sjoerg &sc->ndis_altmem_rid, 21720253Sjoerg 0, ~0, 1, RF_ACTIVE); 21820253Sjoerg if (sc->ndis_res_altmem == NULL) { 21920253Sjoerg device_printf(dev, 22020253Sjoerg "couldn't map alt " 22120253Sjoerg "memory\n"); 22220253Sjoerg error = ENXIO; 22356000Sdavidn goto fail; 22420253Sjoerg } 22520253Sjoerg } else { 22656000Sdavidn sc->ndis_mem_rid = rle->rid; 22756000Sdavidn sc->ndis_res_mem = 22856000Sdavidn bus_alloc_resource(dev, 22920253Sjoerg SYS_RES_MEMORY, 23020253Sjoerg &sc->ndis_mem_rid, 231284118Sbapt 0, ~0, 1, RF_ACTIVE); 23252512Sdavidn if (sc->ndis_res_mem == NULL) { 233284149Sbapt device_printf(dev, 234285396Sbapt "couldn't map memory\n"); 23520267Sjoerg error = ENXIO; 23620267Sjoerg goto fail; 23720253Sjoerg } 23820253Sjoerg } 23920253Sjoerg break; 24020253Sjoerg case SYS_RES_IRQ: 24120267Sjoerg rid = rle->rid; 24220253Sjoerg sc->ndis_irq = bus_alloc_resource(dev, 24321052Sdavidn SYS_RES_IRQ, &rid, 0, ~0, 1, 244167919Sle RF_SHAREABLE | RF_ACTIVE); 245167919Sle if (sc->ndis_irq == NULL) { 246167919Sle device_printf(dev, 247167919Sle "couldn't map interrupt\n"); 248167919Sle error = ENXIO; 249219408Sjkim goto fail; 250167919Sle } 251168044Sle break; 252167919Sle default: 25321052Sdavidn break; 25421052Sdavidn } 25521052Sdavidn sc->ndis_rescnt++; 25621052Sdavidn } 257224535Sdelphij } 25821052Sdavidn 25921052Sdavidn /* 26021052Sdavidn * If the BIOS did not set up an interrupt for this device, 26121052Sdavidn * the resource traversal code above will fail to set up 26221052Sdavidn * an IRQ resource. This is usually a bad thing, so try to 26321052Sdavidn * force the allocation of an interrupt here. If one was 26430259Scharnier * not assigned to us by the BIOS, bus_alloc_resource() 26521052Sdavidn * should route one for us. 26621052Sdavidn */ 26721052Sdavidn if (sc->ndis_irq == NULL) { 26821052Sdavidn rid = 0; 26921242Sdavidn sc->ndis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, 27021242Sdavidn &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 27121242Sdavidn if (sc->ndis_irq == NULL) { 27221242Sdavidn device_printf(dev, "couldn't route interrupt\n"); 27321242Sdavidn error = ENXIO; 27421242Sdavidn goto fail; 27521242Sdavidn } 276282683Sbapt sc->ndis_rescnt++; 277219408Sjkim } 27821242Sdavidn 279148584Spjd /* 280148584Spjd * Allocate the parent bus DMA tag appropriate for PCI. 281148584Spjd */ 282148584Spjd#define NDIS_NSEG_NEW 32 283148584Spjd error = bus_dma_tag_create(NULL, /* parent */ 28421242Sdavidn 1, 0, /* alignment, boundary */ 28521242Sdavidn BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 28621242Sdavidn BUS_SPACE_MAXADDR, /* highaddr */ 287130633Srobert NULL, NULL, /* filter, filterarg */ 288130633Srobert MAXBSIZE, NDIS_NSEG_NEW,/* maxsize, nsegments */ 28921242Sdavidn BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 290252377Skientzle BUS_DMA_ALLOCNOW, /* flags */ 29121242Sdavidn NULL, NULL, /* lockfunc, lockarg */ 29221242Sdavidn &sc->ndis_parent_tag); 293219408Sjkim 29421242Sdavidn if (error) 29521242Sdavidn goto fail; 29621242Sdavidn 29730259Scharnier sc->ndis_iftype = PCIBus; 29821242Sdavidn 29921242Sdavidn /* Figure out exactly which device we matched. */ 30021052Sdavidn 30121242Sdavidn t = ndis_devs; 302219408Sjkim 30330259Scharnier while(t->ndis_name != NULL) { 30421052Sdavidn if ((pci_get_vendor(dev) == t->ndis_vid) && 30521052Sdavidn (pci_get_device(dev) == t->ndis_did)) { 30621052Sdavidn if (t->ndis_subsys == 0) 30721052Sdavidn defidx = devidx; 30830259Scharnier else { 30921052Sdavidn if (t->ndis_subsys == 31021052Sdavidn pci_read_config(dev, PCIR_SUBVEND_0, 4)) 31120253Sjoerg break; 31220253Sjoerg } 31320253Sjoerg } 31421330Sdavidn t++; 31521330Sdavidn devidx++; 31621330Sdavidn } 31720253Sjoerg 31820253Sjoerg if (ndis_devs[devidx].ndis_name == NULL) 31920253Sjoerg sc->ndis_devidx = defidx; 32020253Sjoerg else 32163596Sdavidn sc->ndis_devidx = devidx; 32263596Sdavidn 32363596Sdavidn error = ndis_attach(dev); 32463596Sdavidn 32563596Sdavidnfail: 32663596Sdavidn return(error); 32763596Sdavidn} 32863596Sdavidn 32920253Sjoergstatic struct resource_list * 33020253Sjoergndis_get_resource_list(dev, child) 33120253Sjoerg device_t dev; 332284110Sbapt device_t child; 33320253Sjoerg{ 33420253Sjoerg struct ndis_softc *sc; 33552527Sdavidn 33620253Sjoerg sc = device_get_softc(dev); 33720747Sdavidn return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev)); 33844229Sdavidn} 33961957Sache 34030259Scharnier#endif /* NDIS_PCI_DEV_TABLE */ 34120253Sjoerg