aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorOlivier Galibert <galibert@pobox.com>2007-02-13 07:26:20 -0500
committerAndi Kleen <andi@basil.nowhere.org>2007-02-13 07:26:20 -0500
commit9358c693c5ac1afde28f24ac651f7903d32a850c (patch)
treeadd51939771569d41a44e9e7b48633b8037ded45 /arch/i386
parent5f027387bbdb5a4a4c1babd557fd976cd09d7495 (diff)
[PATCH] mmconfig: Detect and support the E7520 and the 945G/GZ/P/PL
It seems that the only way to reliably support mmconfig in the presence of funky biosen is to detect the hostbridge and read where the window is mapped from its registers. Do that for the E7520 and the 945G/GZ/P/PL for a start. Signed-off-by: Olivier Galibert <galibert@pobox.com> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org>
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/pci/mmconfig-shared.c121
1 files changed, 119 insertions, 2 deletions
diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index 779c987acc5b..d72f0439147c 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -3,6 +3,7 @@
3 * MMCONFIG - common code between i386 and x86-64. 3 * MMCONFIG - common code between i386 and x86-64.
4 * 4 *
5 * This code does: 5 * This code does:
6 * - known chipset handling
6 * - ACPI decoding and validation 7 * - ACPI decoding and validation
7 * 8 *
8 * Per-architecture code takes care of the mappings and accesses 9 * Per-architecture code takes care of the mappings and accesses
@@ -55,12 +56,128 @@ static __init void unreachable_devices(void)
55 } 56 }
56} 57}
57 58
59static __init const char *pci_mmcfg_e7520(void)
60{
61 u32 win;
62 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
63
64 pci_mmcfg_config_num = 1;
65 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
66 if (!pci_mmcfg_config)
67 return NULL;
68 pci_mmcfg_config[0].address = (win & 0xf000) << 16;
69 pci_mmcfg_config[0].pci_segment = 0;
70 pci_mmcfg_config[0].start_bus_number = 0;
71 pci_mmcfg_config[0].end_bus_number = 255;
72
73 return "Intel Corporation E7520 Memory Controller Hub";
74}
75
76static __init const char *pci_mmcfg_intel_945(void)
77{
78 u32 pciexbar, mask = 0, len = 0;
79
80 pci_mmcfg_config_num = 1;
81
82 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
83
84 /* Enable bit */
85 if (!(pciexbar & 1))
86 pci_mmcfg_config_num = 0;
87
88 /* Size bits */
89 switch ((pciexbar >> 1) & 3) {
90 case 0:
91 mask = 0xf0000000U;
92 len = 0x10000000U;
93 break;
94 case 1:
95 mask = 0xf8000000U;
96 len = 0x08000000U;
97 break;
98 case 2:
99 mask = 0xfc000000U;
100 len = 0x04000000U;
101 break;
102 default:
103 pci_mmcfg_config_num = 0;
104 }
105
106 /* Errata #2, things break when not aligned on a 256Mb boundary */
107 /* Can only happen in 64M/128M mode */
108
109 if ((pciexbar & mask) & 0x0fffffffU)
110 pci_mmcfg_config_num = 0;
111
112 if (pci_mmcfg_config_num) {
113 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
114 if (!pci_mmcfg_config)
115 return NULL;
116 pci_mmcfg_config[0].address = pciexbar & mask;
117 pci_mmcfg_config[0].pci_segment = 0;
118 pci_mmcfg_config[0].start_bus_number = 0;
119 pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
120 }
121
122 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
123}
124
125struct pci_mmcfg_hostbridge_probe {
126 u32 vendor;
127 u32 device;
128 const char *(*probe)(void);
129};
130
131static __initdata struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] = {
132 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
133 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
134};
135
136static int __init pci_mmcfg_check_hostbridge(void)
137{
138 u32 l;
139 u16 vendor, device;
140 int i;
141 const char *name;
142
143 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
144 vendor = l & 0xffff;
145 device = (l >> 16) & 0xffff;
146
147 pci_mmcfg_config_num = 0;
148 pci_mmcfg_config = NULL;
149 name = NULL;
150
151 for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++)
152 if ((pci_mmcfg_probes[i].vendor == PCI_ANY_ID ||
153 pci_mmcfg_probes[i].vendor == vendor) &&
154 (pci_mmcfg_probes[i].device == PCI_ANY_ID ||
155 pci_mmcfg_probes[i].device == device))
156 name = pci_mmcfg_probes[i].probe();
157
158 if (name) {
159 if (pci_mmcfg_config_num)
160 printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n", name);
161 else
162 printk(KERN_INFO "PCI: Found %s without MMCONFIG support.\n",
163 name);
164 }
165
166 return name != NULL;
167}
168
58void __init pci_mmcfg_init(int type) 169void __init pci_mmcfg_init(int type)
59{ 170{
171 int known_bridge = 0;
172
60 if ((pci_probe & PCI_PROBE_MMCONF) == 0) 173 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
61 return; 174 return;
62 175
63 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); 176 if (type == 1 && pci_mmcfg_check_hostbridge())
177 known_bridge = 1;
178
179 if (!known_bridge)
180 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
64 181
65 if ((pci_mmcfg_config_num == 0) || 182 if ((pci_mmcfg_config_num == 0) ||
66 (pci_mmcfg_config == NULL) || 183 (pci_mmcfg_config == NULL) ||
@@ -69,7 +186,7 @@ void __init pci_mmcfg_init(int type)
69 186
70 /* Only do this check when type 1 works. If it doesn't work 187 /* Only do this check when type 1 works. If it doesn't work
71 assume we run on a Mac and always use MCFG */ 188 assume we run on a Mac and always use MCFG */
72 if (type == 1 && 189 if (type == 1 && !known_bridge &&
73 !e820_all_mapped(pci_mmcfg_config[0].address, 190 !e820_all_mapped(pci_mmcfg_config[0].address,
74 pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, 191 pci_mmcfg_config[0].address + MMCONFIG_APER_MIN,
75 E820_RESERVED)) { 192 E820_RESERVED)) {