From owner-svn-src-stable@FreeBSD.ORG Wed Jan 27 10:32:02 2010 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 73EBE1065693; Wed, 27 Jan 2010 10:32:02 +0000 (UTC) (envelope-from joerg@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5F5738FC19; Wed, 27 Jan 2010 10:32:02 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o0RAW2Pd082225; Wed, 27 Jan 2010 10:32:02 GMT (envelope-from joerg@svn.freebsd.org) Received: (from joerg@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o0RAW2nj082220; Wed, 27 Jan 2010 10:32:02 GMT (envelope-from joerg@svn.freebsd.org) Message-Id: <201001271032.o0RAW2nj082220@svn.freebsd.org> From: Joerg Wunsch Date: Wed, 27 Jan 2010 10:32:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r203064 - stable/8/sys/dev/ieee488 X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 27 Jan 2010 10:32:02 -0000 Author: joerg Date: Wed Jan 27 10:32:02 2010 New Revision: 203064 URL: http://svn.freebsd.org/changeset/base/203064 Log: Merge of r202870,202898: Overhaul of the pcii driver: . Properly allocate all IO space resources. These cards scatter their IO addresses over a range of 0x1600 bytes, and they require an additional address for "special interrupt handling". . Implement the "special interrupt handling" per the GPIB-PCIIA Technical Reference Manual; this was apparently not declared for the clone card this driver has been originally implemented for, but it turned out to be needed for both, an original NI brand PCII/PCIIA card as well as the Axiom AX5488 clone. . Add some diagnostic messages for various resource allocation etc. failures during probe. . Add some comments about the structure of the IO address space that is used by these cards. Modified: stable/8/sys/dev/ieee488/pcii.c stable/8/sys/dev/ieee488/tnt4882.c stable/8/sys/dev/ieee488/upd7210.c stable/8/sys/dev/ieee488/upd7210.h Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/xen/xenpci/ (props changed) Modified: stable/8/sys/dev/ieee488/pcii.c ============================================================================== --- stable/8/sys/dev/ieee488/pcii.c Wed Jan 27 10:20:10 2010 (r203063) +++ stable/8/sys/dev/ieee488/pcii.c Wed Jan 27 10:32:02 2010 (r203064) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 2010 Joerg Wunsch * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,6 +34,8 @@ * * Tested and known working: * "B&C Microsystems PC488A-0" + * "National Instruments GPIB-PCII/PCIIA" (in PCIIa mode) + * "Axiom AX5488" * */ @@ -56,7 +59,7 @@ __FBSDID("$FreeBSD$"); struct pcii_softc { int foo; - struct resource *res[3]; + struct resource *res[11]; void *intr_handler; struct upd7210 upd7210; }; @@ -79,6 +82,14 @@ static struct resource_spec pcii_res_spe { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE}, { SYS_RES_DRQ, 0, RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL}, { SYS_RES_IOPORT, 0, RF_ACTIVE}, + { SYS_RES_IOPORT, 1, RF_ACTIVE}, + { SYS_RES_IOPORT, 2, RF_ACTIVE}, + { SYS_RES_IOPORT, 3, RF_ACTIVE}, + { SYS_RES_IOPORT, 4, RF_ACTIVE}, + { SYS_RES_IOPORT, 5, RF_ACTIVE}, + { SYS_RES_IOPORT, 6, RF_ACTIVE}, + { SYS_RES_IOPORT, 7, RF_ACTIVE}, + { SYS_RES_IOPORT, 8, RF_ACTIVE | RF_SHAREABLE}, { -1, 0, 0 } }; @@ -92,7 +103,7 @@ static int pcii_probe(device_t dev) { int rid, i, j; - u_long start, count; + u_long start, count, addr; int error = 0; struct pcii_softc *sc; @@ -102,30 +113,90 @@ pcii_probe(device_t dev) rid = 0; if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0) return ENXIO; - if ((start & 0x3ff) != 0x2e1) + /* + * The PCIIA decodes a fixed pattern of 0x2e1 for the lower 10 + * address bits A0 ... A9. Bits A10 through A12 are used by + * the µPD7210 register select lines. This makes the + * individual 7210 register being 0x400 bytes apart in the ISA + * bus address space. Address bits A13 and A14 are compared + * to a DIP switch setting on the card, allowing for up to 4 + * different cards being installed (at base addresses 0x2e1, + * 0x22e1, 0x42e1, and 0x62e1, respectively). A15 has been + * used to select an optional on-board time-of-day clock chip + * (MM58167A) on the original PCIIA rather than the µPD7210 + * (which is not implemented on later boards). The + * documentation states the respective addresses for that chip + * should be handled as reserved addresses, which we don't do + * (right now). Finally, the IO addresses 0x2f0 ... 0x2f7 for + * a "special interrupt handling feature" (re-enable + * interrupts so the IRQ can be shared). + * + * Usually, the user will only set the base address in the + * device hints, so we handle the rest here. + * + * (Source: GPIB-PCIIA Technical Reference Manual, September + * 1989 Edition, National Instruments.) + */ + if ((start & 0x3ff) != 0x2e1) { + if (bootverbose) + printf("pcii_probe: PCIIA base address 0x%lx not " + "0x2e1/0x22e1/0x42e1/0x62e1\n", + start); return (ENXIO); - count = 1; - if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0) + } + + for (rid = 0, addr = start; rid < 8; rid++, addr += 0x400) { + if (bus_set_resource(dev, SYS_RES_IOPORT, rid, addr, 1) != 0) { + printf("pcii_probe: could not set IO port 0x%lx\n", + addr); + return (ENXIO); + } + } + if (bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &count) != 0) { + printf("pcii_probe: cannot obtain IRQ level\n"); + return ENXIO; + } + if (start > 7) { + printf("pcii_probe: IRQ level %lu too high\n", start); return ENXIO; + } + + if (bus_set_resource(dev, SYS_RES_IOPORT, 8, 0x2f0 + start, 1) != 0) { + printf("pcii_probe: could not set IO port 0x%3lx\n", + 0x2f0 + start); + return (ENXIO); + } + error = bus_alloc_resources(dev, pcii_res_spec, sc->res); - if (error) + if (error) { + printf("pcii_probe: Could not allocate resources\n"); return (error); + } error = ENXIO; + /* + * Perform some basic tests on the µPD7210 registers. At + * least *some* register must read different from 0x00 or + * 0xff. + */ for (i = 0; i < 8; i++) { - j = bus_read_1(sc->res[2], i * 0x400); + j = bus_read_1(sc->res[2 + i], 0); if (j != 0x00 && j != 0xff) error = 0; } + /* SPSR/SPMR read/write test */ if (!error) { - bus_write_1(sc->res[2], 3 * 0x400, 0x55); - if (bus_read_1(sc->res[2], 3 * 0x400) != 0x55) + bus_write_1(sc->res[2 + 3], 0, 0x55); + if (bus_read_1(sc->res[2 + 3], 0) != 0x55) error = ENXIO; } if (!error) { - bus_write_1(sc->res[2], 3 * 0x400, 0xaa); - if (bus_read_1(sc->res[2], 3 * 0x400) != 0xaa) + bus_write_1(sc->res[2 + 3], 0, 0xaa); + if (bus_read_1(sc->res[2 + 3], 0) != 0xaa) error = ENXIO; } + if (error) + printf("pcii_probe: probe failure\n"); + bus_release_resources(dev, pcii_res_spec, sc->res); return (error); } @@ -134,6 +205,7 @@ static int pcii_attach(device_t dev) { struct pcii_softc *sc; + u_long start, count; int unit; int rid; int error = 0; @@ -144,6 +216,11 @@ pcii_attach(device_t dev) device_set_desc(dev, "PCII IEEE-4888 controller"); + if (bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &count) != 0) { + printf("pcii_attach: cannot obtain IRQ number\n"); + return ENXIO; + } + error = bus_alloc_resources(dev, pcii_res_spec, sc->res); if (error) return (error); @@ -157,9 +234,10 @@ pcii_attach(device_t dev) } for (rid = 0; rid < 8; rid++) { - sc->upd7210.reg_res[rid] = sc->res[2]; - sc->upd7210.reg_offset[rid] = 0x400 * rid; + sc->upd7210.reg_res[rid] = sc->res[2 + rid]; + sc->upd7210.reg_offset[rid] = 0; } + sc->upd7210.irq_clear_res = sc->res[10]; if (sc->res[1] == NULL) sc->upd7210.dmachan = -1; Modified: stable/8/sys/dev/ieee488/tnt4882.c ============================================================================== --- stable/8/sys/dev/ieee488/tnt4882.c Wed Jan 27 10:20:10 2010 (r203063) +++ stable/8/sys/dev/ieee488/tnt4882.c Wed Jan 27 10:32:02 2010 (r203064) @@ -309,6 +309,9 @@ tnt_attach(device_t dev) /* No DMA help */ sc->upd7210.dmachan = -1; + /* No "special interrupt handling" needed here. */ + sc->upd7210.irq_clear_res = NULL; + upd7210attach(&sc->upd7210); return (0); Modified: stable/8/sys/dev/ieee488/upd7210.c ============================================================================== --- stable/8/sys/dev/ieee488/upd7210.c Wed Jan 27 10:20:10 2010 (r203063) +++ stable/8/sys/dev/ieee488/upd7210.c Wed Jan 27 10:32:02 2010 (r203064) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 2010 Joerg Wunsch * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -96,19 +97,36 @@ upd7210intr(void *arg) mtx_lock(&u->mutex); isr1 = upd7210_rd(u, ISR1); isr2 = upd7210_rd(u, ISR2); - if (u->busy == 0 || u->irq == NULL || !u->irq(u, 1)) { + if (isr1 != 0 || isr2 != 0) { + if (u->busy == 0 || u->irq == NULL || !u->irq(u, 1)) { #if 0 - printf("upd7210intr [%02x %02x %02x", - upd7210_rd(u, DIR), isr1, isr2); - printf(" %02x %02x %02x %02x %02x] ", - upd7210_rd(u, SPSR), - upd7210_rd(u, ADSR), - upd7210_rd(u, CPTR), - upd7210_rd(u, ADR0), + printf("upd7210intr [%02x %02x %02x", + upd7210_rd(u, DIR), isr1, isr2); + printf(" %02x %02x %02x %02x %02x] ", + upd7210_rd(u, SPSR), + upd7210_rd(u, ADSR), + upd7210_rd(u, CPTR), + upd7210_rd(u, ADR0), upd7210_rd(u, ADR1)); - upd7210_print_isr(isr1, isr2); - printf("\n"); + upd7210_print_isr(isr1, isr2); + printf("\n"); #endif + } + /* + * "special interrupt handling" + * + * In order to implement shared IRQs, the original + * PCIIa uses IO locations 0x2f0 + (IRQ#) as an output + * location. If an ISR for a particular card has + * detected this card triggered the IRQ, it must reset + * the card's IRQ by writing (anything) to that IO + * location. + * + * Some clones apparently don't implement this + * feature, but National Instrument cards do. + */ + if (u->irq_clear_res != NULL) + bus_write_1(u->irq_clear_res, 0, 42); } mtx_unlock(&u->mutex); } Modified: stable/8/sys/dev/ieee488/upd7210.h ============================================================================== --- stable/8/sys/dev/ieee488/upd7210.h Wed Jan 27 10:20:10 2010 (r203063) +++ stable/8/sys/dev/ieee488/upd7210.h Wed Jan 27 10:32:02 2010 (r203064) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 2010 Joerg Wunsch * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +49,7 @@ typedef int upd7210_irq_t(struct upd7210 struct upd7210 { struct resource *reg_res[8]; + struct resource *irq_clear_res; u_int reg_offset[8]; int dmachan; int unit;