summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2004-03-22 00:41:41 +0000
committerwpaul <wpaul@FreeBSD.org>2004-03-22 00:41:41 +0000
commite7b058478d636902088f5a1b282ed707c6b8af70 (patch)
tree47b063ef427401aac5ceaaf95eb4af806cb59c9f
parente3bae61eeded23dcd28e10872a88650bb92eca50 (diff)
downloadFreeBSD-src-e7b058478d636902088f5a1b282ed707c6b8af70.zip
FreeBSD-src-e7b058478d636902088f5a1b282ed707c6b8af70.tar.gz
The Intel 2200BG NDIS driver does an alloca() of about 5000 bytes
when it associates with a net. Because FreeBSD's kstack size is only 2 pages by default, this blows the stack and causes a double fault. To deal with this, we now create all our kthreads with 8 stack pages. Also, we now run all timer callouts in the ndis swi thread (since they would otherwise run in the clock ithread, whose stack is too small). It happens that the alloca() in this case was occuring within the interrupt handler, which was already running in the ndis swi thread, but I want to deal with the callouts too just to be extra safe. NOTE: this will only work if you update vm_machdep.c with the change I just committed. If you don't include this fix, setting the number of stack pages with kthread_create() has essentially no effect.
-rw-r--r--sys/compat/ndis/kern_ndis.c6
-rw-r--r--sys/compat/ndis/ntoskrnl_var.h7
-rw-r--r--sys/compat/ndis/subr_ntoskrnl.c27
3 files changed, 32 insertions, 8 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
index cebe300..fbb62b1 100644
--- a/sys/compat/ndis/kern_ndis.c
+++ b/sys/compat/ndis/kern_ndis.c
@@ -268,14 +268,16 @@ ndis_create_kthreads()
ndis_tproc.np_q = &ndis_ttodo;
ndis_tproc.np_state = NDIS_PSTATE_SLEEPING;
error = kthread_create(ndis_runq, &ndis_tproc,
- &ndis_tproc.np_p, RFHIGHPID, 0, "ndis taskqueue");
+ &ndis_tproc.np_p, RFHIGHPID,
+ NDIS_KSTACK_PAGES, "ndis taskqueue");
}
if (error == 0) {
ndis_iproc.np_q = &ndis_itodo;
ndis_iproc.np_state = NDIS_PSTATE_SLEEPING;
error = kthread_create(ndis_runq, &ndis_iproc,
- &ndis_iproc.np_p, RFHIGHPID, 0, "ndis swi");
+ &ndis_iproc.np_p, RFHIGHPID,
+ NDIS_KSTACK_PAGES, "ndis swi");
}
if (error) {
diff --git a/sys/compat/ndis/ntoskrnl_var.h b/sys/compat/ndis/ntoskrnl_var.h
index 33e0d38..ccd9259 100644
--- a/sys/compat/ndis/ntoskrnl_var.h
+++ b/sys/compat/ndis/ntoskrnl_var.h
@@ -466,6 +466,13 @@ typedef uint32_t (*driver_dispatch)(device_object *, irp *);
#define STATUS_WAIT_0 0x00000000
+/*
+ * FreeBSD's kernel stack is 2 pages in size by default. The
+ * Windows stack is larger, so we need to give our threads more
+ * stack pages. 4 should be enough, we use 8 just to extra safe.
+ */
+#define NDIS_KSTACK_PAGES 8
+
extern image_patch_table ntoskrnl_functbl[];
extern struct mtx *ntoskrnl_dispatchlock;
diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c
index cc656c0..1395a7f 100644
--- a/sys/compat/ndis/subr_ntoskrnl.c
+++ b/sys/compat/ndis/subr_ntoskrnl.c
@@ -85,6 +85,7 @@ __stdcall static uint32_t ntoskrnl_waitforobjs(uint32_t,
int64_t *, wait_block *);
static void ntoskrnl_wakeup(void *);
static void ntoskrnl_timercall(void *);
+static void ntoskrnl_timersched(void *);
__stdcall static void ntoskrnl_writereg_ushort(uint16_t *, uint16_t);
__stdcall static uint16_t ntoskrnl_readreg_ushort(uint16_t *);
__stdcall static void ntoskrnl_writereg_ulong(uint32_t *, uint32_t);
@@ -1585,7 +1586,7 @@ ntoskrnl_create_thread(handle, reqaccess, objattrs, phandle,
sprintf(tname, "windows kthread %d", ntoskrnl_kth);
error = kthread_create(ntoskrnl_thrfunc, tc, &p,
- RFHIGHPID, 0, tname);
+ RFHIGHPID, NDIS_KSTACK_PAGES, tname);
*handle = p;
ntoskrnl_kth++;
@@ -1641,9 +1642,23 @@ ntoskrnl_debugger(void)
return;
}
+/*
+ * We run all timer callouts in the ndis swi thread to take
+ * advantage of its larger stack size. If we don't do this,
+ * the callout will run in the clock ithread context.
+ */
+
+static void
+ntoskrnl_timersched(arg)
+ void *arg;
+{
+ ndis_sched(ntoskrnl_timercall, arg, NDIS_SWI);
+ return;
+}
+
static void
ntoskrnl_timercall(arg)
- void *arg;
+ void *arg;
{
ktimer *timer;
__stdcall kdpc_func timerfunc;
@@ -1666,7 +1681,7 @@ ntoskrnl_timercall(arg)
tv.tv_sec = 0;
tv.tv_usec = timer->k_period * 1000;
timer->k_handle =
- timeout(ntoskrnl_timercall, timer, tvtohz(&tv));
+ timeout(ntoskrnl_timersched, timer, tvtohz(&tv));
}
if (dpc != NULL) {
@@ -1744,7 +1759,7 @@ ntoskrnl_set_timer_ex(timer, duetime, period, dpc)
if (timer->k_handle.callout != NULL &&
callout_pending(timer->k_handle.callout)) {
- untimeout(ntoskrnl_timercall, timer, timer->k_handle);
+ untimeout(ntoskrnl_timersched, timer, timer->k_handle);
pending = TRUE;
} else
pending = FALSE;
@@ -1769,7 +1784,7 @@ ntoskrnl_set_timer_ex(timer, duetime, period, dpc)
}
}
- timer->k_handle = timeout(ntoskrnl_timercall, timer, tvtohz(&tv));
+ timer->k_handle = timeout(ntoskrnl_timersched, timer, tvtohz(&tv));
return(pending);
}
@@ -1798,7 +1813,7 @@ ntoskrnl_cancel_timer(timer)
else
pending = FALSE;
- untimeout(ntoskrnl_timercall, timer, timer->k_handle);
+ untimeout(ntoskrnl_timersched, timer, timer->k_handle);
return(pending);
}
OpenPOWER on IntegriCloud