Date: Tue, 1 Jun 2004 15:31:09 -0400 From: John Baldwin <jhb@FreeBSD.org> To: acpi@FreeBSD.org Cc: marcel@FreeBSD.org Subject: Patch: Defer bus_config_intr() until bus_alloc_resource().. Message-ID: <200406011531.09077.jhb@FreeBSD.org>
next in thread | raw e-mail | index | archive | help
I need the patch below in order to turn on bus_config_intr() when using the I/O APICs. The original problem is that the _CRS of link devices is configured which is the PIC IRQ and thus screws up intpins when using the APIC. It basically takes bus_config_intr() out of the resource parsing code and does the config when an IRQ is allocated via bus_alloc_resource() for normal devices, and when a PCI IRQ is routed for PCI link devices. --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi.c 2004/05/06 01:05:39 +++ //depot/user/jhb/acpipci/dev/acpica/acpi.c 2004/05/28 10:02:20 @@ -849,15 +849,82 @@ return (0); } +static void +acpi_config_intr(device_t dev, u_int irq, int trig, int pol) +{ + + BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ? + INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ? + INTR_POLARITY_HIGH : INTR_POLARITY_LOW); +} + static struct resource * acpi_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct acpi_device *ad = device_get_ivars(child); struct resource_list *rl = &ad->ad_rl; + struct resource *res; + ACPI_RESOURCE *ares; + ACPI_BUFFER buf; + char *curr, *last; + int i; - return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, - flags)); + res = resource_list_alloc(rl, bus, child, type, rid, start, end, count, + flags); + if (res == NULL || device_get_parent(child) != bus) + return (res); + switch (type) { + case SYS_RES_IRQ: + buf.Length = ACPI_ALLOCATE_BUFFER; + if (ACPI_FAILURE((AcpiGetCurrentResources(ad->ad_handle, &buf)))) + break; + i = 0; + curr = buf.Pointer; + last = (char *)buf.Pointer + buf.Length; + while (curr < last) { + ares = (ACPI_RESOURCE *)curr; + curr += ares->Length; + switch (ares->Id) { + case ACPI_RSTYPE_END_TAG: + curr = last; + break; + case ACPI_RSTYPE_IRQ: + if (ares->Data.Irq.NumberOfInterrupts != 1) + break; + if (i != *rid) { + i++; + break; + } + KASSERT(ares->Data.Irq.Interrupts[0] == + rman_get_start(res), + ("IRQ resources do not match")); + acpi_config_intr(child, + ares->Data.Irq.Interrupts[0], + ares->Data.Irq.EdgeLevel, + ares->Data.Irq.ActiveHighLow); + break; + case ACPI_RSTYPE_EXT_IRQ: + if (ares->Data.ExtendedIrq.NumberOfInterrupts != 1) + break; + if (i != *rid) { + i++; + break; + } + KASSERT(ares->Data.ExtendedIrq.Interrupts[0] == + rman_get_start(res), + ("IRQ resources do not match")); + acpi_config_intr(child, + ares->Data.ExtendedIrq.Interrupts[0], + ares->Data.ExtendedIrq.EdgeLevel, + ares->Data.ExtendedIrq.ActiveHighLow); + break; + } + } + AcpiOsFree(buf.Pointer); + break; + } + return (res); } static int --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pcib.c 2004/05/05 19:22:26 +++ //depot/user/jhb/acpipci/dev/acpica/acpi_pcib.c 2004/05/28 06:38:57 @@ -121,10 +121,11 @@ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + crsres = NULL; buf.Pointer = NULL; crsbuf.Pointer = NULL; prsbuf.Pointer = NULL; - interrupt = 255; + interrupt = PCI_INVALID_IRQ; /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */ pin--; @@ -348,6 +349,7 @@ /* XXX Data.Irq and Data.ExtendedIrq are implicitly structure-copied. */ crsbuf.Pointer = NULL; + crsres = NULL; if (prsres->Id == ACPI_RSTYPE_IRQ) { resbuf.Id = ACPI_RSTYPE_IRQ; resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ); @@ -378,6 +380,7 @@ AcpiFormatException(status)); goto out; } + crsres = &resbuf; /* Return the interrupt we just routed. */ device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", @@ -386,6 +389,20 @@ interrupt = Interrupts[0]; out: + if (PCI_INTERRUPT_VALID(interrupt) && crsres != NULL) { + int trig, pol; + + if (crsres->Id == ACPI_RSTYPE_IRQ) { + trig = crsres->Data.Irq.EdgeLevel; + pol = crsres->Data.Irq.ActiveHighLow; + } else { + trig = crsres->Data.ExtendedIrq.EdgeLevel; + pol = crsres->Data.ExtendedIrq.ActiveHighLow; + } + BUS_CONFIG_INTR(dev, interrupt, (trig == ACPI_EDGE_SENSITIVE) ? + INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ? + INTR_POLARITY_HIGH : INTR_POLARITY_LOW); + } if (crsbuf.Pointer != NULL) AcpiOsFree(crsbuf.Pointer); if (prsbuf.Pointer != NULL) @@ -393,6 +410,5 @@ if (buf.Pointer != NULL) AcpiOsFree(buf.Pointer); - /* XXX APIC_IO interrupt mapping? */ return_VALUE (interrupt); } --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_resource.c 2004/04/09 11:15:38 +++ //depot/user/jhb/acpipci/dev/acpica/acpi_resource.c 2004/05/28 10:02:20 @@ -495,9 +495,6 @@ return; bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); - BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ? - INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ? - INTR_POLARITY_HIGH : INTR_POLARITY_LOW); } static void -- John Baldwin <jhb@FreeBSD.org> <>< http://www.FreeBSD.org/~jhb/ "Power Users Use the Power to Serve" = http://www.FreeBSD.org
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200406011531.09077.jhb>