aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Zhao <yu.zhao@intel.com>2009-05-18 01:51:35 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-05-18 09:45:13 -0400
commit6ba6c3a4cacfd68bf970e3e04e2ff0d66fa0f695 (patch)
tree02afc5c010ec841f7e6ad9fc68e8a76f7f18909a
parentaa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7 (diff)
VT-d: add device IOTLB invalidation support
Support device IOTLB invalidation to flush the translation cached in the Endpoint. Signed-off-by: Yu Zhao <yu.zhao@intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/pci/dmar.c77
-rw-r--r--include/linux/intel-iommu.h14
2 files changed, 82 insertions, 9 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 6d7f9619b8a9..7b287cb38b7a 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -699,7 +699,8 @@ void free_iommu(struct intel_iommu *iommu)
699 */ 699 */
700static inline void reclaim_free_desc(struct q_inval *qi) 700static inline void reclaim_free_desc(struct q_inval *qi)
701{ 701{
702 while (qi->desc_status[qi->free_tail] == QI_DONE) { 702 while (qi->desc_status[qi->free_tail] == QI_DONE ||
703 qi->desc_status[qi->free_tail] == QI_ABORT) {
703 qi->desc_status[qi->free_tail] = QI_FREE; 704 qi->desc_status[qi->free_tail] = QI_FREE;
704 qi->free_tail = (qi->free_tail + 1) % QI_LENGTH; 705 qi->free_tail = (qi->free_tail + 1) % QI_LENGTH;
705 qi->free_cnt++; 706 qi->free_cnt++;
@@ -709,10 +710,13 @@ static inline void reclaim_free_desc(struct q_inval *qi)
709static int qi_check_fault(struct intel_iommu *iommu, int index) 710static int qi_check_fault(struct intel_iommu *iommu, int index)
710{ 711{
711 u32 fault; 712 u32 fault;
712 int head; 713 int head, tail;
713 struct q_inval *qi = iommu->qi; 714 struct q_inval *qi = iommu->qi;
714 int wait_index = (index + 1) % QI_LENGTH; 715 int wait_index = (index + 1) % QI_LENGTH;
715 716
717 if (qi->desc_status[wait_index] == QI_ABORT)
718 return -EAGAIN;
719
716 fault = readl(iommu->reg + DMAR_FSTS_REG); 720 fault = readl(iommu->reg + DMAR_FSTS_REG);
717 721
718 /* 722 /*
@@ -722,7 +726,11 @@ static int qi_check_fault(struct intel_iommu *iommu, int index)
722 */ 726 */
723 if (fault & DMA_FSTS_IQE) { 727 if (fault & DMA_FSTS_IQE) {
724 head = readl(iommu->reg + DMAR_IQH_REG); 728 head = readl(iommu->reg + DMAR_IQH_REG);
725 if ((head >> 4) == index) { 729 if ((head >> DMAR_IQ_SHIFT) == index) {
730 printk(KERN_ERR "VT-d detected invalid descriptor: "
731 "low=%llx, high=%llx\n",
732 (unsigned long long)qi->desc[index].low,
733 (unsigned long long)qi->desc[index].high);
726 memcpy(&qi->desc[index], &qi->desc[wait_index], 734 memcpy(&qi->desc[index], &qi->desc[wait_index],
727 sizeof(struct qi_desc)); 735 sizeof(struct qi_desc));
728 __iommu_flush_cache(iommu, &qi->desc[index], 736 __iommu_flush_cache(iommu, &qi->desc[index],
@@ -732,6 +740,32 @@ static int qi_check_fault(struct intel_iommu *iommu, int index)
732 } 740 }
733 } 741 }
734 742
743 /*
744 * If ITE happens, all pending wait_desc commands are aborted.
745 * No new descriptors are fetched until the ITE is cleared.
746 */
747 if (fault & DMA_FSTS_ITE) {
748 head = readl(iommu->reg + DMAR_IQH_REG);
749 head = ((head >> DMAR_IQ_SHIFT) - 1 + QI_LENGTH) % QI_LENGTH;
750 head |= 1;
751 tail = readl(iommu->reg + DMAR_IQT_REG);
752 tail = ((tail >> DMAR_IQ_SHIFT) - 1 + QI_LENGTH) % QI_LENGTH;
753
754 writel(DMA_FSTS_ITE, iommu->reg + DMAR_FSTS_REG);
755
756 do {
757 if (qi->desc_status[head] == QI_IN_USE)
758 qi->desc_status[head] = QI_ABORT;
759 head = (head - 2 + QI_LENGTH) % QI_LENGTH;
760 } while (head != tail);
761
762 if (qi->desc_status[wait_index] == QI_ABORT)
763 return -EAGAIN;
764 }
765
766 if (fault & DMA_FSTS_ICE)
767 writel(DMA_FSTS_ICE, iommu->reg + DMAR_FSTS_REG);
768
735 return 0; 769 return 0;
736} 770}
737 771
@@ -741,7 +775,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index)
741 */ 775 */
742int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) 776int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
743{ 777{
744 int rc = 0; 778 int rc;
745 struct q_inval *qi = iommu->qi; 779 struct q_inval *qi = iommu->qi;
746 struct qi_desc *hw, wait_desc; 780 struct qi_desc *hw, wait_desc;
747 int wait_index, index; 781 int wait_index, index;
@@ -752,6 +786,9 @@ int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
752 786
753 hw = qi->desc; 787 hw = qi->desc;
754 788
789restart:
790 rc = 0;
791
755 spin_lock_irqsave(&qi->q_lock, flags); 792 spin_lock_irqsave(&qi->q_lock, flags);
756 while (qi->free_cnt < 3) { 793 while (qi->free_cnt < 3) {
757 spin_unlock_irqrestore(&qi->q_lock, flags); 794 spin_unlock_irqrestore(&qi->q_lock, flags);
@@ -782,7 +819,7 @@ int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
782 * update the HW tail register indicating the presence of 819 * update the HW tail register indicating the presence of
783 * new descriptors. 820 * new descriptors.
784 */ 821 */
785 writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG); 822 writel(qi->free_head << DMAR_IQ_SHIFT, iommu->reg + DMAR_IQT_REG);
786 823
787 while (qi->desc_status[wait_index] != QI_DONE) { 824 while (qi->desc_status[wait_index] != QI_DONE) {
788 /* 825 /*
@@ -794,18 +831,21 @@ int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
794 */ 831 */
795 rc = qi_check_fault(iommu, index); 832 rc = qi_check_fault(iommu, index);
796 if (rc) 833 if (rc)
797 goto out; 834 break;
798 835
799 spin_unlock(&qi->q_lock); 836 spin_unlock(&qi->q_lock);
800 cpu_relax(); 837 cpu_relax();
801 spin_lock(&qi->q_lock); 838 spin_lock(&qi->q_lock);
802 } 839 }
803out: 840
804 qi->desc_status[index] = qi->desc_status[wait_index] = QI_DONE; 841 qi->desc_status[index] = QI_DONE;
805 842
806 reclaim_free_desc(qi); 843 reclaim_free_desc(qi);
807 spin_unlock_irqrestore(&qi->q_lock, flags); 844 spin_unlock_irqrestore(&qi->q_lock, flags);
808 845
846 if (rc == -EAGAIN)
847 goto restart;
848
809 return rc; 849 return rc;
810} 850}
811 851
@@ -857,6 +897,27 @@ void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
857 qi_submit_sync(&desc, iommu); 897 qi_submit_sync(&desc, iommu);
858} 898}
859 899
900void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep,
901 u64 addr, unsigned mask)
902{
903 struct qi_desc desc;
904
905 if (mask) {
906 BUG_ON(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1));
907 addr |= (1 << (VTD_PAGE_SHIFT + mask - 1)) - 1;
908 desc.high = QI_DEV_IOTLB_ADDR(addr) | QI_DEV_IOTLB_SIZE;
909 } else
910 desc.high = QI_DEV_IOTLB_ADDR(addr);
911
912 if (qdep >= QI_DEV_IOTLB_MAX_INVS)
913 qdep = 0;
914
915 desc.low = QI_DEV_IOTLB_SID(sid) | QI_DEV_IOTLB_QDEP(qdep) |
916 QI_DIOTLB_TYPE;
917
918 qi_submit_sync(&desc, iommu);
919}
920
860/* 921/*
861 * Disable Queued Invalidation interface. 922 * Disable Queued Invalidation interface.
862 */ 923 */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 0a1939f200fc..40561b224a17 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -53,6 +53,7 @@
53#define DMAR_PHMLIMIT_REG 0x78 /* pmrr high limit */ 53#define DMAR_PHMLIMIT_REG 0x78 /* pmrr high limit */
54#define DMAR_IQH_REG 0x80 /* Invalidation queue head register */ 54#define DMAR_IQH_REG 0x80 /* Invalidation queue head register */
55#define DMAR_IQT_REG 0x88 /* Invalidation queue tail register */ 55#define DMAR_IQT_REG 0x88 /* Invalidation queue tail register */
56#define DMAR_IQ_SHIFT 4 /* Invalidation queue head/tail shift */
56#define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */ 57#define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */
57#define DMAR_ICS_REG 0x98 /* Invalidation complete status register */ 58#define DMAR_ICS_REG 0x98 /* Invalidation complete status register */
58#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr register */ 59#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr register */
@@ -198,6 +199,8 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
198#define DMA_FSTS_PPF ((u32)2) 199#define DMA_FSTS_PPF ((u32)2)
199#define DMA_FSTS_PFO ((u32)1) 200#define DMA_FSTS_PFO ((u32)1)
200#define DMA_FSTS_IQE (1 << 4) 201#define DMA_FSTS_IQE (1 << 4)
202#define DMA_FSTS_ICE (1 << 5)
203#define DMA_FSTS_ITE (1 << 6)
201#define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff) 204#define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff)
202 205
203/* FRCD_REG, 32 bits access */ 206/* FRCD_REG, 32 bits access */
@@ -226,7 +229,8 @@ do { \
226enum { 229enum {
227 QI_FREE, 230 QI_FREE,
228 QI_IN_USE, 231 QI_IN_USE,
229 QI_DONE 232 QI_DONE,
233 QI_ABORT
230}; 234};
231 235
232#define QI_CC_TYPE 0x1 236#define QI_CC_TYPE 0x1
@@ -255,6 +259,12 @@ enum {
255#define QI_CC_DID(did) (((u64)did) << 16) 259#define QI_CC_DID(did) (((u64)did) << 16)
256#define QI_CC_GRAN(gran) (((u64)gran) >> (DMA_CCMD_INVL_GRANU_OFFSET-4)) 260#define QI_CC_GRAN(gran) (((u64)gran) >> (DMA_CCMD_INVL_GRANU_OFFSET-4))
257 261
262#define QI_DEV_IOTLB_SID(sid) ((u64)((sid) & 0xffff) << 32)
263#define QI_DEV_IOTLB_QDEP(qdep) (((qdep) & 0x1f) << 16)
264#define QI_DEV_IOTLB_ADDR(addr) ((u64)(addr) & VTD_PAGE_MASK)
265#define QI_DEV_IOTLB_SIZE 1
266#define QI_DEV_IOTLB_MAX_INVS 32
267
258struct qi_desc { 268struct qi_desc {
259 u64 low, high; 269 u64 low, high;
260}; 270};
@@ -344,6 +354,8 @@ extern void qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid,
344 u8 fm, u64 type); 354 u8 fm, u64 type);
345extern void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, 355extern void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
346 unsigned int size_order, u64 type); 356 unsigned int size_order, u64 type);
357extern void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep,
358 u64 addr, unsigned mask);
347 359
348extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu); 360extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
349 361