host-bridge.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Host bridge related code
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/pci.h>
  7. #include <linux/module.h>
  8. #include "pci.h"
  9. static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
  10. {
  11. while (bus->parent)
  12. bus = bus->parent;
  13. return bus;
  14. }
  15. struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus)
  16. {
  17. struct pci_bus *root_bus = find_pci_root_bus(bus);
  18. return to_pci_host_bridge(root_bus->bridge);
  19. }
  20. EXPORT_SYMBOL_GPL(pci_find_host_bridge);
  21. struct device *pci_get_host_bridge_device(struct pci_dev *dev)
  22. {
  23. struct pci_bus *root_bus = find_pci_root_bus(dev->bus);
  24. struct device *bridge = root_bus->bridge;
  25. kobject_get(&bridge->kobj);
  26. return bridge;
  27. }
  28. EXPORT_SYMBOL_GPL(pci_get_host_bridge_device);
  29. void pci_put_host_bridge_device(struct device *dev)
  30. {
  31. kobject_put(&dev->kobj);
  32. }
  33. void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
  34. void (*release_fn)(struct pci_host_bridge *),
  35. void *release_data)
  36. {
  37. bridge->release_fn = release_fn;
  38. bridge->release_data = release_data;
  39. }
  40. EXPORT_SYMBOL_GPL(pci_set_host_bridge_release);
  41. void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
  42. struct resource *res)
  43. {
  44. struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
  45. struct resource_entry *window;
  46. resource_size_t offset = 0;
  47. resource_list_for_each_entry(window, &bridge->windows) {
  48. if (resource_contains(window->res, res)) {
  49. offset = window->offset;
  50. break;
  51. }
  52. }
  53. region->start = res->start - offset;
  54. region->end = res->end - offset;
  55. }
  56. EXPORT_SYMBOL(pcibios_resource_to_bus);
  57. static bool region_contains(struct pci_bus_region *region1,
  58. struct pci_bus_region *region2)
  59. {
  60. return region1->start <= region2->start && region1->end >= region2->end;
  61. }
  62. void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
  63. struct pci_bus_region *region)
  64. {
  65. struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
  66. struct resource_entry *window;
  67. resource_size_t offset = 0;
  68. resource_list_for_each_entry(window, &bridge->windows) {
  69. struct pci_bus_region bus_region;
  70. if (resource_type(res) != resource_type(window->res))
  71. continue;
  72. bus_region.start = window->res->start - window->offset;
  73. bus_region.end = window->res->end - window->offset;
  74. if (region_contains(&bus_region, region)) {
  75. offset = window->offset;
  76. break;
  77. }
  78. }
  79. res->start = region->start + offset;
  80. res->end = region->end + offset;
  81. }
  82. EXPORT_SYMBOL(pcibios_bus_to_resource);