diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-01-23 17:58:47 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-01-23 17:58:47 -0500 |
| commit | 550695925de06e1777f9268a9266dd1addce5a34 (patch) | |
| tree | 20a2b9236b8d8179ec857fe7099f33c7b6a91cce | |
| parent | b8de08da0402b1cbc3ce1963929161d141d2f933 (diff) | |
| parent | f175aa2c9f6cc08f043e85ea37f44ef3676cbac1 (diff) | |
Merge tag 'pci-v3.19-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI fixes from Bjorn Helgaas:
"These are fixes for:
- a resource management problem that causes a Radeon "Fatal error
during GPU init" on machines where the BIOS programmed an invalid
Root Port window. This was a regression in v3.16.
- an Atheros AR93xx device that doesn't handle PCI bus resets
correctly. This was a regression in v3.14.
- an out-of-date email address"
* tag 'pci-v3.19-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
MAINTAINERS: Update Richard Zhu's email address
sparc/PCI: Clip bridge windows to fit in upstream windows
powerpc/PCI: Clip bridge windows to fit in upstream windows
parisc/PCI: Clip bridge windows to fit in upstream windows
mn10300/PCI: Clip bridge windows to fit in upstream windows
microblaze/PCI: Clip bridge windows to fit in upstream windows
ia64/PCI: Clip bridge windows to fit in upstream windows
frv/PCI: Clip bridge windows to fit in upstream windows
alpha/PCI: Clip bridge windows to fit in upstream windows
x86/PCI: Clip bridge windows to fit in upstream windows
PCI: Add pci_claim_bridge_resource() to clip window if necessary
PCI: Add pci_bus_clip_resource() to clip to fit upstream window
PCI: Pass bridge device, not bus, when updating bridge windows
PCI: Mark Atheros AR93xx to avoid bus reset
PCI: Add flag for devices where we can't use bus reset
| -rw-r--r-- | MAINTAINERS | 2 | ||||
| -rw-r--r-- | arch/alpha/kernel/pci.c | 8 | ||||
| -rw-r--r-- | arch/frv/mb93090-mb00/pci-frv.c | 2 | ||||
| -rw-r--r-- | arch/ia64/pci/pci.c | 48 | ||||
| -rw-r--r-- | arch/microblaze/pci/pci-common.c | 13 | ||||
| -rw-r--r-- | arch/mn10300/unit-asb2305/pci-asb2305.c | 2 | ||||
| -rw-r--r-- | arch/mn10300/unit-asb2305/pci.c | 47 | ||||
| -rw-r--r-- | arch/powerpc/kernel/pci-common.c | 12 | ||||
| -rw-r--r-- | arch/sparc/kernel/pci.c | 5 | ||||
| -rw-r--r-- | arch/x86/pci/i386.c | 2 | ||||
| -rw-r--r-- | drivers/parisc/lba_pci.c | 5 | ||||
| -rw-r--r-- | drivers/pci/bus.c | 43 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 40 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 1 | ||||
| -rw-r--r-- | drivers/pci/quirks.c | 14 | ||||
| -rw-r--r-- | drivers/pci/setup-bus.c | 56 | ||||
| -rw-r--r-- | include/linux/pci.h | 3 |
17 files changed, 222 insertions, 81 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 55b7024579ab..6b7a694bf454 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -7274,7 +7274,7 @@ S: Maintained | |||
| 7274 | F: drivers/pci/host/*layerscape* | 7274 | F: drivers/pci/host/*layerscape* |
| 7275 | 7275 | ||
| 7276 | PCI DRIVER FOR IMX6 | 7276 | PCI DRIVER FOR IMX6 |
| 7277 | M: Richard Zhu <r65037@freescale.com> | 7277 | M: Richard Zhu <Richard.Zhu@freescale.com> |
| 7278 | M: Lucas Stach <l.stach@pengutronix.de> | 7278 | M: Lucas Stach <l.stach@pengutronix.de> |
| 7279 | L: linux-pci@vger.kernel.org | 7279 | L: linux-pci@vger.kernel.org |
| 7280 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) | 7280 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) |
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 076c35cd6cde..98a1525fa164 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c | |||
| @@ -285,8 +285,12 @@ pcibios_claim_one_bus(struct pci_bus *b) | |||
| 285 | if (r->parent || !r->start || !r->flags) | 285 | if (r->parent || !r->start || !r->flags) |
| 286 | continue; | 286 | continue; |
| 287 | if (pci_has_flag(PCI_PROBE_ONLY) || | 287 | if (pci_has_flag(PCI_PROBE_ONLY) || |
| 288 | (r->flags & IORESOURCE_PCI_FIXED)) | 288 | (r->flags & IORESOURCE_PCI_FIXED)) { |
| 289 | pci_claim_resource(dev, i); | 289 | if (pci_claim_resource(dev, i) == 0) |
| 290 | continue; | ||
| 291 | |||
| 292 | pci_claim_bridge_resource(dev, i); | ||
| 293 | } | ||
| 290 | } | 294 | } |
| 291 | } | 295 | } |
| 292 | 296 | ||
diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c index 67b1d1685759..0635bd6c2af3 100644 --- a/arch/frv/mb93090-mb00/pci-frv.c +++ b/arch/frv/mb93090-mb00/pci-frv.c | |||
| @@ -94,7 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) | |||
| 94 | r = &dev->resource[idx]; | 94 | r = &dev->resource[idx]; |
| 95 | if (!r->start) | 95 | if (!r->start) |
| 96 | continue; | 96 | continue; |
| 97 | pci_claim_resource(dev, idx); | 97 | pci_claim_bridge_resource(dev, idx); |
| 98 | } | 98 | } |
| 99 | } | 99 | } |
| 100 | pcibios_allocate_bus_resources(&bus->children); | 100 | pcibios_allocate_bus_resources(&bus->children); |
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 291a582777cf..900cc93e5409 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
| @@ -487,45 +487,39 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) | |||
| 487 | return 0; | 487 | return 0; |
| 488 | } | 488 | } |
| 489 | 489 | ||
| 490 | static int is_valid_resource(struct pci_dev *dev, int idx) | 490 | void pcibios_fixup_device_resources(struct pci_dev *dev) |
| 491 | { | 491 | { |
| 492 | unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; | 492 | int idx; |
| 493 | struct resource *devr = &dev->resource[idx], *busr; | ||
| 494 | 493 | ||
| 495 | if (!dev->bus) | 494 | if (!dev->bus) |
| 496 | return 0; | 495 | return; |
| 497 | |||
| 498 | pci_bus_for_each_resource(dev->bus, busr, i) { | ||
| 499 | if (!busr || ((busr->flags ^ devr->flags) & type_mask)) | ||
| 500 | continue; | ||
| 501 | if ((devr->start) && (devr->start >= busr->start) && | ||
| 502 | (devr->end <= busr->end)) | ||
| 503 | return 1; | ||
| 504 | } | ||
| 505 | return 0; | ||
| 506 | } | ||
| 507 | 496 | ||
| 508 | static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit) | 497 | for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { |
| 509 | { | 498 | struct resource *r = &dev->resource[idx]; |
| 510 | int i; | ||
| 511 | 499 | ||
| 512 | for (i = start; i < limit; i++) { | 500 | if (!r->flags || r->parent || !r->start) |
| 513 | if (!dev->resource[i].flags) | ||
| 514 | continue; | 501 | continue; |
| 515 | if ((is_valid_resource(dev, i))) | ||
| 516 | pci_claim_resource(dev, i); | ||
| 517 | } | ||
| 518 | } | ||
| 519 | 502 | ||
| 520 | void pcibios_fixup_device_resources(struct pci_dev *dev) | 503 | pci_claim_resource(dev, idx); |
| 521 | { | 504 | } |
| 522 | pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES); | ||
| 523 | } | 505 | } |
| 524 | EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); | 506 | EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); |
| 525 | 507 | ||
| 526 | static void pcibios_fixup_bridge_resources(struct pci_dev *dev) | 508 | static void pcibios_fixup_bridge_resources(struct pci_dev *dev) |
| 527 | { | 509 | { |
| 528 | pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES); | 510 | int idx; |
| 511 | |||
| 512 | if (!dev->bus) | ||
| 513 | return; | ||
| 514 | |||
| 515 | for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { | ||
| 516 | struct resource *r = &dev->resource[idx]; | ||
| 517 | |||
| 518 | if (!r->flags || r->parent || !r->start) | ||
| 519 | continue; | ||
| 520 | |||
| 521 | pci_claim_bridge_resource(dev, idx); | ||
| 522 | } | ||
| 529 | } | 523 | } |
| 530 | 524 | ||
| 531 | /* | 525 | /* |
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index b30e41c0c033..48528fb81eff 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c | |||
| @@ -1026,6 +1026,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) | |||
| 1026 | pr, (pr && pr->name) ? pr->name : "nil"); | 1026 | pr, (pr && pr->name) ? pr->name : "nil"); |
| 1027 | 1027 | ||
| 1028 | if (pr && !(pr->flags & IORESOURCE_UNSET)) { | 1028 | if (pr && !(pr->flags & IORESOURCE_UNSET)) { |
| 1029 | struct pci_dev *dev = bus->self; | ||
| 1030 | |||
| 1029 | if (request_resource(pr, res) == 0) | 1031 | if (request_resource(pr, res) == 0) |
| 1030 | continue; | 1032 | continue; |
| 1031 | /* | 1033 | /* |
| @@ -1035,6 +1037,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) | |||
| 1035 | */ | 1037 | */ |
| 1036 | if (reparent_resources(pr, res) == 0) | 1038 | if (reparent_resources(pr, res) == 0) |
| 1037 | continue; | 1039 | continue; |
| 1040 | |||
| 1041 | if (dev && i < PCI_BRIDGE_RESOURCE_NUM && | ||
| 1042 | pci_claim_bridge_resource(dev, | ||
| 1043 | i + PCI_BRIDGE_RESOURCES) == 0) | ||
| 1044 | continue; | ||
| 1045 | |||
| 1038 | } | 1046 | } |
| 1039 | pr_warn("PCI: Cannot allocate resource region "); | 1047 | pr_warn("PCI: Cannot allocate resource region "); |
| 1040 | pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number); | 1048 | pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number); |
| @@ -1227,7 +1235,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) | |||
| 1227 | (unsigned long long)r->end, | 1235 | (unsigned long long)r->end, |
| 1228 | (unsigned int)r->flags); | 1236 | (unsigned int)r->flags); |
| 1229 | 1237 | ||
| 1230 | pci_claim_resource(dev, i); | 1238 | if (pci_claim_resource(dev, i) == 0) |
| 1239 | continue; | ||
| 1240 | |||
| 1241 | pci_claim_bridge_resource(dev, i); | ||
| 1231 | } | 1242 | } |
| 1232 | } | 1243 | } |
| 1233 | 1244 | ||
diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c index febb9cd83177..b5b036f64275 100644 --- a/arch/mn10300/unit-asb2305/pci-asb2305.c +++ b/arch/mn10300/unit-asb2305/pci-asb2305.c | |||
| @@ -106,7 +106,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) | |||
| 106 | if (!r->flags) | 106 | if (!r->flags) |
| 107 | continue; | 107 | continue; |
| 108 | if (!r->start || | 108 | if (!r->start || |
| 109 | pci_claim_resource(dev, idx) < 0) { | 109 | pci_claim_bridge_resource(dev, idx) < 0) { |
| 110 | printk(KERN_ERR "PCI:" | 110 | printk(KERN_ERR "PCI:" |
| 111 | " Cannot allocate resource" | 111 | " Cannot allocate resource" |
| 112 | " region %d of bridge %s\n", | 112 | " region %d of bridge %s\n", |
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c index 6b4339f8c9c2..471ff398090c 100644 --- a/arch/mn10300/unit-asb2305/pci.c +++ b/arch/mn10300/unit-asb2305/pci.c | |||
| @@ -281,42 +281,37 @@ static int __init pci_check_direct(void) | |||
| 281 | return -ENODEV; | 281 | return -ENODEV; |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | static int is_valid_resource(struct pci_dev *dev, int idx) | 284 | static void pcibios_fixup_device_resources(struct pci_dev *dev) |
| 285 | { | 285 | { |
| 286 | unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; | 286 | int idx; |
| 287 | struct resource *devr = &dev->resource[idx], *busr; | ||
| 288 | |||
| 289 | if (dev->bus) { | ||
| 290 | pci_bus_for_each_resource(dev->bus, busr, i) { | ||
| 291 | if (!busr || (busr->flags ^ devr->flags) & type_mask) | ||
| 292 | continue; | ||
| 293 | |||
| 294 | if (devr->start && | ||
| 295 | devr->start >= busr->start && | ||
| 296 | devr->end <= busr->end) | ||
| 297 | return 1; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | 287 | ||
| 301 | return 0; | 288 | if (!dev->bus) |
| 289 | return; | ||
| 290 | |||
| 291 | for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { | ||
| 292 | struct resource *r = &dev->resource[idx]; | ||
| 293 | |||
| 294 | if (!r->flags || r->parent || !r->start) | ||
| 295 | continue; | ||
| 296 | |||
| 297 | pci_claim_resource(dev, idx); | ||
| 298 | } | ||
| 302 | } | 299 | } |
| 303 | 300 | ||
| 304 | static void pcibios_fixup_device_resources(struct pci_dev *dev) | 301 | static void pcibios_fixup_bridge_resources(struct pci_dev *dev) |
| 305 | { | 302 | { |
| 306 | int limit, i; | 303 | int idx; |
| 307 | 304 | ||
| 308 | if (dev->bus->number != 0) | 305 | if (!dev->bus) |
| 309 | return; | 306 | return; |
| 310 | 307 | ||
| 311 | limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? | 308 | for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { |
| 312 | PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES; | 309 | struct resource *r = &dev->resource[idx]; |
| 313 | 310 | ||
| 314 | for (i = 0; i < limit; i++) { | 311 | if (!r->flags || r->parent || !r->start) |
| 315 | if (!dev->resource[i].flags) | ||
| 316 | continue; | 312 | continue; |
| 317 | 313 | ||
| 318 | if (is_valid_resource(dev, i)) | 314 | pci_claim_bridge_resource(dev, idx); |
| 319 | pci_claim_resource(dev, i); | ||
| 320 | } | 315 | } |
| 321 | } | 316 | } |
| 322 | 317 | ||
| @@ -330,7 +325,7 @@ void pcibios_fixup_bus(struct pci_bus *bus) | |||
| 330 | 325 | ||
| 331 | if (bus->self) { | 326 | if (bus->self) { |
| 332 | pci_read_bridge_bases(bus); | 327 | pci_read_bridge_bases(bus); |
| 333 | pcibios_fixup_device_resources(bus->self); | 328 | pcibios_fixup_bridge_resources(bus->self); |
| 334 | } | 329 | } |
| 335 | 330 | ||
| 336 | list_for_each_entry(dev, &bus->devices, bus_list) | 331 | list_for_each_entry(dev, &bus->devices, bus_list) |
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 37d512d35943..2a525c938158 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c | |||
| @@ -1184,6 +1184,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) | |||
| 1184 | pr, (pr && pr->name) ? pr->name : "nil"); | 1184 | pr, (pr && pr->name) ? pr->name : "nil"); |
| 1185 | 1185 | ||
| 1186 | if (pr && !(pr->flags & IORESOURCE_UNSET)) { | 1186 | if (pr && !(pr->flags & IORESOURCE_UNSET)) { |
| 1187 | struct pci_dev *dev = bus->self; | ||
| 1188 | |||
| 1187 | if (request_resource(pr, res) == 0) | 1189 | if (request_resource(pr, res) == 0) |
| 1188 | continue; | 1190 | continue; |
| 1189 | /* | 1191 | /* |
| @@ -1193,6 +1195,11 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) | |||
| 1193 | */ | 1195 | */ |
| 1194 | if (reparent_resources(pr, res) == 0) | 1196 | if (reparent_resources(pr, res) == 0) |
| 1195 | continue; | 1197 | continue; |
| 1198 | |||
| 1199 | if (dev && i < PCI_BRIDGE_RESOURCE_NUM && | ||
| 1200 | pci_claim_bridge_resource(dev, | ||
| 1201 | i + PCI_BRIDGE_RESOURCES) == 0) | ||
| 1202 | continue; | ||
| 1196 | } | 1203 | } |
| 1197 | pr_warning("PCI: Cannot allocate resource region " | 1204 | pr_warning("PCI: Cannot allocate resource region " |
| 1198 | "%d of PCI bridge %d, will remap\n", i, bus->number); | 1205 | "%d of PCI bridge %d, will remap\n", i, bus->number); |
| @@ -1401,7 +1408,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) | |||
| 1401 | (unsigned long long)r->end, | 1408 | (unsigned long long)r->end, |
| 1402 | (unsigned int)r->flags); | 1409 | (unsigned int)r->flags); |
| 1403 | 1410 | ||
| 1404 | pci_claim_resource(dev, i); | 1411 | if (pci_claim_resource(dev, i) == 0) |
| 1412 | continue; | ||
| 1413 | |||
| 1414 | pci_claim_bridge_resource(dev, i); | ||
| 1405 | } | 1415 | } |
| 1406 | } | 1416 | } |
| 1407 | 1417 | ||
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index b36365f49478..9ce5afe167ff 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c | |||
| @@ -639,7 +639,10 @@ static void pci_claim_bus_resources(struct pci_bus *bus) | |||
| 639 | (unsigned long long)r->end, | 639 | (unsigned long long)r->end, |
| 640 | (unsigned int)r->flags); | 640 | (unsigned int)r->flags); |
| 641 | 641 | ||
| 642 | pci_claim_resource(dev, i); | 642 | if (pci_claim_resource(dev, i) == 0) |
| 643 | continue; | ||
| 644 | |||
| 645 | pci_claim_bridge_resource(dev, i); | ||
| 643 | } | 646 | } |
| 644 | } | 647 | } |
| 645 | 648 | ||
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 9b18ef315a55..349c0d32cc0b 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c | |||
| @@ -216,7 +216,7 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev) | |||
| 216 | continue; | 216 | continue; |
| 217 | if (r->parent) /* Already allocated */ | 217 | if (r->parent) /* Already allocated */ |
| 218 | continue; | 218 | continue; |
| 219 | if (!r->start || pci_claim_resource(dev, idx) < 0) { | 219 | if (!r->start || pci_claim_bridge_resource(dev, idx) < 0) { |
| 220 | /* | 220 | /* |
| 221 | * Something is wrong with the region. | 221 | * Something is wrong with the region. |
| 222 | * Invalidate the resource to prevent | 222 | * Invalidate the resource to prevent |
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 37e71ff6408d..dceb9ddfd99a 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c | |||
| @@ -694,9 +694,8 @@ lba_fixup_bus(struct pci_bus *bus) | |||
| 694 | int i; | 694 | int i; |
| 695 | /* PCI-PCI Bridge */ | 695 | /* PCI-PCI Bridge */ |
| 696 | pci_read_bridge_bases(bus); | 696 | pci_read_bridge_bases(bus); |
| 697 | for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { | 697 | for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) |
| 698 | pci_claim_resource(bus->self, i); | 698 | pci_claim_bridge_resource(bus->self, i); |
| 699 | } | ||
| 700 | } else { | 699 | } else { |
| 701 | /* Host-PCI Bridge */ | 700 | /* Host-PCI Bridge */ |
| 702 | int err; | 701 | int err; |
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 73aef51a28f0..8fb16188cd82 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
| @@ -228,6 +228,49 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, | |||
| 228 | } | 228 | } |
| 229 | EXPORT_SYMBOL(pci_bus_alloc_resource); | 229 | EXPORT_SYMBOL(pci_bus_alloc_resource); |
| 230 | 230 | ||
| 231 | /* | ||
| 232 | * The @idx resource of @dev should be a PCI-PCI bridge window. If this | ||
| 233 | * resource fits inside a window of an upstream bridge, do nothing. If it | ||
| 234 | * overlaps an upstream window but extends outside it, clip the resource so | ||
| 235 | * it fits completely inside. | ||
| 236 | */ | ||
| 237 | bool pci_bus_clip_resource(struct pci_dev *dev, int idx) | ||
| 238 | { | ||
| 239 | struct pci_bus *bus = dev->bus; | ||
| 240 | struct resource *res = &dev->resource[idx]; | ||
| 241 | struct resource orig_res = *res; | ||
| 242 | struct resource *r; | ||
| 243 | int i; | ||
| 244 | |||
| 245 | pci_bus_for_each_resource(bus, r, i) { | ||
| 246 | resource_size_t start, end; | ||
| 247 | |||
| 248 | if (!r) | ||
| 249 | continue; | ||
| 250 | |||
| 251 | if (resource_type(res) != resource_type(r)) | ||
| 252 | continue; | ||
| 253 | |||
| 254 | start = max(r->start, res->start); | ||
| 255 | end = min(r->end, res->end); | ||
| 256 | |||
| 257 | if (start > end) | ||
| 258 | continue; /* no overlap */ | ||
| 259 | |||
| 260 | if (res->start == start && res->end == end) | ||
| 261 | return false; /* no change */ | ||
| 262 | |||
| 263 | res->start = start; | ||
| 264 | res->end = end; | ||
| 265 | dev_printk(KERN_DEBUG, &dev->dev, "%pR clipped to %pR\n", | ||
| 266 | &orig_res, res); | ||
| 267 | |||
| 268 | return true; | ||
| 269 | } | ||
| 270 | |||
| 271 | return false; | ||
| 272 | } | ||
| 273 | |||
| 231 | void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } | 274 | void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } |
| 232 | 275 | ||
| 233 | /** | 276 | /** |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cab05f31223f..e9d4fd861ba1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -3271,7 +3271,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe) | |||
| 3271 | { | 3271 | { |
| 3272 | struct pci_dev *pdev; | 3272 | struct pci_dev *pdev; |
| 3273 | 3273 | ||
| 3274 | if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self) | 3274 | if (pci_is_root_bus(dev->bus) || dev->subordinate || |
| 3275 | !dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET) | ||
| 3275 | return -ENOTTY; | 3276 | return -ENOTTY; |
| 3276 | 3277 | ||
| 3277 | list_for_each_entry(pdev, &dev->bus->devices, bus_list) | 3278 | list_for_each_entry(pdev, &dev->bus->devices, bus_list) |
| @@ -3305,7 +3306,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) | |||
| 3305 | { | 3306 | { |
| 3306 | struct pci_dev *pdev; | 3307 | struct pci_dev *pdev; |
| 3307 | 3308 | ||
| 3308 | if (dev->subordinate || !dev->slot) | 3309 | if (dev->subordinate || !dev->slot || |
| 3310 | dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET) | ||
| 3309 | return -ENOTTY; | 3311 | return -ENOTTY; |
| 3310 | 3312 | ||
| 3311 | list_for_each_entry(pdev, &dev->bus->devices, bus_list) | 3313 | list_for_each_entry(pdev, &dev->bus->devices, bus_list) |
| @@ -3557,6 +3559,20 @@ int pci_try_reset_function(struct pci_dev *dev) | |||
| 3557 | } | 3559 | } |
| 3558 | EXPORT_SYMBOL_GPL(pci_try_reset_function); | 3560 | EXPORT_SYMBOL_GPL(pci_try_reset_function); |
| 3559 | 3561 | ||
| 3562 | /* Do any devices on or below this bus prevent a bus reset? */ | ||
| 3563 | static bool pci_bus_resetable(struct pci_bus *bus) | ||
| 3564 | { | ||
| 3565 | struct pci_dev *dev; | ||
| 3566 | |||
| 3567 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
| 3568 | if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || | ||
| 3569 | (dev->subordinate && !pci_bus_resetable(dev->subordinate))) | ||
| 3570 | return false; | ||
| 3571 | } | ||
| 3572 | |||
| 3573 | return true; | ||
| 3574 | } | ||
| 3575 | |||
| 3560 | /* Lock devices from the top of the tree down */ | 3576 | /* Lock devices from the top of the tree down */ |
| 3561 | static void pci_bus_lock(struct pci_bus *bus) | 3577 | static void pci_bus_lock(struct pci_bus *bus) |
| 3562 | { | 3578 | { |
| @@ -3607,6 +3623,22 @@ unlock: | |||
| 3607 | return 0; | 3623 | return 0; |
| 3608 | } | 3624 | } |
| 3609 | 3625 | ||
| 3626 | /* Do any devices on or below this slot prevent a bus reset? */ | ||
| 3627 | static bool pci_slot_resetable(struct pci_slot *slot) | ||
| 3628 | { | ||
| 3629 | struct pci_dev *dev; | ||
| 3630 | |||
| 3631 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | ||
| 3632 | if (!dev->slot || dev->slot != slot) | ||
| 3633 | continue; | ||
| 3634 | if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || | ||
| 3635 | (dev->subordinate && !pci_bus_resetable(dev->subordinate))) | ||
| 3636 | return false; | ||
| 3637 | } | ||
| 3638 | |||
| 3639 | return true; | ||
| 3640 | } | ||
| 3641 | |||
| 3610 | /* Lock devices from the top of the tree down */ | 3642 | /* Lock devices from the top of the tree down */ |
| 3611 | static void pci_slot_lock(struct pci_slot *slot) | 3643 | static void pci_slot_lock(struct pci_slot *slot) |
| 3612 | { | 3644 | { |
| @@ -3728,7 +3760,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe) | |||
| 3728 | { | 3760 | { |
| 3729 | int rc; | 3761 | int rc; |
| 3730 | 3762 | ||
| 3731 | if (!slot) | 3763 | if (!slot || !pci_slot_resetable(slot)) |
| 3732 | return -ENOTTY; | 3764 | return -ENOTTY; |
| 3733 | 3765 | ||
| 3734 | if (!probe) | 3766 | if (!probe) |
| @@ -3820,7 +3852,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot); | |||
| 3820 | 3852 | ||
| 3821 | static int pci_bus_reset(struct pci_bus *bus, int probe) | 3853 | static int pci_bus_reset(struct pci_bus *bus, int probe) |
| 3822 | { | 3854 | { |
| 3823 | if (!bus->self) | 3855 | if (!bus->self || !pci_bus_resetable(bus)) |
| 3824 | return -ENOTTY; | 3856 | return -ENOTTY; |
| 3825 | 3857 | ||
| 3826 | if (probe) | 3858 | if (probe) |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8aff29a804ff..d54632a1db43 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -208,6 +208,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, | |||
| 208 | void __pci_bus_assign_resources(const struct pci_bus *bus, | 208 | void __pci_bus_assign_resources(const struct pci_bus *bus, |
| 209 | struct list_head *realloc_head, | 209 | struct list_head *realloc_head, |
| 210 | struct list_head *fail_head); | 210 | struct list_head *fail_head); |
| 211 | bool pci_bus_clip_resource(struct pci_dev *dev, int idx); | ||
| 211 | 212 | ||
| 212 | /** | 213 | /** |
| 213 | * pci_ari_enabled - query ARI forwarding status | 214 | * pci_ari_enabled - query ARI forwarding status |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ed6f89b6efe5..e52356aa09b8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
| @@ -3028,6 +3028,20 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169, | |||
| 3028 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, | 3028 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, |
| 3029 | quirk_broken_intx_masking); | 3029 | quirk_broken_intx_masking); |
| 3030 | 3030 | ||
| 3031 | static void quirk_no_bus_reset(struct pci_dev *dev) | ||
| 3032 | { | ||
| 3033 | dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET; | ||
| 3034 | } | ||
| 3035 | |||
| 3036 | /* | ||
| 3037 | * Atheros AR93xx chips do not behave after a bus reset. The device will | ||
| 3038 | * throw a Link Down error on AER-capable systems and regardless of AER, | ||
| 3039 | * config space of the device is never accessible again and typically | ||
| 3040 | * causes the system to hang or reset when access is attempted. | ||
| 3041 | * http://www.spinics.net/lists/linux-pci/msg34797.html | ||
| 3042 | */ | ||
| 3043 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset); | ||
| 3044 | |||
| 3031 | #ifdef CONFIG_ACPI | 3045 | #ifdef CONFIG_ACPI |
| 3032 | /* | 3046 | /* |
| 3033 | * Apple: Shutdown Cactus Ridge Thunderbolt controller. | 3047 | * Apple: Shutdown Cactus Ridge Thunderbolt controller. |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 0482235eee92..e3e17f3c0f0f 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
| @@ -530,9 +530,8 @@ EXPORT_SYMBOL(pci_setup_cardbus); | |||
| 530 | config space writes, so it's quite possible that an I/O window of | 530 | config space writes, so it's quite possible that an I/O window of |
| 531 | the bridge will have some undesirable address (e.g. 0) after the | 531 | the bridge will have some undesirable address (e.g. 0) after the |
| 532 | first write. Ditto 64-bit prefetchable MMIO. */ | 532 | first write. Ditto 64-bit prefetchable MMIO. */ |
| 533 | static void pci_setup_bridge_io(struct pci_bus *bus) | 533 | static void pci_setup_bridge_io(struct pci_dev *bridge) |
| 534 | { | 534 | { |
| 535 | struct pci_dev *bridge = bus->self; | ||
| 536 | struct resource *res; | 535 | struct resource *res; |
| 537 | struct pci_bus_region region; | 536 | struct pci_bus_region region; |
| 538 | unsigned long io_mask; | 537 | unsigned long io_mask; |
| @@ -545,7 +544,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus) | |||
| 545 | io_mask = PCI_IO_1K_RANGE_MASK; | 544 | io_mask = PCI_IO_1K_RANGE_MASK; |
| 546 | 545 | ||
| 547 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ | 546 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ |
| 548 | res = bus->resource[0]; | 547 | res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0]; |
| 549 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | 548 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
| 550 | if (res->flags & IORESOURCE_IO) { | 549 | if (res->flags & IORESOURCE_IO) { |
| 551 | pci_read_config_word(bridge, PCI_IO_BASE, &l); | 550 | pci_read_config_word(bridge, PCI_IO_BASE, &l); |
| @@ -568,15 +567,14 @@ static void pci_setup_bridge_io(struct pci_bus *bus) | |||
| 568 | pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); | 567 | pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); |
| 569 | } | 568 | } |
| 570 | 569 | ||
| 571 | static void pci_setup_bridge_mmio(struct pci_bus *bus) | 570 | static void pci_setup_bridge_mmio(struct pci_dev *bridge) |
| 572 | { | 571 | { |
| 573 | struct pci_dev *bridge = bus->self; | ||
| 574 | struct resource *res; | 572 | struct resource *res; |
| 575 | struct pci_bus_region region; | 573 | struct pci_bus_region region; |
| 576 | u32 l; | 574 | u32 l; |
| 577 | 575 | ||
| 578 | /* Set up the top and bottom of the PCI Memory segment for this bus. */ | 576 | /* Set up the top and bottom of the PCI Memory segment for this bus. */ |
| 579 | res = bus->resource[1]; | 577 | res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1]; |
| 580 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | 578 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
| 581 | if (res->flags & IORESOURCE_MEM) { | 579 | if (res->flags & IORESOURCE_MEM) { |
| 582 | l = (region.start >> 16) & 0xfff0; | 580 | l = (region.start >> 16) & 0xfff0; |
| @@ -588,9 +586,8 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus) | |||
| 588 | pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); | 586 | pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); |
| 589 | } | 587 | } |
| 590 | 588 | ||
| 591 | static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) | 589 | static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge) |
| 592 | { | 590 | { |
| 593 | struct pci_dev *bridge = bus->self; | ||
| 594 | struct resource *res; | 591 | struct resource *res; |
| 595 | struct pci_bus_region region; | 592 | struct pci_bus_region region; |
| 596 | u32 l, bu, lu; | 593 | u32 l, bu, lu; |
| @@ -602,7 +599,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) | |||
| 602 | 599 | ||
| 603 | /* Set up PREF base/limit. */ | 600 | /* Set up PREF base/limit. */ |
| 604 | bu = lu = 0; | 601 | bu = lu = 0; |
| 605 | res = bus->resource[2]; | 602 | res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2]; |
| 606 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | 603 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
| 607 | if (res->flags & IORESOURCE_PREFETCH) { | 604 | if (res->flags & IORESOURCE_PREFETCH) { |
| 608 | l = (region.start >> 16) & 0xfff0; | 605 | l = (region.start >> 16) & 0xfff0; |
| @@ -630,13 +627,13 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) | |||
| 630 | &bus->busn_res); | 627 | &bus->busn_res); |
| 631 | 628 | ||
| 632 | if (type & IORESOURCE_IO) | 629 | if (type & IORESOURCE_IO) |
| 633 | pci_setup_bridge_io(bus); | 630 | pci_setup_bridge_io(bridge); |
| 634 | 631 | ||
| 635 | if (type & IORESOURCE_MEM) | 632 | if (type & IORESOURCE_MEM) |
| 636 | pci_setup_bridge_mmio(bus); | 633 | pci_setup_bridge_mmio(bridge); |
| 637 | 634 | ||
| 638 | if (type & IORESOURCE_PREFETCH) | 635 | if (type & IORESOURCE_PREFETCH) |
| 639 | pci_setup_bridge_mmio_pref(bus); | 636 | pci_setup_bridge_mmio_pref(bridge); |
| 640 | 637 | ||
| 641 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); | 638 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); |
| 642 | } | 639 | } |
| @@ -649,6 +646,41 @@ void pci_setup_bridge(struct pci_bus *bus) | |||
| 649 | __pci_setup_bridge(bus, type); | 646 | __pci_setup_bridge(bus, type); |
| 650 | } | 647 | } |
| 651 | 648 | ||
| 649 | |||
| 650 | int pci_claim_bridge_resource(struct pci_dev *bridge, int i) | ||
| 651 | { | ||
| 652 | if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END) | ||
| 653 | return 0; | ||
| 654 | |||
| 655 | if (pci_claim_resource(bridge, i) == 0) | ||
| 656 | return 0; /* claimed the window */ | ||
| 657 | |||
| 658 | if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI) | ||
| 659 | return 0; | ||
| 660 | |||
| 661 | if (!pci_bus_clip_resource(bridge, i)) | ||
| 662 | return -EINVAL; /* clipping didn't change anything */ | ||
| 663 | |||
| 664 | switch (i - PCI_BRIDGE_RESOURCES) { | ||
| 665 | case 0: | ||
| 666 | pci_setup_bridge_io(bridge); | ||
| 667 | break; | ||
| 668 | case 1: | ||
| 669 | pci_setup_bridge_mmio(bridge); | ||
| 670 | break; | ||
| 671 | case 2: | ||
| 672 | pci_setup_bridge_mmio_pref(bridge); | ||
| 673 | break; | ||
| 674 | default: | ||
| 675 | return -EINVAL; | ||
| 676 | } | ||
| 677 | |||
| 678 | if (pci_claim_resource(bridge, i) == 0) | ||
| 679 | return 0; /* claimed a smaller window */ | ||
| 680 | |||
| 681 | return -EINVAL; | ||
| 682 | } | ||
| 683 | |||
| 652 | /* Check whether the bridge supports optional I/O and | 684 | /* Check whether the bridge supports optional I/O and |
| 653 | prefetchable memory ranges. If not, the respective | 685 | prefetchable memory ranges. If not, the respective |
| 654 | base/limit registers must be read-only and read as 0. */ | 686 | base/limit registers must be read-only and read as 0. */ |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 360a966a97a5..9603094ed59b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
| @@ -175,6 +175,8 @@ enum pci_dev_flags { | |||
| 175 | PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), | 175 | PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), |
| 176 | /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ | 176 | /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ |
| 177 | PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), | 177 | PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), |
| 178 | /* Do not use bus resets for device */ | ||
| 179 | PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6), | ||
| 178 | }; | 180 | }; |
| 179 | 181 | ||
| 180 | enum pci_irq_reroute_variant { | 182 | enum pci_irq_reroute_variant { |
| @@ -1065,6 +1067,7 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx); | |||
| 1065 | void pci_bus_assign_resources(const struct pci_bus *bus); | 1067 | void pci_bus_assign_resources(const struct pci_bus *bus); |
| 1066 | void pci_bus_size_bridges(struct pci_bus *bus); | 1068 | void pci_bus_size_bridges(struct pci_bus *bus); |
| 1067 | int pci_claim_resource(struct pci_dev *, int); | 1069 | int pci_claim_resource(struct pci_dev *, int); |
| 1070 | int pci_claim_bridge_resource(struct pci_dev *bridge, int i); | ||
| 1068 | void pci_assign_unassigned_resources(void); | 1071 | void pci_assign_unassigned_resources(void); |
| 1069 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); | 1072 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); |
| 1070 | void pci_assign_unassigned_bus_resources(struct pci_bus *bus); | 1073 | void pci_assign_unassigned_bus_resources(struct pci_bus *bus); |
