diff options
author | wpaul <wpaul@FreeBSD.org> | 2005-10-18 19:52:15 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2005-10-18 19:52:15 +0000 |
commit | 81737fff083ffbd9a4647cdb650c88e3b2ddfb0b (patch) | |
tree | eb7542dc4f8dcba11ed0c854bba191337a85c784 /sys/compat/ndis/kern_ndis.c | |
parent | 71b612fc9b17c019175bbd48e522b6d5079418d7 (diff) | |
download | FreeBSD-src-81737fff083ffbd9a4647cdb650c88e3b2ddfb0b.zip FreeBSD-src-81737fff083ffbd9a4647cdb650c88e3b2ddfb0b.tar.gz |
Another round of cleanups and fixes:
- Change ndis_return() from a DPC to a workitem so that it doesn't
run at DISPATCH_LEVEL (with the dispatcher lock held).
- In if_ndis.c, submit packets to the stack via (*ifp->if_input)() in
a workitem instead of doing it directly in ndis_rxeof(), because
ndis_rxeof() runs in a DPC, and hence at DISPATCH_LEVEL. This
implies that the 'dispatch level' mutex for the current CPU is
being held, and we don't want to call if_input while holding
any locks.
- Reimplement IoConnectInterrupt()/IoDisconnectInterrupt(). The original
approach I used to track down the interrupt resource (by scanning
the device tree starting at the nexus) is prone to problems when
two devices share an interrupt. (E.g removing ndis1 might disable
interrupts for ndis0.) The new approach is to multiplex all the
NDIS interrupts through a common internal dispatcher (ntoskrnl_intr())
and allow IoConnectInterrupt()/IoDisconnectInterrupt() to add or
remove interrupts from the dispatch list.
- Implement KeAcquireInterruptSpinLock() and KeReleaseInterruptSpinLock().
- Change the DPC and workitem threads to use the KeXXXSpinLock
API instead of mtx_lock_spin()/mtx_unlock_spin().
- Simplify the NdisXXXPacket routines by creating an actual
packet pool structure and using the InterlockedSList routines
to manage the packet queue.
- Only honor the value returned by OID_GEN_MAXIMUM_SEND_PACKETS
for serialized drivers. For deserialized drivers, we now create
a packet array of 64 entries. (The Microsoft DDK documentation
says that for deserialized miniports, OID_GEN_MAXIMUM_SEND_PACKETS
is ignored, and the driver for the Marvell 8335 chip, which is
a deserialized miniport, returns 1 when queried.)
- Clean up timer handling in subr_ntoskrnl.
- Add the following conditional debugging code:
NTOSKRNL_DEBUG_TIMERS - add debugging and stats for timers
NDIS_DEBUG_PACKETS - add extra sanity checking for NdisXXXPacket API
NTOSKRNL_DEBUG_SPINLOCKS - add test for spinning too long
- In kern_ndis.c, always start the HAL first and shut it down last,
since Windows spinlocks depend on it. Ntoskrnl should similarly be
started second and shut down next to last.
Diffstat (limited to 'sys/compat/ndis/kern_ndis.c')
-rw-r--r-- | sys/compat/ndis/kern_ndis.c | 118 |
1 files changed, 93 insertions, 25 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c index a3fd8309..a5754b6 100644 --- a/sys/compat/ndis/kern_ndis.c +++ b/sys/compat/ndis/kern_ndis.c @@ -84,7 +84,7 @@ static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); static void ndis_sendrsrcavail_func(ndis_handle); static void ndis_intrsetup(kdpc *, device_object *, irp *, struct ndis_softc *); -static void ndis_return(kdpc *, void *, void *, void *); +static void ndis_return(device_object *, void *); static image_patch_table kernndis_functbl[] = { IMPORT_SFUNC(ndis_status_func, 4), @@ -106,6 +106,18 @@ static struct nd_head ndis_devhead; * Note that we call ourselves 'ndisapi' to avoid a namespace * collision with if_ndis.ko, which internally calls itself * 'ndis.' + * + * Note: some of the subsystems depend on each other, so the + * order in which they're started is important. The order of + * importance is: + * + * HAL - spinlocks and IRQL manipulation + * ntoskrnl - DPC and workitem threads, object waiting + * windrv - driver/device registration + * + * The HAL should also be the last thing shut down, since + * the ntoskrnl subsystem will use spinlocks right up until + * the DPC and workitem threads are terminated. */ static int @@ -117,10 +129,10 @@ ndis_modevent(module_t mod, int cmd, void *arg) switch (cmd) { case MOD_LOAD: /* Initialize subsystems */ - windrv_libinit(); hal_libinit(); - ndis_libinit(); ntoskrnl_libinit(); + windrv_libinit(); + ndis_libinit(); usbd_libinit(); patch = kernndis_functbl; @@ -137,11 +149,11 @@ ndis_modevent(module_t mod, int cmd, void *arg) case MOD_SHUTDOWN: if (TAILQ_FIRST(&ndis_devhead) == NULL) { /* Shut down subsystems */ - hal_libfini(); ndis_libfini(); - ntoskrnl_libfini(); usbd_libfini(); windrv_libfini(); + ntoskrnl_libfini(); + hal_libfini(); patch = kernndis_functbl; while (patch->ipt_func != NULL) { @@ -152,11 +164,11 @@ ndis_modevent(module_t mod, int cmd, void *arg) break; case MOD_UNLOAD: /* Shut down subsystems */ - hal_libfini(); ndis_libfini(); - ntoskrnl_libfini(); usbd_libfini(); windrv_libfini(); + ntoskrnl_libfini(); + hal_libfini(); patch = kernndis_functbl; while (patch->ipt_func != NULL) { @@ -441,32 +453,39 @@ ndis_flush_sysctls(arg) } static void -ndis_return(dpc, arg, sysarg1, sysarg2) - kdpc *dpc; +ndis_return(dobj, arg) + device_object *dobj; void *arg; - void *sysarg1; - void *sysarg2; { - struct ndis_softc *sc; + ndis_miniport_block *block; + ndis_miniport_characteristics *ch; ndis_return_handler returnfunc; ndis_handle adapter; ndis_packet *p; uint8_t irql; + list_entry *l; + + block = arg; + ch = IoGetDriverObjectExtension(dobj->do_drvobj, (void *)1); p = arg; - sc = p->np_softc; - adapter = sc->ndis_block->nmb_miniportadapterctx; + adapter = block->nmb_miniportadapterctx; if (adapter == NULL) return; - returnfunc = sc->ndis_chars->nmc_return_packet_func; + returnfunc = ch->nmc_return_packet_func; - if (NDIS_SERIALIZED(sc->ndis_block)) - KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); - MSCALL2(returnfunc, adapter, p); - if (NDIS_SERIALIZED(sc->ndis_block)) - KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + KeAcquireSpinLock(&block->nmb_returnlock, &irql); + while (!IsListEmpty(&block->nmb_returnlist)) { + l = RemoveHeadList((&block->nmb_returnlist)); + p = CONTAINING_RECORD(l, ndis_packet, np_list); + InitializeListHead((&p->np_list)); + KeReleaseSpinLock(&block->nmb_returnlock, irql); + MSCALL2(returnfunc, adapter, p); + KeAcquireSpinLock(&block->nmb_returnlock, &irql); + } + KeReleaseSpinLock(&block->nmb_returnlock, irql); return; } @@ -477,6 +496,7 @@ ndis_return_packet(buf, arg) void *arg; { ndis_packet *p; + ndis_miniport_block *block; if (arg == NULL) return; @@ -490,8 +510,16 @@ ndis_return_packet(buf, arg) if (p->np_refcnt) return; - KeInitializeDpc(&p->np_dpc, kernndis_functbl[7].ipt_wrap, p); - KeInsertQueueDpc(&p->np_dpc, NULL, NULL); + block = ((struct ndis_softc *)p->np_softc)->ndis_block; + + KeAcquireSpinLockAtDpcLevel(&block->nmb_returnlock); + InitializeListHead((&p->np_list)); + InsertHeadList((&block->nmb_returnlist), (&p->np_list)); + KeReleaseSpinLockFromDpcLevel(&block->nmb_returnlock); + + IoQueueWorkItem(block->nmb_returnitem, + (io_workitem_func)kernndis_functbl[7].ipt_wrap, + WORKQUEUE_CRITICAL, block); return; } @@ -621,8 +649,13 @@ ndis_convert_res(arg) case SYS_RES_IRQ: prd->cprd_type = CmResourceTypeInterrupt; prd->cprd_flags = 0; + /* + * Always mark interrupt resources as + * shared, since in our implementation, + * they will be. + */ prd->cprd_sharedisp = - CmResourceShareDeviceExclusive; + CmResourceShareShared; prd->u.cprd_intr.cprd_level = brle->start; prd->u.cprd_intr.cprd_vector = brle->start; prd->u.cprd_intr.cprd_affinity = 0; @@ -1087,8 +1120,12 @@ ndis_halt_nic(arg) #ifdef NDIS_REAP_TIMERS ndis_miniport_timer *t, *n; #endif + ndis_miniport_block *block; + int empty = 0; + uint8_t irql; sc = arg; + block = sc->ndis_block; #ifdef NDIS_REAP_TIMERS /* @@ -1111,6 +1148,19 @@ ndis_halt_nic(arg) if (!cold) KeFlushQueuedDpcs(); + /* + * Wait for all packets to be returned. + */ + + while (1) { + KeAcquireSpinLock(&block->nmb_returnlock, &irql); + empty = IsListEmpty(&block->nmb_returnlist); + KeReleaseSpinLock(&block->nmb_returnlock, irql); + if (empty) + break; + NdisMSleep(1000); + } + NDIS_LOCK(sc); adapter = sc->ndis_block->nmb_miniportadapterctx; if (adapter == NULL) { @@ -1398,6 +1448,17 @@ NdisAddDevice(drv, pdo) ndis_miniport_block *block; struct ndis_softc *sc; uint32_t status; + int error; + + sc = device_get_softc(pdo->do_devext); + + if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) { + error = bus_setup_intr(sc->ndis_dev, sc->ndis_irq, + INTR_TYPE_NET | INTR_MPSAFE, + ntoskrnl_intr, NULL, &sc->ndis_intrhand); + if (error) + return(NDIS_STATUS_FAILURE); + } status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); @@ -1412,17 +1473,19 @@ NdisAddDevice(drv, pdo) block->nmb_physdeviceobj = pdo; block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); KeInitializeSpinLock(&block->nmb_lock); - InitializeListHead(&block->nmb_parmlist); + KeInitializeSpinLock(&block->nmb_returnlock); KeInitializeEvent(&block->nmb_getevent, EVENT_TYPE_NOTIFY, TRUE); KeInitializeEvent(&block->nmb_setevent, EVENT_TYPE_NOTIFY, TRUE); KeInitializeEvent(&block->nmb_resetevent, EVENT_TYPE_NOTIFY, TRUE); + InitializeListHead(&block->nmb_parmlist); + InitializeListHead(&block->nmb_returnlist); + block->nmb_returnitem = IoAllocateWorkItem(fdo); /* * Stash pointers to the miniport block and miniport * characteristics info in the if_ndis softc so the * UNIX wrapper driver can get to them later. */ - sc = device_get_softc(pdo->do_devext); sc->ndis_block = block; sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); @@ -1471,6 +1534,10 @@ ndis_unload_driver(arg) sc = arg; + if (sc->ndis_intrhand) + bus_teardown_intr(sc->ndis_dev, + sc->ndis_irq, sc->ndis_intrhand); + if (sc->ndis_block->nmb_rlist != NULL) free(sc->ndis_block->nmb_rlist, M_DEVBUF); @@ -1481,6 +1548,7 @@ ndis_unload_driver(arg) if (sc->ndis_chars->nmc_transferdata_func != NULL) NdisFreePacketPool(sc->ndis_block->nmb_rxpool); fdo = sc->ndis_block->nmb_deviceobj; + IoFreeWorkItem(sc->ndis_block->nmb_returnitem); IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); IoDeleteDevice(fdo); |