Subject: Suspending interrupts
To: None <tech-kern@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: tech-kern
Date: 07/03/2007 21:32:49
--4Ckj6UjgE2iN1+kY
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,
during a discuss with Jared about the ACPI suspend/resume code in some
drivers and the comment about failing pci_intr_establish triggered some
thinking about how to do this better.

The attached patch can be considered a PoC. It introduces two new
functions pci_intr_disable and pci_intr_reenable meant to temporary
disable an interrupt handler. The backend implement just sets them to a
void handler. The idea is that the handler won't be called again, the
hardware was shutdown already and that the interrupt can always be
enabled again later. This is helpful in a number of other cases beside
suspend/resume, where the driver knows that no interrupt will occur
(e.g. NICs that are down).

Joerg

--4Ckj6UjgE2iN1+kY
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="intr_suspend.diff"

Index: arch/x86/include/intr.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/arch/x86/include/intr.h,v
retrieving revision 1.26
diff -u -r1.26 intr.h
--- arch/x86/include/intr.h	17 May 2007 14:51:34 -0000	1.26
+++ arch/x86/include/intr.h	2 Jul 2007 23:04:51 -0000
@@ -179,6 +179,8 @@
 		       int *);
 void *intr_establish(int, struct pic *, int, int, int, int (*)(void *), void *);
 void intr_disestablish(struct intrhand *);
+void intr_disable(struct intrhand *);
+void intr_reenable(struct intrhand *);
 void intr_add_pcibus(struct pcibus_attach_args *);
 const char *intr_string(int);
 void cpu_intr_init(struct cpu_info *);
Index: arch/x86/include/pci_machdep.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/arch/x86/include/pci_machdep.h,v
retrieving revision 1.6
diff -u -r1.6 pci_machdep.h
--- arch/x86/include/pci_machdep.h	20 Jun 2005 11:04:15 -0000	1.6
+++ arch/x86/include/pci_machdep.h	2 Jul 2007 23:06:35 -0000
@@ -105,7 +105,8 @@
 void		*pci_intr_establish(pci_chipset_tag_t, pci_intr_handle_t,
 		    int, int (*)(void *), void *);
 void		pci_intr_disestablish(pci_chipset_tag_t, void *);
-
+void		pci_intr_disable(void *);
+void		pci_intr_reenable(void *);
 
 /*
  * ALL OF THE FOLLOWING ARE MACHINE-DEPENDENT, AND SHOULD NOT BE USED
Index: arch/x86/pci/pci_intr_machdep.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/arch/x86/pci/pci_intr_machdep.c,v
retrieving revision 1.6
diff -u -r1.6 pci_intr_machdep.c
--- arch/x86/pci/pci_intr_machdep.c	16 Nov 2006 01:32:39 -0000	1.6
+++ arch/x86/pci/pci_intr_machdep.c	2 Jul 2007 23:07:16 -0000
@@ -262,3 +262,17 @@
 
 	intr_disestablish(cookie);
 }
+
+void
+pci_intr_disable(void *cookie)
+{
+
+	intr_disable(cookie);
+}
+
+void
+pci_intr_reenable(void *cookie)
+{
+
+	intr_reenable(cookie);
+}
Index: arch/x86/x86/intr.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/arch/x86/x86/intr.c,v
retrieving revision 1.28
diff -u -r1.28 intr.c
--- arch/x86/x86/intr.c	21 Feb 2007 22:59:55 -0000	1.28
+++ arch/x86/x86/intr.c	2 Jul 2007 23:18:17 -0000
@@ -758,6 +758,46 @@
 	simple_unlock(&ci->ci_slock);
 }
 
+static int
+dummy_intr_handler(void *v)
+{
+	(void)v;
+
+	return 0;
+}
+
+void
+intr_disable(struct intrhand *ih)
+{
+	struct cpu_info *ci;
+	ci = ih->ih_cpu;
+
+	simple_lock(&ci->ci_slock);
+	ih->ih_fun = dummy_intr_handler;
+	simple_unlock(&ci->ci_slock);
+}
+
+void
+intr_reenable(struct intrhand *ih)
+{
+	struct cpu_info *ci;
+#ifdef MULTIPROCESSOR
+	bool mpsafe = level >= IPL_SCHED;
+#endif /* MULTIPROCESSOR */
+
+	ci = ih->ih_cpu;
+	simple_lock(&ci->ci_slock);
+
+#ifdef MULTIPROCESSOR
+	if (!mpsafe)
+		ih->ih_fun = intr_biglock_wrapper;
+	else
+#endif /* MULTIPROCESSOR */
+	ih->ih_fun = ih->ih_realfun;
+
+	simple_unlock(&ci->ci_slock);
+}
+
 const char *
 intr_string(int ih)
 {
Index: dev/pci/cs4280.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/dev/pci/cs4280.c,v
retrieving revision 1.46
diff -u -r1.46 cs4280.c
--- dev/pci/cs4280.c	15 Jun 2007 13:26:57 -0000	1.46
+++ dev/pci/cs4280.c	2 Jul 2007 23:09:11 -0000
@@ -952,7 +952,7 @@
 
 		pci_conf_capture(sc->sc_pc, sc->sc_pt, &sc->sc_pciconf);
 		if (sc->sc_ih != NULL)
-			pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
+			pci_intr_disable(sc->sc_ih);
 
 		break;
 	case PWR_RESUME:
@@ -962,14 +962,8 @@
 			return;
 		}
 
-		sc->sc_ih = pci_intr_establish(sc->sc_pc, sc->intrh,
-		    IPL_AUDIO, cs4280_intr, sc);
-		if (sc->sc_ih == NULL) {
-			aprint_error("%s: can't establish interrupt",
-			    sc->sc_dev.dv_xname);
-			/* XXX jmcneill what should we do here? */
-			return;
-		}
+		if (sc->sc_ih != NULL)
+			pci_intr_reenable(sc->sc_ih);
 		pci_conf_restore(sc->sc_pc, sc->sc_pt, &sc->sc_pciconf);
 
 		sc->sc_suspend = why;

--4Ckj6UjgE2iN1+kY--