Fix the code to look up the BIOS IRQ for a given link device by reading
the IRQ set by the BIOS in existing devices to actually get the correct bus number of the child PCI bus. I was not reading the bus number from the bridge device correctly. The __BUS_ACCESSOR() macros (from which pcib_get_bus() is built) assume that the passed in argument is a child device. However, at the time I'm reading the bus there is no child device yet, so I was passing in the pcib device as the child device. The parent of the pcib device probably returned an error in the case of a host bridge, thus resulting in random stack garbage for the bus number. For PCI-PCI bridges, the bus number being used was actually the subvendor of the PCI-PCI bridge device itself. MFC after: 1 week
This commit is contained in:
parent
f5e19c7342
commit
a4104d1c3b
@ -608,7 +608,19 @@ acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
|
|||||||
{
|
{
|
||||||
struct link *link;
|
struct link *link;
|
||||||
uint8_t bios_irq;
|
uint8_t bios_irq;
|
||||||
|
uintptr_t bus;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the PCI bus for the specified PCI bridge device. Note
|
||||||
|
* that the PCI bridge device might not have any children yet.
|
||||||
|
* However, looking up its bus number doesn't require a valid child
|
||||||
|
* device, so we just pass NULL.
|
||||||
|
*/
|
||||||
|
if (BUS_READ_IVAR(pcib, NULL, PCIB_IVAR_BUS, &bus) != 0) {
|
||||||
|
device_printf(pcib, "Unable to read PCI bus number");
|
||||||
|
panic("this is bad");
|
||||||
|
}
|
||||||
|
|
||||||
/* Bump the reference count. */
|
/* Bump the reference count. */
|
||||||
ACPI_SERIAL_BEGIN(pci_link);
|
ACPI_SERIAL_BEGIN(pci_link);
|
||||||
link = acpi_pci_link_lookup(dev, index);
|
link = acpi_pci_link_lookup(dev, index);
|
||||||
@ -619,7 +631,7 @@ acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
|
|||||||
pci_link_interrupt_weights[link->l_irq]++;
|
pci_link_interrupt_weights[link->l_irq]++;
|
||||||
|
|
||||||
/* Try to find a BIOS IRQ setting from any matching devices. */
|
/* Try to find a BIOS IRQ setting from any matching devices. */
|
||||||
bios_irq = acpi_pci_link_search_irq(pcib_get_bus(pcib), slot, pin);
|
bios_irq = acpi_pci_link_search_irq(bus, slot, pin);
|
||||||
if (!PCI_INTERRUPT_VALID(bios_irq)) {
|
if (!PCI_INTERRUPT_VALID(bios_irq)) {
|
||||||
ACPI_SERIAL_END(pci_link);
|
ACPI_SERIAL_END(pci_link);
|
||||||
return;
|
return;
|
||||||
@ -628,7 +640,7 @@ acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
|
|||||||
/* Validate the BIOS IRQ. */
|
/* Validate the BIOS IRQ. */
|
||||||
if (!link_valid_irq(link, bios_irq)) {
|
if (!link_valid_irq(link, bios_irq)) {
|
||||||
device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n",
|
device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n",
|
||||||
bios_irq, pcib_get_bus(pcib), slot, pin + 'A');
|
bios_irq, (int)bus, slot, pin + 'A');
|
||||||
} else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) {
|
} else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) {
|
||||||
link->l_bios_irq = bios_irq;
|
link->l_bios_irq = bios_irq;
|
||||||
if (bios_irq < NUM_ISA_INTERRUPTS)
|
if (bios_irq < NUM_ISA_INTERRUPTS)
|
||||||
@ -641,7 +653,7 @@ acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
|
|||||||
} else if (bios_irq != link->l_bios_irq)
|
} else if (bios_irq != link->l_bios_irq)
|
||||||
device_printf(dev,
|
device_printf(dev,
|
||||||
"BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n",
|
"BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n",
|
||||||
bios_irq, pcib_get_bus(pcib), slot, pin + 'A',
|
bios_irq, (int)bus, slot, pin + 'A',
|
||||||
link->l_bios_irq);
|
link->l_bios_irq);
|
||||||
ACPI_SERIAL_END(pci_link);
|
ACPI_SERIAL_END(pci_link);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user