diff options
author | Bjorn Helgaas | 2016-08-01 12:23:44 -0500 |
---|---|---|
committer | Bjorn Helgaas | 2016-08-01 12:23:44 -0500 |
commit | 3efc7023787f8a6ddc50fa96707614677a568466 (patch) | |
tree | 40014e14e68d3b2d66b030ce1f06914ecd6a814e /drivers/pci | |
parent | a00c74c1664e6de4ad671c7c921a06ef164622c0 (diff) | |
parent | ab2b750cad0276cebbb9f765ca5652bd35dcb7af (diff) |
Merge branch 'pci/resource' into next
* pci/resource:
unicore32/PCI: Remove pci=firmware command line parameter handling
ARM/PCI: Remove arch-specific pcibios_enable_device()
ARM64/PCI: Remove arch-specific pcibios_enable_device()
MIPS/PCI: Claim bus resources on PCI_PROBE_ONLY set-ups
ARM/PCI: Claim bus resources on PCI_PROBE_ONLY set-ups
PCI: generic: Claim bus resources on PCI_PROBE_ONLY set-ups
PCI: Add generic pci_bus_claim_resources()
alx: Use pci_(request|release)_mem_regions
ethernet/intel: Use pci_(request|release)_mem_regions
GenWQE: Use pci_(request|release)_mem_regions
lpfc: Use pci_(request|release)_mem_regions
NVMe: Use pci_(request|release)_mem_regions
PCI: Add helpers to request/release memory and I/O regions
PCI: Extending pci=resource_alignment to specify device/vendor IDs
sparc/PCI: Implement pci_resource_to_user() with pcibios_resource_to_bus()
powerpc/pci: Implement pci_resource_to_user() with pcibios_resource_to_bus()
microblaze/PCI: Implement pci_resource_to_user() with pcibios_resource_to_bus()
PCI: Unify pci_resource_to_user() declarations
microblaze/PCI: Remove useless __pci_mmap_set_pgprot()
powerpc/pci: Remove __pci_mmap_set_pgprot()
PCI: Ignore write combining when mapping I/O port space
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/host/pci-host-common.c | 9 | ||||
-rw-r--r-- | drivers/pci/pci.c | 66 | ||||
-rw-r--r-- | drivers/pci/proc.c | 9 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 68 |
4 files changed, 129 insertions, 23 deletions
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c index c18b9e3bb8bd..542b3992ebf3 100644 --- a/drivers/pci/host/pci-host-common.c +++ b/drivers/pci/host/pci-host-common.c @@ -154,7 +154,14 @@ int pci_host_common_probe(struct platform_device *pdev, pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); - if (!pci_has_flag(PCI_PROBE_ONLY)) { + /* + * We insert PCI resources into the iomem_resource and + * ioport_resource trees in either pci_bus_claim_resources() + * or pci_bus_assign_resources(). + */ + if (pci_has_flag(PCI_PROBE_ONLY)) { + pci_bus_claim_resources(bus); + } else { pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 14d24b4fc508..9a6bc77ce3aa 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4953,6 +4953,7 @@ static DEFINE_SPINLOCK(resource_alignment_lock); static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev) { int seg, bus, slot, func, align_order, count; + unsigned short vendor, device, subsystem_vendor, subsystem_device; resource_size_t align = 0; char *p; @@ -4966,28 +4967,55 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev) } else { align_order = -1; } - if (sscanf(p, "%x:%x:%x.%x%n", - &seg, &bus, &slot, &func, &count) != 4) { - seg = 0; - if (sscanf(p, "%x:%x.%x%n", - &bus, &slot, &func, &count) != 3) { - /* Invalid format */ - printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n", - p); + if (strncmp(p, "pci:", 4) == 0) { + /* PCI vendor/device (subvendor/subdevice) ids are specified */ + p += 4; + if (sscanf(p, "%hx:%hx:%hx:%hx%n", + &vendor, &device, &subsystem_vendor, &subsystem_device, &count) != 4) { + if (sscanf(p, "%hx:%hx%n", &vendor, &device, &count) != 2) { + printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: pci:%s\n", + p); + break; + } + subsystem_vendor = subsystem_device = 0; + } + p += count; + if ((!vendor || (vendor == dev->vendor)) && + (!device || (device == dev->device)) && + (!subsystem_vendor || (subsystem_vendor == dev->subsystem_vendor)) && + (!subsystem_device || (subsystem_device == dev->subsystem_device))) { + if (align_order == -1) + align = PAGE_SIZE; + else + align = 1 << align_order; + /* Found */ break; } } - p += count; - if (seg == pci_domain_nr(dev->bus) && - bus == dev->bus->number && - slot == PCI_SLOT(dev->devfn) && - func == PCI_FUNC(dev->devfn)) { - if (align_order == -1) - align = PAGE_SIZE; - else - align = 1 << align_order; - /* Found */ - break; + else { + if (sscanf(p, "%x:%x:%x.%x%n", + &seg, &bus, &slot, &func, &count) != 4) { + seg = 0; + if (sscanf(p, "%x:%x.%x%n", + &bus, &slot, &func, &count) != 3) { + /* Invalid format */ + printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n", + p); + break; + } + } + p += count; + if (seg == pci_domain_nr(dev->bus) && + bus == dev->bus->number && + slot == PCI_SLOT(dev->devfn) && + func == PCI_FUNC(dev->devfn)) { + if (align_order == -1) + align = PAGE_SIZE; + else + align = 1 << align_order; + /* Found */ + break; + } } if (*p != ';' && *p != ',') { /* End of param or invalid format */ diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 3f155e78513f..2408abe4ee8c 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -231,7 +231,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) { struct pci_dev *dev = PDE_DATA(file_inode(file)); struct pci_filp_private *fpriv = file->private_data; - int i, ret; + int i, ret, write_combine; if (!capable(CAP_SYS_RAWIO)) return -EPERM; @@ -245,9 +245,12 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) if (i >= PCI_ROM_RESOURCE) return -ENODEV; + if (fpriv->mmap_state == pci_mmap_mem) + write_combine = fpriv->write_combine; + else + write_combine = 0; ret = pci_mmap_page_range(dev, vma, - fpriv->mmap_state, - fpriv->write_combine); + fpriv->mmap_state, write_combine); if (ret < 0) return ret; diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 55641a39a3e9..1d1a2c952c35 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1423,6 +1423,74 @@ void pci_bus_assign_resources(const struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_assign_resources); +static void pci_claim_device_resources(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { + struct resource *r = &dev->resource[i]; + + if (!r->flags || r->parent) + continue; + + pci_claim_resource(dev, i); + } +} + +static void pci_claim_bridge_resources(struct pci_dev *dev) +{ + int i; + + for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { + struct resource *r = &dev->resource[i]; + + if (!r->flags || r->parent) + continue; + + pci_claim_bridge_resource(dev, i); + } +} + +static void pci_bus_allocate_dev_resources(struct pci_bus *b) +{ + struct pci_dev *dev; + struct pci_bus *child; + + list_for_each_entry(dev, &b->devices, bus_list) { + pci_claim_device_resources(dev); + + child = dev->subordinate; + if (child) + pci_bus_allocate_dev_resources(child); + } +} + +static void pci_bus_allocate_resources(struct pci_bus *b) +{ + struct pci_bus *child; + + /* + * Carry out a depth-first search on the PCI bus + * tree to allocate bridge apertures. Read the + * programmed bridge bases and recursively claim + * the respective bridge resources. + */ + if (b->self) { + pci_read_bridge_bases(b); + pci_claim_bridge_resources(b->self); + } + + list_for_each_entry(child, &b->children, node) + pci_bus_allocate_resources(child); +} + +void pci_bus_claim_resources(struct pci_bus *b) +{ + pci_bus_allocate_resources(b); + pci_bus_allocate_dev_resources(b); +} +EXPORT_SYMBOL(pci_bus_claim_resources); + static void __pci_bridge_assign_resources(const struct pci_dev *bridge, struct list_head *add_head, struct list_head *fail_head) |