A quick and dirty lpt patch..

John Baldwin jhb at freebsd.org
Tue Jan 8 16:55:07 PST 2008

Fixing ppbus to act sanely with interrupts is going to require a bit of work
and all of the solutions in my head involve non-trivial changes that I don't
really want to rush into a release.  Given that I've come up with a bit of a
hack fix that is small and self-contained and can be used for 7.0 until a
better solution is developed and tested.  The basic problem is the ppbus'
drivers insistence on tearing down the interrupt handler and then setting it
back up again for each read or write to /dev/lpt and that ppbus doesn't
multiplex interrupts to child devices itself, but lets the nexus driver do
a full setup/teardown for each child device request.  On 6.x this was
annoying but not fatal because we never free'd an ithread once it existed.
In 7.x I fleshed out that part of the interrupt handling so that it now
frees ithreads when all the interrupt handlers go away, and in fact it
will release an IRQ's given IDT vector when that happens as well.  Even this
would be fine except that the lpt(4) driver appears to have a bug where it
doesn't always wait for an interrupt to come after a read/write, so the
failure case people are seeing with trap 30's are that the lpt device does
a read/write and tears down the interrupt handler which frees the ithread
and the IDT vector and then the IRQ 7 finally fires but for an IDT vector
that isn't hooked up to anything.  The hack-fix I have is to change the
ppbus driver to register a dummy interrupt handler for it's entire lifetime
so that the IRQ for the lpt device never has 0 interrupt handlers and we
don't keep freeing and reallocating ithreads and IDT vectors for the lpt
device.  This basically restores the behavior of 6.x where the extra
interrupts were treated as stray interrupts.

Longer term fixes for lpt involve a few things.  Probably I will make
child devices of ppbus take exclusive ownership of the bus for longer
periods of time (and keep their interrupt handler registered for the
same length of time) such as from open to close for ppi(4) and lpt(4).

Hack patch is at http://www.FreeBSD.org/~jhb/patches/ppbus_intr.patch and
inline below.  I know it compiles, but I haven't runtested it. :)

--- //depot/user/jhb/acpipci/dev/ppbus/ppbconf.c
+++ /home/john/work/p4/acpipci/dev/ppbus/ppbconf.c
@@ -36,6 +36,9 @@
 #include <sys/module.h>
 #include <sys/bus.h>
 #include <sys/malloc.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
 #include <dev/ppbus/ppbconf.h>
 #include <dev/ppbus/ppb_1284.h>
@@ -380,10 +383,39 @@
 #endif /* !DONTPROBE_1284 */
+static void
+ppbus_dummy_intr(void *arg)
 static int
 ppbus_attach(device_t dev)
+	struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev);
+	uintptr_t irq;
+	int error, rid;
+	/* Attach a dummy interrupt handler to suck up any stray interrupts. */
+	BUS_READ_IVAR(device_get_parent(dev), dev, PPC_IVAR_IRQ, &irq);
+	if (irq > 0) {
+		rid = 0;
+		ppb->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq,
+		    irq, 1, RF_SHAREABLE);
+		if (ppb->irq_res != NULL) {
+			error = bus_setup_intr(dev, ppb->irq_res,
+			    INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppbus_dummy_intr,
+			    ppb, &ppb->intr_cookie);
+			if (error) {
+				device_printf(dev,
+				    "failed to setup interrupt handler\n");
+				bus_release_resource(dev, SYS_RES_IRQ, 0,
+				    ppb->irq_res);
+				return (error);
+			}
+		}
+	}
 	/* Locate our children */
@@ -401,6 +433,7 @@
 static int
 ppbus_detach(device_t dev)
+	struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev);
         device_t *children;
         int nchildren, i;
@@ -412,6 +445,10 @@
 		free(children, M_TEMP);
+	if (ppb->irq_res != NULL) {
+		bus_teardown_intr(dev, ppb->irq_res, ppb->intr_cookie);
+		bus_release_resource(dev, SYS_RES_IRQ, 0, ppb->irq_res);
+	}
 	return (0);
--- //depot/user/jhb/acpipci/dev/ppbus/ppbconf.h
+++ /home/john/work/p4/acpipci/dev/ppbus/ppbconf.h
@@ -248,6 +248,9 @@
 				 * NIBBLE, PS2, EPP or ECP */
 	void *ppb_owner;	/* device which owns the bus */
+	struct resource *irq_res;
+	void *intr_cookie;
 #ifdef _KERNEL

John Baldwin

More information about the freebsd-current mailing list