host-bridge.c 2.4 KB

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