aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/dmar.c
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2009-03-16 20:04:55 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2009-03-17 18:38:59 -0400
commit9d783ba042771284fb4ee5013c3d94220755ae7f (patch)
tree102ec9f89d363589108ae35e4b38c12fc6e2765c /drivers/pci/dmar.c
parent0ac2491f57af5644f88383d28809760902d6f4d7 (diff)
x86, x2apic: enable fault handling for intr-remapping
Impact: interface augmentation (not yet used) Enable fault handling flow for intr-remapping aswell. Fault handling code now shared by both dma-remapping and intr-remapping. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'drivers/pci/dmar.c')
-rw-r--r--drivers/pci/dmar.c102
1 files changed, 84 insertions, 18 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 75d34bf2db50..bb4ed985f9c7 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -511,6 +511,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
511 return -ENOMEM; 511 return -ENOMEM;
512 512
513 iommu->seq_id = iommu_allocated++; 513 iommu->seq_id = iommu_allocated++;
514 sprintf (iommu->name, "dmar%d", iommu->seq_id);
514 515
515 iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE); 516 iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
516 if (!iommu->reg) { 517 if (!iommu->reg) {
@@ -817,7 +818,13 @@ int dmar_enable_qi(struct intel_iommu *iommu)
817 818
818/* iommu interrupt handling. Most stuff are MSI-like. */ 819/* iommu interrupt handling. Most stuff are MSI-like. */
819 820
820static const char *fault_reason_strings[] = 821enum faulttype {
822 DMA_REMAP,
823 INTR_REMAP,
824 UNKNOWN,
825};
826
827static const char *dma_remap_fault_reasons[] =
821{ 828{
822 "Software", 829 "Software",
823 "Present bit in root entry is clear", 830 "Present bit in root entry is clear",
@@ -833,14 +840,33 @@ static const char *fault_reason_strings[] =
833 "non-zero reserved fields in CTP", 840 "non-zero reserved fields in CTP",
834 "non-zero reserved fields in PTE", 841 "non-zero reserved fields in PTE",
835}; 842};
843
844static const char *intr_remap_fault_reasons[] =
845{
846 "Detected reserved fields in the decoded interrupt-remapped request",
847 "Interrupt index exceeded the interrupt-remapping table size",
848 "Present field in the IRTE entry is clear",
849 "Error accessing interrupt-remapping table pointed by IRTA_REG",
850 "Detected reserved fields in the IRTE entry",
851 "Blocked a compatibility format interrupt request",
852 "Blocked an interrupt request due to source-id verification failure",
853};
854
836#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1) 855#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1)
837 856
838const char *dmar_get_fault_reason(u8 fault_reason) 857const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
839{ 858{
840 if (fault_reason > MAX_FAULT_REASON_IDX) 859 if (fault_reason >= 0x20 && (fault_reason <= 0x20 +
860 ARRAY_SIZE(intr_remap_fault_reasons))) {
861 *fault_type = INTR_REMAP;
862 return intr_remap_fault_reasons[fault_reason - 0x20];
863 } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) {
864 *fault_type = DMA_REMAP;
865 return dma_remap_fault_reasons[fault_reason];
866 } else {
867 *fault_type = UNKNOWN;
841 return "Unknown"; 868 return "Unknown";
842 else 869 }
843 return fault_reason_strings[fault_reason];
844} 870}
845 871
846void dmar_msi_unmask(unsigned int irq) 872void dmar_msi_unmask(unsigned int irq)
@@ -897,16 +923,25 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
897 u8 fault_reason, u16 source_id, unsigned long long addr) 923 u8 fault_reason, u16 source_id, unsigned long long addr)
898{ 924{
899 const char *reason; 925 const char *reason;
926 int fault_type;
900 927
901 reason = dmar_get_fault_reason(fault_reason); 928 reason = dmar_get_fault_reason(fault_reason, &fault_type);
902 929
903 printk(KERN_ERR 930 if (fault_type == INTR_REMAP)
904 "DMAR:[%s] Request device [%02x:%02x.%d] " 931 printk(KERN_ERR "INTR-REMAP: Request device [[%02x:%02x.%d] "
905 "fault addr %llx \n" 932 "fault index %llx\n"
906 "DMAR:[fault reason %02d] %s\n", 933 "INTR-REMAP:[fault reason %02d] %s\n",
907 (type ? "DMA Read" : "DMA Write"), 934 (source_id >> 8), PCI_SLOT(source_id & 0xFF),
908 (source_id >> 8), PCI_SLOT(source_id & 0xFF), 935 PCI_FUNC(source_id & 0xFF), addr >> 48,
909 PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason); 936 fault_reason, reason);
937 else
938 printk(KERN_ERR
939 "DMAR:[%s] Request device [%02x:%02x.%d] "
940 "fault addr %llx \n"
941 "DMAR:[fault reason %02d] %s\n",
942 (type ? "DMA Read" : "DMA Write"),
943 (source_id >> 8), PCI_SLOT(source_id & 0xFF),
944 PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
910 return 0; 945 return 0;
911} 946}
912 947
@@ -920,10 +955,13 @@ static irqreturn_t dmar_fault(int irq, void *dev_id)
920 955
921 spin_lock_irqsave(&iommu->register_lock, flag); 956 spin_lock_irqsave(&iommu->register_lock, flag);
922 fault_status = readl(iommu->reg + DMAR_FSTS_REG); 957 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
958 if (fault_status)
959 printk(KERN_ERR "DRHD: handling fault status reg %x\n",
960 fault_status);
923 961
924 /* TBD: ignore advanced fault log currently */ 962 /* TBD: ignore advanced fault log currently */
925 if (!(fault_status & DMA_FSTS_PPF)) 963 if (!(fault_status & DMA_FSTS_PPF))
926 goto clear_overflow; 964 goto clear_rest;
927 965
928 fault_index = dma_fsts_fault_record_index(fault_status); 966 fault_index = dma_fsts_fault_record_index(fault_status);
929 reg = cap_fault_reg_offset(iommu->cap); 967 reg = cap_fault_reg_offset(iommu->cap);
@@ -964,11 +1002,10 @@ static irqreturn_t dmar_fault(int irq, void *dev_id)
964 fault_index = 0; 1002 fault_index = 0;
965 spin_lock_irqsave(&iommu->register_lock, flag); 1003 spin_lock_irqsave(&iommu->register_lock, flag);
966 } 1004 }
967clear_overflow: 1005clear_rest:
968 /* clear primary fault overflow */ 1006 /* clear all the other faults */
969 fault_status = readl(iommu->reg + DMAR_FSTS_REG); 1007 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
970 if (fault_status & DMA_FSTS_PFO) 1008 writel(fault_status, iommu->reg + DMAR_FSTS_REG);
971 writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
972 1009
973 spin_unlock_irqrestore(&iommu->register_lock, flag); 1010 spin_unlock_irqrestore(&iommu->register_lock, flag);
974 return IRQ_HANDLED; 1011 return IRQ_HANDLED;
@@ -978,6 +1015,12 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
978{ 1015{
979 int irq, ret; 1016 int irq, ret;
980 1017
1018 /*
1019 * Check if the fault interrupt is already initialized.
1020 */
1021 if (iommu->irq)
1022 return 0;
1023
981 irq = create_irq(); 1024 irq = create_irq();
982 if (!irq) { 1025 if (!irq) {
983 printk(KERN_ERR "IOMMU: no free vectors\n"); 1026 printk(KERN_ERR "IOMMU: no free vectors\n");
@@ -1003,3 +1046,26 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
1003 printk(KERN_ERR "IOMMU: can't request irq\n"); 1046 printk(KERN_ERR "IOMMU: can't request irq\n");
1004 return ret; 1047 return ret;
1005} 1048}
1049
1050int __init enable_drhd_fault_handling(void)
1051{
1052 struct dmar_drhd_unit *drhd;
1053
1054 /*
1055 * Enable fault control interrupt.
1056 */
1057 for_each_drhd_unit(drhd) {
1058 int ret;
1059 struct intel_iommu *iommu = drhd->iommu;
1060 ret = dmar_set_interrupt(iommu);
1061
1062 if (ret) {
1063 printk(KERN_ERR "DRHD %Lx: failed to enable fault, "
1064 " interrupt, ret %d\n",
1065 (unsigned long long)drhd->reg_base_addr, ret);
1066 return -1;
1067 }
1068 }
1069
1070 return 0;
1071}