From owner-linux-pci@atrey.karlin.mff.cuni.cz Tue Apr 18 17:20:07 2006 Message-ID: <44458228.1010302@zytor.com> Date: Tue, 18 Apr 2006 17:19:52 -0700 From: "H. Peter Anvin" To: Greg KH Subject: PCI: Ignore pre-set 64-bit BARs on 32-bit platforms From: H. Peter Anvin [pci] Ignore pre-set 64-bit BARs on 32-bit platforms Currently, Linux always rejects a device which has a pre-set 64-bit address on a 32-bit platform. On systems which do not do PCI initialization in firmware, this causes some devices which don't correctly power up with all BARs zero to fail. This patch makes the kernel automatically zero out such an address (thus treating it as if it had not been set at all, meaning it will assign an address if necessary). I have done this only for devices, not bridges. It seems potentially hazardous to do for bridges. Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) --- gregkh-2.6.orig/drivers/pci/probe.c +++ gregkh-2.6/drivers/pci/probe.c @@ -180,25 +180,31 @@ static void pci_read_bases(struct pci_de res->flags |= pci_calc_resource_flags(l); if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { - pci_read_config_dword(dev, reg+4, &l); + u32 szhi, lhi; + pci_read_config_dword(dev, reg+4, &lhi); + pci_write_config_dword(dev, reg+4, ~0); + pci_read_config_dword(dev, reg+4, &szhi); + pci_write_config_dword(dev, reg+4, lhi); + szhi = pci_size(lhi, szhi, 0xffffffff); next++; #if BITS_PER_LONG == 64 - res->start |= ((unsigned long) l) << 32; + res->start |= ((unsigned long) lhi) << 32; res->end = res->start + sz; - pci_write_config_dword(dev, reg+4, ~0); - pci_read_config_dword(dev, reg+4, &sz); - pci_write_config_dword(dev, reg+4, l); - sz = pci_size(l, sz, 0xffffffff); - if (sz) { + if (szhi) { /* This BAR needs > 4GB? Wow. */ - res->end |= (unsigned long)sz<<32; + res->end |= (unsigned long)szhi<<32; } #else - if (l) { - printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev)); + if (szhi) { + printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); res->start = 0; res->flags = 0; - continue; + } else if (l) { + /* 64-bit wide address, treat as disabled */ + pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); + pci_write_config_dword(dev, reg+4, 0); + res->start = 0; + res->end = sz; } #endif }