Date: Sat, 15 May 2010 15:03:18 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r208114 - projects/ppc64/sys/powerpc/powermac Message-ID: <201005151503.o4FF3IUb009442@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Sat May 15 15:03:18 2010 New Revision: 208114 URL: http://svn.freebsd.org/changeset/base/208114 Log: Revise the way htpic(4) programs edge interrupts into the remote IO/APIC. This fixes things like smu (although smu still does not work, but at least does not cause kernel panics) that depend on interrupts attached to GPIO lines on U4 systems. Modified: projects/ppc64/sys/powerpc/powermac/cpcht.c Modified: projects/ppc64/sys/powerpc/powermac/cpcht.c ============================================================================== --- projects/ppc64/sys/powerpc/powermac/cpcht.c Sat May 15 12:51:22 2010 (r208113) +++ projects/ppc64/sys/powerpc/powermac/cpcht.c Sat May 15 15:03:18 2010 (r208114) @@ -156,6 +156,10 @@ static devclass_t cpcht_devclass; DRIVER_MODULE(cpcht, nexus, cpcht_driver, cpcht_devclass, 0, 0); +#define HTAPIC_REQUEST_EOI 0x20 +#define HTAPIC_TRIGGER_LEVEL 0x02 +#define HTAPIC_MASK 0x01 + struct cpcht_range { u_int32_t pci_hi; u_int32_t pci_mid; @@ -316,21 +320,20 @@ cpcht_configure_htbridge(device_t dev, p /* Ask for the IRQ count */ PCIB_WRITE_CONFIG(dev, 0, s, f, ptr + PCIR_HT_COMMAND, 0x1, 1); nirq = PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4); - nirq = (nirq >> 16) & 0xff; + nirq = ((nirq >> 16) & 0xff) + 1; device_printf(dev, "%d HT IRQs on device %d.%d\n", nirq, s, f); - for (i = 0; i <= nirq; i++) { + for (i = 0; i < nirq; i++) { PCIB_WRITE_CONFIG(dev, 0, s, f, ptr + PCIR_HT_COMMAND, 0x10 + (i << 1), 1); irq = PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4); /* - * Enable immediately as a level interrupt. - * It is still masked in the MPIC. + * Mask this interrupt for now. */ PCIB_WRITE_CONFIG(dev, 0, s, f, ptr + 4, - (irq & ~0x23) | 0x22, 4); + irq | HTAPIC_MASK, 4); irq = (irq >> 16) & 0xff; sc->htirq_map[irq].ht_source = i; @@ -612,6 +615,12 @@ static device_method_t openpic_cpcht_me { 0, 0 }, }; +struct openpic_cpcht_softc { + struct openpic_softc sc_openpic; + + struct mtx sc_ht_mtx; +}; + static driver_t openpic_cpcht_driver = { "htpic", openpic_cpcht_methods, @@ -635,6 +644,7 @@ openpic_cpcht_probe(device_t dev) static int openpic_cpcht_attach(device_t dev) { + struct openpic_cpcht_softc *sc; int err, irq; err = openpic_attach(dev); @@ -642,6 +652,13 @@ openpic_cpcht_attach(device_t dev) return (err); /* + * The HT APIC stuff is not thread-safe, so we need a mutex to + * protect it. + */ + sc = device_get_softc(dev); + mtx_init(&sc->sc_ht_mtx, "htpic", NULL, MTX_SPIN); + + /* * Interrupts 0-3 are internally sourced and are level triggered * active low. Interrupts 4-123 are connected to a pulse generator * and should be programmed as edge triggered low-to-high. @@ -661,7 +678,7 @@ static void openpic_cpcht_config(device_t dev, u_int irq, enum intr_trigger trig, enum intr_polarity pol) { -#ifdef NOTYET + struct openpic_cpcht_softc *sc; uint32_t ht_irq; /* @@ -671,48 +688,105 @@ openpic_cpcht_config(device_t dev, u_int * link. */ + sc = device_get_softc(dev); + if (cpcht_irqmap != NULL && irq < 128 && - cpcht_irqmap[irq].ht_base > 0) { + cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) { + mtx_lock_spin(&sc->sc_ht_mtx); + /* Program the data port */ out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND, 0x10 + (cpcht_irqmap[irq].ht_source << 1)); /* Grab the IRQ config register */ - ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4) & ~23; + ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4); + + /* Mask the IRQ while we fiddle settings */ + out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq | HTAPIC_MASK); - if (trig == INTR_TRIGGER_EDGE) + /* Program the interrupt sense */ + ht_irq &= ~(HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI); + if (trig == INTR_TRIGGER_EDGE) { cpcht_irqmap[irq].edge = 1; - else - ht_irq |= 0x22; - + } else { + cpcht_irqmap[irq].edge = 0; + ht_irq |= HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI; + } out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq); + + mtx_unlock_spin(&sc->sc_ht_mtx); } -#endif - } static void openpic_cpcht_enable(device_t dev, u_int irq, u_int vec) { + struct openpic_cpcht_softc *sc; + uint32_t ht_irq; + openpic_enable(dev, irq, vec); + + sc = device_get_softc(dev); + + if (cpcht_irqmap != NULL && irq < 128 && + cpcht_irqmap[irq].ht_base > 0) { + mtx_lock_spin(&sc->sc_ht_mtx); + + /* Program the data port */ + out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND, + 0x10 + (cpcht_irqmap[irq].ht_source << 1)); + + /* Unmask the interrupt */ + ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4); + ht_irq &= ~HTAPIC_MASK; + out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq); + + mtx_unlock_spin(&sc->sc_ht_mtx); + } + openpic_cpcht_eoi(dev, irq); } static void openpic_cpcht_unmask(device_t dev, u_int irq) { + struct openpic_cpcht_softc *sc; + uint32_t ht_irq; + openpic_unmask(dev, irq); + + sc = device_get_softc(dev); + + if (cpcht_irqmap != NULL && irq < 128 && + cpcht_irqmap[irq].ht_base > 0) { + mtx_lock_spin(&sc->sc_ht_mtx); + + /* Program the data port */ + out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND, + 0x10 + (cpcht_irqmap[irq].ht_source << 1)); + + /* Unmask the interrupt */ + ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4); + ht_irq &= ~HTAPIC_MASK; + out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq); + + mtx_unlock_spin(&sc->sc_ht_mtx); + } + openpic_cpcht_eoi(dev, irq); } static void openpic_cpcht_eoi(device_t dev, u_int irq) { + struct openpic_cpcht_softc *sc; uint32_t off, mask; if (irq == 255) return; + sc = device_get_softc(dev); + if (cpcht_irqmap != NULL && irq < 128 && cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) { /* If this is an HT IRQ, acknowledge it at the remote APIC */ @@ -722,10 +796,14 @@ openpic_cpcht_eoi(device_t dev, u_int ir mask = 1 << (cpcht_irqmap[irq].ht_source & 0x1f); out32rb(cpcht_irqmap[irq].apple_eoi + off, mask); } else { + mtx_lock_spin(&sc->sc_ht_mtx); + out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND, 0x11 + (cpcht_irqmap[irq].ht_source << 1)); out32rb(cpcht_irqmap[irq].ht_base + 4, cpcht_irqmap[irq].eoi_data); + + mtx_unlock_spin(&sc->sc_ht_mtx); } }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201005151503.o4FF3IUb009442>