diff options
author | Tony Luck <tony.luck@intel.com> | 2005-06-29 18:21:41 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-06-29 18:21:41 -0400 |
commit | d18bfacff20f08aecf01bb971b110ca108eef3c7 (patch) | |
tree | 255f862839c593c796e609328575b611e3f56cf3 /arch/x86_64/pci/mmconfig.c | |
parent | a68db763af9b676590c3fe9ec3f17bf18015eb2f (diff) | |
parent | fd782a4a99d2d3e818b9465c427b10f7f027d7da (diff) |
Auto merge with /home/aegl/GIT/linus
Diffstat (limited to 'arch/x86_64/pci/mmconfig.c')
-rw-r--r-- | arch/x86_64/pci/mmconfig.c | 68 |
1 files changed, 54 insertions, 14 deletions
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index b693c232fd07..657e88aa0902 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c | |||
@@ -7,25 +7,50 @@ | |||
7 | 7 | ||
8 | #include <linux/pci.h> | 8 | #include <linux/pci.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/acpi.h> | ||
10 | #include "pci.h" | 11 | #include "pci.h" |
11 | 12 | ||
12 | #define MMCONFIG_APER_SIZE (256*1024*1024) | 13 | #define MMCONFIG_APER_SIZE (256*1024*1024) |
13 | 14 | ||
14 | /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ | ||
15 | u32 pci_mmcfg_base_addr; | ||
16 | |||
17 | /* Static virtual mapping of the MMCONFIG aperture */ | 15 | /* Static virtual mapping of the MMCONFIG aperture */ |
18 | 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; | ||
19 | 21 | ||
20 | static inline char *pci_dev_base(unsigned int bus, unsigned int devfn) | 22 | static char *get_virt(unsigned int seg, int bus) |
21 | { | 23 | { |
22 | 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)); | ||
23 | } | 48 | } |
24 | 49 | ||
25 | static int pci_mmcfg_read(unsigned int seg, unsigned int bus, | 50 | static int pci_mmcfg_read(unsigned int seg, unsigned int bus, |
26 | unsigned int devfn, int reg, int len, u32 *value) | 51 | unsigned int devfn, int reg, int len, u32 *value) |
27 | { | 52 | { |
28 | char *addr = pci_dev_base(bus, devfn); | 53 | char *addr = pci_dev_base(seg, bus, devfn); |
29 | 54 | ||
30 | if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) | 55 | if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) |
31 | return -EINVAL; | 56 | return -EINVAL; |
@@ -48,7 +73,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, | |||
48 | static int pci_mmcfg_write(unsigned int seg, unsigned int bus, | 73 | static int pci_mmcfg_write(unsigned int seg, unsigned int bus, |
49 | unsigned int devfn, int reg, int len, u32 value) | 74 | unsigned int devfn, int reg, int len, u32 value) |
50 | { | 75 | { |
51 | char *addr = pci_dev_base(bus,devfn); | 76 | char *addr = pci_dev_base(seg, bus, devfn); |
52 | 77 | ||
53 | if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) | 78 | if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) |
54 | return -EINVAL; | 79 | return -EINVAL; |
@@ -75,9 +100,15 @@ static struct pci_raw_ops pci_mmcfg = { | |||
75 | 100 | ||
76 | static int __init pci_mmcfg_init(void) | 101 | static int __init pci_mmcfg_init(void) |
77 | { | 102 | { |
103 | int i; | ||
104 | |||
78 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) | 105 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
79 | return 0; | 106 | return 0; |
80 | if (!pci_mmcfg_base_addr) | 107 | |
108 | acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); | ||
109 | if ((pci_mmcfg_config_num == 0) || | ||
110 | (pci_mmcfg_config == NULL) || | ||
111 | (pci_mmcfg_config[0].base_address == 0)) | ||
81 | return 0; | 112 | return 0; |
82 | 113 | ||
83 | /* Kludge for now. Don't use mmconfig on AMD systems because | 114 | /* Kludge for now. Don't use mmconfig on AMD systems because |
@@ -88,13 +119,22 @@ static int __init pci_mmcfg_init(void) | |||
88 | return 0; | 119 | return 0; |
89 | 120 | ||
90 | /* RED-PEN i386 doesn't do _nocache right now */ | 121 | /* RED-PEN i386 doesn't do _nocache right now */ |
91 | pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE); | 122 | pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); |
92 | if (!pci_mmcfg_virt) { | 123 | if (pci_mmcfg_virt == NULL) { |
93 | printk("PCI: Cannot map mmconfig aperture\n"); | 124 | printk("PCI: Can not allocate memory for mmconfig structures\n"); |
94 | return 0; | 125 | return 0; |
95 | } | 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 | } | ||
96 | 137 | ||
97 | printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_base_addr); | ||
98 | raw_pci_ops = &pci_mmcfg; | 138 | raw_pci_ops = &pci_mmcfg; |
99 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; | 139 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; |
100 | 140 | ||