aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
authorYongji Xie <elohimes@gmail.com>2017-04-10 07:58:14 -0400
committerBjorn Helgaas <bhelgaas@google.com>2017-04-19 13:52:47 -0400
commite3adec72a3c50b733eb277a9f93c044f59ff55eb (patch)
tree001be0a9f278e5196e85a7d487ffdea161767b5c /drivers/pci/pci.c
parent0dde1c08d1b9dea01cefb327dba8a6e3ae795214 (diff)
PCI: Don't resize resources when realigning all devices in system
The "pci=resource_alignment" argument aligns BARs of designated devices by artificially increasing their size. Increasing the size increases the alignment and prevents other resources from being assigned in the same alignment region, e.g., in the same page, but it can break drivers that use the BAR size to locate things, e.g., ilo_map_device() does this: off = pci_resource_len(pdev, bar) - 0x2000; The new pcibios_default_alignment() interface allows an arch to request that *all* BARs in the system be aligned to a larger size. In this case, we don't need to artificially increase the resource size because we know every BAR of every device will be realigned, so nothing will share the same alignment region. Use IORESOURCE_STARTALIGN to request realignment of PCI BARs when we know we're realigning all BARs in the system. [bhelgaas: comment, changelog] Signed-off-by: Yongji Xie <elohimes@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c59
1 files changed, 43 insertions, 16 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 7eb6eb384e36..c140cb29ee7e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4959,11 +4959,13 @@ static DEFINE_SPINLOCK(resource_alignment_lock);
4959/** 4959/**
4960 * pci_specified_resource_alignment - get resource alignment specified by user. 4960 * pci_specified_resource_alignment - get resource alignment specified by user.
4961 * @dev: the PCI device to get 4961 * @dev: the PCI device to get
4962 * @resize: whether or not to change resources' size when reassigning alignment
4962 * 4963 *
4963 * RETURNS: Resource alignment if it is specified. 4964 * RETURNS: Resource alignment if it is specified.
4964 * Zero if it is not specified. 4965 * Zero if it is not specified.
4965 */ 4966 */
4966static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev) 4967static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
4968 bool *resize)
4967{ 4969{
4968 int seg, bus, slot, func, align_order, count; 4970 int seg, bus, slot, func, align_order, count;
4969 unsigned short vendor, device, subsystem_vendor, subsystem_device; 4971 unsigned short vendor, device, subsystem_vendor, subsystem_device;
@@ -5005,6 +5007,7 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
5005 (!device || (device == dev->device)) && 5007 (!device || (device == dev->device)) &&
5006 (!subsystem_vendor || (subsystem_vendor == dev->subsystem_vendor)) && 5008 (!subsystem_vendor || (subsystem_vendor == dev->subsystem_vendor)) &&
5007 (!subsystem_device || (subsystem_device == dev->subsystem_device))) { 5009 (!subsystem_device || (subsystem_device == dev->subsystem_device))) {
5010 *resize = true;
5008 if (align_order == -1) 5011 if (align_order == -1)
5009 align = PAGE_SIZE; 5012 align = PAGE_SIZE;
5010 else 5013 else
@@ -5030,6 +5033,7 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
5030 bus == dev->bus->number && 5033 bus == dev->bus->number &&
5031 slot == PCI_SLOT(dev->devfn) && 5034 slot == PCI_SLOT(dev->devfn) &&
5032 func == PCI_FUNC(dev->devfn)) { 5035 func == PCI_FUNC(dev->devfn)) {
5036 *resize = true;
5033 if (align_order == -1) 5037 if (align_order == -1)
5034 align = PAGE_SIZE; 5038 align = PAGE_SIZE;
5035 else 5039 else
@@ -5050,7 +5054,7 @@ out:
5050} 5054}
5051 5055
5052static void pci_request_resource_alignment(struct pci_dev *dev, int bar, 5056static void pci_request_resource_alignment(struct pci_dev *dev, int bar,
5053 resource_size_t align) 5057 resource_size_t align, bool resize)
5054{ 5058{
5055 struct resource *r = &dev->resource[bar]; 5059 struct resource *r = &dev->resource[bar];
5056 resource_size_t size; 5060 resource_size_t size;
@@ -5069,23 +5073,45 @@ static void pci_request_resource_alignment(struct pci_dev *dev, int bar,
5069 return; 5073 return;
5070 5074
5071 /* 5075 /*
5072 * Increase the size of the resource. BARs are aligned on their 5076 * Increase the alignment of the resource. There are two ways we
5073 * size, so when we reallocate space for this resource, we'll 5077 * can do this:
5074 * allocate it with the larger alignment. It also prevents
5075 * assignment of any other BARs inside the size. If we're
5076 * requesting page alignment, this means no other BARs will share
5077 * the page.
5078 * 5078 *
5079 * This makes the resource larger than the hardware BAR, which may 5079 * 1) Increase the size of the resource. BARs are aligned on their
5080 * break drivers that compute things based on the resource size, 5080 * size, so when we reallocate space for this resource, we'll
5081 * e.g., to find registers at a fixed offset before the end of the 5081 * allocate it with the larger alignment. This also prevents
5082 * BAR. We hope users don't request alignment for such devices. 5082 * assignment of any other BARs inside the alignment region, so
5083 * if we're requesting page alignment, this means no other BARs
5084 * will share the page.
5085 *
5086 * The disadvantage is that this makes the resource larger than
5087 * the hardware BAR, which may break drivers that compute things
5088 * based on the resource size, e.g., to find registers at a
5089 * fixed offset before the end of the BAR.
5090 *
5091 * 2) Retain the resource size, but use IORESOURCE_STARTALIGN and
5092 * set r->start to the desired alignment. By itself this
5093 * doesn't prevent other BARs being put inside the alignment
5094 * region, but if we realign *every* resource of every device in
5095 * the system, none of them will share an alignment region.
5096 *
5097 * When the user has requested alignment for only some devices via
5098 * the "pci=resource_alignment" argument, "resize" is true and we
5099 * use the first method. Otherwise we assume we're aligning all
5100 * devices and we use the second.
5083 */ 5101 */
5102
5084 dev_info(&dev->dev, "BAR%d %pR: requesting alignment to %#llx\n", 5103 dev_info(&dev->dev, "BAR%d %pR: requesting alignment to %#llx\n",
5085 bar, r, (unsigned long long)align); 5104 bar, r, (unsigned long long)align);
5086 5105
5087 r->start = 0; 5106 if (resize) {
5088 r->end = align - 1; 5107 r->start = 0;
5108 r->end = align - 1;
5109 } else {
5110 r->flags &= ~IORESOURCE_SIZEALIGN;
5111 r->flags |= IORESOURCE_STARTALIGN;
5112 r->start = align;
5113 r->end = r->start + size - 1;
5114 }
5089 r->flags |= IORESOURCE_UNSET; 5115 r->flags |= IORESOURCE_UNSET;
5090} 5116}
5091 5117
@@ -5102,6 +5128,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
5102 struct resource *r; 5128 struct resource *r;
5103 resource_size_t align; 5129 resource_size_t align;
5104 u16 command; 5130 u16 command;
5131 bool resize = false;
5105 5132
5106 /* 5133 /*
5107 * VF BARs are read-only zero according to SR-IOV spec r1.1, sec 5134 * VF BARs are read-only zero according to SR-IOV spec r1.1, sec
@@ -5113,7 +5140,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
5113 return; 5140 return;
5114 5141
5115 /* check if specified PCI is target device to reassign */ 5142 /* check if specified PCI is target device to reassign */
5116 align = pci_specified_resource_alignment(dev); 5143 align = pci_specified_resource_alignment(dev, &resize);
5117 if (!align) 5144 if (!align)
5118 return; 5145 return;
5119 5146
@@ -5131,7 +5158,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
5131 pci_write_config_word(dev, PCI_COMMAND, command); 5158 pci_write_config_word(dev, PCI_COMMAND, command);
5132 5159
5133 for (i = 0; i <= PCI_ROM_RESOURCE; i++) 5160 for (i = 0; i <= PCI_ROM_RESOURCE; i++)
5134 pci_request_resource_alignment(dev, i, align); 5161 pci_request_resource_alignment(dev, i, align, resize);
5135 5162
5136 /* 5163 /*
5137 * Need to disable bridge's resource window, 5164 * Need to disable bridge's resource window,