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