diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 2 | ||||
-rw-r--r-- | arch/i386/kernel/setup.c | 32 | ||||
-rw-r--r-- | arch/i386/pci/common.c | 5 | ||||
-rw-r--r-- | arch/i386/pci/mmconfig.c | 34 | ||||
-rw-r--r-- | arch/i386/pci/pci.h | 3 | ||||
-rw-r--r-- | arch/x86_64/kernel/e820.c | 29 | ||||
-rw-r--r-- | arch/x86_64/pci/mmconfig.c | 34 |
7 files changed, 82 insertions, 57 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 87a17337c7f6..71d05f481727 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1189,8 +1189,6 @@ running once the system is up. | |||
1189 | Mechanism 2. | 1189 | Mechanism 2. |
1190 | nommconf [IA-32,X86_64] Disable use of MMCONFIG for PCI | 1190 | nommconf [IA-32,X86_64] Disable use of MMCONFIG for PCI |
1191 | Configuration | 1191 | Configuration |
1192 | mmconf [IA-32,X86_64] Force MMCONFIG. This is useful | ||
1193 | to override the builtin blacklist. | ||
1194 | nomsi [MSI] If the PCI_MSI kernel config parameter is | 1192 | nomsi [MSI] If the PCI_MSI kernel config parameter is |
1195 | enabled, this kernel boot option can be used to | 1193 | enabled, this kernel boot option can be used to |
1196 | disable the use of MSI interrupts system-wide. | 1194 | disable the use of MSI interrupts system-wide. |
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 345ffb7d904d..f1682206d304 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c | |||
@@ -956,6 +956,38 @@ efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg) | |||
956 | return 0; | 956 | return 0; |
957 | } | 957 | } |
958 | 958 | ||
959 | /* | ||
960 | * This function checks if the entire range <start,end> is mapped with type. | ||
961 | * | ||
962 | * Note: this function only works correct if the e820 table is sorted and | ||
963 | * not-overlapping, which is the case | ||
964 | */ | ||
965 | int __init | ||
966 | e820_all_mapped(unsigned long s, unsigned long e, unsigned type) | ||
967 | { | ||
968 | u64 start = s; | ||
969 | u64 end = e; | ||
970 | int i; | ||
971 | for (i = 0; i < e820.nr_map; i++) { | ||
972 | struct e820entry *ei = &e820.map[i]; | ||
973 | if (type && ei->type != type) | ||
974 | continue; | ||
975 | /* is the region (part) in overlap with the current region ?*/ | ||
976 | if (ei->addr >= end || ei->addr + ei->size <= start) | ||
977 | continue; | ||
978 | /* if the region is at the beginning of <start,end> we move | ||
979 | * start to the end of the region since it's ok until there | ||
980 | */ | ||
981 | if (ei->addr <= start) | ||
982 | start = ei->addr + ei->size; | ||
983 | /* if start is now at or beyond end, we're done, full | ||
984 | * coverage */ | ||
985 | if (start >= end) | ||
986 | return 1; /* we're done */ | ||
987 | } | ||
988 | return 0; | ||
989 | } | ||
990 | |||
959 | /* | 991 | /* |
960 | * Find the highest page frame number we have available | 992 | * Find the highest page frame number we have available |
961 | */ | 993 | */ |
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 1220dd828ce3..0a362e3aeac5 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c | |||
@@ -237,11 +237,6 @@ char * __devinit pcibios_setup(char *str) | |||
237 | pci_probe &= ~PCI_PROBE_MMCONF; | 237 | pci_probe &= ~PCI_PROBE_MMCONF; |
238 | return NULL; | 238 | return NULL; |
239 | } | 239 | } |
240 | /* override DMI blacklist */ | ||
241 | else if (!strcmp(str, "mmconf")) { | ||
242 | pci_probe |= PCI_PROBE_MMCONF_FORCE; | ||
243 | return NULL; | ||
244 | } | ||
245 | #endif | 240 | #endif |
246 | else if (!strcmp(str, "noacpi")) { | 241 | else if (!strcmp(str, "noacpi")) { |
247 | acpi_noirq_set(); | 242 | acpi_noirq_set(); |
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index ef5a2faa7d82..972180f738d9 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/acpi.h> | 14 | #include <linux/acpi.h> |
15 | #include <linux/dmi.h> | ||
16 | #include <asm/e820.h> | 15 | #include <asm/e820.h> |
17 | #include "pci.h" | 16 | #include "pci.h" |
18 | 17 | ||
@@ -188,31 +187,9 @@ static __init void unreachable_devices(void) | |||
188 | } | 187 | } |
189 | } | 188 | } |
190 | 189 | ||
191 | static int disable_mcfg(struct dmi_system_id *d) | ||
192 | { | ||
193 | printk("PCI: %s detected. Disabling MCFG.\n", d->ident); | ||
194 | pci_probe &= ~PCI_PROBE_MMCONF; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static struct dmi_system_id __initdata dmi_bad_mcfg[] = { | ||
199 | /* Has broken MCFG table that makes the system hang when used */ | ||
200 | { | ||
201 | .callback = disable_mcfg, | ||
202 | .ident = "Intel D3C5105 SDV", | ||
203 | .matches = { | ||
204 | DMI_MATCH(DMI_BIOS_VENDOR, "Intel"), | ||
205 | DMI_MATCH(DMI_BOARD_NAME, "D26928"), | ||
206 | }, | ||
207 | }, | ||
208 | {} | ||
209 | }; | ||
210 | |||
211 | void __init pci_mmcfg_init(void) | 190 | void __init pci_mmcfg_init(void) |
212 | { | 191 | { |
213 | dmi_check_system(dmi_bad_mcfg); | 192 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
214 | |||
215 | if ((pci_probe & (PCI_PROBE_MMCONF_FORCE|PCI_PROBE_MMCONF)) == 0) | ||
216 | return; | 193 | return; |
217 | 194 | ||
218 | acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); | 195 | acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); |
@@ -221,6 +198,15 @@ void __init pci_mmcfg_init(void) | |||
221 | (pci_mmcfg_config[0].base_address == 0)) | 198 | (pci_mmcfg_config[0].base_address == 0)) |
222 | return; | 199 | return; |
223 | 200 | ||
201 | if (!e820_all_mapped(pci_mmcfg_config[0].base_address, | ||
202 | pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN, | ||
203 | E820_RESERVED)) { | ||
204 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n", | ||
205 | pci_mmcfg_config[0].base_address); | ||
206 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | ||
207 | return; | ||
208 | } | ||
209 | |||
224 | printk(KERN_INFO "PCI: Using MMCONFIG\n"); | 210 | printk(KERN_INFO "PCI: Using MMCONFIG\n"); |
225 | raw_pci_ops = &pci_mmcfg; | 211 | raw_pci_ops = &pci_mmcfg; |
226 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; | 212 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; |
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index 49a849b3a241..bf4e79335388 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h | |||
@@ -16,8 +16,7 @@ | |||
16 | #define PCI_PROBE_CONF1 0x0002 | 16 | #define PCI_PROBE_CONF1 0x0002 |
17 | #define PCI_PROBE_CONF2 0x0004 | 17 | #define PCI_PROBE_CONF2 0x0004 |
18 | #define PCI_PROBE_MMCONF 0x0008 | 18 | #define PCI_PROBE_MMCONF 0x0008 |
19 | #define PCI_PROBE_MMCONF_FORCE 0x0010 | 19 | #define PCI_PROBE_MASK 0x000f |
20 | #define PCI_PROBE_MASK 0x00ff | ||
21 | 20 | ||
22 | #define PCI_NO_SORT 0x0100 | 21 | #define PCI_NO_SORT 0x0100 |
23 | #define PCI_BIOS_SORT 0x0200 | 22 | #define PCI_BIOS_SORT 0x0200 |
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 764bf23c7103..d6d7f731f6f0 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c | |||
@@ -108,6 +108,35 @@ e820_any_mapped(unsigned long start, unsigned long end, unsigned type) | |||
108 | return 0; | 108 | return 0; |
109 | } | 109 | } |
110 | 110 | ||
111 | /* | ||
112 | * This function checks if the entire range <start,end> is mapped with type. | ||
113 | * | ||
114 | * Note: this function only works correct if the e820 table is sorted and | ||
115 | * not-overlapping, which is the case | ||
116 | */ | ||
117 | int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type) | ||
118 | { | ||
119 | int i; | ||
120 | for (i = 0; i < e820.nr_map; i++) { | ||
121 | struct e820entry *ei = &e820.map[i]; | ||
122 | if (type && ei->type != type) | ||
123 | continue; | ||
124 | /* is the region (part) in overlap with the current region ?*/ | ||
125 | if (ei->addr >= end || ei->addr + ei->size <= start) | ||
126 | continue; | ||
127 | |||
128 | /* if the region is at the beginning of <start,end> we move | ||
129 | * start to the end of the region since it's ok until there | ||
130 | */ | ||
131 | if (ei->addr <= start) | ||
132 | start = ei->addr + ei->size; | ||
133 | /* if start is now at or beyond end, we're done, full coverage */ | ||
134 | if (start >= end) | ||
135 | return 1; /* we're done */ | ||
136 | } | ||
137 | return 0; | ||
138 | } | ||
139 | |||
111 | /* | 140 | /* |
112 | * Find a free area in a specific range. | 141 | * Find a free area in a specific range. |
113 | */ | 142 | */ |
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index 2d48a7941d48..3c55c76c6fd5 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/acpi.h> | 10 | #include <linux/acpi.h> |
11 | #include <linux/bitmap.h> | 11 | #include <linux/bitmap.h> |
12 | #include <linux/dmi.h> | ||
13 | #include <asm/e820.h> | 12 | #include <asm/e820.h> |
14 | 13 | ||
15 | #include "pci.h" | 14 | #include "pci.h" |
@@ -165,33 +164,11 @@ static __init void unreachable_devices(void) | |||
165 | } | 164 | } |
166 | } | 165 | } |
167 | 166 | ||
168 | static int disable_mcfg(struct dmi_system_id *d) | ||
169 | { | ||
170 | printk("PCI: %s detected. Disabling MCFG.\n", d->ident); | ||
171 | pci_probe &= ~PCI_PROBE_MMCONF; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static struct dmi_system_id __initdata dmi_bad_mcfg[] = { | ||
176 | /* Has broken MCFG table that makes the system hang when used */ | ||
177 | { | ||
178 | .callback = disable_mcfg, | ||
179 | .ident = "Intel D3C5105 SDV", | ||
180 | .matches = { | ||
181 | DMI_MATCH(DMI_BIOS_VENDOR, "Intel"), | ||
182 | DMI_MATCH(DMI_BOARD_NAME, "D26928"), | ||
183 | }, | ||
184 | }, | ||
185 | {} | ||
186 | }; | ||
187 | |||
188 | void __init pci_mmcfg_init(void) | 167 | void __init pci_mmcfg_init(void) |
189 | { | 168 | { |
190 | int i; | 169 | int i; |
191 | 170 | ||
192 | dmi_check_system(dmi_bad_mcfg); | 171 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
193 | |||
194 | if ((pci_probe & (PCI_PROBE_MMCONF|PCI_PROBE_MMCONF_FORCE)) == 0) | ||
195 | return; | 172 | return; |
196 | 173 | ||
197 | acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); | 174 | acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); |
@@ -200,6 +177,15 @@ void __init pci_mmcfg_init(void) | |||
200 | (pci_mmcfg_config[0].base_address == 0)) | 177 | (pci_mmcfg_config[0].base_address == 0)) |
201 | return; | 178 | return; |
202 | 179 | ||
180 | if (!e820_all_mapped(pci_mmcfg_config[0].base_address, | ||
181 | pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN, | ||
182 | E820_RESERVED)) { | ||
183 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n", | ||
184 | pci_mmcfg_config[0].base_address); | ||
185 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | ||
186 | return; | ||
187 | } | ||
188 | |||
203 | /* RED-PEN i386 doesn't do _nocache right now */ | 189 | /* RED-PEN i386 doesn't do _nocache right now */ |
204 | pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); | 190 | pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); |
205 | if (pci_mmcfg_virt == NULL) { | 191 | if (pci_mmcfg_virt == NULL) { |