From 81a5e70e0de55707c3184d186b2103b5bb9377ec Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 14 Apr 2017 14:12:06 -0500 Subject: [PATCH] PCI: Factor pci_reassigndev_resource_alignment() Pull the BAR size adjustment out into a new function, pci_request_resource_alignment(), and add a comment about how and why we increase the resource size and alignment. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 69 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d22fb35be26e..1d8bb090a40b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5049,6 +5049,48 @@ out: return align; } +static void pci_request_resource_alignment(struct pci_dev *dev, int bar, + resource_size_t align) +{ + struct resource *r = &dev->resource[bar]; + resource_size_t size; + + if (!(r->flags & IORESOURCE_MEM)) + return; + + if (r->flags & IORESOURCE_PCI_FIXED) { + dev_info(&dev->dev, "BAR%d %pR: ignoring requested alignment %#llx\n", + bar, r, (unsigned long long)align); + return; + } + + size = resource_size(r); + if (size < align) { + + /* + * Increase the size of the resource. BARs are aligned on + * their size, so when we reallocate space for this + * resource, we'll allocate it with the larger alignment. + * It also prevents assignment of any other BARs inside the + * size. If we're requesting page alignment, this means no + * other BARs will share the page. + * + * This makes the resource larger than the hardware BAR, + * which may break drivers that compute things based on the + * resource size, e.g., to find registers at a fixed offset + * before the end of the BAR. We hope users don't request + * alignment for such devices. + */ + size = align; + dev_info(&dev->dev, "BAR%d %pR: requesting alignment to %#llx\n", + bar, r, (unsigned long long)align); + + } + r->flags |= IORESOURCE_UNSET; + r->end = size - 1; + r->start = 0; +} + /* * This function disables memory decoding and releases memory resources * of the device specified by kernel's boot parameter 'pci=resource_alignment='. @@ -5060,7 +5102,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev) { int i; struct resource *r; - resource_size_t align, size; + resource_size_t align; u16 command; /* @@ -5090,28 +5132,11 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev) command &= ~PCI_COMMAND_MEMORY; pci_write_config_word(dev, PCI_COMMAND, command); - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - r = &dev->resource[i]; - if (!(r->flags & IORESOURCE_MEM)) - continue; - if (r->flags & IORESOURCE_PCI_FIXED) { - dev_info(&dev->dev, "Ignoring requested alignment for BAR%d: %pR\n", - i, r); - continue; - } + for (i = 0; i <= PCI_ROM_RESOURCE; i++) + pci_request_resource_alignment(dev, i, align); - size = resource_size(r); - if (size < align) { - size = align; - dev_info(&dev->dev, - "Rounding up size of resource #%d to %#llx.\n", - i, (unsigned long long)size); - } - r->flags |= IORESOURCE_UNSET; - r->end = size - 1; - r->start = 0; - } - /* Need to disable bridge's resource window, + /* + * Need to disable bridge's resource window, * to enable the kernel to reassign new resource * window later on. */