diff options
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/pci/mmconfig.c | 58 |
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 */ |
16 | static char *pci_mmcfg_virt; | 16 | struct mmcfg_virt { |
17 | struct acpi_table_mcfg_config *cfg; | ||
18 | char *virt; | ||
19 | }; | ||
20 | static struct mmcfg_virt *pci_mmcfg_virt; | ||
17 | 21 | ||
18 | static inline char *pci_dev_base(unsigned int bus, unsigned int devfn) | 22 | static 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 | |||
44 | static 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 | ||
23 | static int pci_mmcfg_read(unsigned int seg, unsigned int bus, | 50 | static 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, | |||
46 | static int pci_mmcfg_write(unsigned int seg, unsigned int bus, | 73 | static 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 | ||
74 | static int __init pci_mmcfg_init(void) | 101 | static 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 | ||