diff options
Diffstat (limited to 'drivers/iommu/intel_irq_remapping.c')
-rw-r--r-- | drivers/iommu/intel_irq_remapping.c | 48 |
1 files changed, 40 insertions, 8 deletions
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index af8904de1d44..f3b8f23b5d8f 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c | |||
@@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
68 | { | 68 | { |
69 | struct ir_table *table = iommu->ir_table; | 69 | struct ir_table *table = iommu->ir_table; |
70 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 70 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
71 | struct irq_cfg *cfg = irq_get_chip_data(irq); | ||
71 | u16 index, start_index; | 72 | u16 index, start_index; |
72 | unsigned int mask = 0; | 73 | unsigned int mask = 0; |
73 | unsigned long flags; | 74 | unsigned long flags; |
@@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
115 | for (i = index; i < index + count; i++) | 116 | for (i = index; i < index + count; i++) |
116 | table->base[i].present = 1; | 117 | table->base[i].present = 1; |
117 | 118 | ||
119 | cfg->remapped = 1; | ||
118 | irq_iommu->iommu = iommu; | 120 | irq_iommu->iommu = iommu; |
119 | irq_iommu->irte_index = index; | 121 | irq_iommu->irte_index = index; |
120 | irq_iommu->sub_handle = 0; | 122 | irq_iommu->sub_handle = 0; |
@@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle) | |||
155 | static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) | 157 | static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) |
156 | { | 158 | { |
157 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 159 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
160 | struct irq_cfg *cfg = irq_get_chip_data(irq); | ||
158 | unsigned long flags; | 161 | unsigned long flags; |
159 | 162 | ||
160 | if (!irq_iommu) | 163 | if (!irq_iommu) |
@@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha | |||
162 | 165 | ||
163 | raw_spin_lock_irqsave(&irq_2_ir_lock, flags); | 166 | raw_spin_lock_irqsave(&irq_2_ir_lock, flags); |
164 | 167 | ||
168 | cfg->remapped = 1; | ||
165 | irq_iommu->iommu = iommu; | 169 | irq_iommu->iommu = iommu; |
166 | irq_iommu->irte_index = index; | 170 | irq_iommu->irte_index = index; |
167 | irq_iommu->sub_handle = subhandle; | 171 | irq_iommu->sub_handle = subhandle; |
@@ -425,11 +429,22 @@ static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode) | |||
425 | 429 | ||
426 | /* Enable interrupt-remapping */ | 430 | /* Enable interrupt-remapping */ |
427 | iommu->gcmd |= DMA_GCMD_IRE; | 431 | iommu->gcmd |= DMA_GCMD_IRE; |
432 | iommu->gcmd &= ~DMA_GCMD_CFI; /* Block compatibility-format MSIs */ | ||
428 | writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); | 433 | writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); |
429 | 434 | ||
430 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, | 435 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, |
431 | readl, (sts & DMA_GSTS_IRES), sts); | 436 | readl, (sts & DMA_GSTS_IRES), sts); |
432 | 437 | ||
438 | /* | ||
439 | * With CFI clear in the Global Command register, we should be | ||
440 | * protected from dangerous (i.e. compatibility) interrupts | ||
441 | * regardless of x2apic status. Check just to be sure. | ||
442 | */ | ||
443 | if (sts & DMA_GSTS_CFIS) | ||
444 | WARN(1, KERN_WARNING | ||
445 | "Compatibility-format IRQs enabled despite intr remapping;\n" | ||
446 | "you are vulnerable to IRQ injection.\n"); | ||
447 | |||
433 | raw_spin_unlock_irqrestore(&iommu->register_lock, flags); | 448 | raw_spin_unlock_irqrestore(&iommu->register_lock, flags); |
434 | } | 449 | } |
435 | 450 | ||
@@ -526,20 +541,24 @@ static int __init intel_irq_remapping_supported(void) | |||
526 | static int __init intel_enable_irq_remapping(void) | 541 | static int __init intel_enable_irq_remapping(void) |
527 | { | 542 | { |
528 | struct dmar_drhd_unit *drhd; | 543 | struct dmar_drhd_unit *drhd; |
544 | bool x2apic_present; | ||
529 | int setup = 0; | 545 | int setup = 0; |
530 | int eim = 0; | 546 | int eim = 0; |
531 | 547 | ||
548 | x2apic_present = x2apic_supported(); | ||
549 | |||
532 | if (parse_ioapics_under_ir() != 1) { | 550 | if (parse_ioapics_under_ir() != 1) { |
533 | printk(KERN_INFO "Not enable interrupt remapping\n"); | 551 | printk(KERN_INFO "Not enable interrupt remapping\n"); |
534 | return -1; | 552 | goto error; |
535 | } | 553 | } |
536 | 554 | ||
537 | if (x2apic_supported()) { | 555 | if (x2apic_present) { |
538 | eim = !dmar_x2apic_optout(); | 556 | eim = !dmar_x2apic_optout(); |
539 | WARN(!eim, KERN_WARNING | 557 | if (!eim) |
540 | "Your BIOS is broken and requested that x2apic be disabled\n" | 558 | printk(KERN_WARNING |
541 | "This will leave your machine vulnerable to irq-injection attacks\n" | 559 | "Your BIOS is broken and requested that x2apic be disabled.\n" |
542 | "Use 'intremap=no_x2apic_optout' to override BIOS request\n"); | 560 | "This will slightly decrease performance.\n" |
561 | "Use 'intremap=no_x2apic_optout' to override BIOS request.\n"); | ||
543 | } | 562 | } |
544 | 563 | ||
545 | for_each_drhd_unit(drhd) { | 564 | for_each_drhd_unit(drhd) { |
@@ -578,7 +597,7 @@ static int __init intel_enable_irq_remapping(void) | |||
578 | if (eim && !ecap_eim_support(iommu->ecap)) { | 597 | if (eim && !ecap_eim_support(iommu->ecap)) { |
579 | printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " | 598 | printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " |
580 | " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); | 599 | " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); |
581 | return -1; | 600 | goto error; |
582 | } | 601 | } |
583 | } | 602 | } |
584 | 603 | ||
@@ -594,7 +613,7 @@ static int __init intel_enable_irq_remapping(void) | |||
594 | printk(KERN_ERR "DRHD %Lx: failed to enable queued, " | 613 | printk(KERN_ERR "DRHD %Lx: failed to enable queued, " |
595 | " invalidation, ecap %Lx, ret %d\n", | 614 | " invalidation, ecap %Lx, ret %d\n", |
596 | drhd->reg_base_addr, iommu->ecap, ret); | 615 | drhd->reg_base_addr, iommu->ecap, ret); |
597 | return -1; | 616 | goto error; |
598 | } | 617 | } |
599 | } | 618 | } |
600 | 619 | ||
@@ -617,6 +636,14 @@ static int __init intel_enable_irq_remapping(void) | |||
617 | goto error; | 636 | goto error; |
618 | 637 | ||
619 | irq_remapping_enabled = 1; | 638 | irq_remapping_enabled = 1; |
639 | |||
640 | /* | ||
641 | * VT-d has a different layout for IO-APIC entries when | ||
642 | * interrupt remapping is enabled. So it needs a special routine | ||
643 | * to print IO-APIC entries for debugging purposes too. | ||
644 | */ | ||
645 | x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries; | ||
646 | |||
620 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); | 647 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); |
621 | 648 | ||
622 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; | 649 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; |
@@ -625,6 +652,11 @@ error: | |||
625 | /* | 652 | /* |
626 | * handle error condition gracefully here! | 653 | * handle error condition gracefully here! |
627 | */ | 654 | */ |
655 | |||
656 | if (x2apic_present) | ||
657 | WARN(1, KERN_WARNING | ||
658 | "Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); | ||
659 | |||
628 | return -1; | 660 | return -1; |
629 | } | 661 | } |
630 | 662 | ||