Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 22 Dec 2008 12:15:38 GMT
From:      Weongyo Jeong <weongyo@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 155115 for review
Message-ID:  <200812221215.mBMCFcK7051247@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=155115

Change 155115 by weongyo@weongyo_ws on 2008/12/22 12:15:29

	record history of timers which are allocated by USB NDIS driver; then
	try to cancel all of it because some NDIS USB drivers are buggy that
	it doesn't cancel timers so the ndisulator encounter a page fault
	after halting or detaching.
	
	I don't like this kind of approach to solve the problem but it looks
	no ways to fix this problem if NDIS drivers have bugs.

Affected files ...

.. //depot/projects/ndisusb/sys/compat/ndis/subr_ndis.c#5 edit

Differences ...

==== //depot/projects/ndisusb/sys/compat/ndis/subr_ndis.c#5 (text+ko) ====

@@ -304,6 +304,15 @@
  */
 #define NDIS_POOL_EXTRA		16
 
+struct ktimer_list {
+	ktimer			*kl_timer;
+	list_entry		kl_next;
+};
+
+static struct list_entry	ndis_timerlist;
+static kspin_lock		ndis_timerlock;
+static int			ndis_isusbdev;
+
 int
 ndis_libinit()
 {
@@ -319,6 +328,9 @@
 		patch++;
 	}
 
+	KeInitializeSpinLock(&ndis_timerlock);
+	InitializeListHead(&ndis_timerlist);
+
 	return(0);
 }
 
@@ -1217,6 +1229,16 @@
 	ndis_timer_function	func;
 	void			*ctx;
 {
+	ndis_miniport_block	*block;
+	struct ktimer_list	*kl;
+	struct ndis_softc	*sc;
+	uint8_t			irql;
+
+	block = (ndis_miniport_block *)handle;
+	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+	if (sc->ndis_iftype == PNPBus && ndis_isusbdev == 0)
+		ndis_isusbdev = 1;
+
 	/* Save the driver's funcptr and context */
 
 	timer->nmt_timerfunc = func;
@@ -1234,7 +1256,38 @@
 	    ndis_findwrap((funcptr)ndis_timercall), timer);
 	timer->nmt_ktimer.k_dpc = &timer->nmt_kdpc;
 
-	return;
+	if (ndis_isusbdev == 1) {
+		kl = (struct ktimer_list *)malloc(sizeof(*kl), M_DEVBUF,
+		    M_NOWAIT | M_ZERO);
+		if (kl == NULL)
+			panic("out of memory");	/* no way to report errors  */
+
+		kl->kl_timer = &timer->nmt_ktimer;
+		KeAcquireSpinLock(&ndis_timerlock, &irql);
+		InsertHeadList((&ndis_timerlist), (&kl->kl_next));
+		KeReleaseSpinLock(&ndis_timerlock, irql);
+	}
+}
+
+void
+ndis_cancel_timerlist(void)
+{
+	list_entry		*l;
+	struct ktimer_list	*kl;
+	uint8_t			cancelled, irql;
+
+	KeAcquireSpinLock(&ndis_timerlock, &irql);
+
+	while(!IsListEmpty(&ndis_timerlist)) {
+		l = RemoveHeadList(&ndis_timerlist);
+		kl = CONTAINING_RECORD(l, struct ktimer_list, kl_next);
+		KeReleaseSpinLock(&ndis_timerlock, irql);
+		cancelled = KeCancelTimer(kl->kl_timer);
+		free(kl, M_DEVBUF);
+		KeAcquireSpinLock(&ndis_timerlock, &irql);
+	}
+
+	KeReleaseSpinLock(&ndis_timerlock, irql);
 }
 
 /*
@@ -1279,6 +1332,26 @@
 	ndis_timer		*timer;
 	uint8_t			*cancelled;
 {
+	list_entry		*l;
+	struct ktimer_list	*kl;
+	uint8_t			irql;
+
+	if (ndis_isusbdev == 1) {
+		KeAcquireSpinLock(&ndis_timerlock, &irql);
+		l = ndis_timerlist.nle_flink;
+		while(l != &ndis_timerlist) {
+			kl = CONTAINING_RECORD(l, struct ktimer_list, kl_next);
+			if (kl->kl_timer == &timer->nt_ktimer) {
+				RemoveEntryList((&kl->kl_next));
+				l = l->nle_flink;
+				free(kl, M_DEVBUF);
+				continue;
+			}
+			l = l->nle_flink;
+		}
+		KeReleaseSpinLock(&ndis_timerlock, irql);
+	}
+
 	*cancelled = KeCancelTimer(&timer->nt_ktimer);
 	return;
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200812221215.mBMCFcK7051247>