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 8#include <linux/pci.h> 9#include <linux/init.h> 10#include <linux/acpi.h> 11#include <linux/bitmap.h> 12#include <linux/rcupdate.h> 13#include <asm/e820.h> 14#include <asm/pci_x86.h> 15 16#define PREFIX "PCI: " 17 18static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) 19{ 20 struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus); 21 22 if (cfg && cfg->virt) 23 return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12)); 24 return NULL; 25} 26 27static int pci_mmcfg_read(unsigned int seg, unsigned int bus, 28 unsigned int devfn, int reg, int len, u32 *value) 29{ 30 char __iomem *addr; 31 32 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ 33 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) { 34err: *value = -1; 35 return -EINVAL; 36 } 37 38 rcu_read_lock(); 39 addr = pci_dev_base(seg, bus, devfn); 40 if (!addr) { 41 rcu_read_unlock(); 42 goto err; 43 } 44 45 switch (len) { 46 case 1: 47 *value = mmio_config_readb(addr + reg); 48 break; 49 case 2: 50 *value = mmio_config_readw(addr + reg); 51 break; 52 case 4: 53 *value = mmio_config_readl(addr + reg); 54 break; 55 } 56 rcu_read_unlock(); 57 58 return 0; 59} 60 61static int pci_mmcfg_write(unsigned int seg, unsigned int bus, 62 unsigned int devfn, int reg, int len, u32 value) 63{ 64 char __iomem *addr; 65 66 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ 67 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) 68 return -EINVAL; 69 70 rcu_read_lock(); 71 addr = pci_dev_base(seg, bus, devfn); 72 if (!addr) { 73 rcu_read_unlock(); 74 return -EINVAL; 75 } 76 77 switch (len) { 78 case 1: 79 mmio_config_writeb(addr + reg, value); 80 break; 81 case 2: 82 mmio_config_writew(addr + reg, value); 83 break; 84 case 4: 85 mmio_config_writel(addr + reg, value); 86 break; 87 } 88 rcu_read_unlock(); 89 90 return 0; 91} 92 93const struct pci_raw_ops pci_mmcfg = { 94 .read = pci_mmcfg_read, 95 .write = pci_mmcfg_write, 96}; 97 98static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg) 99{ 100 void __iomem *addr; 101 u64 start, size; 102 int num_buses; 103 104 start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus); 105 num_buses = cfg->end_bus - cfg->start_bus + 1; 106 size = PCI_MMCFG_BUS_OFFSET(num_buses); 107 addr = ioremap_nocache(start, size); 108 if (addr) 109 addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus); 110 return addr; 111} 112 113int __init pci_mmcfg_arch_init(void) 114{ 115 struct pci_mmcfg_region *cfg; 116 117 list_for_each_entry(cfg, &pci_mmcfg_list, list) 118 if (pci_mmcfg_arch_map(cfg)) { 119 pci_mmcfg_arch_free(); 120 return 0; 121 } 122 123 raw_pci_ext_ops = &pci_mmcfg; 124 125 return 1; 126} 127 128void __init pci_mmcfg_arch_free(void) 129{ 130 struct pci_mmcfg_region *cfg; 131 132 list_for_each_entry(cfg, &pci_mmcfg_list, list) 133 pci_mmcfg_arch_unmap(cfg); 134} 135 136int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg) 137{ 138 cfg->virt = mcfg_ioremap(cfg); 139 if (!cfg->virt) { 140 pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res); 141 return -ENOMEM; 142 } 143 144 return 0; 145} 146 147void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg) 148{ 149 if (cfg && cfg->virt) { 150 iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus)); 151 cfg->virt = NULL; 152 } 153} 154