Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: improve resource allocation under transparent bridges

We could run out of space under under 4g, but devices under transparent
bridges can use 64bit resources, so keep trying on the parent bus until
we hit a non-transparent bridge.

Impact: better support for assigning unassigned resources

Reviewed-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

authored by

Yinghai Lu and committed by
Jesse Barnes
d09ee968 1f82de10

+36 -14
-1
drivers/pci/setup-bus.c
··· 58 58 res = list->res; 59 59 idx = res - &list->dev->resource[0]; 60 60 if (pci_assign_resource(list->dev, idx)) { 61 - /* FIXME: get rid of this */ 62 61 res->start = 0; 63 62 res->end = 0; 64 63 res->flags = 0;
+36 -13
drivers/pci/setup-res.c
··· 135 135 } 136 136 #endif /* CONFIG_PCI_QUIRKS */ 137 137 138 - int pci_assign_resource(struct pci_dev *dev, int resno) 138 + static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, 139 + int resno) 139 140 { 140 - struct pci_bus *bus = dev->bus; 141 141 struct resource *res = dev->resource + resno; 142 142 resource_size_t size, min, align; 143 143 int ret; 144 144 145 145 size = resource_size(res); 146 146 min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; 147 - 148 147 align = resource_alignment(res); 149 - if (!align) { 150 - dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " 151 - "alignment) %pR flags %#lx\n", 152 - resno, res, res->flags); 153 - return -EINVAL; 154 - } 155 148 156 149 /* First, try exact prefetching match.. */ 157 150 ret = pci_bus_alloc_resource(bus, res, size, align, min, ··· 162 169 pcibios_align_resource, dev); 163 170 } 164 171 165 - if (ret) { 166 - dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", 167 - resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); 168 - } else { 172 + if (!ret) { 169 173 res->flags &= ~IORESOURCE_STARTALIGN; 170 174 if (resno < PCI_BRIDGE_RESOURCES) 171 175 pci_update_resource(dev, resno); 172 176 } 177 + 178 + return ret; 179 + } 180 + 181 + int pci_assign_resource(struct pci_dev *dev, int resno) 182 + { 183 + struct resource *res = dev->resource + resno; 184 + resource_size_t align; 185 + struct pci_bus *bus; 186 + int ret; 187 + 188 + align = resource_alignment(res); 189 + if (!align) { 190 + dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " 191 + "alignment) %pR flags %#lx\n", 192 + resno, res, res->flags); 193 + return -EINVAL; 194 + } 195 + 196 + bus = dev->bus; 197 + while ((ret = __pci_assign_resource(bus, dev, resno))) { 198 + if (bus->parent && bus->self->transparent) 199 + bus = bus->parent; 200 + else 201 + bus = NULL; 202 + if (bus) 203 + continue; 204 + break; 205 + } 206 + 207 + if (ret) 208 + dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", 209 + resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); 173 210 174 211 return ret; 175 212 }