Home | History | Annotate | Line # | Download | only in if_ndis
if_ndis_pci.c revision 1.20
      1 /*-
      2  * Copyright (c) 2003
      3  *	Bill Paul <wpaul (at) windriver.com>.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by Bill Paul.
     16  * 4. Neither the name of the author nor the names of any co-contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     30  * THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: if_ndis_pci.c,v 1.19 2012/10/27 17:18:23 chs Exp $");
     35 #ifdef __FreeBSD__
     36 __FBSDID("$FreeBSD: src/sys/dev/if_ndis/if_ndis_pci.c,v 1.8.2.3 2005/03/31 04:24:36 wpaul Exp $");
     37 #endif
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/kernel.h>
     42 #include <sys/module.h>
     43 #include <sys/socket.h>
     44 #include <sys/queue.h>
     45 #include <sys/sysctl.h>
     46 
     47 #include <net/if.h>
     48 #include <net/if_arp.h>
     49 #include <net/if_media.h>
     50 
     51 #include <sys/bus.h>
     52 
     53 #include <sys/kthread.h>
     54 #include <net/if_ether.h>
     55 
     56 #include <net80211/ieee80211_var.h>
     57 
     58 #include <dev/pci/pcireg.h>
     59 #include <dev/pci/pcivar.h>
     60 
     61 #include <compat/ndis/pe_var.h>
     62 #include <compat/ndis/resource_var.h>
     63 #include <compat/ndis/ntoskrnl_var.h>
     64 #include <compat/ndis/ndis_var.h>
     65 #include <compat/ndis/cfg_var.h>
     66 #include <dev/if_ndis/if_ndisvar.h>
     67 
     68 #include "ndis_driver_data.h"
     69 
     70 #ifndef _MODULE
     71 #include <compat/ndis/hal_var.h>
     72 #endif
     73 
     74 #ifdef NDIS_PCI_DEV_TABLE
     75 
     76 
     77 /*
     78  * Various supported device vendors/types and their names.
     79  * These are defined in the ndis_driver_data.h file.
     80  */
     81 static struct ndis_pci_type ndis_devs[] = {
     82 #ifdef NDIS_PCI_DEV_TABLE
     83 	NDIS_PCI_DEV_TABLE
     84 #endif
     85 	{ 0, 0, 0, NULL }
     86 };
     87 
     88 /*static*/ int  ndis_probe_pci(device_t parent,
     89 				cfdata_t match,
     90 				void *aux);
     91 /*static*/ void ndis_attach_pci(device_t parent,
     92 				device_t self,
     93 				void *aux);
     94 extern void ndis_attach		(void *);
     95 extern int ndis_shutdown	(device_t);
     96 extern int ndis_detach		(device_t, int);
     97 extern int ndis_suspend		(device_t);
     98 extern int ndis_resume		(device_t);
     99 
    100 extern int ndis_intr(void *);
    101 
    102 extern unsigned char drv_data[];
    103 
    104 #ifndef _MODULE
    105 //static funcptr ndis_txeof_wrap;
    106 //static funcptr ndis_rxeof_wrap;
    107 //static funcptr ndis_linksts_wrap;
    108 //static funcptr ndis_linksts_done_wrap;
    109 #endif
    110 
    111 
    112 CFATTACH_DECL_NEW(
    113 #ifdef NDIS_DEVNAME
    114 	NDIS_DEVNAME,
    115 #else
    116 	ndis,
    117 #endif
    118 	sizeof(struct ndis_softc),
    119 	ndis_probe_pci,
    120 	ndis_attach_pci,
    121 	ndis_detach,
    122 	NULL);
    123 
    124 
    125 
    126 #ifdef _MODULE
    127 extern int
    128 ndisdrv_modevent(module_t mod, int cmd);
    129 
    130 /*
    131  * These are just for the in-kernel version, to delay calling
    132  * these functions untill enough context is built up.
    133  */
    134 void load_ndisapi(void *);
    135 void load_ndisdrv(void *);
    136 
    137 void load_ndisapi(void *arg)
    138 {
    139 	ndis_lkm_handle(NULL, MOD_LOAD);
    140 }
    141 void load_ndisdrv(void *arg)
    142 {
    143 	ndisdrv_modevent(NULL, MOD_LOAD);
    144 }
    145 #endif
    146 
    147 /*static*/ int
    148 ndis_probe_pci(device_t parent, cfdata_t match, void *aux)
    149 {
    150 	struct pci_attach_args *pa = aux;
    151 	int vendor  = PCI_VENDOR(pa->pa_id);
    152 	int product = PCI_PRODUCT(pa->pa_id);
    153 
    154 	struct ndis_pci_type *t = ndis_devs;
    155 	driver_object        *drv = NULL;	/* = windrv_lookup(0, "PCI Bus");**/
    156 
    157 #ifdef NDIS_DBG
    158 	printf("in ndis_probe_pci\n");
    159 	printf("vendor = %x, product = %x\n", vendor, product);
    160 #endif
    161 
    162 	while(t->ndis_name != NULL) {
    163 #ifdef NDIS_DBG
    164 			printf("t->ndis_vid = %x, t->ndis_did = %x\n",
    165 			       t->ndis_vid, t->ndis_did);
    166 #endif
    167 		if((vendor  == t->ndis_vid) && (product == t->ndis_did)) {
    168 #ifdef _MODULE
    169 			ndisdrv_modevent(NULL, MOD_LOAD);
    170 			//kthread_create(load_ndisdrv, NULL);
    171 #endif /* _MODULE */
    172 
    173 			drv = windrv_lookup(0, "PCI Bus");
    174 			printf("Matching vendor: %x, product: %x, name: %s\n", vendor, product, t->ndis_name);
    175 			windrv_create_pdo(drv, parent);
    176 			return 1;
    177 		}
    178 		t++;
    179 	}
    180 
    181 	return 0;  /* dosen't match */
    182 }
    183 
    184 /* 6 BADR's + 1 IRQ  (so far) */
    185 #define MAX_RESOURCES 7
    186 
    187 /*static*/
    188 void ndis_attach_pci(device_t parent, device_t self, void *aux)
    189 {
    190 	struct ndis_softc *sc = device_private(self);
    191 	struct pci_attach_args *pa = aux;
    192 #ifdef NDIS_DBG
    193 	char devinfo[256];
    194 #endif
    195 	pci_intr_handle_t ih;
    196 	pcireg_t type;
    197 	bus_addr_t	base;
    198 	bus_size_t	size;
    199 	int		flags;
    200 	ndis_resource_list 		*rl  = NULL;
    201 	struct cm_partial_resource_desc	*prd = NULL;
    202 #ifdef NDIS_DBG
    203 	struct pci_conf_state conf_state;
    204 	int revision, i;
    205 #endif
    206 	int bar;
    207 
    208 	printf("in ndis_attach_pci()\n");
    209 
    210 	/* initalize the softc */
    211 	//sc->ndis_hardware_type  = NDIS_PCI;
    212 	sc->ndis_dev		= self;
    213 	sc->ndis_iftype 	= PCIBus;
    214 	sc->ndis_res_pc		= pa->pa_pc;
    215 	sc->ndis_res_pctag	= pa->pa_tag;
    216 	/* TODO: is this correct? All are just pa->pa_dmat? */
    217 	sc->ndis_mtag		= pa->pa_dmat;
    218 	sc->ndis_ttag		= pa->pa_dmat;
    219 	sc->ndis_parent_tag 	= pa->pa_dmat;
    220 	sc->ndis_res_io		= NULL;
    221 	sc->ndis_res_mem	= NULL;
    222 	sc->ndis_res_altmem	= NULL;
    223 	sc->ndis_block 		= NULL;
    224 	sc->ndis_shlist		= NULL;
    225 
    226 	ndis_in_isr		= FALSE;
    227 
    228 	printf("sc->ndis_mtag = %x\n", (unsigned int)sc->ndis_mtag);
    229 
    230 	rl = malloc(sizeof(ndis_resource_list) +
    231 	    (sizeof(cm_partial_resource_desc) * (MAX_RESOURCES-1)),
    232 	    M_DEVBUF, M_NOWAIT|M_ZERO);
    233 
    234 	if(rl == NULL) {
    235 		sc->error = ENOMEM;
    236 		//printf("error: out of memory\n");
    237 		return;
    238 	}
    239 
    240 	rl->cprl_version = 5;
    241 	rl->cprl_version = 1;
    242 	rl->cprl_count = 0;
    243 	prd = rl->cprl_partial_descs;
    244 
    245 #ifdef NDIS_DBG
    246         pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof devinfo);
    247         revision = PCI_REVISION(pa->pa_class);
    248         printf(": %s (rev. 0x%02x)\n", devinfo, revision);
    249 
    250 	pci_conf_print(sc->ndis_res_pc, sc->ndis_res_pctag, NULL);
    251 
    252 	pci_conf_capture(sc->ndis_res_pc, sc->ndis_res_pctag, &conf_state);
    253 	for(i=0; i<16; i++) {
    254 		printf("conf_state.reg[%d] = %x\n", i, conf_state.reg[i]);
    255 	}
    256 #endif
    257 
    258 	/* just do the conversion work in attach instead of calling ndis_convert_res() */
    259 	for(bar = 0x10; bar <= 0x24; bar += 0x04) {
    260 		type = pci_mapreg_type(sc->ndis_res_pc, sc->ndis_res_pctag, bar);
    261 		if(pci_mapreg_info(sc->ndis_res_pc, sc->ndis_res_pctag, bar, type, &base,
    262 			&size, &flags)) {
    263 			printf("pci_mapreg_info() failed on BAR 0x%x!\n", bar);
    264 		} else {
    265 			switch(type) {
    266 			case PCI_MAPREG_TYPE_IO:
    267 				prd->cprd_type 				= CmResourceTypePort;
    268 				prd->cprd_flags 			= CM_RESOURCE_PORT_IO;
    269 				prd->u.cprd_port.cprd_start.np_quad 	= (uint64_t)base;
    270 				prd->u.cprd_port.cprd_len  	  	= (uint32_t)size;
    271 				if((sc->ndis_res_io =
    272 					malloc(sizeof(struct ndis_resource), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
    273 					//printf("error: out of memory\n");
    274 					sc->error = ENOMEM;
    275 					return;
    276 				}
    277 				sc->ndis_res_io->res_base = base;
    278 				sc->ndis_res_io->res_size = size;
    279 				sc->ndis_res_io->res_tag  = x86_bus_space_io;
    280 				bus_space_map(sc->ndis_res_io->res_tag,
    281 					 sc->ndis_res_io->res_base,
    282 					 sc->ndis_res_io->res_size,
    283 					 flags,
    284 					&sc->ndis_res_io->res_handle);
    285 				break;
    286 			case PCI_MAPREG_TYPE_MEM:
    287 				prd->cprd_type 				= CmResourceTypeMemory;
    288 				prd->cprd_flags 			= CM_RESOURCE_MEMORY_READ_WRITE;
    289 				prd->u.cprd_mem.cprd_start.np_quad 	= (uint64_t)base;
    290 				prd->u.cprd_mem.cprd_len		= (uint32_t)size;
    291 
    292 				if(sc->ndis_res_mem != NULL &&
    293 					sc->ndis_res_altmem != NULL) {
    294 					printf("too many resources\n");
    295 					sc->error = ENXIO;
    296 					return;
    297 				}
    298 				if(sc->ndis_res_mem) {
    299 					if((sc->ndis_res_altmem =
    300 						malloc(sizeof(struct ndis_resource), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
    301 						sc->error = ENOMEM;
    302 						return;
    303 					}
    304 					sc->ndis_res_altmem->res_base = base;
    305 					sc->ndis_res_altmem->res_size = size;
    306 					sc->ndis_res_altmem->res_tag  = x86_bus_space_mem;
    307 
    308 
    309 					if(bus_space_map(sc->ndis_res_altmem->res_tag,
    310 						sc->ndis_res_altmem->res_base,
    311 						sc->ndis_res_altmem->res_size,
    312 						flags|BUS_SPACE_MAP_LINEAR,
    313 						&sc->ndis_res_altmem->res_handle)) {
    314 							printf("bus_space_map failed\n");
    315 					}
    316 				} else {
    317 					if((sc->ndis_res_mem =
    318 						malloc(sizeof(struct ndis_resource), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
    319 						sc->error = ENOMEM;
    320 						return;
    321 					}
    322 					sc->ndis_res_mem->res_base = base;
    323 					sc->ndis_res_mem->res_size = size;
    324 					sc->ndis_res_mem->res_tag  = x86_bus_space_mem;
    325 
    326 					if(bus_space_map(sc->ndis_res_mem->res_tag,
    327 						sc->ndis_res_mem->res_base,
    328 						sc->ndis_res_mem->res_size,
    329 						flags|BUS_SPACE_MAP_LINEAR,
    330 						&sc->ndis_res_mem->res_handle)) {
    331 							printf("bus_space_map failed\n");
    332 					}
    333 				}
    334 				break;
    335 
    336 			default:
    337 				printf("unknown type\n");
    338 			}
    339 			prd->cprd_sharedisp = CmResourceShareDeviceExclusive;
    340 
    341 			rl->cprl_count++;
    342 			prd++;
    343 		}
    344 	}
    345 
    346 	/* add the interrupt to the list */
    347 	prd->cprd_type 	= CmResourceTypeInterrupt;
    348 	prd->cprd_flags = 0;
    349 	/* TODO: is this all we need to save for the interrupt? */
    350 	prd->u.cprd_intr.cprd_level = pa->pa_intrline;
    351 	prd->u.cprd_intr.cprd_vector = pa->pa_intrline;
    352 	prd->u.cprd_intr.cprd_affinity = 0;
    353 	rl->cprl_count++;
    354 
    355 	pci_intr_map(pa, &ih);
    356 	sc->ndis_intrhand = pci_intr_establish(pa->pa_pc, ih, IPL_NET /*| PCATCH*/, ndis_intr, sc);
    357 	sc->ndis_irq = (void *)sc->ndis_intrhand;
    358 
    359 	printf("pci interrupt: %s\n", pci_intr_string(pa->pa_pc, ih));
    360 
    361 	/* save resource list in the softc */
    362 	sc->ndis_rl = rl;
    363 	sc->ndis_rescnt = rl->cprl_count;
    364 
    365 	kthread_create(PRI_NONE, 0, NULL, ndis_attach, (void *)sc,
    366 	    NULL, "ndis_attach");
    367 }
    368 
    369 
    370 #endif /* NDIS_PCI_DEV_TABLE */
    371