aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2015-10-14 02:29:42 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-10-16 16:18:52 -0400
commit02715e86b21955f107f376d84d165424ba9cd372 (patch)
treef125cf50969446a7fc15c965997aff919d4e7937
parent4d6b4e69a245e9df4b84dba387596086cb66887d (diff)
ia64/PCI/ACPI: Use common interface to support PCI host bridge
Use common interface to simplify PCI host bridge implementation. Tested-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--arch/ia64/pci/pci.c235
1 files changed, 48 insertions, 187 deletions
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index b1846b891ea5..8f6ac2f8ae4c 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -116,15 +116,12 @@ struct pci_ops pci_root_ops = {
116}; 116};
117 117
118struct pci_root_info { 118struct pci_root_info {
119 struct acpi_pci_root_info common;
119 struct pci_controller controller; 120 struct pci_controller controller;
120 struct acpi_device *bridge;
121 struct list_head resources;
122 struct list_head io_resources; 121 struct list_head io_resources;
123 char name[16];
124}; 122};
125 123
126static unsigned int 124static unsigned int new_space(u64 phys_base, int sparse)
127new_space (u64 phys_base, int sparse)
128{ 125{
129 u64 mmio_base; 126 u64 mmio_base;
130 int i; 127 int i;
@@ -160,11 +157,11 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
160 unsigned long base, min, max, base_port; 157 unsigned long base, min, max, base_port;
161 unsigned int sparse = 0, space_nr, len; 158 unsigned int sparse = 0, space_nr, len;
162 159
163 len = strlen(info->name) + 32; 160 len = strlen(info->common.name) + 32;
164 iospace = resource_list_create_entry(NULL, len); 161 iospace = resource_list_create_entry(NULL, len);
165 if (!iospace) { 162 if (!iospace) {
166 dev_err(dev, "PCI: No memory for %s I/O port space\n", 163 dev_err(dev, "PCI: No memory for %s I/O port space\n",
167 info->name); 164 info->common.name);
168 return -ENOMEM; 165 return -ENOMEM;
169 } 166 }
170 167
@@ -179,7 +176,7 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
179 max = res->end - entry->offset; 176 max = res->end - entry->offset;
180 base = __pa(io_space[space_nr].mmio_base); 177 base = __pa(io_space[space_nr].mmio_base);
181 base_port = IO_SPACE_BASE(space_nr); 178 base_port = IO_SPACE_BASE(space_nr);
182 snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name, 179 snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->common.name,
183 base_port + min, base_port + max); 180 base_port + min, base_port + max);
184 181
185 /* 182 /*
@@ -234,217 +231,81 @@ static bool resource_is_pcicfg_ioport(struct resource *res)
234 res->start == 0xCF8 && res->end == 0xCFF; 231 res->start == 0xCF8 && res->end == 0xCFF;
235} 232}
236 233
237static int 234static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
238probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
239 int busnum, int domain)
240{ 235{
241 int ret; 236 struct device *dev = &ci->bridge->dev;
242 struct list_head *list = &info->resources; 237 struct pci_root_info *info;
238 struct resource *res;
243 struct resource_entry *entry, *tmp; 239 struct resource_entry *entry, *tmp;
244 240 int status;
245 ret = acpi_dev_get_resources(device, list, 241
246 acpi_dev_filter_resource_type_cb, 242 status = acpi_pci_probe_root_resources(ci);
247 (void *)(IORESOURCE_IO | IORESOURCE_MEM)); 243 if (status > 0) {
248 if (ret < 0) 244 info = container_of(ci, struct pci_root_info, common);
249 dev_warn(&device->dev, 245 resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
250 "failed to parse _CRS method, error code %d\n", ret); 246 res = entry->res;
251 else if (ret == 0) 247 if (res->flags & IORESOURCE_MEM) {
252 dev_dbg(&device->dev, 248 /*
253 "no IO and memory resources present in _CRS\n"); 249 * HP's firmware has a hack to work around a
254 else 250 * Windows bug. Ignore these tiny memory ranges.
255 resource_list_for_each_entry_safe(entry, tmp, list) { 251 */
256 if ((entry->res->flags & IORESOURCE_DISABLED) || 252 if (resource_size(res) <= 16) {
257 resource_is_pcicfg_ioport(entry->res)) 253 resource_list_del(entry);
258 resource_list_destroy_entry(entry); 254 insert_resource(&iomem_resource,
259 else 255 entry->res);
260 entry->res->name = info->name; 256 resource_list_add_tail(entry,
261 } 257 &info->io_resources);
262 258 }
263 return ret; 259 } else if (res->flags & IORESOURCE_IO) {
264} 260 if (resource_is_pcicfg_ioport(entry->res))
265 261 resource_list_destroy_entry(entry);
266static void validate_resources(struct device *dev, struct list_head *resources, 262 else if (add_io_space(dev, info, entry))
267 unsigned long type) 263 resource_list_destroy_entry(entry);
268{
269 LIST_HEAD(list);
270 struct resource *res1, *res2, *root = NULL;
271 struct resource_entry *tmp, *entry, *entry2;
272
273 BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
274 root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
275
276 list_splice_init(resources, &list);
277 resource_list_for_each_entry_safe(entry, tmp, &list) {
278 bool free = false;
279 resource_size_t end;
280
281 res1 = entry->res;
282 if (!(res1->flags & type))
283 goto next;
284
285 /* Exclude non-addressable range or non-addressable portion */
286 end = min(res1->end, root->end);
287 if (end <= res1->start) {
288 dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
289 res1);
290 free = true;
291 goto next;
292 } else if (res1->end != end) {
293 dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
294 res1, (unsigned long long)end + 1,
295 (unsigned long long)res1->end);
296 res1->end = end;
297 }
298
299 resource_list_for_each_entry(entry2, resources) {
300 res2 = entry2->res;
301 if (!(res2->flags & type))
302 continue;
303
304 /*
305 * I don't like throwing away windows because then
306 * our resources no longer match the ACPI _CRS, but
307 * the kernel resource tree doesn't allow overlaps.
308 */
309 if (resource_overlaps(res1, res2)) {
310 res2->start = min(res1->start, res2->start);
311 res2->end = max(res1->end, res2->end);
312 dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
313 res2, res1);
314 free = true;
315 goto next;
316 } 264 }
317 } 265 }
318
319next:
320 resource_list_del(entry);
321 if (free)
322 resource_list_free_entry(entry);
323 else
324 resource_list_add_tail(entry, resources);
325 } 266 }
326}
327 267
328static void add_resources(struct pci_root_info *info, struct device *dev) 268 return status;
329{
330 struct resource_entry *entry, *tmp;
331 struct resource *res, *conflict, *root = NULL;
332 struct list_head *list = &info->resources;
333
334 validate_resources(dev, list, IORESOURCE_MEM);
335 validate_resources(dev, list, IORESOURCE_IO);
336
337 resource_list_for_each_entry_safe(entry, tmp, list) {
338 res = entry->res;
339 if (res->flags & IORESOURCE_MEM) {
340 root = &iomem_resource;
341 /*
342 * HP's firmware has a hack to work around a Windows
343 * bug. Ignore these tiny memory ranges.
344 */
345 if (resource_size(res) <= 16) {
346 resource_list_destroy_entry(entry);
347 continue;
348 }
349 } else if (res->flags & IORESOURCE_IO) {
350 root = &ioport_resource;
351 if (add_io_space(&info->bridge->dev, info, entry)) {
352 resource_list_destroy_entry(entry);
353 continue;
354 }
355 } else {
356 BUG_ON(res);
357 }
358
359 conflict = insert_resource_conflict(root, res);
360 if (conflict) {
361 dev_info(dev,
362 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
363 res, conflict->name, conflict);
364 resource_list_destroy_entry(entry);
365 }
366 }
367} 269}
368 270
369static void __release_pci_root_info(struct pci_root_info *info) 271static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
370{ 272{
371 struct resource *res; 273 struct pci_root_info *info;
372 struct resource_entry *entry, *tentry; 274 struct resource_entry *entry, *tmp;
373 275
374 resource_list_for_each_entry_safe(entry, tentry, &info->io_resources) { 276 info = container_of(ci, struct pci_root_info, common);
277 resource_list_for_each_entry_safe(entry, tmp, &info->io_resources) {
375 release_resource(entry->res); 278 release_resource(entry->res);
376 resource_list_destroy_entry(entry); 279 resource_list_destroy_entry(entry);
377 } 280 }
378
379 resource_list_for_each_entry_safe(entry, tentry, &info->resources) {
380 res = entry->res;
381 if (res->parent &&
382 (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
383 release_resource(res);
384 resource_list_destroy_entry(entry);
385 }
386
387 kfree(info); 281 kfree(info);
388} 282}
389 283
390static void release_pci_root_info(struct pci_host_bridge *bridge) 284static struct acpi_pci_root_ops pci_acpi_root_ops = {
391{ 285 .pci_ops = &pci_root_ops,
392 struct pci_root_info *info = bridge->release_data; 286 .release_info = pci_acpi_root_release_info,
393 287 .prepare_resources = pci_acpi_root_prepare_resources,
394 __release_pci_root_info(info); 288};
395}
396 289
397struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 290struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
398{ 291{
399 struct acpi_device *device = root->device; 292 struct acpi_device *device = root->device;
400 int domain = root->segment;
401 int bus = root->secondary.start;
402 struct pci_root_info *info; 293 struct pci_root_info *info;
403 struct pci_bus *pbus;
404 int ret;
405 294
406 info = kzalloc(sizeof(*info), GFP_KERNEL); 295 info = kzalloc(sizeof(*info), GFP_KERNEL);
407 if (!info) { 296 if (!info) {
408 dev_err(&device->dev, 297 dev_err(&device->dev,
409 "pci_bus %04x:%02x: ignored (out of memory)\n", 298 "pci_bus %04x:%02x: ignored (out of memory)\n",
410 domain, bus); 299 root->segment, (int)root->secondary.start);
411 return NULL; 300 return NULL;
412 } 301 }
413 302
414 info->controller.segment = domain; 303 info->controller.segment = root->segment;
415 info->controller.companion = device; 304 info->controller.companion = device;
416 info->controller.node = acpi_get_node(device->handle); 305 info->controller.node = acpi_get_node(device->handle);
417 info->bridge = device;
418 INIT_LIST_HEAD(&info->resources);
419 INIT_LIST_HEAD(&info->io_resources); 306 INIT_LIST_HEAD(&info->io_resources);
420 snprintf(info->name, sizeof(info->name), 307 return acpi_pci_root_create(root, &pci_acpi_root_ops,
421 "PCI Bus %04x:%02x", domain, bus); 308 &info->common, &info->controller);
422
423 ret = probe_pci_root_info(info, device, bus, domain);
424 if (ret <= 0) {
425 kfree(info);
426 return NULL;
427 }
428 add_resources(info, &info->bridge->dev);
429 pci_add_resource(&info->resources, &root->secondary);
430
431 /*
432 * See arch/x86/pci/acpi.c.
433 * The desired pci bus might already be scanned in a quirk. We
434 * should handle the case here, but it appears that IA64 hasn't
435 * such quirk. So we just ignore the case now.
436 */
437 pbus = pci_create_root_bus(NULL, bus, &pci_root_ops,
438 &info->controller, &info->resources);
439 if (!pbus) {
440 __release_pci_root_info(info);
441 return NULL;
442 }
443
444 pci_set_host_bridge_release(to_pci_host_bridge(pbus->bridge),
445 release_pci_root_info, info);
446 pci_scan_child_bus(pbus);
447 return pbus;
448} 309}
449 310
450int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) 311int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)