diff options
-rw-r--r-- | drivers/pci/pci.c | 59 |
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 | */ |
4966 | static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev) | 4967 | static 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 | ||
5052 | static void pci_request_resource_alignment(struct pci_dev *dev, int bar, | 5056 | static 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, |