mmconfig_64.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
  3. *
  4. * This is an 64bit optimized version that always keeps the full mmconfig
  5. * space mapped. This allows lockless config space operation.
  6. */
  7. #include <linux/pci.h>
  8. #include <linux/init.h>
  9. #include <linux/acpi.h>
  10. #include <linux/bitmap.h>
  11. #include <asm/e820.h>
  12. #include <asm/pci_x86.h>
  13. #define PREFIX "PCI: "
  14. static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
  15. {
  16. struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
  17. if (cfg && cfg->virt)
  18. return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
  19. return NULL;
  20. }
  21. static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
  22. unsigned int devfn, int reg, int len, u32 *value)
  23. {
  24. char __iomem *addr;
  25. /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
  26. if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
  27. err: *value = -1;
  28. return -EINVAL;
  29. }
  30. addr = pci_dev_base(seg, bus, devfn);
  31. if (!addr)
  32. goto err;
  33. switch (len) {
  34. case 1:
  35. *value = mmio_config_readb(addr + reg);
  36. break;
  37. case 2:
  38. *value = mmio_config_readw(addr + reg);
  39. break;
  40. case 4:
  41. *value = mmio_config_readl(addr + reg);
  42. break;
  43. }
  44. return 0;
  45. }
  46. static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
  47. unsigned int devfn, int reg, int len, u32 value)
  48. {
  49. char __iomem *addr;
  50. /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
  51. if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
  52. return -EINVAL;
  53. addr = pci_dev_base(seg, bus, devfn);
  54. if (!addr)
  55. return -EINVAL;
  56. switch (len) {
  57. case 1:
  58. mmio_config_writeb(addr + reg, value);
  59. break;
  60. case 2:
  61. mmio_config_writew(addr + reg, value);
  62. break;
  63. case 4:
  64. mmio_config_writel(addr + reg, value);
  65. break;
  66. }
  67. return 0;
  68. }
  69. static struct pci_raw_ops pci_mmcfg = {
  70. .read = pci_mmcfg_read,
  71. .write = pci_mmcfg_write,
  72. };
  73. static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg)
  74. {
  75. void __iomem *addr;
  76. u64 start, size;
  77. int num_buses;
  78. start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
  79. num_buses = cfg->end_bus - cfg->start_bus + 1;
  80. size = PCI_MMCFG_BUS_OFFSET(num_buses);
  81. addr = ioremap_nocache(start, size);
  82. if (addr)
  83. addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
  84. return addr;
  85. }
  86. int __init pci_mmcfg_arch_init(void)
  87. {
  88. struct pci_mmcfg_region *cfg;
  89. list_for_each_entry(cfg, &pci_mmcfg_list, list) {
  90. cfg->virt = mcfg_ioremap(cfg);
  91. if (!cfg->virt) {
  92. printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR\n",
  93. &cfg->res);
  94. pci_mmcfg_arch_free();
  95. return 0;
  96. }
  97. }
  98. raw_pci_ext_ops = &pci_mmcfg;
  99. return 1;
  100. }
  101. void __init pci_mmcfg_arch_free(void)
  102. {
  103. struct pci_mmcfg_region *cfg;
  104. list_for_each_entry(cfg, &pci_mmcfg_list, list) {
  105. if (cfg->virt) {
  106. iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
  107. cfg->virt = NULL;
  108. }
  109. }
  110. }