diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 10:11:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 10:11:53 -0400 |
commit | 982653009b883ef1529089e3e6f1ae2fee41cbe2 (patch) | |
tree | eec3b1fe947d442ee204a2d648133bc5223e5c59 /drivers/iommu | |
parent | 37d96c28ecf0af1215bb6bbf580dbb1fabb5a6ec (diff) | |
parent | c020570138f5d9cb1fc0a853f9cf9e641178b5c5 (diff) |
Merge branch 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, ioapic: Consolidate the explicit EOI code
x86, ioapic: Restore the mask bit correctly in eoi_ioapic_irq()
x86, kdump, ioapic: Reset remote-IRR in clear_IO_APIC
iommu: Rename the DMAR and INTR_REMAP config options
x86, ioapic: Define irq_remap_modify_chip_defaults()
x86, msi, intr-remap: Use the ioapic set affinity routine
iommu: Cleanup ifdefs in detect_intel_iommu()
iommu: No need to set dmar_disabled in check_zero_address()
iommu: Move IOMMU specific code to intel-iommu.c
intr_remap: Call dmar_dev_scope_init() explicitly
x86, x2apic: Enable the bios request for x2apic optout
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/Kconfig | 25 | ||||
-rw-r--r-- | drivers/iommu/Makefile | 5 | ||||
-rw-r--r-- | drivers/iommu/dmar.c | 198 | ||||
-rw-r--r-- | drivers/iommu/intel-iommu.c | 167 | ||||
-rw-r--r-- | drivers/iommu/intr_remapping.c | 53 |
5 files changed, 244 insertions, 204 deletions
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index b57b3fa492f3..7d7eaa15e773 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig | |||
@@ -59,10 +59,14 @@ config AMD_IOMMU_STATS | |||
59 | If unsure, say N. | 59 | If unsure, say N. |
60 | 60 | ||
61 | # Intel IOMMU support | 61 | # Intel IOMMU support |
62 | config DMAR | 62 | config DMAR_TABLE |
63 | bool "Support for DMA Remapping Devices" | 63 | bool |
64 | |||
65 | config INTEL_IOMMU | ||
66 | bool "Support for Intel IOMMU using DMA Remapping Devices" | ||
64 | depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC) | 67 | depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC) |
65 | select IOMMU_API | 68 | select IOMMU_API |
69 | select DMAR_TABLE | ||
66 | help | 70 | help |
67 | DMA remapping (DMAR) devices support enables independent address | 71 | DMA remapping (DMAR) devices support enables independent address |
68 | translations for Direct Memory Access (DMA) from devices. | 72 | translations for Direct Memory Access (DMA) from devices. |
@@ -70,18 +74,18 @@ config DMAR | |||
70 | and include PCI device scope covered by these DMA | 74 | and include PCI device scope covered by these DMA |
71 | remapping devices. | 75 | remapping devices. |
72 | 76 | ||
73 | config DMAR_DEFAULT_ON | 77 | config INTEL_IOMMU_DEFAULT_ON |
74 | def_bool y | 78 | def_bool y |
75 | prompt "Enable DMA Remapping Devices by default" | 79 | prompt "Enable Intel DMA Remapping Devices by default" |
76 | depends on DMAR | 80 | depends on INTEL_IOMMU |
77 | help | 81 | help |
78 | Selecting this option will enable a DMAR device at boot time if | 82 | Selecting this option will enable a DMAR device at boot time if |
79 | one is found. If this option is not selected, DMAR support can | 83 | one is found. If this option is not selected, DMAR support can |
80 | be enabled by passing intel_iommu=on to the kernel. | 84 | be enabled by passing intel_iommu=on to the kernel. |
81 | 85 | ||
82 | config DMAR_BROKEN_GFX_WA | 86 | config INTEL_IOMMU_BROKEN_GFX_WA |
83 | bool "Workaround broken graphics drivers (going away soon)" | 87 | bool "Workaround broken graphics drivers (going away soon)" |
84 | depends on DMAR && BROKEN && X86 | 88 | depends on INTEL_IOMMU && BROKEN && X86 |
85 | ---help--- | 89 | ---help--- |
86 | Current Graphics drivers tend to use physical address | 90 | Current Graphics drivers tend to use physical address |
87 | for DMA and avoid using DMA APIs. Setting this config | 91 | for DMA and avoid using DMA APIs. Setting this config |
@@ -90,18 +94,19 @@ config DMAR_BROKEN_GFX_WA | |||
90 | to use physical addresses for DMA, at least until this | 94 | to use physical addresses for DMA, at least until this |
91 | option is removed in the 2.6.32 kernel. | 95 | option is removed in the 2.6.32 kernel. |
92 | 96 | ||
93 | config DMAR_FLOPPY_WA | 97 | config INTEL_IOMMU_FLOPPY_WA |
94 | def_bool y | 98 | def_bool y |
95 | depends on DMAR && X86 | 99 | depends on INTEL_IOMMU && X86 |
96 | ---help--- | 100 | ---help--- |
97 | Floppy disk drivers are known to bypass DMA API calls | 101 | Floppy disk drivers are known to bypass DMA API calls |
98 | thereby failing to work when IOMMU is enabled. This | 102 | thereby failing to work when IOMMU is enabled. This |
99 | workaround will setup a 1:1 mapping for the first | 103 | workaround will setup a 1:1 mapping for the first |
100 | 16MiB to make floppy (an ISA device) work. | 104 | 16MiB to make floppy (an ISA device) work. |
101 | 105 | ||
102 | config INTR_REMAP | 106 | config IRQ_REMAP |
103 | bool "Support for Interrupt Remapping (EXPERIMENTAL)" | 107 | bool "Support for Interrupt Remapping (EXPERIMENTAL)" |
104 | depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL | 108 | depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL |
109 | select DMAR_TABLE | ||
105 | ---help--- | 110 | ---help--- |
106 | Supports Interrupt remapping for IO-APIC and MSI devices. | 111 | Supports Interrupt remapping for IO-APIC and MSI devices. |
107 | To use x2apic mode in the CPU's which support x2APIC enhancements or | 112 | To use x2apic mode in the CPU's which support x2APIC enhancements or |
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 4d4d77df7cac..6394994a2b9d 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-$(CONFIG_IOMMU_API) += iommu.o | 1 | obj-$(CONFIG_IOMMU_API) += iommu.o |
2 | obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o | 2 | obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o |
3 | obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o | 3 | obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o |
4 | obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o | 4 | obj-$(CONFIG_DMAR_TABLE) += dmar.o |
5 | obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o | 5 | obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o |
6 | obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o | ||
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 6dcc7e2d54de..587e8f2d38d8 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c | |||
@@ -46,7 +46,7 @@ | |||
46 | */ | 46 | */ |
47 | LIST_HEAD(dmar_drhd_units); | 47 | LIST_HEAD(dmar_drhd_units); |
48 | 48 | ||
49 | static struct acpi_table_header * __initdata dmar_tbl; | 49 | struct acpi_table_header * __initdata dmar_tbl; |
50 | static acpi_size dmar_tbl_size; | 50 | static acpi_size dmar_tbl_size; |
51 | 51 | ||
52 | static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) | 52 | static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) |
@@ -118,8 +118,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, | |||
118 | return 0; | 118 | return 0; |
119 | } | 119 | } |
120 | 120 | ||
121 | static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, | 121 | int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, |
122 | struct pci_dev ***devices, u16 segment) | 122 | struct pci_dev ***devices, u16 segment) |
123 | { | 123 | { |
124 | struct acpi_dmar_device_scope *scope; | 124 | struct acpi_dmar_device_scope *scope; |
125 | void * tmp = start; | 125 | void * tmp = start; |
@@ -217,133 +217,6 @@ static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru) | |||
217 | return ret; | 217 | return ret; |
218 | } | 218 | } |
219 | 219 | ||
220 | #ifdef CONFIG_DMAR | ||
221 | LIST_HEAD(dmar_rmrr_units); | ||
222 | |||
223 | static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr) | ||
224 | { | ||
225 | list_add(&rmrr->list, &dmar_rmrr_units); | ||
226 | } | ||
227 | |||
228 | |||
229 | static int __init | ||
230 | dmar_parse_one_rmrr(struct acpi_dmar_header *header) | ||
231 | { | ||
232 | struct acpi_dmar_reserved_memory *rmrr; | ||
233 | struct dmar_rmrr_unit *rmrru; | ||
234 | |||
235 | rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); | ||
236 | if (!rmrru) | ||
237 | return -ENOMEM; | ||
238 | |||
239 | rmrru->hdr = header; | ||
240 | rmrr = (struct acpi_dmar_reserved_memory *)header; | ||
241 | rmrru->base_address = rmrr->base_address; | ||
242 | rmrru->end_address = rmrr->end_address; | ||
243 | |||
244 | dmar_register_rmrr_unit(rmrru); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int __init | ||
249 | rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) | ||
250 | { | ||
251 | struct acpi_dmar_reserved_memory *rmrr; | ||
252 | int ret; | ||
253 | |||
254 | rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; | ||
255 | ret = dmar_parse_dev_scope((void *)(rmrr + 1), | ||
256 | ((void *)rmrr) + rmrr->header.length, | ||
257 | &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); | ||
258 | |||
259 | if (ret || (rmrru->devices_cnt == 0)) { | ||
260 | list_del(&rmrru->list); | ||
261 | kfree(rmrru); | ||
262 | } | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static LIST_HEAD(dmar_atsr_units); | ||
267 | |||
268 | static int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr) | ||
269 | { | ||
270 | struct acpi_dmar_atsr *atsr; | ||
271 | struct dmar_atsr_unit *atsru; | ||
272 | |||
273 | atsr = container_of(hdr, struct acpi_dmar_atsr, header); | ||
274 | atsru = kzalloc(sizeof(*atsru), GFP_KERNEL); | ||
275 | if (!atsru) | ||
276 | return -ENOMEM; | ||
277 | |||
278 | atsru->hdr = hdr; | ||
279 | atsru->include_all = atsr->flags & 0x1; | ||
280 | |||
281 | list_add(&atsru->list, &dmar_atsr_units); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) | ||
287 | { | ||
288 | int rc; | ||
289 | struct acpi_dmar_atsr *atsr; | ||
290 | |||
291 | if (atsru->include_all) | ||
292 | return 0; | ||
293 | |||
294 | atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); | ||
295 | rc = dmar_parse_dev_scope((void *)(atsr + 1), | ||
296 | (void *)atsr + atsr->header.length, | ||
297 | &atsru->devices_cnt, &atsru->devices, | ||
298 | atsr->segment); | ||
299 | if (rc || !atsru->devices_cnt) { | ||
300 | list_del(&atsru->list); | ||
301 | kfree(atsru); | ||
302 | } | ||
303 | |||
304 | return rc; | ||
305 | } | ||
306 | |||
307 | int dmar_find_matched_atsr_unit(struct pci_dev *dev) | ||
308 | { | ||
309 | int i; | ||
310 | struct pci_bus *bus; | ||
311 | struct acpi_dmar_atsr *atsr; | ||
312 | struct dmar_atsr_unit *atsru; | ||
313 | |||
314 | dev = pci_physfn(dev); | ||
315 | |||
316 | list_for_each_entry(atsru, &dmar_atsr_units, list) { | ||
317 | atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); | ||
318 | if (atsr->segment == pci_domain_nr(dev->bus)) | ||
319 | goto found; | ||
320 | } | ||
321 | |||
322 | return 0; | ||
323 | |||
324 | found: | ||
325 | for (bus = dev->bus; bus; bus = bus->parent) { | ||
326 | struct pci_dev *bridge = bus->self; | ||
327 | |||
328 | if (!bridge || !pci_is_pcie(bridge) || | ||
329 | bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) | ||
330 | return 0; | ||
331 | |||
332 | if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { | ||
333 | for (i = 0; i < atsru->devices_cnt; i++) | ||
334 | if (atsru->devices[i] == bridge) | ||
335 | return 1; | ||
336 | break; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | if (atsru->include_all) | ||
341 | return 1; | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | #endif | ||
346 | |||
347 | #ifdef CONFIG_ACPI_NUMA | 220 | #ifdef CONFIG_ACPI_NUMA |
348 | static int __init | 221 | static int __init |
349 | dmar_parse_one_rhsa(struct acpi_dmar_header *header) | 222 | dmar_parse_one_rhsa(struct acpi_dmar_header *header) |
@@ -484,14 +357,10 @@ parse_dmar_table(void) | |||
484 | ret = dmar_parse_one_drhd(entry_header); | 357 | ret = dmar_parse_one_drhd(entry_header); |
485 | break; | 358 | break; |
486 | case ACPI_DMAR_TYPE_RESERVED_MEMORY: | 359 | case ACPI_DMAR_TYPE_RESERVED_MEMORY: |
487 | #ifdef CONFIG_DMAR | ||
488 | ret = dmar_parse_one_rmrr(entry_header); | 360 | ret = dmar_parse_one_rmrr(entry_header); |
489 | #endif | ||
490 | break; | 361 | break; |
491 | case ACPI_DMAR_TYPE_ATSR: | 362 | case ACPI_DMAR_TYPE_ATSR: |
492 | #ifdef CONFIG_DMAR | ||
493 | ret = dmar_parse_one_atsr(entry_header); | 363 | ret = dmar_parse_one_atsr(entry_header); |
494 | #endif | ||
495 | break; | 364 | break; |
496 | case ACPI_DMAR_HARDWARE_AFFINITY: | 365 | case ACPI_DMAR_HARDWARE_AFFINITY: |
497 | #ifdef CONFIG_ACPI_NUMA | 366 | #ifdef CONFIG_ACPI_NUMA |
@@ -557,34 +426,31 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev) | |||
557 | 426 | ||
558 | int __init dmar_dev_scope_init(void) | 427 | int __init dmar_dev_scope_init(void) |
559 | { | 428 | { |
429 | static int dmar_dev_scope_initialized; | ||
560 | struct dmar_drhd_unit *drhd, *drhd_n; | 430 | struct dmar_drhd_unit *drhd, *drhd_n; |
561 | int ret = -ENODEV; | 431 | int ret = -ENODEV; |
562 | 432 | ||
433 | if (dmar_dev_scope_initialized) | ||
434 | return dmar_dev_scope_initialized; | ||
435 | |||
436 | if (list_empty(&dmar_drhd_units)) | ||
437 | goto fail; | ||
438 | |||
563 | list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) { | 439 | list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) { |
564 | ret = dmar_parse_dev(drhd); | 440 | ret = dmar_parse_dev(drhd); |
565 | if (ret) | 441 | if (ret) |
566 | return ret; | 442 | goto fail; |
567 | } | 443 | } |
568 | 444 | ||
569 | #ifdef CONFIG_DMAR | 445 | ret = dmar_parse_rmrr_atsr_dev(); |
570 | { | 446 | if (ret) |
571 | struct dmar_rmrr_unit *rmrr, *rmrr_n; | 447 | goto fail; |
572 | struct dmar_atsr_unit *atsr, *atsr_n; | ||
573 | |||
574 | list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) { | ||
575 | ret = rmrr_parse_dev(rmrr); | ||
576 | if (ret) | ||
577 | return ret; | ||
578 | } | ||
579 | 448 | ||
580 | list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) { | 449 | dmar_dev_scope_initialized = 1; |
581 | ret = atsr_parse_dev(atsr); | 450 | return 0; |
582 | if (ret) | ||
583 | return ret; | ||
584 | } | ||
585 | } | ||
586 | #endif | ||
587 | 451 | ||
452 | fail: | ||
453 | dmar_dev_scope_initialized = ret; | ||
588 | return ret; | 454 | return ret; |
589 | } | 455 | } |
590 | 456 | ||
@@ -611,14 +477,6 @@ int __init dmar_table_init(void) | |||
611 | return -ENODEV; | 477 | return -ENODEV; |
612 | } | 478 | } |
613 | 479 | ||
614 | #ifdef CONFIG_DMAR | ||
615 | if (list_empty(&dmar_rmrr_units)) | ||
616 | printk(KERN_INFO PREFIX "No RMRR found\n"); | ||
617 | |||
618 | if (list_empty(&dmar_atsr_units)) | ||
619 | printk(KERN_INFO PREFIX "No ATSR found\n"); | ||
620 | #endif | ||
621 | |||
622 | return 0; | 480 | return 0; |
623 | } | 481 | } |
624 | 482 | ||
@@ -682,9 +540,6 @@ int __init check_zero_address(void) | |||
682 | return 1; | 540 | return 1; |
683 | 541 | ||
684 | failed: | 542 | failed: |
685 | #ifdef CONFIG_DMAR | ||
686 | dmar_disabled = 1; | ||
687 | #endif | ||
688 | return 0; | 543 | return 0; |
689 | } | 544 | } |
690 | 545 | ||
@@ -696,22 +551,21 @@ int __init detect_intel_iommu(void) | |||
696 | if (ret) | 551 | if (ret) |
697 | ret = check_zero_address(); | 552 | ret = check_zero_address(); |
698 | { | 553 | { |
699 | #ifdef CONFIG_INTR_REMAP | ||
700 | struct acpi_table_dmar *dmar; | 554 | struct acpi_table_dmar *dmar; |
701 | 555 | ||
702 | dmar = (struct acpi_table_dmar *) dmar_tbl; | 556 | dmar = (struct acpi_table_dmar *) dmar_tbl; |
703 | if (ret && cpu_has_x2apic && dmar->flags & 0x1) | 557 | |
558 | if (ret && intr_remapping_enabled && cpu_has_x2apic && | ||
559 | dmar->flags & 0x1) | ||
704 | printk(KERN_INFO | 560 | printk(KERN_INFO |
705 | "Queued invalidation will be enabled to support " | 561 | "Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); |
706 | "x2apic and Intr-remapping.\n"); | 562 | |
707 | #endif | ||
708 | #ifdef CONFIG_DMAR | ||
709 | if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { | 563 | if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { |
710 | iommu_detected = 1; | 564 | iommu_detected = 1; |
711 | /* Make sure ACS will be enabled */ | 565 | /* Make sure ACS will be enabled */ |
712 | pci_request_acs(); | 566 | pci_request_acs(); |
713 | } | 567 | } |
714 | #endif | 568 | |
715 | #ifdef CONFIG_X86 | 569 | #ifdef CONFIG_X86 |
716 | if (ret) | 570 | if (ret) |
717 | x86_init.iommu.iommu_init = intel_iommu_init; | 571 | x86_init.iommu.iommu_init = intel_iommu_init; |
@@ -758,7 +612,6 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
758 | goto err_unmap; | 612 | goto err_unmap; |
759 | } | 613 | } |
760 | 614 | ||
761 | #ifdef CONFIG_DMAR | ||
762 | agaw = iommu_calculate_agaw(iommu); | 615 | agaw = iommu_calculate_agaw(iommu); |
763 | if (agaw < 0) { | 616 | if (agaw < 0) { |
764 | printk(KERN_ERR | 617 | printk(KERN_ERR |
@@ -773,7 +626,6 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
773 | iommu->seq_id); | 626 | iommu->seq_id); |
774 | goto err_unmap; | 627 | goto err_unmap; |
775 | } | 628 | } |
776 | #endif | ||
777 | iommu->agaw = agaw; | 629 | iommu->agaw = agaw; |
778 | iommu->msagaw = msagaw; | 630 | iommu->msagaw = msagaw; |
779 | 631 | ||
@@ -817,9 +669,7 @@ void free_iommu(struct intel_iommu *iommu) | |||
817 | if (!iommu) | 669 | if (!iommu) |
818 | return; | 670 | return; |
819 | 671 | ||
820 | #ifdef CONFIG_DMAR | ||
821 | free_dmar_iommu(iommu); | 672 | free_dmar_iommu(iommu); |
822 | #endif | ||
823 | 673 | ||
824 | if (iommu->reg) | 674 | if (iommu->reg) |
825 | iounmap(iommu->reg); | 675 | iounmap(iommu->reg); |
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index a88f3cbb100b..f28d933c7927 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -398,11 +398,11 @@ static long list_size; | |||
398 | 398 | ||
399 | static void domain_remove_dev_info(struct dmar_domain *domain); | 399 | static void domain_remove_dev_info(struct dmar_domain *domain); |
400 | 400 | ||
401 | #ifdef CONFIG_DMAR_DEFAULT_ON | 401 | #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON |
402 | int dmar_disabled = 0; | 402 | int dmar_disabled = 0; |
403 | #else | 403 | #else |
404 | int dmar_disabled = 1; | 404 | int dmar_disabled = 1; |
405 | #endif /*CONFIG_DMAR_DEFAULT_ON*/ | 405 | #endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/ |
406 | 406 | ||
407 | static int dmar_map_gfx = 1; | 407 | static int dmar_map_gfx = 1; |
408 | static int dmar_forcedac; | 408 | static int dmar_forcedac; |
@@ -2157,7 +2157,7 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr, | |||
2157 | rmrr->end_address); | 2157 | rmrr->end_address); |
2158 | } | 2158 | } |
2159 | 2159 | ||
2160 | #ifdef CONFIG_DMAR_FLOPPY_WA | 2160 | #ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA |
2161 | static inline void iommu_prepare_isa(void) | 2161 | static inline void iommu_prepare_isa(void) |
2162 | { | 2162 | { |
2163 | struct pci_dev *pdev; | 2163 | struct pci_dev *pdev; |
@@ -2180,7 +2180,7 @@ static inline void iommu_prepare_isa(void) | |||
2180 | { | 2180 | { |
2181 | return; | 2181 | return; |
2182 | } | 2182 | } |
2183 | #endif /* !CONFIG_DMAR_FLPY_WA */ | 2183 | #endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */ |
2184 | 2184 | ||
2185 | static int md_domain_init(struct dmar_domain *domain, int guest_width); | 2185 | static int md_domain_init(struct dmar_domain *domain, int guest_width); |
2186 | 2186 | ||
@@ -2491,7 +2491,7 @@ static int __init init_dmars(void) | |||
2491 | if (iommu_pass_through) | 2491 | if (iommu_pass_through) |
2492 | iommu_identity_mapping |= IDENTMAP_ALL; | 2492 | iommu_identity_mapping |= IDENTMAP_ALL; |
2493 | 2493 | ||
2494 | #ifdef CONFIG_DMAR_BROKEN_GFX_WA | 2494 | #ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA |
2495 | iommu_identity_mapping |= IDENTMAP_GFX; | 2495 | iommu_identity_mapping |= IDENTMAP_GFX; |
2496 | #endif | 2496 | #endif |
2497 | 2497 | ||
@@ -3399,6 +3399,151 @@ static void __init init_iommu_pm_ops(void) | |||
3399 | static inline void init_iommu_pm_ops(void) {} | 3399 | static inline void init_iommu_pm_ops(void) {} |
3400 | #endif /* CONFIG_PM */ | 3400 | #endif /* CONFIG_PM */ |
3401 | 3401 | ||
3402 | LIST_HEAD(dmar_rmrr_units); | ||
3403 | |||
3404 | static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr) | ||
3405 | { | ||
3406 | list_add(&rmrr->list, &dmar_rmrr_units); | ||
3407 | } | ||
3408 | |||
3409 | |||
3410 | int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header) | ||
3411 | { | ||
3412 | struct acpi_dmar_reserved_memory *rmrr; | ||
3413 | struct dmar_rmrr_unit *rmrru; | ||
3414 | |||
3415 | rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); | ||
3416 | if (!rmrru) | ||
3417 | return -ENOMEM; | ||
3418 | |||
3419 | rmrru->hdr = header; | ||
3420 | rmrr = (struct acpi_dmar_reserved_memory *)header; | ||
3421 | rmrru->base_address = rmrr->base_address; | ||
3422 | rmrru->end_address = rmrr->end_address; | ||
3423 | |||
3424 | dmar_register_rmrr_unit(rmrru); | ||
3425 | return 0; | ||
3426 | } | ||
3427 | |||
3428 | static int __init | ||
3429 | rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) | ||
3430 | { | ||
3431 | struct acpi_dmar_reserved_memory *rmrr; | ||
3432 | int ret; | ||
3433 | |||
3434 | rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; | ||
3435 | ret = dmar_parse_dev_scope((void *)(rmrr + 1), | ||
3436 | ((void *)rmrr) + rmrr->header.length, | ||
3437 | &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); | ||
3438 | |||
3439 | if (ret || (rmrru->devices_cnt == 0)) { | ||
3440 | list_del(&rmrru->list); | ||
3441 | kfree(rmrru); | ||
3442 | } | ||
3443 | return ret; | ||
3444 | } | ||
3445 | |||
3446 | static LIST_HEAD(dmar_atsr_units); | ||
3447 | |||
3448 | int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr) | ||
3449 | { | ||
3450 | struct acpi_dmar_atsr *atsr; | ||
3451 | struct dmar_atsr_unit *atsru; | ||
3452 | |||
3453 | atsr = container_of(hdr, struct acpi_dmar_atsr, header); | ||
3454 | atsru = kzalloc(sizeof(*atsru), GFP_KERNEL); | ||
3455 | if (!atsru) | ||
3456 | return -ENOMEM; | ||
3457 | |||
3458 | atsru->hdr = hdr; | ||
3459 | atsru->include_all = atsr->flags & 0x1; | ||
3460 | |||
3461 | list_add(&atsru->list, &dmar_atsr_units); | ||
3462 | |||
3463 | return 0; | ||
3464 | } | ||
3465 | |||
3466 | static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) | ||
3467 | { | ||
3468 | int rc; | ||
3469 | struct acpi_dmar_atsr *atsr; | ||
3470 | |||
3471 | if (atsru->include_all) | ||
3472 | return 0; | ||
3473 | |||
3474 | atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); | ||
3475 | rc = dmar_parse_dev_scope((void *)(atsr + 1), | ||
3476 | (void *)atsr + atsr->header.length, | ||
3477 | &atsru->devices_cnt, &atsru->devices, | ||
3478 | atsr->segment); | ||
3479 | if (rc || !atsru->devices_cnt) { | ||
3480 | list_del(&atsru->list); | ||
3481 | kfree(atsru); | ||
3482 | } | ||
3483 | |||
3484 | return rc; | ||
3485 | } | ||
3486 | |||
3487 | int dmar_find_matched_atsr_unit(struct pci_dev *dev) | ||
3488 | { | ||
3489 | int i; | ||
3490 | struct pci_bus *bus; | ||
3491 | struct acpi_dmar_atsr *atsr; | ||
3492 | struct dmar_atsr_unit *atsru; | ||
3493 | |||
3494 | dev = pci_physfn(dev); | ||
3495 | |||
3496 | list_for_each_entry(atsru, &dmar_atsr_units, list) { | ||
3497 | atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); | ||
3498 | if (atsr->segment == pci_domain_nr(dev->bus)) | ||
3499 | goto found; | ||
3500 | } | ||
3501 | |||
3502 | return 0; | ||
3503 | |||
3504 | found: | ||
3505 | for (bus = dev->bus; bus; bus = bus->parent) { | ||
3506 | struct pci_dev *bridge = bus->self; | ||
3507 | |||
3508 | if (!bridge || !pci_is_pcie(bridge) || | ||
3509 | bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) | ||
3510 | return 0; | ||
3511 | |||
3512 | if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { | ||
3513 | for (i = 0; i < atsru->devices_cnt; i++) | ||
3514 | if (atsru->devices[i] == bridge) | ||
3515 | return 1; | ||
3516 | break; | ||
3517 | } | ||
3518 | } | ||
3519 | |||
3520 | if (atsru->include_all) | ||
3521 | return 1; | ||
3522 | |||
3523 | return 0; | ||
3524 | } | ||
3525 | |||
3526 | int dmar_parse_rmrr_atsr_dev(void) | ||
3527 | { | ||
3528 | struct dmar_rmrr_unit *rmrr, *rmrr_n; | ||
3529 | struct dmar_atsr_unit *atsr, *atsr_n; | ||
3530 | int ret = 0; | ||
3531 | |||
3532 | list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) { | ||
3533 | ret = rmrr_parse_dev(rmrr); | ||
3534 | if (ret) | ||
3535 | return ret; | ||
3536 | } | ||
3537 | |||
3538 | list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) { | ||
3539 | ret = atsr_parse_dev(atsr); | ||
3540 | if (ret) | ||
3541 | return ret; | ||
3542 | } | ||
3543 | |||
3544 | return ret; | ||
3545 | } | ||
3546 | |||
3402 | /* | 3547 | /* |
3403 | * Here we only respond to action of unbound device from driver. | 3548 | * Here we only respond to action of unbound device from driver. |
3404 | * | 3549 | * |
@@ -3448,16 +3593,12 @@ int __init intel_iommu_init(void) | |||
3448 | return -ENODEV; | 3593 | return -ENODEV; |
3449 | } | 3594 | } |
3450 | 3595 | ||
3451 | if (dmar_dev_scope_init()) { | 3596 | if (dmar_dev_scope_init() < 0) { |
3452 | if (force_on) | 3597 | if (force_on) |
3453 | panic("tboot: Failed to initialize DMAR device scope\n"); | 3598 | panic("tboot: Failed to initialize DMAR device scope\n"); |
3454 | return -ENODEV; | 3599 | return -ENODEV; |
3455 | } | 3600 | } |
3456 | 3601 | ||
3457 | /* | ||
3458 | * Check the need for DMA-remapping initialization now. | ||
3459 | * Above initialization will also be used by Interrupt-remapping. | ||
3460 | */ | ||
3461 | if (no_iommu || dmar_disabled) | 3602 | if (no_iommu || dmar_disabled) |
3462 | return -ENODEV; | 3603 | return -ENODEV; |
3463 | 3604 | ||
@@ -3467,6 +3608,12 @@ int __init intel_iommu_init(void) | |||
3467 | return -ENODEV; | 3608 | return -ENODEV; |
3468 | } | 3609 | } |
3469 | 3610 | ||
3611 | if (list_empty(&dmar_rmrr_units)) | ||
3612 | printk(KERN_INFO "DMAR: No RMRR found\n"); | ||
3613 | |||
3614 | if (list_empty(&dmar_atsr_units)) | ||
3615 | printk(KERN_INFO "DMAR: No ATSR found\n"); | ||
3616 | |||
3470 | if (dmar_init_reserved_ranges()) { | 3617 | if (dmar_init_reserved_ranges()) { |
3471 | if (force_on) | 3618 | if (force_on) |
3472 | panic("tboot: Failed to reserve iommu ranges\n"); | 3619 | panic("tboot: Failed to reserve iommu ranges\n"); |
diff --git a/drivers/iommu/intr_remapping.c b/drivers/iommu/intr_remapping.c index 1a89d4a2cadf..cfb0dd4bf0b6 100644 --- a/drivers/iommu/intr_remapping.c +++ b/drivers/iommu/intr_remapping.c | |||
@@ -21,6 +21,7 @@ int intr_remapping_enabled; | |||
21 | 21 | ||
22 | static int disable_intremap; | 22 | static int disable_intremap; |
23 | static int disable_sourceid_checking; | 23 | static int disable_sourceid_checking; |
24 | static int no_x2apic_optout; | ||
24 | 25 | ||
25 | static __init int setup_nointremap(char *str) | 26 | static __init int setup_nointremap(char *str) |
26 | { | 27 | { |
@@ -34,12 +35,20 @@ static __init int setup_intremap(char *str) | |||
34 | if (!str) | 35 | if (!str) |
35 | return -EINVAL; | 36 | return -EINVAL; |
36 | 37 | ||
37 | if (!strncmp(str, "on", 2)) | 38 | while (*str) { |
38 | disable_intremap = 0; | 39 | if (!strncmp(str, "on", 2)) |
39 | else if (!strncmp(str, "off", 3)) | 40 | disable_intremap = 0; |
40 | disable_intremap = 1; | 41 | else if (!strncmp(str, "off", 3)) |
41 | else if (!strncmp(str, "nosid", 5)) | 42 | disable_intremap = 1; |
42 | disable_sourceid_checking = 1; | 43 | else if (!strncmp(str, "nosid", 5)) |
44 | disable_sourceid_checking = 1; | ||
45 | else if (!strncmp(str, "no_x2apic_optout", 16)) | ||
46 | no_x2apic_optout = 1; | ||
47 | |||
48 | str += strcspn(str, ","); | ||
49 | while (*str == ',') | ||
50 | str++; | ||
51 | } | ||
43 | 52 | ||
44 | return 0; | 53 | return 0; |
45 | } | 54 | } |
@@ -501,6 +510,15 @@ end: | |||
501 | spin_unlock_irqrestore(&iommu->register_lock, flags); | 510 | spin_unlock_irqrestore(&iommu->register_lock, flags); |
502 | } | 511 | } |
503 | 512 | ||
513 | static int __init dmar_x2apic_optout(void) | ||
514 | { | ||
515 | struct acpi_table_dmar *dmar; | ||
516 | dmar = (struct acpi_table_dmar *)dmar_tbl; | ||
517 | if (!dmar || no_x2apic_optout) | ||
518 | return 0; | ||
519 | return dmar->flags & DMAR_X2APIC_OPT_OUT; | ||
520 | } | ||
521 | |||
504 | int __init intr_remapping_supported(void) | 522 | int __init intr_remapping_supported(void) |
505 | { | 523 | { |
506 | struct dmar_drhd_unit *drhd; | 524 | struct dmar_drhd_unit *drhd; |
@@ -521,16 +539,25 @@ int __init intr_remapping_supported(void) | |||
521 | return 1; | 539 | return 1; |
522 | } | 540 | } |
523 | 541 | ||
524 | int __init enable_intr_remapping(int eim) | 542 | int __init enable_intr_remapping(void) |
525 | { | 543 | { |
526 | struct dmar_drhd_unit *drhd; | 544 | struct dmar_drhd_unit *drhd; |
527 | int setup = 0; | 545 | int setup = 0; |
546 | int eim = 0; | ||
528 | 547 | ||
529 | if (parse_ioapics_under_ir() != 1) { | 548 | if (parse_ioapics_under_ir() != 1) { |
530 | printk(KERN_INFO "Not enable interrupt remapping\n"); | 549 | printk(KERN_INFO "Not enable interrupt remapping\n"); |
531 | return -1; | 550 | return -1; |
532 | } | 551 | } |
533 | 552 | ||
553 | if (x2apic_supported()) { | ||
554 | eim = !dmar_x2apic_optout(); | ||
555 | WARN(!eim, KERN_WARNING | ||
556 | "Your BIOS is broken and requested that x2apic be disabled\n" | ||
557 | "This will leave your machine vulnerable to irq-injection attacks\n" | ||
558 | "Use 'intremap=no_x2apic_optout' to override BIOS request\n"); | ||
559 | } | ||
560 | |||
534 | for_each_drhd_unit(drhd) { | 561 | for_each_drhd_unit(drhd) { |
535 | struct intel_iommu *iommu = drhd->iommu; | 562 | struct intel_iommu *iommu = drhd->iommu; |
536 | 563 | ||
@@ -606,8 +633,9 @@ int __init enable_intr_remapping(int eim) | |||
606 | goto error; | 633 | goto error; |
607 | 634 | ||
608 | intr_remapping_enabled = 1; | 635 | intr_remapping_enabled = 1; |
636 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); | ||
609 | 637 | ||
610 | return 0; | 638 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; |
611 | 639 | ||
612 | error: | 640 | error: |
613 | /* | 641 | /* |
@@ -745,6 +773,15 @@ int __init parse_ioapics_under_ir(void) | |||
745 | return ir_supported; | 773 | return ir_supported; |
746 | } | 774 | } |
747 | 775 | ||
776 | int ir_dev_scope_init(void) | ||
777 | { | ||
778 | if (!intr_remapping_enabled) | ||
779 | return 0; | ||
780 | |||
781 | return dmar_dev_scope_init(); | ||
782 | } | ||
783 | rootfs_initcall(ir_dev_scope_init); | ||
784 | |||
748 | void disable_intr_remapping(void) | 785 | void disable_intr_remapping(void) |
749 | { | 786 | { |
750 | struct dmar_drhd_unit *drhd; | 787 | struct dmar_drhd_unit *drhd; |