1 /* 2 * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx> 3 * Copyright (C) 2004 Intel Corp. 4 * 5 * This code is released under the GNU General Public License version 2. 6 */ 7 8 /* 9 * mmconfig.c - Low-level direct PCI config space access via MMCONFIG 10 */ 11 12 #include <linux/pci.h> 13 #include <linux/init.h> 14 #include <linux/acpi.h> 15 #include <asm/e820.h> 16 #include <asm/pci_x86.h> 17 18 /* Assume systems with more busses have correct MCFG */ 19 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) 20 21 /* The base address of the last MMCONFIG device accessed */ 22 static u32 mmcfg_last_accessed_device; 23 static int mmcfg_last_accessed_cpu; 24 25 /* 26 * Functions for accessing PCI configuration space with MMCONFIG accesses 27 */ 28 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) 29 { 30 struct acpi_mcfg_allocation *cfg; 31 int cfg_num; 32 33 for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { 34 cfg = &pci_mmcfg_config[cfg_num]; 35 if (cfg->pci_segment == seg && 36 (cfg->start_bus_number <= bus) && 37 (cfg->end_bus_number >= bus)) 38 return cfg->address; 39 } 40 41 /* Fall back to type 0 */ 42 return 0; 43 } 44 45 /* 46 * This is always called under pci_config_lock 47 */ 48 static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) 49 { 50 u32 dev_base = base | (bus << 20) | (devfn << 12); 51 int cpu = smp_processor_id(); 52 if (dev_base != mmcfg_last_accessed_device || 53 cpu != mmcfg_last_accessed_cpu) { 54 mmcfg_last_accessed_device = dev_base; 55 mmcfg_last_accessed_cpu = cpu; 56 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); 57 } 58 } 59 60 static int pci_mmcfg_read(unsigned int seg, unsigned int bus, 61 unsigned int devfn, int reg, int len, u32 *value) 62 { 63 unsigned long flags; 64 u32 base; 65 66 if ((bus > 255) || (devfn > 255) || (reg > 4095)) { 67 err: *value = -1; 68 return -EINVAL; 69 } 70 71 base = get_base_addr(seg, bus, devfn); 72 if (!base) 73 goto err; 74 75 spin_lock_irqsave(&pci_config_lock, flags); 76 77 pci_exp_set_dev_base(base, bus, devfn); 78 79 switch (len) { 80 case 1: 81 *value = mmio_config_readb(mmcfg_virt_addr + reg); 82 break; 83 case 2: 84 *value = mmio_config_readw(mmcfg_virt_addr + reg); 85 break; 86 case 4: 87 *value = mmio_config_readl(mmcfg_virt_addr + reg); 88 break; 89 } 90 spin_unlock_irqrestore(&pci_config_lock, flags); 91 92 return 0; 93 } 94 95 static int pci_mmcfg_write(unsigned int seg, unsigned int bus, 96 unsigned int devfn, int reg, int len, u32 value) 97 { 98 unsigned long flags; 99 u32 base; 100 101 if ((bus > 255) || (devfn > 255) || (reg > 4095)) 102 return -EINVAL; 103 104 base = get_base_addr(seg, bus, devfn); 105 if (!base) 106 return -EINVAL; 107 108 spin_lock_irqsave(&pci_config_lock, flags); 109 110 pci_exp_set_dev_base(base, bus, devfn); 111 112 switch (len) { 113 case 1: 114 mmio_config_writeb(mmcfg_virt_addr + reg, value); 115 break; 116 case 2: 117 mmio_config_writew(mmcfg_virt_addr + reg, value); 118 break; 119 case 4: 120 mmio_config_writel(mmcfg_virt_addr + reg, value); 121 break; 122 } 123 spin_unlock_irqrestore(&pci_config_lock, flags); 124 125 return 0; 126 } 127 128 static struct pci_raw_ops pci_mmcfg = { 129 .read = pci_mmcfg_read, 130 .write = pci_mmcfg_write, 131 }; 132 133 int __init pci_mmcfg_arch_init(void) 134 { 135 printk(KERN_INFO "PCI: Using MMCONFIG for extended config space\n"); 136 raw_pci_ext_ops = &pci_mmcfg; 137 return 1; 138 } 139 140 void __init pci_mmcfg_arch_free(void) 141 { 142 } 143