Commit 550695925de06e1777f9268a9266dd1addce5a34
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
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
Showing 17 changed files Side-by-side Diff
- MAINTAINERS
- arch/alpha/kernel/pci.c
- arch/frv/mb93090-mb00/pci-frv.c
- arch/ia64/pci/pci.c
- arch/microblaze/pci/pci-common.c
- arch/mn10300/unit-asb2305/pci-asb2305.c
- arch/mn10300/unit-asb2305/pci.c
- arch/powerpc/kernel/pci-common.c
- arch/sparc/kernel/pci.c
- arch/x86/pci/i386.c
- drivers/parisc/lba_pci.c
- drivers/pci/bus.c
- drivers/pci/pci.c
- drivers/pci/pci.h
- drivers/pci/quirks.c
- drivers/pci/setup-bus.c
- include/linux/pci.h
MAINTAINERS
... | ... | @@ -7274,7 +7274,7 @@ |
7274 | 7274 | F: drivers/pci/host/*layerscape* |
7275 | 7275 | |
7276 | 7276 | PCI DRIVER FOR IMX6 |
7277 | -M: Richard Zhu <r65037@freescale.com> | |
7277 | +M: Richard Zhu <Richard.Zhu@freescale.com> | |
7278 | 7278 | M: Lucas Stach <l.stach@pengutronix.de> |
7279 | 7279 | L: linux-pci@vger.kernel.org |
7280 | 7280 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) |
arch/alpha/kernel/pci.c
... | ... | @@ -285,8 +285,12 @@ |
285 | 285 | if (r->parent || !r->start || !r->flags) |
286 | 286 | continue; |
287 | 287 | if (pci_has_flag(PCI_PROBE_ONLY) || |
288 | - (r->flags & IORESOURCE_PCI_FIXED)) | |
289 | - pci_claim_resource(dev, i); | |
288 | + (r->flags & IORESOURCE_PCI_FIXED)) { | |
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 |
arch/frv/mb93090-mb00/pci-frv.c
arch/ia64/pci/pci.c
... | ... | @@ -487,45 +487,39 @@ |
487 | 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; | |
493 | - struct resource *devr = &dev->resource[idx], *busr; | |
492 | + int idx; | |
494 | 493 | |
495 | 494 | if (!dev->bus) |
496 | - return 0; | |
495 | + return; | |
497 | 496 | |
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 | -} | |
497 | + for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { | |
498 | + struct resource *r = &dev->resource[idx]; | |
507 | 499 | |
508 | -static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit) | |
509 | -{ | |
510 | - int i; | |
511 | - | |
512 | - for (i = start; i < limit; i++) { | |
513 | - if (!dev->resource[i].flags) | |
500 | + if (!r->flags || r->parent || !r->start) | |
514 | 501 | continue; |
515 | - if ((is_valid_resource(dev, i))) | |
516 | - pci_claim_resource(dev, i); | |
502 | + | |
503 | + pci_claim_resource(dev, idx); | |
517 | 504 | } |
518 | 505 | } |
519 | - | |
520 | -void pcibios_fixup_device_resources(struct pci_dev *dev) | |
521 | -{ | |
522 | - pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES); | |
523 | -} | |
524 | 506 | EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); |
525 | 507 | |
526 | 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 | /* |
arch/microblaze/pci/pci-common.c
... | ... | @@ -1026,6 +1026,8 @@ |
1026 | 1026 | pr, (pr && pr->name) ? pr->name : "nil"); |
1027 | 1027 | |
1028 | 1028 | if (pr && !(pr->flags & IORESOURCE_UNSET)) { |
1029 | + struct pci_dev *dev = bus->self; | |
1030 | + | |
1029 | 1031 | if (request_resource(pr, res) == 0) |
1030 | 1032 | continue; |
1031 | 1033 | /* |
... | ... | @@ -1035,6 +1037,12 @@ |
1035 | 1037 | */ |
1036 | 1038 | if (reparent_resources(pr, res) == 0) |
1037 | 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 | 1047 | pr_warn("PCI: Cannot allocate resource region "); |
1040 | 1048 | pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number); |
... | ... | @@ -1227,7 +1235,10 @@ |
1227 | 1235 | (unsigned long long)r->end, |
1228 | 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 |
arch/mn10300/unit-asb2305/pci-asb2305.c
arch/mn10300/unit-asb2305/pci.c
... | ... | @@ -281,42 +281,37 @@ |
281 | 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; | |
287 | - struct resource *devr = &dev->resource[idx], *busr; | |
286 | + int idx; | |
288 | 287 | |
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; | |
288 | + if (!dev->bus) | |
289 | + return; | |
293 | 290 | |
294 | - if (devr->start && | |
295 | - devr->start >= busr->start && | |
296 | - devr->end <= busr->end) | |
297 | - return 1; | |
298 | - } | |
299 | - } | |
291 | + for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { | |
292 | + struct resource *r = &dev->resource[idx]; | |
300 | 293 | |
301 | - return 0; | |
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 | 306 | return; |
310 | 307 | |
311 | - limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? | |
312 | - PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES; | |
308 | + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { | |
309 | + struct resource *r = &dev->resource[idx]; | |
313 | 310 | |
314 | - for (i = 0; i < limit; i++) { | |
315 | - if (!dev->resource[i].flags) | |
311 | + if (!r->flags || r->parent || !r->start) | |
316 | 312 | continue; |
317 | 313 | |
318 | - if (is_valid_resource(dev, i)) | |
319 | - pci_claim_resource(dev, i); | |
314 | + pci_claim_bridge_resource(dev, idx); | |
320 | 315 | } |
321 | 316 | } |
322 | 317 | |
... | ... | @@ -330,7 +325,7 @@ |
330 | 325 | |
331 | 326 | if (bus->self) { |
332 | 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 | 331 | list_for_each_entry(dev, &bus->devices, bus_list) |
arch/powerpc/kernel/pci-common.c
... | ... | @@ -1184,6 +1184,8 @@ |
1184 | 1184 | pr, (pr && pr->name) ? pr->name : "nil"); |
1185 | 1185 | |
1186 | 1186 | if (pr && !(pr->flags & IORESOURCE_UNSET)) { |
1187 | + struct pci_dev *dev = bus->self; | |
1188 | + | |
1187 | 1189 | if (request_resource(pr, res) == 0) |
1188 | 1190 | continue; |
1189 | 1191 | /* |
... | ... | @@ -1193,6 +1195,11 @@ |
1193 | 1195 | */ |
1194 | 1196 | if (reparent_resources(pr, res) == 0) |
1195 | 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 | 1204 | pr_warning("PCI: Cannot allocate resource region " |
1198 | 1205 | "%d of PCI bridge %d, will remap\n", i, bus->number); |
... | ... | @@ -1401,7 +1408,10 @@ |
1401 | 1408 | (unsigned long long)r->end, |
1402 | 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 |
arch/sparc/kernel/pci.c
arch/x86/pci/i386.c
... | ... | @@ -216,7 +216,7 @@ |
216 | 216 | continue; |
217 | 217 | if (r->parent) /* Already allocated */ |
218 | 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 | 221 | * Something is wrong with the region. |
222 | 222 | * Invalidate the resource to prevent |
drivers/parisc/lba_pci.c
... | ... | @@ -694,9 +694,8 @@ |
694 | 694 | int i; |
695 | 695 | /* PCI-PCI Bridge */ |
696 | 696 | pci_read_bridge_bases(bus); |
697 | - for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { | |
698 | - pci_claim_resource(bus->self, i); | |
699 | - } | |
697 | + for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) | |
698 | + pci_claim_bridge_resource(bus->self, i); | |
700 | 699 | } else { |
701 | 700 | /* Host-PCI Bridge */ |
702 | 701 | int err; |
drivers/pci/bus.c
... | ... | @@ -228,6 +228,49 @@ |
228 | 228 | } |
229 | 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 | 274 | void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } |
232 | 275 | |
233 | 276 | /** |
drivers/pci/pci.c
... | ... | @@ -3271,7 +3271,8 @@ |
3271 | 3271 | { |
3272 | 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 | 3276 | return -ENOTTY; |
3276 | 3277 | |
3277 | 3278 | list_for_each_entry(pdev, &dev->bus->devices, bus_list) |
... | ... | @@ -3305,7 +3306,8 @@ |
3305 | 3306 | { |
3306 | 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 | 3311 | return -ENOTTY; |
3310 | 3312 | |
3311 | 3313 | list_for_each_entry(pdev, &dev->bus->devices, bus_list) |
... | ... | @@ -3557,6 +3559,20 @@ |
3557 | 3559 | } |
3558 | 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 | 3576 | /* Lock devices from the top of the tree down */ |
3561 | 3577 | static void pci_bus_lock(struct pci_bus *bus) |
3562 | 3578 | { |
... | ... | @@ -3607,6 +3623,22 @@ |
3607 | 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 | 3642 | /* Lock devices from the top of the tree down */ |
3611 | 3643 | static void pci_slot_lock(struct pci_slot *slot) |
3612 | 3644 | { |
... | ... | @@ -3728,7 +3760,7 @@ |
3728 | 3760 | { |
3729 | 3761 | int rc; |
3730 | 3762 | |
3731 | - if (!slot) | |
3763 | + if (!slot || !pci_slot_resetable(slot)) | |
3732 | 3764 | return -ENOTTY; |
3733 | 3765 | |
3734 | 3766 | if (!probe) |
... | ... | @@ -3820,7 +3852,7 @@ |
3820 | 3852 | |
3821 | 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 | 3856 | return -ENOTTY; |
3825 | 3857 | |
3826 | 3858 | if (probe) |
drivers/pci/pci.h
... | ... | @@ -208,6 +208,7 @@ |
208 | 208 | void __pci_bus_assign_resources(const struct pci_bus *bus, |
209 | 209 | struct list_head *realloc_head, |
210 | 210 | struct list_head *fail_head); |
211 | +bool pci_bus_clip_resource(struct pci_dev *dev, int idx); | |
211 | 212 | |
212 | 213 | /** |
213 | 214 | * pci_ari_enabled - query ARI forwarding status |
drivers/pci/quirks.c
... | ... | @@ -3028,6 +3028,20 @@ |
3028 | 3028 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, |
3029 | 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 | 3045 | #ifdef CONFIG_ACPI |
3032 | 3046 | /* |
3033 | 3047 | * Apple: Shutdown Cactus Ridge Thunderbolt controller. |
drivers/pci/setup-bus.c
... | ... | @@ -530,9 +530,8 @@ |
530 | 530 | config space writes, so it's quite possible that an I/O window of |
531 | 531 | the bridge will have some undesirable address (e.g. 0) after the |
532 | 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 | 535 | struct resource *res; |
537 | 536 | struct pci_bus_region region; |
538 | 537 | unsigned long io_mask; |
... | ... | @@ -545,7 +544,7 @@ |
545 | 544 | io_mask = PCI_IO_1K_RANGE_MASK; |
546 | 545 | |
547 | 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 | 548 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
550 | 549 | if (res->flags & IORESOURCE_IO) { |
551 | 550 | pci_read_config_word(bridge, PCI_IO_BASE, &l); |
552 | 551 | |
553 | 552 | |
... | ... | @@ -568,15 +567,14 @@ |
568 | 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 | 572 | struct resource *res; |
575 | 573 | struct pci_bus_region region; |
576 | 574 | u32 l; |
577 | 575 | |
578 | 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 | 578 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
581 | 579 | if (res->flags & IORESOURCE_MEM) { |
582 | 580 | l = (region.start >> 16) & 0xfff0; |
583 | 581 | |
... | ... | @@ -588,9 +586,8 @@ |
588 | 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 | 591 | struct resource *res; |
595 | 592 | struct pci_bus_region region; |
596 | 593 | u32 l, bu, lu; |
... | ... | @@ -602,7 +599,7 @@ |
602 | 599 | |
603 | 600 | /* Set up PREF base/limit. */ |
604 | 601 | bu = lu = 0; |
605 | - res = bus->resource[2]; | |
602 | + res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2]; | |
606 | 603 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
607 | 604 | if (res->flags & IORESOURCE_PREFETCH) { |
608 | 605 | l = (region.start >> 16) & 0xfff0; |
609 | 606 | |
610 | 607 | |
... | ... | @@ -630,13 +627,13 @@ |
630 | 627 | &bus->busn_res); |
631 | 628 | |
632 | 629 | if (type & IORESOURCE_IO) |
633 | - pci_setup_bridge_io(bus); | |
630 | + pci_setup_bridge_io(bridge); | |
634 | 631 | |
635 | 632 | if (type & IORESOURCE_MEM) |
636 | - pci_setup_bridge_mmio(bus); | |
633 | + pci_setup_bridge_mmio(bridge); | |
637 | 634 | |
638 | 635 | if (type & IORESOURCE_PREFETCH) |
639 | - pci_setup_bridge_mmio_pref(bus); | |
636 | + pci_setup_bridge_mmio_pref(bridge); | |
640 | 637 | |
641 | 638 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); |
642 | 639 | } |
... | ... | @@ -647,6 +644,41 @@ |
647 | 644 | IORESOURCE_PREFETCH; |
648 | 645 | |
649 | 646 | __pci_setup_bridge(bus, type); |
647 | +} | |
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; | |
650 | 682 | } |
651 | 683 | |
652 | 684 | /* Check whether the bridge supports optional I/O and |
include/linux/pci.h
... | ... | @@ -175,6 +175,8 @@ |
175 | 175 | PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), |
176 | 176 | /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ |
177 | 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 | 182 | enum pci_irq_reroute_variant { |
... | ... | @@ -1065,6 +1067,7 @@ |
1065 | 1067 | void pci_bus_assign_resources(const struct pci_bus *bus); |
1066 | 1068 | void pci_bus_size_bridges(struct pci_bus *bus); |
1067 | 1069 | int pci_claim_resource(struct pci_dev *, int); |
1070 | +int pci_claim_bridge_resource(struct pci_dev *bridge, int i); | |
1068 | 1071 | void pci_assign_unassigned_resources(void); |
1069 | 1072 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); |
1070 | 1073 | void pci_assign_unassigned_bus_resources(struct pci_bus *bus); |