From: "Yinghai Lu" If the PCI device is 64-bit memory and has a size of 0xnnnnnnnn00000000 then pci_read_bases() will incorrectly assume that it has a size of zero. Cc: Myles Watson Signed-off-by: Yinghai Lu Cc: Greg KH Signed-off-by: Andrew Morton --- drivers/pci/probe.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff -puN drivers/pci/probe.c~pci-check-szhi-when-sz-is-0-for-64-bit-pref-mem drivers/pci/probe.c --- a/drivers/pci/probe.c~pci-check-szhi-when-sz-is-0-for-64-bit-pref-mem +++ a/drivers/pci/probe.c @@ -144,6 +144,14 @@ static u32 pci_size(u32 base, u32 maxbas return size; } +static inline bool is_64_bit_memory(u32 v) +{ + if ((v & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == + (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) + return true; + return false; +} + static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { unsigned int pos, reg, next; @@ -165,7 +173,11 @@ static void pci_read_bases(struct pci_de l = 0; if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK); - if (!sz) + /* + * For a 64bit BAR, sz could be 0 if the real size is + * bigger than 4G so we need to check szhi for that. + */ + if (!is_64_bit_memory(l) && !sz) continue; res->start = l & PCI_BASE_ADDRESS_MEM_MASK; res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; @@ -178,8 +190,7 @@ static void pci_read_bases(struct pci_de } res->end = res->start + (unsigned long) sz; 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)) { + if (is_64_bit_memory(l)) { u32 szhi, lhi; pci_read_config_dword(dev, reg+4, &lhi); pci_write_config_dword(dev, reg+4, ~0); @@ -188,6 +199,12 @@ static void pci_read_bases(struct pci_de szhi = pci_size(lhi, szhi, 0xffffffff); next++; #if BITS_PER_LONG == 64 + if (!sz && !szhi) { + res->start = 0; + res->end = 0; + res->flags = 0; + continue; + } res->start |= ((unsigned long) lhi) << 32; res->end = res->start + sz; if (szhi) { _