aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,