diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/pci/bus.c | 70 |
1 files changed, 49 insertions, 21 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 5624db8c9ad0..003170ea2e39 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
| @@ -64,17 +64,57 @@ void pci_bus_remove_resources(struct pci_bus *bus) | |||
| 64 | } | 64 | } |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static bool pci_bus_resource_better(struct resource *res1, bool pos1, | ||
| 68 | struct resource *res2, bool pos2) | ||
| 69 | { | ||
| 70 | /* If exactly one is positive decode, always prefer that one */ | ||
| 71 | if (pos1 != pos2) | ||
| 72 | return pos1 ? true : false; | ||
| 73 | |||
| 74 | /* Prefer the one that contains the highest address */ | ||
| 75 | if (res1->end != res2->end) | ||
| 76 | return (res1->end > res2->end) ? true : false; | ||
| 77 | |||
| 78 | /* Otherwise, prefer the one with highest "center of gravity" */ | ||
| 79 | if (res1->start != res2->start) | ||
| 80 | return (res1->start > res2->start) ? true : false; | ||
| 81 | |||
| 82 | /* Otherwise, choose one arbitrarily (but consistently) */ | ||
| 83 | return (res1 > res2) ? true : false; | ||
| 84 | } | ||
| 85 | |||
| 86 | static bool pci_bus_resource_positive(struct pci_bus *bus, struct resource *res) | ||
| 87 | { | ||
| 88 | struct pci_bus_resource *bus_res; | ||
| 89 | |||
| 90 | /* | ||
| 91 | * This relies on the fact that pci_bus.resource[] refers to P2P or | ||
| 92 | * CardBus bridge base/limit registers, which are always positively | ||
| 93 | * decoded. The pci_bus.resources list contains host bridge or | ||
| 94 | * subtractively decoded resources. | ||
| 95 | */ | ||
| 96 | list_for_each_entry(bus_res, &bus->resources, list) { | ||
| 97 | if (bus_res->res == res) | ||
| 98 | return (bus_res->flags & PCI_SUBTRACTIVE_DECODE) ? | ||
| 99 | false : true; | ||
| 100 | } | ||
| 101 | return true; | ||
| 102 | } | ||
| 103 | |||
| 67 | /* | 104 | /* |
| 68 | * Find the highest-address bus resource below the cursor "res". If the | 105 | * Find the next-best bus resource after the cursor "res". If the cursor is |
| 69 | * cursor is NULL, return the highest resource. | 106 | * NULL, return the best resource. "Best" means that we prefer positive |
| 107 | * decode regions over subtractive decode, then those at higher addresses. | ||
| 70 | */ | 108 | */ |
| 71 | static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, | 109 | static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, |
| 72 | unsigned int type, | 110 | unsigned int type, |
| 73 | struct resource *res) | 111 | struct resource *res) |
| 74 | { | 112 | { |
| 113 | bool res_pos, r_pos, prev_pos = false; | ||
| 75 | struct resource *r, *prev = NULL; | 114 | struct resource *r, *prev = NULL; |
| 76 | int i; | 115 | int i; |
| 77 | 116 | ||
| 117 | res_pos = pci_bus_resource_positive(bus, res); | ||
| 78 | pci_bus_for_each_resource(bus, r, i) { | 118 | pci_bus_for_each_resource(bus, r, i) { |
| 79 | if (!r) | 119 | if (!r) |
| 80 | continue; | 120 | continue; |
| @@ -82,26 +122,14 @@ static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, | |||
| 82 | if ((r->flags & IORESOURCE_TYPE_BITS) != type) | 122 | if ((r->flags & IORESOURCE_TYPE_BITS) != type) |
| 83 | continue; | 123 | continue; |
| 84 | 124 | ||
| 85 | /* If this resource is at or past the cursor, skip it */ | 125 | r_pos = pci_bus_resource_positive(bus, r); |
| 86 | if (res) { | 126 | if (!res || pci_bus_resource_better(res, res_pos, r, r_pos)) { |
| 87 | if (r == res) | 127 | if (!prev || pci_bus_resource_better(r, r_pos, |
| 88 | continue; | 128 | prev, prev_pos)) { |
| 89 | if (r->end > res->end) | 129 | prev = r; |
| 90 | continue; | 130 | prev_pos = r_pos; |
| 91 | if (r->end == res->end && r->start > res->start) | 131 | } |
| 92 | continue; | ||
| 93 | } | 132 | } |
| 94 | |||
| 95 | if (!prev) | ||
| 96 | prev = r; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * A small resource is higher than a large one that ends at | ||
| 100 | * the same address. | ||
| 101 | */ | ||
| 102 | if (r->end > prev->end || | ||
| 103 | (r->end == prev->end && r->start > prev->start)) | ||
| 104 | prev = r; | ||
| 105 | } | 133 | } |
| 106 | 134 | ||
| 107 | return prev; | 135 | return prev; |
