aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2005-06-23 20:35:56 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-28 00:52:48 -0400
commit1cde8a16815bd85c8137d1ea556398983c597c11 (patch)
treec43ab735f7fd96d0576dfb7749c8ded74f9b63b7 /arch
parentd57e26ceb7dbf44cd08128cb6146116d4281b58b (diff)
[PATCH] PCI: use the MCFG table to properly access pci devices (x86-64)
Now that we have access to the whole MCFG table, let's properly use it for all pci device accesses (as that's what it is there for, some boxes don't put all the busses into one entry.) If, for some reason, the table is incorrect, we fallback to the "old style" of mmconfig accesses, namely, we just assume the first entry in the table is the one for us, and blindly use it. Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86_64/pci/mmconfig.c58
1 files changed, 48 insertions, 10 deletions
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index 09cfcc1234b9..657e88aa0902 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -13,17 +13,44 @@
13#define MMCONFIG_APER_SIZE (256*1024*1024) 13#define MMCONFIG_APER_SIZE (256*1024*1024)
14 14
15/* Static virtual mapping of the MMCONFIG aperture */ 15/* Static virtual mapping of the MMCONFIG aperture */
16static char *pci_mmcfg_virt; 16struct mmcfg_virt {
17 struct acpi_table_mcfg_config *cfg;
18 char *virt;
19};
20static struct mmcfg_virt *pci_mmcfg_virt;
17 21
18static inline char *pci_dev_base(unsigned int bus, unsigned int devfn) 22static char *get_virt(unsigned int seg, int bus)
19{ 23{
20 return pci_mmcfg_virt + ((bus << 20) | (devfn << 12)); 24 int cfg_num = -1;
25 struct acpi_table_mcfg_config *cfg;
26
27 while (1) {
28 ++cfg_num;
29 if (cfg_num >= pci_mmcfg_config_num) {
30 /* something bad is going on, no cfg table is found. */
31 /* so we fall back to the old way we used to do this */
32 /* and just rely on the first entry to be correct. */
33 return pci_mmcfg_virt[0].virt;
34 }
35 cfg = pci_mmcfg_virt[cfg_num].cfg;
36 if (cfg->pci_segment_group_number != seg)
37 continue;
38 if ((cfg->start_bus_number <= bus) &&
39 (cfg->end_bus_number >= bus))
40 return pci_mmcfg_virt[cfg_num].virt;
41 }
42}
43
44static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
45{
46
47 return get_virt(seg, bus) + ((bus << 20) | (devfn << 12));
21} 48}
22 49
23static int pci_mmcfg_read(unsigned int seg, unsigned int bus, 50static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
24 unsigned int devfn, int reg, int len, u32 *value) 51 unsigned int devfn, int reg, int len, u32 *value)
25{ 52{
26 char *addr = pci_dev_base(bus, devfn); 53 char *addr = pci_dev_base(seg, bus, devfn);
27 54
28 if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) 55 if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
29 return -EINVAL; 56 return -EINVAL;
@@ -46,7 +73,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
46static int pci_mmcfg_write(unsigned int seg, unsigned int bus, 73static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
47 unsigned int devfn, int reg, int len, u32 value) 74 unsigned int devfn, int reg, int len, u32 value)
48{ 75{
49 char *addr = pci_dev_base(bus,devfn); 76 char *addr = pci_dev_base(seg, bus, devfn);
50 77
51 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) 78 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
52 return -EINVAL; 79 return -EINVAL;
@@ -73,6 +100,8 @@ static struct pci_raw_ops pci_mmcfg = {
73 100
74static int __init pci_mmcfg_init(void) 101static int __init pci_mmcfg_init(void)
75{ 102{
103 int i;
104
76 if ((pci_probe & PCI_PROBE_MMCONF) == 0) 105 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
77 return 0; 106 return 0;
78 107
@@ -90,13 +119,22 @@ static int __init pci_mmcfg_init(void)
90 return 0; 119 return 0;
91 120
92 /* RED-PEN i386 doesn't do _nocache right now */ 121 /* RED-PEN i386 doesn't do _nocache right now */
93 pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_config[0].base_address, MMCONFIG_APER_SIZE); 122 pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
94 if (!pci_mmcfg_virt) { 123 if (pci_mmcfg_virt == NULL) {
95 printk("PCI: Cannot map mmconfig aperture\n"); 124 printk("PCI: Can not allocate memory for mmconfig structures\n");
96 return 0; 125 return 0;
97 } 126 }
127 for (i = 0; i < pci_mmcfg_config_num; ++i) {
128 pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
129 pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
130 if (!pci_mmcfg_virt[i].virt) {
131 printk("PCI: Cannot map mmconfig aperture for segment %d\n",
132 pci_mmcfg_config[i].pci_segment_group_number);
133 return 0;
134 }
135 printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
136 }
98 137
99 printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[0].base_address);
100 raw_pci_ops = &pci_mmcfg; 138 raw_pci_ops = &pci_mmcfg;
101 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; 139 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
102 140