diff options
-rw-r--r-- | arch/i386/pci/mmconfig-shared.c | 121 |
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 | ||
59 | static __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 | |||
76 | static __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 | |||
125 | struct pci_mmcfg_hostbridge_probe { | ||
126 | u32 vendor; | ||
127 | u32 device; | ||
128 | const char *(*probe)(void); | ||
129 | }; | ||
130 | |||
131 | static __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 | |||
136 | static 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 | |||
58 | void __init pci_mmcfg_init(int type) | 169 | void __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)) { |