aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/dmar.c70
1 files changed, 55 insertions, 15 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index d313039e2fdf..3fbe6af7ad71 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -790,14 +790,41 @@ end:
790} 790}
791 791
792/* 792/*
793 * Enable queued invalidation.
794 */
795static void __dmar_enable_qi(struct intel_iommu *iommu)
796{
797 u32 cmd, sts;
798 unsigned long flags;
799 struct q_inval *qi = iommu->qi;
800
801 qi->free_head = qi->free_tail = 0;
802 qi->free_cnt = QI_LENGTH;
803
804 spin_lock_irqsave(&iommu->register_lock, flags);
805
806 /* write zero to the tail reg */
807 writel(0, iommu->reg + DMAR_IQT_REG);
808
809 dmar_writeq(iommu->reg + DMAR_IQA_REG, virt_to_phys(qi->desc));
810
811 cmd = iommu->gcmd | DMA_GCMD_QIE;
812 iommu->gcmd |= DMA_GCMD_QIE;
813 writel(cmd, iommu->reg + DMAR_GCMD_REG);
814
815 /* Make sure hardware complete it */
816 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_QIES), sts);
817
818 spin_unlock_irqrestore(&iommu->register_lock, flags);
819}
820
821/*
793 * Enable Queued Invalidation interface. This is a must to support 822 * Enable Queued Invalidation interface. This is a must to support
794 * interrupt-remapping. Also used by DMA-remapping, which replaces 823 * interrupt-remapping. Also used by DMA-remapping, which replaces
795 * register based IOTLB invalidation. 824 * register based IOTLB invalidation.
796 */ 825 */
797int dmar_enable_qi(struct intel_iommu *iommu) 826int dmar_enable_qi(struct intel_iommu *iommu)
798{ 827{
799 u32 cmd, sts;
800 unsigned long flags;
801 struct q_inval *qi; 828 struct q_inval *qi;
802 829
803 if (!ecap_qis(iommu->ecap)) 830 if (!ecap_qis(iommu->ecap))
@@ -835,19 +862,7 @@ int dmar_enable_qi(struct intel_iommu *iommu)
835 862
836 spin_lock_init(&qi->q_lock); 863 spin_lock_init(&qi->q_lock);
837 864
838 spin_lock_irqsave(&iommu->register_lock, flags); 865 __dmar_enable_qi(iommu);
839 /* write zero to the tail reg */
840 writel(0, iommu->reg + DMAR_IQT_REG);
841
842 dmar_writeq(iommu->reg + DMAR_IQA_REG, virt_to_phys(qi->desc));
843
844 cmd = iommu->gcmd | DMA_GCMD_QIE;
845 iommu->gcmd |= DMA_GCMD_QIE;
846 writel(cmd, iommu->reg + DMAR_GCMD_REG);
847
848 /* Make sure hardware complete it */
849 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_QIES), sts);
850 spin_unlock_irqrestore(&iommu->register_lock, flags);
851 866
852 return 0; 867 return 0;
853} 868}
@@ -1102,3 +1117,28 @@ int __init enable_drhd_fault_handling(void)
1102 1117
1103 return 0; 1118 return 0;
1104} 1119}
1120
1121/*
1122 * Re-enable Queued Invalidation interface.
1123 */
1124int dmar_reenable_qi(struct intel_iommu *iommu)
1125{
1126 if (!ecap_qis(iommu->ecap))
1127 return -ENOENT;
1128
1129 if (!iommu->qi)
1130 return -ENOENT;
1131
1132 /*
1133 * First disable queued invalidation.
1134 */
1135 dmar_disable_qi(iommu);
1136 /*
1137 * Then enable queued invalidation again. Since there is no pending
1138 * invalidation requests now, it's safe to re-enable queued
1139 * invalidation.
1140 */
1141 __dmar_enable_qi(iommu);
1142
1143 return 0;
1144}