From owner-freebsd-current@FreeBSD.ORG Wed Jan 9 00:55:07 2008 Return-Path: Delivered-To: current@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8275F16A41A for ; Wed, 9 Jan 2008 00:55:07 +0000 (UTC) (envelope-from jhb@freebsd.org) Received: from elvis.mu.org (elvis.mu.org [192.203.228.196]) by mx1.freebsd.org (Postfix) with ESMTP id 7A53F13C4E1 for ; Wed, 9 Jan 2008 00:55:07 +0000 (UTC) (envelope-from jhb@freebsd.org) Received: from zion.baldwin.cx (66-23-211-162.clients.speedfactory.net [66.23.211.162]) by elvis.mu.org (Postfix) with ESMTP id D8B521A3C1A for ; Tue, 8 Jan 2008 16:37:00 -0800 (PST) From: John Baldwin To: current@FreeBSD.org Date: Tue, 8 Jan 2008 19:39:42 -0500 User-Agent: KMail/1.9.7 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200801081939.42297.jhb@freebsd.org> Cc: Subject: A quick and dirty lpt patch.. X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 Jan 2008 00:55:07 -0000 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 #include #include +#include + +#include #include #include @@ -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 */ bus_generic_probe(dev); @@ -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