From: "Keshavamurthy, Anil S" <anil.s.keshavamurthy@intel.com>
To: akpm@linux-foundation.org, linux-kernel@vger.kernel.org
Cc: ak@suse.de, gregkh@suse.de, muli@il.ibm.com,
suresh.b.siddha@intel.com, arjan@linux.intel.com,
ashok.raj@intel.com, davem@davemloft.net, clameter@sgi.com,
Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Subject: [Intel IOMMU 08/10] DMAR fault handling support
Date: Tue, 19 Jun 2007 14:37:09 -0700 [thread overview]
Message-ID: <20070619213808.956237000@askeshav-devel.jf.intel.com> (raw)
In-Reply-To: <20070619213701.219910000@askeshav-devel.jf.intel.com>
[-- Attachment #1: dmar_fault_handling_support.patch --]
[-- Type: text/plain, Size: 10354 bytes --]
MSI interrupt handler registrations and fault handling support
for Intel-IOMMU hadrware.
This patch enables the MSI interrupts for the DMA remapping units
and in the interrupt handler read the fault cause and outputs the
same on to the console.
Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
---
Documentation/Intel-IOMMU.txt | 17 +++
arch/x86_64/kernel/io_apic.c | 59 ++++++++++++
drivers/pci/intel-iommu.c | 194 ++++++++++++++++++++++++++++++++++++++++++
include/linux/dmar.h | 12 ++
4 files changed, 281 insertions(+), 1 deletion(-)
Index: linux-2.6.22-rc4-mm2/Documentation/Intel-IOMMU.txt
===================================================================
--- linux-2.6.22-rc4-mm2.orig/Documentation/Intel-IOMMU.txt 2007-06-18 15:45:46.000000000 -0700
+++ linux-2.6.22-rc4-mm2/Documentation/Intel-IOMMU.txt 2007-06-19 13:05:03.000000000 -0700
@@ -63,6 +63,15 @@
The same is true for peer to peer transactions. Hence we reserve the
address from PCI MMIO ranges so they are not allocated for IOVA addresses.
+
+Fault reporting
+---------------
+When errors are reported, the DMA engine signals via an interrupt. The fault
+reason and device that caused it with fault reason is printed on console.
+
+See below for sample.
+
+
Boot Message Sample
-------------------
@@ -85,6 +94,14 @@
PCI-DMA: Using DMAR IOMMU
+Fault reporting
+---------------
+
+DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000
+DMAR:[fault reason 05] PTE Write access is not set
+DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000
+DMAR:[fault reason 05] PTE Write access is not set
+
TBD
----
Index: linux-2.6.22-rc4-mm2/arch/x86_64/kernel/io_apic.c
===================================================================
--- linux-2.6.22-rc4-mm2.orig/arch/x86_64/kernel/io_apic.c 2007-06-18 15:45:38.000000000 -0700
+++ linux-2.6.22-rc4-mm2/arch/x86_64/kernel/io_apic.c 2007-06-18 15:45:46.000000000 -0700
@@ -31,6 +31,7 @@
#include <linux/sysdev.h>
#include <linux/msi.h>
#include <linux/htirq.h>
+#include <linux/dmar.h>
#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
@@ -2026,8 +2027,64 @@
destroy_irq(irq);
}
-#endif /* CONFIG_PCI_MSI */
+#ifdef CONFIG_DMAR
+#ifdef CONFIG_SMP
+static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
+{
+ struct irq_cfg *cfg = irq_cfg + irq;
+ struct msi_msg msg;
+ unsigned int dest;
+ cpumask_t tmp;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ return;
+
+ if (assign_irq_vector(irq, mask))
+ return;
+
+ cpus_and(tmp, cfg->domain, mask);
+ dest = cpu_mask_to_apicid(tmp);
+
+ dmar_msi_read(irq, &msg);
+
+ msg.data &= ~MSI_DATA_VECTOR_MASK;
+ msg.data |= MSI_DATA_VECTOR(cfg->vector);
+ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+ msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+ dmar_msi_write(irq, &msg);
+ irq_desc[irq].affinity = mask;
+}
+#endif /* CONFIG_SMP */
+
+struct irq_chip dmar_msi_type = {
+ .name = "DMAR_MSI",
+ .unmask = dmar_msi_unmask,
+ .mask = dmar_msi_mask,
+ .ack = ack_apic_edge,
+#ifdef CONFIG_SMP
+ .set_affinity = dmar_msi_set_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_dmar_msi(unsigned int irq)
+{
+ int ret;
+ struct msi_msg msg;
+
+ ret = msi_compose_msg(NULL, irq, &msg);
+ if (ret < 0)
+ return ret;
+ dmar_msi_write(irq, &msg);
+ set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
+ "edge");
+ return 0;
+}
+#endif
+#endif /* CONFIG_PCI_MSI */
/*
* Hypertransport interrupt support
*/
Index: linux-2.6.22-rc4-mm2/drivers/pci/intel-iommu.c
===================================================================
--- linux-2.6.22-rc4-mm2.orig/drivers/pci/intel-iommu.c 2007-06-18 15:45:46.000000000 -0700
+++ linux-2.6.22-rc4-mm2/drivers/pci/intel-iommu.c 2007-06-19 13:05:03.000000000 -0700
@@ -742,6 +742,196 @@
return 0;
}
+/* iommu interrupt handling. Most stuff are MSI-like. */
+
+static char *fault_reason_strings[] =
+{
+ "Software",
+ "Present bit in root entry is clear",
+ "Present bit in context entry is clear",
+ "Invalid context entry",
+ "Access beyond MGAW",
+ "PTE Write access is not set",
+ "PTE Read access is not set",
+ "Next page table ptr is invalid",
+ "Root table address invalid",
+ "Context table ptr is invalid",
+ "non-zero reserved fields in RTP",
+ "non-zero reserved fields in CTP",
+ "non-zero reserved fields in PTE",
+ "Unknown"
+};
+#define MAX_FAULT_REASON_IDX ARRAY_SIZE(fault_reason_strings)
+
+char *dmar_get_fault_reason(u8 fault_reason)
+{
+ if (fault_reason > MAX_FAULT_REASON_IDX)
+ return fault_reason_strings[MAX_FAULT_REASON_IDX];
+ else
+ return fault_reason_strings[fault_reason];
+}
+
+void dmar_msi_unmask(unsigned int irq)
+{
+ struct intel_iommu *iommu = get_irq_data(irq);
+ unsigned long flag;
+
+ /* unmask it */
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ writel(0, iommu->reg + DMAR_FECTL_REG);
+ /* Read a reg to force flush the post write */
+ readl(iommu->reg + DMAR_FECTL_REG);
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_mask(unsigned int irq)
+{
+ unsigned long flag;
+ struct intel_iommu *iommu = get_irq_data(irq);
+
+ /* mask it */
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
+ /* Read a reg to force flush the post write */
+ readl(iommu->reg + DMAR_FECTL_REG);
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_write(int irq, struct msi_msg *msg)
+{
+ struct intel_iommu *iommu = get_irq_data(irq);
+ unsigned long flag;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
+ writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
+ writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_read(int irq, struct msi_msg *msg)
+{
+ struct intel_iommu *iommu = get_irq_data(irq);
+ unsigned long flag;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
+ msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
+ msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type,
+ u8 fault_reason, u16 source_id, u64 addr)
+{
+ char *reason;
+
+ reason = dmar_get_fault_reason(fault_reason);
+
+ printk(KERN_ERR
+ "DMAR:[%s] Request device [%02x:%02x.%d] "
+ "fault addr %llx \n"
+ "DMAR:[fault reason %02d] %s\n",
+ (type ? "DMA Read" : "DMA Write"),
+ (source_id >> 8), PCI_SLOT(source_id & 0xFF),
+ PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
+ return 0;
+}
+
+#define PRIMARY_FAULT_REG_LEN (16)
+static irqreturn_t iommu_page_fault(int irq, void *dev_id)
+{
+ struct intel_iommu *iommu = dev_id;
+ int reg, fault_index;
+ u32 fault_status;
+ unsigned long flag;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+
+ /* TBD: ignore advanced fault log currently */
+ if (!(fault_status & DMA_FSTS_PPF))
+ goto clear_overflow;
+
+ fault_index = dma_fsts_fault_record_index(fault_status);
+ reg = cap_fault_reg_offset(iommu->cap);
+ while (1) {
+ u8 fault_reason;
+ u16 source_id;
+ u64 guest_addr;
+ int type;
+ u32 data;
+
+ /* highest 32 bits */
+ data = readl(iommu->reg + reg +
+ fault_index * PRIMARY_FAULT_REG_LEN + 12);
+ if (!(data & DMA_FRCD_F))
+ break;
+
+ fault_reason = dma_frcd_fault_reason(data);
+ type = dma_frcd_type(data);
+
+ data = readl(iommu->reg + reg +
+ fault_index * PRIMARY_FAULT_REG_LEN + 8);
+ source_id = dma_frcd_source_id(data);
+
+ guest_addr = dmar_readq(iommu->reg + reg +
+ fault_index * PRIMARY_FAULT_REG_LEN);
+ guest_addr = dma_frcd_page_addr(guest_addr);
+ /* clear the fault */
+ writel(DMA_FRCD_F, iommu->reg + reg +
+ fault_index * PRIMARY_FAULT_REG_LEN + 12);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+ iommu_page_fault_do_one(iommu, type, fault_reason,
+ source_id, guest_addr);
+
+ fault_index++;
+ if (fault_index > cap_num_fault_regs(iommu->cap))
+ fault_index = 0;
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ }
+clear_overflow:
+ /* clear primary fault overflow */
+ fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+ if (fault_status & DMA_FSTS_PFO)
+ writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+ return IRQ_HANDLED;
+}
+
+int dmar_set_interrupt(struct intel_iommu *iommu)
+{
+ int irq, ret;
+
+ irq = create_irq();
+ if (!irq) {
+ printk(KERN_ERR "IOMMU: no free vectors\n");
+ return -EINVAL;
+ }
+
+ set_irq_data(irq, iommu);
+ iommu->irq = irq;
+
+ ret = arch_setup_dmar_msi(irq);
+ if (ret) {
+ set_irq_data(irq, NULL);
+ iommu->irq = 0;
+ destroy_irq(irq);
+ return 0;
+ }
+
+ /* Force fault register is cleared */
+ iommu_page_fault(irq, iommu);
+
+ ret = request_irq(irq, iommu_page_fault, 0, iommu->name, iommu);
+ if (ret)
+ printk(KERN_ERR "IOMMU: can't request irq\n");
+ return ret;
+}
+
static int iommu_init_domains(struct intel_iommu *iommu)
{
unsigned long ndomains;
@@ -1489,6 +1679,10 @@
iommu_flush_write_buffer(iommu);
+ ret = dmar_set_interrupt(iommu);
+ if (ret)
+ goto error;
+
iommu_set_root_entry(iommu);
iommu_flush_context_global(iommu, 0);
Index: linux-2.6.22-rc4-mm2/include/linux/dmar.h
===================================================================
--- linux-2.6.22-rc4-mm2.orig/include/linux/dmar.h 2007-06-18 15:45:46.000000000 -0700
+++ linux-2.6.22-rc4-mm2/include/linux/dmar.h 2007-06-18 15:45:46.000000000 -0700
@@ -28,6 +28,18 @@
#ifdef CONFIG_DMAR
struct intel_iommu;
+extern char *dmar_get_fault_reason(u8 fault_reason);
+
+/* Can't use the common MSI interrupt functions
+ * since DMAR is not a pci device
+ */
+extern void dmar_msi_unmask(unsigned int irq);
+extern void dmar_msi_mask(unsigned int irq);
+extern void dmar_msi_read(int irq, struct msi_msg *msg);
+extern void dmar_msi_write(int irq, struct msi_msg *msg);
+extern int dmar_set_interrupt(struct intel_iommu *iommu);
+extern int arch_setup_dmar_msi(unsigned int irq);
+
/* Intel IOMMU detection and initialization functions */
extern void detect_intel_iommu(void);
extern int intel_iommu_init(void);
--
next prev parent reply other threads:[~2007-06-19 22:21 UTC|newest]
Thread overview: 65+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-06-19 21:37 [Intel IOMMU 00/10] Intel IOMMU support, take #2 Keshavamurthy, Anil S
2007-06-19 21:37 ` [Intel IOMMU 01/10] DMAR detection and parsing logic Keshavamurthy, Anil S
2007-07-04 9:18 ` Peter Zijlstra
2007-07-04 10:04 ` Andrew Morton
2007-07-04 10:14 ` Peter Zijlstra
2007-06-19 21:37 ` [Intel IOMMU 02/10] PCI generic helper function Keshavamurthy, Anil S
2007-06-26 5:49 ` Andrew Morton
2007-06-26 14:44 ` Keshavamurthy, Anil S
2007-06-19 21:37 ` [Intel IOMMU 03/10] clflush_cache_range now takes size param Keshavamurthy, Anil S
2007-06-19 21:37 ` [Intel IOMMU 04/10] IOVA allocation and management routines Keshavamurthy, Anil S
2007-06-26 6:07 ` Andrew Morton
2007-06-26 16:16 ` Keshavamurthy, Anil S
2007-06-19 21:37 ` [Intel IOMMU 05/10] Intel IOMMU driver Keshavamurthy, Anil S
2007-06-19 23:32 ` Christoph Lameter
2007-06-19 23:50 ` Keshavamurthy, Anil S
2007-06-19 23:56 ` Christoph Lameter
2007-06-26 6:32 ` Andrew Morton
2007-06-26 16:29 ` Keshavamurthy, Anil S
2007-06-26 6:25 ` Andrew Morton
2007-06-26 16:33 ` Keshavamurthy, Anil S
2007-06-26 6:30 ` Andrew Morton
2007-06-19 21:37 ` [Intel IOMMU 06/10] Avoid memory allocation failures in dma map api calls Keshavamurthy, Anil S
2007-06-19 23:25 ` Christoph Lameter
2007-06-19 23:27 ` Arjan van de Ven
2007-06-19 23:34 ` Christoph Lameter
2007-06-20 0:02 ` Arjan van de Ven
2007-06-20 8:06 ` Peter Zijlstra
2007-06-20 13:03 ` Arjan van de Ven
2007-06-20 17:30 ` Siddha, Suresh B
2007-06-20 18:05 ` Peter Zijlstra
2007-06-20 19:14 ` Arjan van de Ven
2007-06-20 20:08 ` Peter Zijlstra
2007-06-20 23:03 ` Keshavamurthy, Anil S
2007-06-21 6:10 ` Peter Zijlstra
2007-06-21 6:11 ` Arjan van de Ven
2007-06-21 6:29 ` Peter Zijlstra
2007-06-21 6:37 ` Keshavamurthy, Anil S
2007-06-21 7:13 ` Peter Zijlstra
2007-06-21 19:51 ` Keshavamurthy, Anil S
2007-06-21 6:30 ` Keshavamurthy, Anil S
2007-06-26 5:34 ` Andrew Morton
2007-06-19 21:37 ` [Intel IOMMU 07/10] Intel iommu cmdline option - forcedac Keshavamurthy, Anil S
2007-06-19 21:37 ` Keshavamurthy, Anil S [this message]
2007-06-19 21:37 ` [Intel IOMMU 09/10] Iommu Gfx workaround Keshavamurthy, Anil S
2007-06-19 21:37 ` [Intel IOMMU 10/10] Iommu floppy workaround Keshavamurthy, Anil S
2007-06-26 6:42 ` Andrew Morton
2007-06-26 10:37 ` Andi Kleen
2007-06-26 19:25 ` Keshavamurthy, Anil S
2007-06-26 16:26 ` Keshavamurthy, Anil S
2007-06-26 6:45 ` [Intel IOMMU 00/10] Intel IOMMU support, take #2 Andrew Morton
2007-06-26 7:12 ` Andi Kleen
2007-06-26 11:13 ` Muli Ben-Yehuda
2007-06-26 15:03 ` Arjan van de Ven
2007-06-26 15:11 ` Muli Ben-Yehuda
2007-06-26 15:48 ` Keshavamurthy, Anil S
2007-06-26 16:00 ` Muli Ben-Yehuda
2007-06-26 15:56 ` Andi Kleen
2007-06-26 15:09 ` Muli Ben-Yehuda
2007-06-26 15:36 ` Andi Kleen
2007-06-26 15:15 ` Arjan van de Ven
2007-06-26 15:33 ` Andi Kleen
2007-06-26 16:25 ` Arjan van de Ven
2007-06-26 17:31 ` Andi Kleen
2007-06-26 20:10 ` Jesse Barnes
2007-06-26 22:35 ` Andi Kleen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070619213808.956237000@askeshav-devel.jf.intel.com \
--to=anil.s.keshavamurthy@intel.com \
--cc=ak@suse.de \
--cc=akpm@linux-foundation.org \
--cc=arjan@linux.intel.com \
--cc=ashok.raj@intel.com \
--cc=clameter@sgi.com \
--cc=davem@davemloft.net \
--cc=gregkh@suse.de \
--cc=linux-kernel@vger.kernel.org \
--cc=muli@il.ibm.com \
--cc=suresh.b.siddha@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®