diff options
Diffstat (limited to 'drivers/pci/intr_remapping.c')
-rw-r--r-- | drivers/pci/intr_remapping.c | 84 |
1 files changed, 82 insertions, 2 deletions
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index b041a409f4a7..f5e0ea724a6f 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <asm/cpu.h> | 9 | #include <asm/cpu.h> |
10 | #include <linux/intel-iommu.h> | 10 | #include <linux/intel-iommu.h> |
11 | #include "intr_remapping.h" | 11 | #include "intr_remapping.h" |
12 | #include <acpi/acpi.h> | ||
12 | 13 | ||
13 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; | 14 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; |
14 | static int ir_ioapic_num; | 15 | static int ir_ioapic_num; |
@@ -415,12 +416,27 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) | |||
415 | 416 | ||
416 | /* Set interrupt-remapping table pointer */ | 417 | /* Set interrupt-remapping table pointer */ |
417 | cmd = iommu->gcmd | DMA_GCMD_SIRTP; | 418 | cmd = iommu->gcmd | DMA_GCMD_SIRTP; |
419 | iommu->gcmd |= DMA_GCMD_SIRTP; | ||
418 | writel(cmd, iommu->reg + DMAR_GCMD_REG); | 420 | writel(cmd, iommu->reg + DMAR_GCMD_REG); |
419 | 421 | ||
420 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, | 422 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, |
421 | readl, (sts & DMA_GSTS_IRTPS), sts); | 423 | readl, (sts & DMA_GSTS_IRTPS), sts); |
422 | spin_unlock_irqrestore(&iommu->register_lock, flags); | 424 | spin_unlock_irqrestore(&iommu->register_lock, flags); |
423 | 425 | ||
426 | if (mode == 0) { | ||
427 | spin_lock_irqsave(&iommu->register_lock, flags); | ||
428 | |||
429 | /* enable comaptiblity format interrupt pass through */ | ||
430 | cmd = iommu->gcmd | DMA_GCMD_CFI; | ||
431 | iommu->gcmd |= DMA_GCMD_CFI; | ||
432 | writel(cmd, iommu->reg + DMAR_GCMD_REG); | ||
433 | |||
434 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, | ||
435 | readl, (sts & DMA_GSTS_CFIS), sts); | ||
436 | |||
437 | spin_unlock_irqrestore(&iommu->register_lock, flags); | ||
438 | } | ||
439 | |||
424 | /* | 440 | /* |
425 | * global invalidation of interrupt entry cache before enabling | 441 | * global invalidation of interrupt entry cache before enabling |
426 | * interrupt-remapping. | 442 | * interrupt-remapping. |
@@ -470,7 +486,7 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode) | |||
470 | /* | 486 | /* |
471 | * Disable Interrupt Remapping. | 487 | * Disable Interrupt Remapping. |
472 | */ | 488 | */ |
473 | static void disable_intr_remapping(struct intel_iommu *iommu) | 489 | static void iommu_disable_intr_remapping(struct intel_iommu *iommu) |
474 | { | 490 | { |
475 | unsigned long flags; | 491 | unsigned long flags; |
476 | u32 sts; | 492 | u32 sts; |
@@ -478,6 +494,12 @@ static void disable_intr_remapping(struct intel_iommu *iommu) | |||
478 | if (!ecap_ir_support(iommu->ecap)) | 494 | if (!ecap_ir_support(iommu->ecap)) |
479 | return; | 495 | return; |
480 | 496 | ||
497 | /* | ||
498 | * global invalidation of interrupt entry cache before disabling | ||
499 | * interrupt-remapping. | ||
500 | */ | ||
501 | qi_global_iec(iommu); | ||
502 | |||
481 | spin_lock_irqsave(&iommu->register_lock, flags); | 503 | spin_lock_irqsave(&iommu->register_lock, flags); |
482 | 504 | ||
483 | sts = dmar_readq(iommu->reg + DMAR_GSTS_REG); | 505 | sts = dmar_readq(iommu->reg + DMAR_GSTS_REG); |
@@ -503,6 +525,13 @@ int __init enable_intr_remapping(int eim) | |||
503 | struct intel_iommu *iommu = drhd->iommu; | 525 | struct intel_iommu *iommu = drhd->iommu; |
504 | 526 | ||
505 | /* | 527 | /* |
528 | * If the queued invalidation is already initialized, | ||
529 | * shouldn't disable it. | ||
530 | */ | ||
531 | if (iommu->qi) | ||
532 | continue; | ||
533 | |||
534 | /* | ||
506 | * Clear previous faults. | 535 | * Clear previous faults. |
507 | */ | 536 | */ |
508 | dmar_fault(-1, iommu); | 537 | dmar_fault(-1, iommu); |
@@ -511,7 +540,7 @@ int __init enable_intr_remapping(int eim) | |||
511 | * Disable intr remapping and queued invalidation, if already | 540 | * Disable intr remapping and queued invalidation, if already |
512 | * enabled prior to OS handover. | 541 | * enabled prior to OS handover. |
513 | */ | 542 | */ |
514 | disable_intr_remapping(iommu); | 543 | iommu_disable_intr_remapping(iommu); |
515 | 544 | ||
516 | dmar_disable_qi(iommu); | 545 | dmar_disable_qi(iommu); |
517 | } | 546 | } |
@@ -639,3 +668,54 @@ int __init parse_ioapics_under_ir(void) | |||
639 | 668 | ||
640 | return ir_supported; | 669 | return ir_supported; |
641 | } | 670 | } |
671 | |||
672 | void disable_intr_remapping(void) | ||
673 | { | ||
674 | struct dmar_drhd_unit *drhd; | ||
675 | struct intel_iommu *iommu = NULL; | ||
676 | |||
677 | /* | ||
678 | * Disable Interrupt-remapping for all the DRHD's now. | ||
679 | */ | ||
680 | for_each_iommu(iommu, drhd) { | ||
681 | if (!ecap_ir_support(iommu->ecap)) | ||
682 | continue; | ||
683 | |||
684 | iommu_disable_intr_remapping(iommu); | ||
685 | } | ||
686 | } | ||
687 | |||
688 | int reenable_intr_remapping(int eim) | ||
689 | { | ||
690 | struct dmar_drhd_unit *drhd; | ||
691 | int setup = 0; | ||
692 | struct intel_iommu *iommu = NULL; | ||
693 | |||
694 | for_each_iommu(iommu, drhd) | ||
695 | if (iommu->qi) | ||
696 | dmar_reenable_qi(iommu); | ||
697 | |||
698 | /* | ||
699 | * Setup Interrupt-remapping for all the DRHD's now. | ||
700 | */ | ||
701 | for_each_iommu(iommu, drhd) { | ||
702 | if (!ecap_ir_support(iommu->ecap)) | ||
703 | continue; | ||
704 | |||
705 | /* Set up interrupt remapping for iommu.*/ | ||
706 | iommu_set_intr_remapping(iommu, eim); | ||
707 | setup = 1; | ||
708 | } | ||
709 | |||
710 | if (!setup) | ||
711 | goto error; | ||
712 | |||
713 | return 0; | ||
714 | |||
715 | error: | ||
716 | /* | ||
717 | * handle error condition gracefully here! | ||
718 | */ | ||
719 | return -1; | ||
720 | } | ||
721 | |||