host-bridge.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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. void pci_put_host_bridge_device(struct device *dev)
  29. {
  30. kobject_put(&dev->kobj);
  31. }
  32. void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
  33. void (*release_fn)(struct pci_host_bridge *),
  34. void *release_data)
  35. {
  36. bridge->release_fn = release_fn;
  37. bridge->release_data = release_data;
  38. }
  39. EXPORT_SYMBOL_GPL(pci_set_host_bridge_release);
  40. void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
  41. struct resource *res)
  42. {
  43. struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
  44. struct resource_entry *window;
  45. resource_size_t offset = 0;
  46. resource_list_for_each_entry(window, &bridge->windows) {
  47. if (resource_contains(window->res, res)) {
  48. offset = window->offset;
  49. break;
  50. }
  51. }
  52. region->start = res->start - offset;
  53. region->end = res->end - offset;
  54. }
  55. EXPORT_SYMBOL(pcibios_resource_to_bus);
  56. static bool region_contains(struct pci_bus_region *region1,
  57. struct pci_bus_region *region2)
  58. {
  59. return region1->start <= region2->start && region1->end >= region2->end;
  60. }
  61. void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
  62. struct pci_bus_region *region)
  63. {
  64. struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
  65. struct resource_entry *window;
  66. resource_size_t offset = 0;
  67. resource_list_for_each_entry(window, &bridge->windows) {
  68. struct pci_bus_region bus_region;
  69. if (resource_type(res) != resource_type(window->res))
  70. continue;
  71. bus_region.start = window->res->start - window->offset;
  72. bus_region.end = window->res->end - window->offset;
  73. if (region_contains(&bus_region, region)) {
  74. offset = window->offset;
  75. break;
  76. }
  77. }
  78. res->start = region->start + offset;
  79. res->end = region->end + offset;
  80. }
  81. EXPORT_SYMBOL(pcibios_bus_to_resource);