mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-19 10:53:58 +00:00
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.
This commit is contained in:
parent
8c4b6380c7
commit
a3ced67adf
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=151451
@ -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);
|
||||
|
||||
|
@ -343,6 +343,7 @@ typedef uint8_t ndis_kirql;
|
||||
#define NDIS_80211_NETTYPE_11DS 0x00000001
|
||||
#define NDIS_80211_NETTYPE_11OFDM5 0x00000002
|
||||
#define NDIS_80211_NETTYPE_11OFDM24 0x00000003
|
||||
#define NDIS_80211_NETTYPE_AUTO 0x00000004
|
||||
|
||||
struct ndis_80211_nettype_list {
|
||||
uint32_t ntl_items;
|
||||
@ -1312,12 +1313,24 @@ struct ndis_packet {
|
||||
void *np_softc;
|
||||
void *np_m0;
|
||||
int np_txidx;
|
||||
kdpc np_dpc;
|
||||
kspin_lock np_lock;
|
||||
list_entry np_list;
|
||||
};
|
||||
|
||||
typedef struct ndis_packet ndis_packet;
|
||||
|
||||
struct ndis_packet_pool {
|
||||
slist_header np_head;
|
||||
int np_dead;
|
||||
nt_kevent np_event;
|
||||
kspin_lock np_lock;
|
||||
int np_cnt;
|
||||
int np_len;
|
||||
int np_protrsvd;
|
||||
void *np_pktmem;
|
||||
};
|
||||
|
||||
typedef struct ndis_packet_pool ndis_packet_pool;
|
||||
|
||||
/* mbuf ext type for NDIS */
|
||||
#define EXT_NDIS 0x999
|
||||
|
||||
@ -1617,8 +1630,11 @@ struct ndis_miniport_block {
|
||||
ndis_status nmb_setstat;
|
||||
nt_kevent nmb_setevent;
|
||||
nt_kevent nmb_resetevent;
|
||||
io_workitem *nmb_returnitem;
|
||||
ndis_miniport_timer *nmb_timerlist;
|
||||
ndis_handle nmb_rxpool;
|
||||
list_entry nmb_returnlist;
|
||||
kspin_lock nmb_returnlock;
|
||||
TAILQ_ENTRY(ndis_miniport_block) link;
|
||||
};
|
||||
|
||||
@ -1747,7 +1763,7 @@ extern void NdisAllocatePacket(ndis_status *,
|
||||
ndis_packet **, ndis_handle);
|
||||
extern void NdisFreePacket(ndis_packet *);
|
||||
extern ndis_status NdisScheduleWorkItem(ndis_work_item *);
|
||||
|
||||
extern void NdisMSleep(uint32_t);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _NDIS_VAR_H_ */
|
||||
|
@ -35,6 +35,8 @@
|
||||
#ifndef _NTOSKRNL_VAR_H_
|
||||
#define _NTOSKRNL_VAR_H_
|
||||
|
||||
#define MTX_NTOSKRNL_SPIN_LOCK "NDIS thread lock"
|
||||
|
||||
/*
|
||||
* us_buf is really a wchar_t *, but it's inconvenient to include
|
||||
* all the necessary header goop needed to define it, and it's a
|
||||
@ -573,7 +575,9 @@ typedef struct custom_extension custom_extension;
|
||||
*/
|
||||
|
||||
struct kinterrupt {
|
||||
list_entry ki_list;
|
||||
device_t ki_dev;
|
||||
int ki_rid;
|
||||
void *ki_cookie;
|
||||
struct resource *ki_irq;
|
||||
kspin_lock ki_lock_priv;
|
||||
@ -1304,6 +1308,12 @@ extern void ctxsw_wtou(void);
|
||||
extern int ntoskrnl_libinit(void);
|
||||
extern int ntoskrnl_libfini(void);
|
||||
|
||||
extern void ntoskrnl_intr(void *);
|
||||
|
||||
extern uint16_t ExQueryDepthSList(slist_header *);
|
||||
extern slist_entry
|
||||
*InterlockedPushEntrySList(slist_header *, slist_entry *);
|
||||
extern slist_entry *InterlockedPopEntrySList(slist_header *);
|
||||
extern uint32_t RtlUnicodeStringToAnsiString(ansi_string *,
|
||||
unicode_string *, uint8_t);
|
||||
extern uint32_t RtlAnsiStringToUnicodeString(unicode_string *,
|
||||
@ -1342,6 +1352,8 @@ extern void KeAcquireSpinLockAtDpcLevel(kspin_lock *);
|
||||
extern void KeReleaseSpinLockFromDpcLevel(kspin_lock *);
|
||||
#endif
|
||||
extern void KeInitializeSpinLock(kspin_lock *);
|
||||
extern uint8_t KeAcquireInterruptSpinLock(kinterrupt *);
|
||||
extern void KeReleaseInterruptSpinLock(kinterrupt *, uint8_t);
|
||||
extern uint8_t KeSynchronizeExecution(kinterrupt *, void *, void *);
|
||||
extern uintptr_t InterlockedExchange(volatile uint32_t *,
|
||||
uintptr_t);
|
||||
|
@ -112,7 +112,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm_map.h>
|
||||
|
||||
static char ndis_filepath[MAXPATHLEN];
|
||||
extern struct nd_head ndis_devhead;
|
||||
|
||||
SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath,
|
||||
MAXPATHLEN, "Path used by NdisOpenFile() to search for files");
|
||||
@ -238,7 +237,6 @@ static void NdisGetBufferPhysicalArraySize(ndis_buffer *,
|
||||
uint32_t *);
|
||||
static void NdisQueryBufferOffset(ndis_buffer *,
|
||||
uint32_t *, uint32_t *);
|
||||
static void NdisMSleep(uint32_t);
|
||||
static uint32_t NdisReadPcmciaAttributeMemory(ndis_handle,
|
||||
uint32_t, void *, uint32_t);
|
||||
static uint32_t NdisWritePcmciaAttributeMemory(ndis_handle,
|
||||
@ -421,7 +419,6 @@ NdisMRegisterMiniport(handle, characteristics, len)
|
||||
if (IoAllocateDriverObjectExtension(drv, (void *)1,
|
||||
sizeof(ndis_miniport_characteristics), (void **)&ch) !=
|
||||
STATUS_SUCCESS) {
|
||||
printf("register error\n");
|
||||
return(NDIS_STATUS_RESOURCES);
|
||||
}
|
||||
|
||||
@ -1846,27 +1843,43 @@ NdisAllocatePacketPool(status, pool, descnum, protrsvdlen)
|
||||
uint32_t descnum;
|
||||
uint32_t protrsvdlen;
|
||||
{
|
||||
ndis_packet *cur;
|
||||
ndis_packet_pool *p;
|
||||
ndis_packet *packets;
|
||||
int i;
|
||||
|
||||
*pool = malloc((sizeof(ndis_packet) + protrsvdlen) *
|
||||
((descnum + NDIS_POOL_EXTRA) + 1),
|
||||
M_DEVBUF, M_NOWAIT|M_ZERO);
|
||||
|
||||
if (*pool == NULL) {
|
||||
p = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_packet_pool), 0);
|
||||
if (p == NULL) {
|
||||
*status = NDIS_STATUS_RESOURCES;
|
||||
return;
|
||||
}
|
||||
|
||||
cur = (ndis_packet *)*pool;
|
||||
KeInitializeSpinLock(&cur->np_lock);
|
||||
cur->np_private.npp_flags = 0x1; /* mark the head of the list */
|
||||
cur->np_private.npp_totlen = 0; /* init deletetion flag */
|
||||
for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
|
||||
cur->np_private.npp_head = (ndis_handle)(cur + 1);
|
||||
cur++;
|
||||
p->np_cnt = descnum + NDIS_POOL_EXTRA;
|
||||
p->np_protrsvd = protrsvdlen;
|
||||
p->np_len = sizeof(ndis_packet) + protrsvdlen;
|
||||
|
||||
packets = ExAllocatePoolWithTag(NonPagedPool, p->np_cnt *
|
||||
p->np_len, 0);
|
||||
|
||||
|
||||
if (packets == NULL) {
|
||||
ExFreePool(p);
|
||||
*status = NDIS_STATUS_RESOURCES;
|
||||
return;
|
||||
}
|
||||
|
||||
p->np_pktmem = packets;
|
||||
|
||||
for (i = 0; i < p->np_cnt; i++)
|
||||
InterlockedPushEntrySList(&p->np_head,
|
||||
(struct slist_entry *)&packets[i]);
|
||||
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
p->np_dead = 0;
|
||||
KeInitializeSpinLock(&p->np_lock);
|
||||
KeInitializeEvent(&p->np_event, EVENT_TYPE_NOTIFY, TRUE);
|
||||
#endif
|
||||
|
||||
*pool = p;
|
||||
*status = NDIS_STATUS_SUCCESS;
|
||||
return;
|
||||
}
|
||||
@ -1887,41 +1900,42 @@ uint32_t
|
||||
NdisPacketPoolUsage(pool)
|
||||
ndis_handle pool;
|
||||
{
|
||||
ndis_packet *head;
|
||||
uint8_t irql;
|
||||
uint32_t cnt;
|
||||
ndis_packet_pool *p;
|
||||
|
||||
head = (ndis_packet *)pool;
|
||||
KeAcquireSpinLock(&head->np_lock, &irql);
|
||||
cnt = head->np_private.npp_count;
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
|
||||
return(cnt);
|
||||
p = (ndis_packet_pool *)pool;
|
||||
return(p->np_cnt - ExQueryDepthSList(&p->np_head));
|
||||
}
|
||||
|
||||
void
|
||||
NdisFreePacketPool(pool)
|
||||
ndis_handle pool;
|
||||
{
|
||||
ndis_packet *head;
|
||||
ndis_packet_pool *p;
|
||||
int usage;
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
uint8_t irql;
|
||||
#endif
|
||||
|
||||
head = pool;
|
||||
p = (ndis_packet_pool *)pool;
|
||||
|
||||
/* Mark this pool as 'going away.' */
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
KeAcquireSpinLock(&p->np_lock, &irql);
|
||||
#endif
|
||||
|
||||
KeAcquireSpinLock(&head->np_lock, &irql);
|
||||
head->np_private.npp_totlen = 1;
|
||||
usage = NdisPacketPoolUsage(pool);
|
||||
|
||||
/* If there are no buffers loaned out, destroy the pool. */
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
if (usage) {
|
||||
p->np_dead = 1;
|
||||
KeResetEvent(&p->np_event);
|
||||
KeReleaseSpinLock(&p->np_lock, irql);
|
||||
KeWaitForSingleObject(&p->np_event, 0, 0, FALSE, NULL);
|
||||
} else
|
||||
KeReleaseSpinLock(&p->np_lock, irql);
|
||||
#endif
|
||||
|
||||
if (head->np_private.npp_count == 0) {
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
free(pool, M_DEVBUF);
|
||||
} else {
|
||||
printf("NDIS: buggy driver deleting active packet pool!\n");
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
}
|
||||
ExFreePool(p->np_pktmem);
|
||||
ExFreePool(p);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1932,42 +1946,41 @@ NdisAllocatePacket(status, packet, pool)
|
||||
ndis_packet **packet;
|
||||
ndis_handle pool;
|
||||
{
|
||||
ndis_packet *head, *pkt;
|
||||
ndis_packet_pool *p;
|
||||
ndis_packet *pkt;
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
uint8_t irql;
|
||||
#endif
|
||||
|
||||
head = (ndis_packet *)pool;
|
||||
KeAcquireSpinLock(&head->np_lock, &irql);
|
||||
p = (ndis_packet_pool *)pool;
|
||||
|
||||
if (head->np_private.npp_flags != 0x1) {
|
||||
*status = NDIS_STATUS_FAILURE;
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
KeAcquireSpinLock(&p->np_lock, &irql);
|
||||
if (p->np_dead) {
|
||||
KeReleaseSpinLock(&p->np_lock, irql);
|
||||
printf("NDIS: tried to allocate packet from dead pool %p\n",
|
||||
pool);
|
||||
*status = NDIS_STATUS_RESOURCES;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If this pool is marked as 'going away' don't allocate any
|
||||
* more packets out of it.
|
||||
*/
|
||||
pkt = (ndis_packet *)InterlockedPopEntrySList(&p->np_head);
|
||||
|
||||
if (head->np_private.npp_totlen) {
|
||||
*status = NDIS_STATUS_FAILURE;
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = (ndis_packet *)head->np_private.npp_head;
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
KeReleaseSpinLock(&p->np_lock, irql);
|
||||
#endif
|
||||
|
||||
if (pkt == NULL) {
|
||||
*status = NDIS_STATUS_RESOURCES;
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
return;
|
||||
}
|
||||
|
||||
head->np_private.npp_head = pkt->np_private.npp_head;
|
||||
|
||||
pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL;
|
||||
bzero((char *)pkt, sizeof(ndis_packet));
|
||||
|
||||
/* Save pointer to the pool. */
|
||||
pkt->np_private.npp_pool = head;
|
||||
pkt->np_private.npp_pool = pool;
|
||||
|
||||
/* Set the oob offset pointer. Lots of things expect this. */
|
||||
pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob);
|
||||
@ -1983,11 +1996,8 @@ NdisAllocatePacket(status, packet, pool)
|
||||
|
||||
*packet = pkt;
|
||||
|
||||
head->np_private.npp_count++;
|
||||
*status = NDIS_STATUS_SUCCESS;
|
||||
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1995,34 +2005,26 @@ void
|
||||
NdisFreePacket(packet)
|
||||
ndis_packet *packet;
|
||||
{
|
||||
ndis_packet *head;
|
||||
ndis_packet_pool *p;
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
uint8_t irql;
|
||||
#endif
|
||||
|
||||
if (packet == NULL || packet->np_private.npp_pool == NULL)
|
||||
return;
|
||||
p = (ndis_packet_pool *)packet->np_private.npp_pool;
|
||||
|
||||
head = packet->np_private.npp_pool;
|
||||
KeAcquireSpinLock(&head->np_lock, &irql);
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
KeAcquireSpinLock(&p->np_lock, &irql);
|
||||
#endif
|
||||
|
||||
if (head->np_private.npp_flags != 0x1) {
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
return;
|
||||
InterlockedPushEntrySList(&p->np_head, (slist_entry *)packet);
|
||||
|
||||
#ifdef NDIS_DEBUG_PACKETS
|
||||
if (p->np_dead) {
|
||||
if (ExQueryDepthSList(&p->np_head) == p->np_cnt)
|
||||
KeSetEvent(&p->np_event, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
packet->np_private.npp_head = head->np_private.npp_head;
|
||||
head->np_private.npp_head = (ndis_buffer *)packet;
|
||||
head->np_private.npp_count--;
|
||||
|
||||
/*
|
||||
* If the pool has been marked for deletion and there are
|
||||
* no more packets outstanding, nuke the pool.
|
||||
*/
|
||||
|
||||
if (head->np_private.npp_totlen && head->np_private.npp_count == 0) {
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
free(head, M_DEVBUF);
|
||||
} else
|
||||
KeReleaseSpinLock(&head->np_lock, irql);
|
||||
KeReleaseSpinLock(&p->np_lock, irql);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
@ -2255,7 +2257,7 @@ static void
|
||||
NdisSetEvent(event)
|
||||
ndis_event *event;
|
||||
{
|
||||
KeSetEvent(&event->ne_event, 0, 0);
|
||||
KeSetEvent(&event->ne_event, IO_NO_INCREMENT, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2276,7 +2278,7 @@ NdisWaitEvent(event, msecs)
|
||||
uint32_t rval;
|
||||
|
||||
duetime = ((int64_t)msecs * -10000);
|
||||
rval = KeWaitForSingleObject((nt_dispatch_header *)event,
|
||||
rval = KeWaitForSingleObject(event,
|
||||
0, 0, TRUE, msecs ? & duetime : NULL);
|
||||
|
||||
if (rval == STATUS_TIMEOUT)
|
||||
@ -2479,8 +2481,7 @@ NdisMDeregisterInterrupt(intr)
|
||||
|
||||
IoDisconnectInterrupt(intr->ni_introbj);
|
||||
|
||||
KeWaitForSingleObject((nt_dispatch_header *)&intr->ni_dpcevt,
|
||||
0, 0, FALSE, NULL);
|
||||
KeWaitForSingleObject(&intr->ni_dpcevt, 0, 0, FALSE, NULL);
|
||||
KeResetEvent(&intr->ni_dpcevt);
|
||||
|
||||
return;
|
||||
@ -2569,7 +2570,7 @@ NdisQueryBufferOffset(buf, off, len)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
NdisMSleep(usecs)
|
||||
uint32_t usecs;
|
||||
{
|
||||
@ -2586,9 +2587,9 @@ NdisMSleep(usecs)
|
||||
else {
|
||||
KeInitializeTimer(&timer);
|
||||
KeSetTimer(&timer, ((int64_t)usecs * -10), NULL);
|
||||
KeWaitForSingleObject((nt_dispatch_header *)&timer,
|
||||
0, 0, FALSE, NULL);
|
||||
KeWaitForSingleObject(&timer, 0, 0, FALSE, NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -120,12 +120,14 @@ static funcptr ndis_linksts_done_wrap;
|
||||
static funcptr ndis_ticktask_wrap;
|
||||
static funcptr ndis_starttask_wrap;
|
||||
static funcptr ndis_resettask_wrap;
|
||||
static funcptr ndis_inputtask_wrap;
|
||||
|
||||
static void ndis_tick (void *);
|
||||
static void ndis_ticktask (device_object *, void *);
|
||||
static void ndis_start (struct ifnet *);
|
||||
static void ndis_starttask (device_object *, void *);
|
||||
static void ndis_resettask (device_object *, void *);
|
||||
static void ndis_inputtask (device_object *, void *);
|
||||
static int ndis_ioctl (struct ifnet *, u_long, caddr_t);
|
||||
static int ndis_wi_ioctl_get (struct ifnet *, u_long, caddr_t);
|
||||
static int ndis_wi_ioctl_set (struct ifnet *, u_long, caddr_t);
|
||||
@ -199,6 +201,8 @@ ndisdrv_modevent(mod, cmd, arg)
|
||||
2, WINDRV_WRAP_STDCALL);
|
||||
windrv_wrap((funcptr)ndis_resettask, &ndis_resettask_wrap,
|
||||
2, WINDRV_WRAP_STDCALL);
|
||||
windrv_wrap((funcptr)ndis_inputtask, &ndis_inputtask_wrap,
|
||||
2, WINDRV_WRAP_STDCALL);
|
||||
break;
|
||||
case MOD_UNLOAD:
|
||||
ndisdrv_loaded--;
|
||||
@ -217,6 +221,7 @@ ndisdrv_modevent(mod, cmd, arg)
|
||||
windrv_unwrap(ndis_ticktask_wrap);
|
||||
windrv_unwrap(ndis_starttask_wrap);
|
||||
windrv_unwrap(ndis_resettask_wrap);
|
||||
windrv_unwrap(ndis_inputtask_wrap);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
@ -488,6 +493,7 @@ ndis_attach(dev)
|
||||
ifp->if_softc = sc;
|
||||
|
||||
KeInitializeSpinLock(&sc->ndis_spinlock);
|
||||
KeInitializeSpinLock(&sc->ndis_rxlock);
|
||||
InitializeListHead(&sc->ndis_shlist);
|
||||
|
||||
if (sc->ndis_iftype == PCMCIABus) {
|
||||
@ -571,6 +577,14 @@ ndis_attach(dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a deserialized miniport, we don't have
|
||||
* to honor the OID_GEN_MAXIMUM_SEND_PACKETS result.
|
||||
*/
|
||||
|
||||
if (!NDIS_SERIALIZED(sc->ndis_block))
|
||||
sc->ndis_maxpkts = NDIS_TXPKTS;
|
||||
|
||||
/* Enforce some sanity, just in case. */
|
||||
|
||||
if (sc->ndis_maxpkts == 0)
|
||||
@ -582,7 +596,7 @@ ndis_attach(dev)
|
||||
/* Allocate a pool of ndis_packets for TX encapsulation. */
|
||||
|
||||
NdisAllocatePacketPool(&i, &sc->ndis_txpool,
|
||||
sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET);
|
||||
NDIS_TXPKTS, PROTOCOL_RESERVED_SIZE_IN_PACKET);
|
||||
|
||||
if (i != NDIS_STATUS_SUCCESS) {
|
||||
sc->ndis_txpool = NULL;
|
||||
@ -616,6 +630,14 @@ ndis_attach(dev)
|
||||
/* Check for task offload support. */
|
||||
ndis_probe_offload(sc);
|
||||
|
||||
#if __FreeBSD_version < 502109
|
||||
/*
|
||||
* An NDIS device was detected. Inform the world.
|
||||
*/
|
||||
device_printf(dev, "%s address: %6D\n",
|
||||
sc->ndis_80211 ? "802.11" : "Ethernet", eaddr, ":");
|
||||
#endif
|
||||
|
||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
|
||||
ifp->if_mtu = ETHERMTU;
|
||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
||||
@ -888,6 +910,7 @@ ndis_attach(dev)
|
||||
sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
|
||||
sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
|
||||
sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
|
||||
sc->ndis_inputitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
|
||||
KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block);
|
||||
|
||||
|
||||
@ -941,6 +964,8 @@ ndis_detach(dev)
|
||||
IoFreeWorkItem(sc->ndis_startitem);
|
||||
if (sc->ndis_resetitem != NULL)
|
||||
IoFreeWorkItem(sc->ndis_resetitem);
|
||||
if (sc->ndis_inputitem != NULL)
|
||||
IoFreeWorkItem(sc->ndis_inputitem);
|
||||
|
||||
bus_generic_detach(dev);
|
||||
|
||||
@ -1037,6 +1062,9 @@ ndis_resume(dev)
|
||||
/*
|
||||
* The following bunch of routines are here to support drivers that
|
||||
* use the NdisMEthIndicateReceive()/MiniportTransferData() mechanism.
|
||||
* The NdisMEthIndicateReceive() handler runs at DISPATCH_LEVEL for
|
||||
* serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
|
||||
* miniports.
|
||||
*/
|
||||
|
||||
static void
|
||||
@ -1103,14 +1131,19 @@ ndis_rxeof_eth(adapter, ctx, addr, hdr, hdrlen, lookahead, lookaheadlen, pktlen)
|
||||
|
||||
KeAcquireSpinLock(&block->nmb_lock, &irql);
|
||||
|
||||
InsertTailList((&block->nmb_packetlist),
|
||||
((list_entry *)&p->u.np_clrsvd.np_miniport_rsvd));
|
||||
InsertTailList((&block->nmb_packetlist), (&p->np_list));
|
||||
|
||||
KeReleaseSpinLock(&block->nmb_lock, irql);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* NdisMEthIndicateReceiveComplete() handler, runs at DISPATCH_LEVEL
|
||||
* for serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
|
||||
* miniports.
|
||||
*/
|
||||
|
||||
static void
|
||||
ndis_rxeof_done(adapter)
|
||||
ndis_handle adapter;
|
||||
@ -1130,7 +1163,7 @@ ndis_rxeof_done(adapter)
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs at DISPATCH_LEVEL.
|
||||
* MiniportTransferData() handler, runs at DISPATCH_LEVEL.
|
||||
*/
|
||||
static void
|
||||
ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
|
||||
@ -1157,8 +1190,8 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
|
||||
l = block->nmb_packetlist.nle_flink;
|
||||
while(!IsListEmpty(&block->nmb_packetlist)) {
|
||||
l = RemoveHeadList((&block->nmb_packetlist));
|
||||
p = CONTAINING_RECORD(l, ndis_packet,
|
||||
u.np_clrsvd.np_miniport_rsvd);
|
||||
p = CONTAINING_RECORD(l, ndis_packet, np_list);
|
||||
InitializeListHead((&p->np_list));
|
||||
|
||||
priv = (ndis_ethpriv *)&p->np_protocolreserved;
|
||||
m = p->np_m0;
|
||||
@ -1185,8 +1218,12 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
|
||||
if (status == NDIS_STATUS_SUCCESS) {
|
||||
IoFreeMdl(p->np_private.npp_head);
|
||||
NdisFreePacket(p);
|
||||
ifp->if_ipackets++;
|
||||
(*ifp->if_input)(ifp, m);
|
||||
KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
|
||||
_IF_ENQUEUE(&sc->ndis_rxqueue, m);
|
||||
KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
|
||||
IoQueueWorkItem(sc->ndis_inputitem,
|
||||
(io_workitem_func)ndis_inputtask_wrap,
|
||||
WORKQUEUE_CRITICAL, ifp);
|
||||
}
|
||||
|
||||
if (status == NDIS_STATUS_FAILURE)
|
||||
@ -1201,6 +1238,9 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* NdisMTransferDataComplete() handler, runs at DISPATCH_LEVEL.
|
||||
*/
|
||||
static void
|
||||
ndis_rxeof_xfr_done(adapter, packet, status, len)
|
||||
ndis_handle adapter;
|
||||
@ -1228,8 +1268,13 @@ ndis_rxeof_xfr_done(adapter, packet, status, len)
|
||||
|
||||
m->m_len = m->m_pkthdr.len;
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
ifp->if_ipackets++;
|
||||
(*ifp->if_input)(ifp, m);
|
||||
KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
|
||||
_IF_ENQUEUE(&sc->ndis_rxqueue, m);
|
||||
KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
|
||||
IoQueueWorkItem(sc->ndis_inputitem,
|
||||
(io_workitem_func)ndis_inputtask_wrap,
|
||||
WORKQUEUE_CRITICAL, ifp);
|
||||
|
||||
return;
|
||||
}
|
||||
/*
|
||||
@ -1311,7 +1356,6 @@ ndis_rxeof(adapter, packets, pktcnt)
|
||||
}
|
||||
m0 = m;
|
||||
m0->m_pkthdr.rcvif = ifp;
|
||||
ifp->if_ipackets++;
|
||||
|
||||
/* Deal with checksum offload. */
|
||||
|
||||
@ -1333,13 +1377,55 @@ ndis_rxeof(adapter, packets, pktcnt)
|
||||
}
|
||||
}
|
||||
|
||||
(*ifp->if_input)(ifp, m0);
|
||||
KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
|
||||
_IF_ENQUEUE(&sc->ndis_rxqueue, m);
|
||||
KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
|
||||
IoQueueWorkItem(sc->ndis_inputitem,
|
||||
(io_workitem_func)ndis_inputtask_wrap,
|
||||
WORKQUEUE_CRITICAL, ifp);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is run at PASSIVE_LEVEL. We use this routine to pass
|
||||
* packets into the stack in order to avoid calling (*ifp->if_input)()
|
||||
* with any locks held (at DISPATCH_LEVEL, we'll be holding the
|
||||
* 'dispatch level' per-cpu sleep lock).
|
||||
*/
|
||||
|
||||
static void
|
||||
ndis_inputtask(dobj, arg)
|
||||
device_object *dobj;
|
||||
void *arg;
|
||||
{
|
||||
ndis_miniport_block *block;
|
||||
struct ifnet *ifp;
|
||||
struct ndis_softc *sc;
|
||||
struct mbuf *m;
|
||||
uint8_t irql;
|
||||
|
||||
ifp = arg;
|
||||
sc = ifp->if_softc;
|
||||
block = dobj->do_devext;
|
||||
|
||||
KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
|
||||
while(1) {
|
||||
_IF_DEQUEUE(&sc->ndis_rxqueue, m);
|
||||
if (m == NULL)
|
||||
break;
|
||||
KeReleaseSpinLock(&sc->ndis_rxlock, irql);
|
||||
ifp->if_ipackets++;
|
||||
(*ifp->if_input)(ifp, m);
|
||||
KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
|
||||
}
|
||||
KeReleaseSpinLock(&sc->ndis_rxlock, irql);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* A frame was downloaded to the chip. It's safe for us to clean up
|
||||
* the list buffers.
|
||||
|
@ -85,8 +85,9 @@ TAILQ_HEAD(nch, ndis_cfglist);
|
||||
|
||||
#define NDIS_INITIALIZED(sc) (sc->ndis_block->nmb_devicectx != NULL)
|
||||
|
||||
#define NDIS_TXPKTS 64
|
||||
#define NDIS_INC(x) \
|
||||
(x)->ndis_txidx = ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts
|
||||
(x)->ndis_txidx = ((x)->ndis_txidx + 1) % NDIS_TXPKTS
|
||||
|
||||
#if __FreeBSD_version < 600000
|
||||
#define arpcom ic.ic_ac
|
||||
@ -159,11 +160,9 @@ struct ndis_softc {
|
||||
io_workitem *ndis_tickitem;
|
||||
io_workitem *ndis_startitem;
|
||||
io_workitem *ndis_resetitem;
|
||||
io_workitem *ndis_inputitem;
|
||||
kdpc ndis_rxdpc;
|
||||
bus_dma_tag_t ndis_parent_tag;
|
||||
/*
|
||||
struct ndis_shmem *ndis_shlist;
|
||||
*/
|
||||
list_entry ndis_shlist;
|
||||
bus_dma_tag_t ndis_mtag;
|
||||
bus_dma_tag_t ndis_ttag;
|
||||
@ -173,6 +172,8 @@ struct ndis_softc {
|
||||
struct ndis_evt ndis_evt[NDIS_EVENTS];
|
||||
int ndis_evtpidx;
|
||||
int ndis_evtcidx;
|
||||
struct ifqueue ndis_rxqueue;
|
||||
kspin_lock ndis_rxlock;
|
||||
};
|
||||
|
||||
#define NDIS_LOCK(_sc) KeAcquireSpinLock(&(_sc)->ndis_spinlock, \
|
||||
|
Loading…
Reference in New Issue
Block a user