Based on 0006-probe.patch and 0011-probe2.patch by Arjan van de Ven <arjan@linux.intel.com> --- linux-4.2_/drivers/pci/probe.c 2015-08-30 18:34:09.000000000 +0000 +++ linux-4.2/drivers/pci/probe.c 2015-09-02 06:31:48.427519962 +0000 @@ -159,6 +159,281 @@ #define PCI_COMMAND_DECODE_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_IO) + +/* shortcut version of __pci_read_base where we know the sizes already */ +int __pci_read_base_shortcut(struct pci_dev *dev, enum pci_bar_type type, + struct resource *res, unsigned int pos, u32 sz_in, u32 sz2_in) +{ + u32 l, sz; + u64 l64, sz64, mask64; + struct pci_bus_region region, inverted_region; + + res->name = pci_name(dev); + + pci_read_config_dword(dev, pos, &l); + + sz = sz_in; + + /* + * All bits set in sz means the device isn't working properly. + * If the BAR isn't implemented, all bits must be 0. If it's a + * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit + * 1 must be clear. + * Here we set the size and is not 0xffffffff + */ + + /* + * I don't know how l can have all bits set. Copied from old code. + * Maybe it fixes a bug on some ancient platform. + */ + if (l == 0xffffffff) + l = 0; + + if (type == pci_bar_unknown) { + res->flags = decode_bar(dev, l); + res->flags |= IORESOURCE_SIZEALIGN; + if (res->flags & IORESOURCE_IO) { + l64 = l & PCI_BASE_ADDRESS_IO_MASK; + sz64 = sz & PCI_BASE_ADDRESS_IO_MASK; + mask64 = PCI_BASE_ADDRESS_IO_MASK & (u32)IO_SPACE_LIMIT; + } else { + l64 = l & PCI_BASE_ADDRESS_MEM_MASK; + sz64 = sz & PCI_BASE_ADDRESS_MEM_MASK; + mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK; + } + } else { + res->flags |= (l & IORESOURCE_ROM_ENABLE); + l64 = l & PCI_ROM_ADDRESS_MASK; + sz64 = sz & PCI_ROM_ADDRESS_MASK; + mask64 = (u32)PCI_ROM_ADDRESS_MASK; + } + + if (res->flags & IORESOURCE_MEM_64) { + pci_read_config_dword(dev, pos + 4, &l); + sz = sz2_in; + + l64 |= ((u64)l << 32); + sz64 |= ((u64)sz << 32); + mask64 |= ((u64)~0 << 32); + } + + if (!sz64) + goto fail; + + sz64 = pci_size(l64, sz64, mask64); + if (!sz64) { + dev_info(&dev->dev, FW_BUG "reg 0x%x: invalid BAR (can't size)\n", + pos); + goto fail; + } + + if (res->flags & IORESOURCE_MEM_64) { + if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && + sz64 > 0x100000000ULL) { + res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; + res->start = 0; + res->end = 0; + dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n", + pos, (unsigned long long)sz64); + goto out; + } + + if ((sizeof(dma_addr_t) < 8) && l) { + /* Above 32-bit boundary; try to reallocate */ + res->flags |= IORESOURCE_UNSET; + res->start = 0; + res->end = sz64; + dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4GB (bus address %#010llx)\n", + pos, (unsigned long long)l64); + goto out; + } + } + + region.start = l64; + region.end = l64 + sz64; + + pcibios_bus_to_resource(dev->bus, res, ®ion); + pcibios_resource_to_bus(dev->bus, &inverted_region, res); + + /* + * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is + * the corresponding resource address (the physical address used by + * the CPU. Converting that resource address back to a bus address + * should yield the original BAR value: + * + * resource_to_bus(bus_to_resource(A)) == A + * + * If it doesn't, CPU accesses to "bus_to_resource(A)" will not + * be claimed by the device. + */ + if (inverted_region.start != region.start) { + res->flags |= IORESOURCE_UNSET; + res->start = 0; + res->end = region.end - region.start; + dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n", + pos, (unsigned long long)region.start); + } + + goto out; + + +fail: + res->flags = 0; +out: + if (res->flags) + dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); + + return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; +} + +static int is_known_device(struct pci_dev *dev, int pos, int *sz) +{ + switch (dev->vendor) { + /* Intel Corporation */ + case 0x8086: + switch (dev->device) { + /* IDE interface: 82371AB/EB/MB PIIX4 IDE */ + case 0x7111: + switch (pos) { + case 0x20: + *sz = 0xfffffff1; + return 1; + case 0x10: + case 0x14: + case 0x18: + case 0x1c: + case 0x24: + case 0x30: + *sz = 0; /* Not implemented */ + return 1; + } + break; + + /* Bridge: 82371AB/EB/MB PIIX4 ACPI */ + case 0x7113: + switch (pos) { + case 0x10: + case 0x14: + case 0x18: + case 0x1c: + case 0x20: + case 0x24: + case 0x30: + *sz = 0; /* Not implemented */ + return 1; + } + break; + } + break; + + /* VMware, Inc */ + case 0x15ad: + switch (dev->device) { + /* VMware SVGA II Adapter */ + case 0x0405: + switch (pos) { + case 0x10: + *sz = 0xfffffff1; + return 1; + case 0x14: + *sz = 0xfc000000; + return 1; + case 0x18: + *sz = 0xff800000; + return 1; + case 0x1c: + case 0x20: + case 0x24: + *sz = 0; /* Not implemented */ + return 1; + case 0x30: + *sz = 0xffff8000; + return 1; + } + break; + + /* VMware Virtual Machine Communication Interface */ + case 0x0740: + switch (pos) { + case 0x10: + *sz = 0xffffffc1; + return 1; + case 0x14: + *sz = 0xffffe000; + return 1; + case 0x1c: + case 0x20: + case 0x24: + case 0x30: + *sz = 0; /* Not implemented */ + return 1; + } + break; + + /* VMware PCI bridge */ + case 0x0790: + /* VMware PCI Express Root Port */ + case 0x07a0: + switch (pos) { + case 0x10: + case 0x14: + case 0x38: + *sz = 0; /* Not implemented */ + return 1; + } + break; + + /* VMware VMXNET3 Ethernet Controller */ + case 0x07b0: + switch (pos) { + case 0x10: + *sz = 0xfffff000; + return 1; + case 0x14: + *sz = 0xfffff000; + return 1; + case 0x18: + *sz = 0xffffe000; + return 1; + case 0x1c: + *sz = 0xfffffff1; + return 1; + case 0x20: + case 0x24: + *sz = 0; /* Not implemented */ + return 1; + case 0x30: + *sz = 0xffff0000; + return 1; + } + break; + + /* VMware PVSCSI SCSI Controller */ + case 0x07c0: + switch (pos) { + case 0x10: + *sz = 0xfffffff9; + return 1; + case 0x14: + *sz = 0xffff8000; + return 1; + case 0x1c: + case 0x20: + case 0x24: + *sz = 0; /* Not implemented */ + return 1; + case 0x30: + *sz = 0xffff0000; + return 1; + } + break; + } + break; + + } + return 0; +} + /** * pci_read_base - read a PCI BAR * @dev: the PCI device @@ -178,6 +453,13 @@ mask = type ? PCI_ROM_ADDRESS_MASK : ~0; + if (is_known_device(dev, pos, &sz)) + return __pci_read_base_shortcut(dev, type, res, pos, sz, 0); + + res->name = pci_name(dev); + + printk("Starting probe for %s %x:%x:%x\n", res->name, dev->vendor, dev->device, pos); + /* No printks while decoding is disabled! */ if (!dev->mmio_always_on) { pci_read_config_word(dev, PCI_COMMAND, &orig_cmd); @@ -187,7 +469,6 @@ } } - res->name = pci_name(dev); pci_read_config_dword(dev, pos, &l); pci_write_config_dword(dev, pos, l | mask); @@ -1108,6 +1389,28 @@ #define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) +static int guess_bar_count(int class) +{ + if (class == 0x068000) + return 0; + if (class == 0x020000) + return 3; + if (class == 0x010000) + return 2; + if (class == 0x00ff00) + return 1; + return 6; +} + +static int has_rom(int class, int rom) +{ + if (class == 0x020000) + return 0; + if (class == 0x010000 || class == 0x00ff00) + return 0; + return rom; +} + void pci_msi_setup_pci_dev(struct pci_dev *dev) { /* @@ -1142,6 +1445,7 @@ int pos = 0; struct pci_bus_region region; struct resource *res; + int maxbar; if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type)) return -EIO; @@ -1191,7 +1495,11 @@ if (class == PCI_CLASS_BRIDGE_PCI) goto bad; pci_read_irq(dev); - pci_read_bases(dev, 6, PCI_ROM_ADDRESS); + + maxbar = guess_bar_count(dev->class); + + if (class != PCI_CLASS_STORAGE_IDE) + pci_read_bases(dev, maxbar, has_rom(dev->class, PCI_ROM_ADDRESS)); pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);