1
0
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:
Bill Paul 2005-10-18 19:52:15 +00:00
parent 8c4b6380c7
commit a3ced67adf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=151451
7 changed files with 649 additions and 410 deletions

View File

@ -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);

View File

@ -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_ */

View File

@ -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);

View File

@ -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

View File

@ -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.

View File

@ -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, \