Skip to content

Commit

Permalink
PCI: Work around devices wrongly set as bridge class by buggy BIOS
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mmuman committed Dec 23, 2012
1 parent e1988c7 commit 53eb64d
Showing 1 changed file with 31 additions and 2 deletions.
33 changes: 31 additions & 2 deletions src/add-ons/kernel/bus_managers/pci/pci.cpp
Expand Up @@ -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 "
Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 53eb64d

Please sign in to comment.