PCI: Work around devices wrongly set as bridge class by buggy BIOS
This is a proper fix for the issue I tried to fix with hrev43552. Previous fix only fixed the stack overflow caused by it but still generated ghost devices due to the duplicated enumeration. Affected motherboards include FIC PA-2013 (mine), and FIC VA503+ as mentionned on: http://lkml.indiana.edu/hypermail/linux/kernel/9912.0/0539.html We now check the header type for bridge devices and just ignore wrong ones.
This commit is contained in:
parent
e1988c7d53
commit
53eb64dd71
@ -739,6 +739,12 @@ PCI::_EnumerateBus(int domain, uint8 bus, uint8 *subordinateBus)
|
||||
if (baseClass != PCI_bridge || subClass != PCI_pci)
|
||||
continue;
|
||||
|
||||
// skip incorrectly configured devices
|
||||
uint8 headerType = ReadConfig(domain, bus, dev, function,
|
||||
PCI_header_type, 1) & PCI_header_type_mask;
|
||||
if (headerType != PCI_header_type_PCI_to_PCI_bridge)
|
||||
continue;
|
||||
|
||||
TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
|
||||
domain, bus, dev, function));
|
||||
TRACE(("PCI: original settings: pcicmd %04" B_PRIx32 ", primary-bus "
|
||||
@ -793,6 +799,12 @@ PCI::_EnumerateBus(int domain, uint8 bus, uint8 *subordinateBus)
|
||||
if (baseClass != PCI_bridge || subClass != PCI_pci)
|
||||
continue;
|
||||
|
||||
// skip incorrectly configured devices
|
||||
uint8 headerType = ReadConfig(domain, bus, dev, function,
|
||||
PCI_header_type, 1) & PCI_header_type_mask;
|
||||
if (headerType != PCI_header_type_PCI_to_PCI_bridge)
|
||||
continue;
|
||||
|
||||
TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
|
||||
domain, bus, dev, function));
|
||||
|
||||
@ -877,6 +889,18 @@ PCI::_FixupDevices(int domain, uint8 bus)
|
||||
if (subClass != PCI_pci)
|
||||
continue;
|
||||
|
||||
// some FIC motherboards have a buggy BIOS...
|
||||
// make sure the header type is correct for a bridge,
|
||||
uint8 headerType = ReadConfig(domain, bus, dev, function,
|
||||
PCI_header_type, 1) & PCI_header_type_mask;
|
||||
if (headerType != PCI_header_type_PCI_to_PCI_bridge) {
|
||||
dprintf("PCI: dom %u, bus %u, dev %2u, func %u, PCI bridge"
|
||||
" class but wrong header type 0x%02x, ignoring.\n",
|
||||
domain, bus, dev, function, headerType);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
int busBehindBridge = ReadConfig(domain, bus, dev, function,
|
||||
PCI_secondary_bus, 1);
|
||||
|
||||
@ -894,7 +918,9 @@ PCI::_ConfigureBridges(PCIBus *bus)
|
||||
{
|
||||
for (PCIDev *dev = bus->child; dev; dev = dev->next) {
|
||||
if (dev->info.class_base == PCI_bridge
|
||||
&& dev->info.class_sub == PCI_pci) {
|
||||
&& dev->info.class_sub == PCI_pci
|
||||
&& (dev->info.header_type & PCI_header_type_mask)
|
||||
== PCI_header_type_PCI_to_PCI_bridge) {
|
||||
uint16 bridgeControlOld = ReadConfig(dev->domain, dev->bus,
|
||||
dev->device, dev->function, PCI_bridge_control, 2);
|
||||
uint16 bridgeControlNew = bridgeControlOld;
|
||||
@ -1058,7 +1084,10 @@ PCI::_DiscoverDevice(PCIBus *bus, uint8 dev, uint8 function)
|
||||
PCI_class_base, 1);
|
||||
uint8 subClass = ReadConfig(bus->domain, bus->bus, dev, function,
|
||||
PCI_class_sub, 1);
|
||||
if (baseClass == PCI_bridge && subClass == PCI_pci) {
|
||||
uint8 headerType = ReadConfig(bus->domain, bus->bus, dev, function,
|
||||
PCI_header_type, 1) & PCI_header_type_mask;
|
||||
if (baseClass == PCI_bridge && subClass == PCI_pci
|
||||
&& headerType == PCI_header_type_PCI_to_PCI_bridge) {
|
||||
uint8 secondaryBus = ReadConfig(bus->domain, bus->bus, dev, function,
|
||||
PCI_secondary_bus, 1);
|
||||
PCIBus *newBus = _CreateBus(newDev, bus->domain, secondaryBus);
|
||||
|
Loading…
Reference in New Issue
Block a user