ecam.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2016 Broadcom
  4. */
  5. #include <linux/device.h>
  6. #include <linux/io.h>
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/pci.h>
  10. #include <linux/pci-ecam.h>
  11. #include <linux/slab.h>
  12. /*
  13. * On 64-bit systems, we do a single ioremap for the whole config space
  14. * since we have enough virtual address range available. On 32-bit, we
  15. * ioremap the config space for each bus individually.
  16. */
  17. static const bool per_bus_mapping = !IS_ENABLED(CONFIG_64BIT);
  18. /*
  19. * Create a PCI config space window
  20. * - reserve mem region
  21. * - alloc struct pci_config_window with space for all mappings
  22. * - ioremap the config space
  23. */
  24. struct pci_config_window *pci_ecam_create(struct device *dev,
  25. struct resource *cfgres, struct resource *busr,
  26. const struct pci_ecam_ops *ops)
  27. {
  28. struct pci_config_window *cfg;
  29. unsigned int bus_range, bus_range_max, bsz;
  30. struct resource *conflict;
  31. int i, err;
  32. if (busr->start > busr->end)
  33. return ERR_PTR(-EINVAL);
  34. cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
  35. if (!cfg)
  36. return ERR_PTR(-ENOMEM);
  37. cfg->parent = dev;
  38. cfg->ops = ops;
  39. cfg->busr.start = busr->start;
  40. cfg->busr.end = busr->end;
  41. cfg->busr.flags = IORESOURCE_BUS;
  42. bus_range = resource_size(&cfg->busr);
  43. bus_range_max = resource_size(cfgres) >> ops->bus_shift;
  44. if (bus_range > bus_range_max) {
  45. bus_range = bus_range_max;
  46. cfg->busr.end = busr->start + bus_range - 1;
  47. dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n",
  48. cfgres, &cfg->busr, busr);
  49. }
  50. bsz = 1 << ops->bus_shift;
  51. cfg->res.start = cfgres->start;
  52. cfg->res.end = cfgres->end;
  53. cfg->res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
  54. cfg->res.name = "PCI ECAM";
  55. conflict = request_resource_conflict(&iomem_resource, &cfg->res);
  56. if (conflict) {
  57. err = -EBUSY;
  58. dev_err(dev, "can't claim ECAM area %pR: address conflict with %s %pR\n",
  59. &cfg->res, conflict->name, conflict);
  60. goto err_exit;
  61. }
  62. if (per_bus_mapping) {
  63. cfg->winp = kcalloc(bus_range, sizeof(*cfg->winp), GFP_KERNEL);
  64. if (!cfg->winp)
  65. goto err_exit_malloc;
  66. for (i = 0; i < bus_range; i++) {
  67. cfg->winp[i] =
  68. pci_remap_cfgspace(cfgres->start + i * bsz,
  69. bsz);
  70. if (!cfg->winp[i])
  71. goto err_exit_iomap;
  72. }
  73. } else {
  74. cfg->win = pci_remap_cfgspace(cfgres->start, bus_range * bsz);
  75. if (!cfg->win)
  76. goto err_exit_iomap;
  77. }
  78. if (ops->init) {
  79. err = ops->init(cfg);
  80. if (err)
  81. goto err_exit;
  82. }
  83. dev_info(dev, "ECAM at %pR for %pR\n", &cfg->res, &cfg->busr);
  84. return cfg;
  85. err_exit_iomap:
  86. dev_err(dev, "ECAM ioremap failed\n");
  87. err_exit_malloc:
  88. err = -ENOMEM;
  89. err_exit:
  90. pci_ecam_free(cfg);
  91. return ERR_PTR(err);
  92. }
  93. EXPORT_SYMBOL_GPL(pci_ecam_create);
  94. void pci_ecam_free(struct pci_config_window *cfg)
  95. {
  96. int i;
  97. if (per_bus_mapping) {
  98. if (cfg->winp) {
  99. for (i = 0; i < resource_size(&cfg->busr); i++)
  100. if (cfg->winp[i])
  101. iounmap(cfg->winp[i]);
  102. kfree(cfg->winp);
  103. }
  104. } else {
  105. if (cfg->win)
  106. iounmap(cfg->win);
  107. }
  108. if (cfg->res.parent)
  109. release_resource(&cfg->res);
  110. kfree(cfg);
  111. }
  112. EXPORT_SYMBOL_GPL(pci_ecam_free);
  113. /*
  114. * Function to implement the pci_ops ->map_bus method
  115. */
  116. void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
  117. int where)
  118. {
  119. struct pci_config_window *cfg = bus->sysdata;
  120. unsigned int devfn_shift = cfg->ops->bus_shift - 8;
  121. unsigned int busn = bus->number;
  122. void __iomem *base;
  123. if (busn < cfg->busr.start || busn > cfg->busr.end)
  124. return NULL;
  125. busn -= cfg->busr.start;
  126. if (per_bus_mapping)
  127. base = cfg->winp[busn];
  128. else
  129. base = cfg->win + (busn << cfg->ops->bus_shift);
  130. return base + (devfn << devfn_shift) + where;
  131. }
  132. EXPORT_SYMBOL_GPL(pci_ecam_map_bus);
  133. /* ECAM ops */
  134. const struct pci_ecam_ops pci_generic_ecam_ops = {
  135. .bus_shift = 20,
  136. .pci_ops = {
  137. .map_bus = pci_ecam_map_bus,
  138. .read = pci_generic_config_read,
  139. .write = pci_generic_config_write,
  140. }
  141. };
  142. EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
  143. #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
  144. /* ECAM ops for 32-bit access only (non-compliant) */
  145. const struct pci_ecam_ops pci_32b_ops = {
  146. .bus_shift = 20,
  147. .pci_ops = {
  148. .map_bus = pci_ecam_map_bus,
  149. .read = pci_generic_config_read32,
  150. .write = pci_generic_config_write32,
  151. }
  152. };
  153. /* ECAM ops for 32-bit read only (non-compliant) */
  154. const struct pci_ecam_ops pci_32b_read_ops = {
  155. .bus_shift = 20,
  156. .pci_ops = {
  157. .map_bus = pci_ecam_map_bus,
  158. .read = pci_generic_config_read32,
  159. .write = pci_generic_config_write,
  160. }
  161. };
  162. #endif