1f68c0654SThomas Gleixner /* 2f68c0654SThomas Gleixner * mmconfig.c - Low-level direct PCI config space access via MMCONFIG 3f68c0654SThomas Gleixner * 4f68c0654SThomas Gleixner * This is an 64bit optimized version that always keeps the full mmconfig 5f68c0654SThomas Gleixner * space mapped. This allows lockless config space operation. 6f68c0654SThomas Gleixner */ 7f68c0654SThomas Gleixner 8f68c0654SThomas Gleixner #include <linux/pci.h> 9f68c0654SThomas Gleixner #include <linux/init.h> 10f68c0654SThomas Gleixner #include <linux/acpi.h> 11f68c0654SThomas Gleixner #include <linux/bitmap.h> 12f68c0654SThomas Gleixner #include <asm/e820.h> 13f68c0654SThomas Gleixner 14f68c0654SThomas Gleixner #include "pci.h" 15f68c0654SThomas Gleixner 16f68c0654SThomas Gleixner /* Static virtual mapping of the MMCONFIG aperture */ 17f68c0654SThomas Gleixner struct mmcfg_virt { 18f68c0654SThomas Gleixner struct acpi_mcfg_allocation *cfg; 19f68c0654SThomas Gleixner char __iomem *virt; 20f68c0654SThomas Gleixner }; 21f68c0654SThomas Gleixner static struct mmcfg_virt *pci_mmcfg_virt; 22f68c0654SThomas Gleixner 23f68c0654SThomas Gleixner static char __iomem *get_virt(unsigned int seg, unsigned bus) 24f68c0654SThomas Gleixner { 25f68c0654SThomas Gleixner struct acpi_mcfg_allocation *cfg; 26f68c0654SThomas Gleixner int cfg_num; 27f68c0654SThomas Gleixner 28f68c0654SThomas Gleixner for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { 29f68c0654SThomas Gleixner cfg = pci_mmcfg_virt[cfg_num].cfg; 30f68c0654SThomas Gleixner if (cfg->pci_segment == seg && 31f68c0654SThomas Gleixner (cfg->start_bus_number <= bus) && 32f68c0654SThomas Gleixner (cfg->end_bus_number >= bus)) 33f68c0654SThomas Gleixner return pci_mmcfg_virt[cfg_num].virt; 34f68c0654SThomas Gleixner } 35f68c0654SThomas Gleixner 36f68c0654SThomas Gleixner /* Fall back to type 0 */ 37f68c0654SThomas Gleixner return NULL; 38f68c0654SThomas Gleixner } 39f68c0654SThomas Gleixner 40f68c0654SThomas Gleixner static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) 41f68c0654SThomas Gleixner { 42f68c0654SThomas Gleixner char __iomem *addr; 43*a0ca9909SIvan Kokshaysky 44f68c0654SThomas Gleixner addr = get_virt(seg, bus); 45f68c0654SThomas Gleixner if (!addr) 46f68c0654SThomas Gleixner return NULL; 47f68c0654SThomas Gleixner return addr + ((bus << 20) | (devfn << 12)); 48f68c0654SThomas Gleixner } 49f68c0654SThomas Gleixner 50f68c0654SThomas Gleixner static int pci_mmcfg_read(unsigned int seg, unsigned int bus, 51f68c0654SThomas Gleixner unsigned int devfn, int reg, int len, u32 *value) 52f68c0654SThomas Gleixner { 53f68c0654SThomas Gleixner char __iomem *addr; 54f68c0654SThomas Gleixner 55f68c0654SThomas Gleixner /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ 56f68c0654SThomas Gleixner if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) { 57*a0ca9909SIvan Kokshaysky err: *value = -1; 58f68c0654SThomas Gleixner return -EINVAL; 59f68c0654SThomas Gleixner } 60f68c0654SThomas Gleixner 61*a0ca9909SIvan Kokshaysky if (reg < 256) 62*a0ca9909SIvan Kokshaysky return pci_conf1_read(seg,bus,devfn,reg,len,value); 63*a0ca9909SIvan Kokshaysky 64f68c0654SThomas Gleixner addr = pci_dev_base(seg, bus, devfn); 65f68c0654SThomas Gleixner if (!addr) 66*a0ca9909SIvan Kokshaysky goto err; 67f68c0654SThomas Gleixner 68f68c0654SThomas Gleixner switch (len) { 69f68c0654SThomas Gleixner case 1: 70f68c0654SThomas Gleixner *value = mmio_config_readb(addr + reg); 71f68c0654SThomas Gleixner break; 72f68c0654SThomas Gleixner case 2: 73f68c0654SThomas Gleixner *value = mmio_config_readw(addr + reg); 74f68c0654SThomas Gleixner break; 75f68c0654SThomas Gleixner case 4: 76f68c0654SThomas Gleixner *value = mmio_config_readl(addr + reg); 77f68c0654SThomas Gleixner break; 78f68c0654SThomas Gleixner } 79f68c0654SThomas Gleixner 80f68c0654SThomas Gleixner return 0; 81f68c0654SThomas Gleixner } 82f68c0654SThomas Gleixner 83f68c0654SThomas Gleixner static int pci_mmcfg_write(unsigned int seg, unsigned int bus, 84f68c0654SThomas Gleixner unsigned int devfn, int reg, int len, u32 value) 85f68c0654SThomas Gleixner { 86f68c0654SThomas Gleixner char __iomem *addr; 87f68c0654SThomas Gleixner 88f68c0654SThomas Gleixner /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ 89f68c0654SThomas Gleixner if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) 90f68c0654SThomas Gleixner return -EINVAL; 91f68c0654SThomas Gleixner 92*a0ca9909SIvan Kokshaysky if (reg < 256) 93*a0ca9909SIvan Kokshaysky return pci_conf1_write(seg,bus,devfn,reg,len,value); 94*a0ca9909SIvan Kokshaysky 95f68c0654SThomas Gleixner addr = pci_dev_base(seg, bus, devfn); 96f68c0654SThomas Gleixner if (!addr) 97*a0ca9909SIvan Kokshaysky return -EINVAL; 98f68c0654SThomas Gleixner 99f68c0654SThomas Gleixner switch (len) { 100f68c0654SThomas Gleixner case 1: 101f68c0654SThomas Gleixner mmio_config_writeb(addr + reg, value); 102f68c0654SThomas Gleixner break; 103f68c0654SThomas Gleixner case 2: 104f68c0654SThomas Gleixner mmio_config_writew(addr + reg, value); 105f68c0654SThomas Gleixner break; 106f68c0654SThomas Gleixner case 4: 107f68c0654SThomas Gleixner mmio_config_writel(addr + reg, value); 108f68c0654SThomas Gleixner break; 109f68c0654SThomas Gleixner } 110f68c0654SThomas Gleixner 111f68c0654SThomas Gleixner return 0; 112f68c0654SThomas Gleixner } 113f68c0654SThomas Gleixner 114f68c0654SThomas Gleixner static struct pci_raw_ops pci_mmcfg = { 115f68c0654SThomas Gleixner .read = pci_mmcfg_read, 116f68c0654SThomas Gleixner .write = pci_mmcfg_write, 117f68c0654SThomas Gleixner }; 118f68c0654SThomas Gleixner 119f68c0654SThomas Gleixner static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg) 120f68c0654SThomas Gleixner { 121f68c0654SThomas Gleixner void __iomem *addr; 122f68c0654SThomas Gleixner u32 size; 123f68c0654SThomas Gleixner 124f68c0654SThomas Gleixner size = (cfg->end_bus_number + 1) << 20; 125f68c0654SThomas Gleixner addr = ioremap_nocache(cfg->address, size); 126f68c0654SThomas Gleixner if (addr) { 127f68c0654SThomas Gleixner printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n", 128f68c0654SThomas Gleixner cfg->address, cfg->address + size - 1); 129f68c0654SThomas Gleixner } 130f68c0654SThomas Gleixner return addr; 131f68c0654SThomas Gleixner } 132f68c0654SThomas Gleixner 133f68c0654SThomas Gleixner int __init pci_mmcfg_arch_init(void) 134f68c0654SThomas Gleixner { 135f68c0654SThomas Gleixner int i; 136f68c0654SThomas Gleixner pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * 137f68c0654SThomas Gleixner pci_mmcfg_config_num, GFP_KERNEL); 138f68c0654SThomas Gleixner if (pci_mmcfg_virt == NULL) { 139f68c0654SThomas Gleixner printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n"); 140f68c0654SThomas Gleixner return 0; 141f68c0654SThomas Gleixner } 142f68c0654SThomas Gleixner 143f68c0654SThomas Gleixner for (i = 0; i < pci_mmcfg_config_num; ++i) { 144f68c0654SThomas Gleixner pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; 145f68c0654SThomas Gleixner pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]); 146f68c0654SThomas Gleixner if (!pci_mmcfg_virt[i].virt) { 147f68c0654SThomas Gleixner printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " 148f68c0654SThomas Gleixner "segment %d\n", 149f68c0654SThomas Gleixner pci_mmcfg_config[i].pci_segment); 150f68c0654SThomas Gleixner return 0; 151f68c0654SThomas Gleixner } 152f68c0654SThomas Gleixner } 153f68c0654SThomas Gleixner raw_pci_ops = &pci_mmcfg; 154f68c0654SThomas Gleixner return 1; 155f68c0654SThomas Gleixner } 156