aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/dmar.c
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2009-03-16 20:04:54 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2009-03-17 18:37:06 -0400
commit0ac2491f57af5644f88383d28809760902d6f4d7 (patch)
tree0dcf5875ef83a5bd14cbe37f8b4671a4601cc797 /drivers/pci/dmar.c
parent4c5502b1c5744b2090414e1b80ca6388d5c46e06 (diff)
x86, dmar: move page fault handling code to dmar.c
Impact: code movement Move page fault handling code to dmar.c This will be shared both by DMA-remapping and Intr-remapping code. 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.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 5f333403c2ea..75d34bf2db50 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -31,6 +31,8 @@
31#include <linux/iova.h> 31#include <linux/iova.h>
32#include <linux/intel-iommu.h> 32#include <linux/intel-iommu.h>
33#include <linux/timer.h> 33#include <linux/timer.h>
34#include <linux/irq.h>
35#include <linux/interrupt.h>
34 36
35#undef PREFIX 37#undef PREFIX
36#define PREFIX "DMAR:" 38#define PREFIX "DMAR:"
@@ -812,3 +814,192 @@ int dmar_enable_qi(struct intel_iommu *iommu)
812 814
813 return 0; 815 return 0;
814} 816}
817
818/* iommu interrupt handling. Most stuff are MSI-like. */
819
820static const char *fault_reason_strings[] =
821{
822 "Software",
823 "Present bit in root entry is clear",
824 "Present bit in context entry is clear",
825 "Invalid context entry",
826 "Access beyond MGAW",
827 "PTE Write access is not set",
828 "PTE Read access is not set",
829 "Next page table ptr is invalid",
830 "Root table address invalid",
831 "Context table ptr is invalid",
832 "non-zero reserved fields in RTP",
833 "non-zero reserved fields in CTP",
834 "non-zero reserved fields in PTE",
835};
836#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1)
837
838const char *dmar_get_fault_reason(u8 fault_reason)
839{
840 if (fault_reason > MAX_FAULT_REASON_IDX)
841 return "Unknown";
842 else
843 return fault_reason_strings[fault_reason];
844}
845
846void dmar_msi_unmask(unsigned int irq)
847{
848 struct intel_iommu *iommu = get_irq_data(irq);
849 unsigned long flag;
850
851 /* unmask it */
852 spin_lock_irqsave(&iommu->register_lock, flag);
853 writel(0, iommu->reg + DMAR_FECTL_REG);
854 /* Read a reg to force flush the post write */
855 readl(iommu->reg + DMAR_FECTL_REG);
856 spin_unlock_irqrestore(&iommu->register_lock, flag);
857}
858
859void dmar_msi_mask(unsigned int irq)
860{
861 unsigned long flag;
862 struct intel_iommu *iommu = get_irq_data(irq);
863
864 /* mask it */
865 spin_lock_irqsave(&iommu->register_lock, flag);
866 writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
867 /* Read a reg to force flush the post write */
868 readl(iommu->reg + DMAR_FECTL_REG);
869 spin_unlock_irqrestore(&iommu->register_lock, flag);
870}
871
872void dmar_msi_write(int irq, struct msi_msg *msg)
873{
874 struct intel_iommu *iommu = get_irq_data(irq);
875 unsigned long flag;
876
877 spin_lock_irqsave(&iommu->register_lock, flag);
878 writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
879 writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
880 writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
881 spin_unlock_irqrestore(&iommu->register_lock, flag);
882}
883
884void dmar_msi_read(int irq, struct msi_msg *msg)
885{
886 struct intel_iommu *iommu = get_irq_data(irq);
887 unsigned long flag;
888
889 spin_lock_irqsave(&iommu->register_lock, flag);
890 msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
891 msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
892 msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
893 spin_unlock_irqrestore(&iommu->register_lock, flag);
894}
895
896static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
897 u8 fault_reason, u16 source_id, unsigned long long addr)
898{
899 const char *reason;
900
901 reason = dmar_get_fault_reason(fault_reason);
902
903 printk(KERN_ERR
904 "DMAR:[%s] Request device [%02x:%02x.%d] "
905 "fault addr %llx \n"
906 "DMAR:[fault reason %02d] %s\n",
907 (type ? "DMA Read" : "DMA Write"),
908 (source_id >> 8), PCI_SLOT(source_id & 0xFF),
909 PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
910 return 0;
911}
912
913#define PRIMARY_FAULT_REG_LEN (16)
914static irqreturn_t dmar_fault(int irq, void *dev_id)
915{
916 struct intel_iommu *iommu = dev_id;
917 int reg, fault_index;
918 u32 fault_status;
919 unsigned long flag;
920
921 spin_lock_irqsave(&iommu->register_lock, flag);
922 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
923
924 /* TBD: ignore advanced fault log currently */
925 if (!(fault_status & DMA_FSTS_PPF))
926 goto clear_overflow;
927
928 fault_index = dma_fsts_fault_record_index(fault_status);
929 reg = cap_fault_reg_offset(iommu->cap);
930 while (1) {
931 u8 fault_reason;
932 u16 source_id;
933 u64 guest_addr;
934 int type;
935 u32 data;
936
937 /* highest 32 bits */
938 data = readl(iommu->reg + reg +
939 fault_index * PRIMARY_FAULT_REG_LEN + 12);
940 if (!(data & DMA_FRCD_F))
941 break;
942
943 fault_reason = dma_frcd_fault_reason(data);
944 type = dma_frcd_type(data);
945
946 data = readl(iommu->reg + reg +
947 fault_index * PRIMARY_FAULT_REG_LEN + 8);
948 source_id = dma_frcd_source_id(data);
949
950 guest_addr = dmar_readq(iommu->reg + reg +
951 fault_index * PRIMARY_FAULT_REG_LEN);
952 guest_addr = dma_frcd_page_addr(guest_addr);
953 /* clear the fault */
954 writel(DMA_FRCD_F, iommu->reg + reg +
955 fault_index * PRIMARY_FAULT_REG_LEN + 12);
956
957 spin_unlock_irqrestore(&iommu->register_lock, flag);
958
959 dmar_fault_do_one(iommu, type, fault_reason,
960 source_id, guest_addr);
961
962 fault_index++;
963 if (fault_index > cap_num_fault_regs(iommu->cap))
964 fault_index = 0;
965 spin_lock_irqsave(&iommu->register_lock, flag);
966 }
967clear_overflow:
968 /* clear primary fault overflow */
969 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
970 if (fault_status & DMA_FSTS_PFO)
971 writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
972
973 spin_unlock_irqrestore(&iommu->register_lock, flag);
974 return IRQ_HANDLED;
975}
976
977int dmar_set_interrupt(struct intel_iommu *iommu)
978{
979 int irq, ret;
980
981 irq = create_irq();
982 if (!irq) {
983 printk(KERN_ERR "IOMMU: no free vectors\n");
984 return -EINVAL;
985 }
986
987 set_irq_data(irq, iommu);
988 iommu->irq = irq;
989
990 ret = arch_setup_dmar_msi(irq);
991 if (ret) {
992 set_irq_data(irq, NULL);
993 iommu->irq = 0;
994 destroy_irq(irq);
995 return 0;
996 }
997
998 /* Force fault register is cleared */
999 dmar_fault(irq, iommu);
1000
1001 ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu);
1002 if (ret)
1003 printk(KERN_ERR "IOMMU: can't request irq\n");
1004 return ret;
1005}