All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lan Tianyu <tianyu.lan@intel.com>
To: xen-devel@lists.xen.org
Cc: Lan Tianyu <tianyu.lan@intel.com>,
	kevin.tian@intel.com, Chao Gao <chao.gao@intel.com>
Subject: [PATCH 24/25] x86/vvtd: Add queued invalidation (QI) support
Date: Thu, 29 Jun 2017 01:50:56 -0400	[thread overview]
Message-ID: <1498715457-16565-25-git-send-email-tianyu.lan@intel.com> (raw)
In-Reply-To: <1498715457-16565-1-git-send-email-tianyu.lan@intel.com>

From: Chao Gao <chao.gao@intel.com>

Queued Invalidation Interface is an expanded invalidation interface with
extended capabilities. Hardware implementations report support for queued
invalidation interface through the Extended Capability Register. The queued
invalidation interface uses an Invalidation Queue (IQ), which is a circular
buffer in system memory. Software submits commands by writing Invalidation
Descriptors to the IQ.

In this patch, a new function viommu_process_iq() is used for emulating how
hardware handles invalidation requests through QI.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
---
 xen/drivers/passthrough/vtd/iommu.h |  29 ++++-
 xen/drivers/passthrough/vtd/vvtd.c  | 244 ++++++++++++++++++++++++++++++++++++
 2 files changed, 272 insertions(+), 1 deletion(-)

diff --git a/xen/drivers/passthrough/vtd/iommu.h b/xen/drivers/passthrough/vtd/iommu.h
index a9e905b..eac0fbe 100644
--- a/xen/drivers/passthrough/vtd/iommu.h
+++ b/xen/drivers/passthrough/vtd/iommu.h
@@ -204,6 +204,32 @@
 #define DMA_IRTA_S(val)         (val & 0xf)
 #define DMA_IRTA_SIZE(val)      (1UL << (DMA_IRTA_S(val) + 1))
 
+/* IQH_REG */
+#define DMA_IQH_QH_SHIFT        4
+#define DMA_IQH_QH(val)         ((val >> 4) & 0x7fffULL)
+
+/* IQT_REG */
+#define DMA_IQT_QT_SHIFT        4
+#define DMA_IQT_QT(val)         ((val >> 4) & 0x7fffULL)
+#define DMA_IQT_RSVD            0xfffffffffff80007ULL
+
+/* IQA_REG */
+#define DMA_MGAW                39  /* Maximum Guest Address Width */
+#define DMA_IQA_ADDR(val)       (val & ~0xfffULL)
+#define DMA_IQA_QS(val)         (val & 0x7)
+#define DMA_IQA_ENTRY_PER_PAGE  (1 << 8)
+#define DMA_IQA_RSVD            (~((1ULL << DMA_MGAW) -1 ) | 0xff8ULL)
+
+/* IECTL_REG */
+#define DMA_IECTL_IM_BIT 31
+#define DMA_IECTL_IM            (1 << DMA_IECTL_IM_BIT)
+#define DMA_IECTL_IP_BIT 30
+#define DMA_IECTL_IP (((u64)1) << DMA_IECTL_IP_BIT)
+
+/* ICS_REG */
+#define DMA_ICS_IWC_BIT         0
+#define DMA_ICS_IWC             (1 << DMA_ICS_IWC_BIT)
+
 /* PMEN_REG */
 #define DMA_PMEN_EPM    (((u32)1) << 31)
 #define DMA_PMEN_PRS    (((u32)1) << 0)
@@ -238,7 +264,8 @@
 #define DMA_FSTS_PPF (1U << DMA_FSTS_PPF_BIT)
 #define DMA_FSTS_AFO (1U << 2)
 #define DMA_FSTS_APF (1U << 3)
-#define DMA_FSTS_IQE (1U << 4)
+#define DMA_FSTS_IQE_BIT 4
+#define DMA_FSTS_IQE (1U << DMA_FSTS_IQE_BIT)
 #define DMA_FSTS_ICE (1U << 5)
 #define DMA_FSTS_ITE (1U << 6)
 #define DMA_FSTS_PRO_BIT 7
diff --git a/xen/drivers/passthrough/vtd/vvtd.c b/xen/drivers/passthrough/vtd/vvtd.c
index bea5315..6e5cfdf 100644
--- a/xen/drivers/passthrough/vtd/vvtd.c
+++ b/xen/drivers/passthrough/vtd/vvtd.c
@@ -428,6 +428,185 @@ static int vvtd_record_fault(struct vvtd *vvtd,
     return X86EMUL_OKAY;
 }
 
+/*
+ * Process a invalidation descriptor. Currently, only two types descriptors,
+ * Interrupt Entry Cache Invalidation Descritor and Invalidation Wait
+ * Descriptor are handled.
+ * @vvtd: the virtual vtd instance
+ * @i: the index of the invalidation descriptor to be processed
+ *
+ * If success return 0, or return -1 when failure.
+ */
+static int process_iqe(struct vvtd *vvtd, int i)
+{
+    uint64_t iqa, addr;
+    struct qinval_entry *qinval_page;
+    void *pg;
+    int ret;
+
+    vvtd_get_reg_quad(vvtd, DMAR_IQA_REG, iqa);
+    ret = map_guest_page(vvtd->domain, DMA_IQA_ADDR(iqa)>>PAGE_SHIFT,
+                         (void**)&qinval_page);
+    if ( ret )
+    {
+        gdprintk(XENLOG_ERR, "Can't map guest IRT (rc %d)", ret);
+        return -1;
+    }
+
+    switch ( qinval_page[i].q.inv_wait_dsc.lo.type )
+    {
+    case TYPE_INVAL_WAIT:
+        if ( qinval_page[i].q.inv_wait_dsc.lo.sw )
+        {
+            addr = (qinval_page[i].q.inv_wait_dsc.hi.saddr << 2);
+            ret = map_guest_page(vvtd->domain, addr >> PAGE_SHIFT, &pg);
+            if ( ret )
+            {
+                gdprintk(XENLOG_ERR, "Can't map guest memory to inform guest "
+                         "IWC completion (rc %d)", ret);
+                goto error;
+            }
+            *(uint32_t *)((uint64_t)pg + (addr & ~PAGE_MASK)) =
+                qinval_page[i].q.inv_wait_dsc.lo.sdata;
+            unmap_guest_page(pg);
+        }
+
+        /*
+         * The following code generates an invalidation completion event
+         * indicating the invalidation wait descriptor completion. Note that
+         * the following code fragment is not tested properly.
+         */
+        if ( qinval_page[i].q.inv_wait_dsc.lo.iflag )
+        {
+            uint32_t ie_data, ie_addr;
+            if ( !vvtd_test_and_set_bit(vvtd, DMAR_ICS_REG, DMA_ICS_IWC_BIT) )
+            {
+                __vvtd_set_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IP_BIT);
+                if ( !vvtd_test_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IM_BIT) )
+                {
+                    ie_data = vvtd_get_reg(vvtd, DMAR_IEDATA_REG);
+                    ie_addr = vvtd_get_reg(vvtd, DMAR_IEADDR_REG);
+                    vvtd_generate_interrupt(vvtd, ie_addr, ie_data);
+                    __vvtd_clear_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IP_BIT);
+                }
+            }
+        }
+        break;
+
+    case TYPE_INVAL_IEC:
+        /*
+         * Currently, no cache is preserved in hypervisor. Only need to update
+         * pIRTEs which are modified in binding process.
+         */
+        break;
+
+    default:
+        goto error;
+    }
+
+    unmap_guest_page((void*)qinval_page);
+    return 0;
+
+ error:
+    unmap_guest_page((void*)qinval_page);
+    gdprintk(XENLOG_ERR, "Internal error in Queue Invalidation.\n");
+    domain_crash(vvtd->domain);
+    return -1;
+}
+
+/*
+ * Invalidate all the descriptors in Invalidation Queue.
+ */
+static void vvtd_process_iq(struct vvtd *vvtd)
+{
+    uint64_t iqh, iqt, iqa, max_entry, i;
+    int ret = 0;
+
+    /*
+     * No new descriptor is fetched from the Invalidation Queue until
+     * software clears the IQE field in the Fault Status Register
+     */
+    if ( vvtd_test_bit(vvtd, DMAR_FSTS_REG, DMA_FSTS_IQE_BIT) )
+        return;
+
+    vvtd_get_reg_quad(vvtd, DMAR_IQH_REG, iqh);
+    vvtd_get_reg_quad(vvtd, DMAR_IQT_REG, iqt);
+    vvtd_get_reg_quad(vvtd, DMAR_IQA_REG, iqa);
+
+    max_entry = DMA_IQA_ENTRY_PER_PAGE << DMA_IQA_QS(iqa);
+    iqh = DMA_IQH_QH(iqh);
+    iqt = DMA_IQT_QT(iqt);
+
+    ASSERT(iqt < max_entry);
+    if ( iqh == iqt )
+        return;
+
+    i = iqh;
+    while ( i != iqt )
+    {
+        ret = process_iqe(vvtd, i);
+        if ( ret )
+            break;
+        else
+            i = (i + 1) % max_entry;
+        vvtd_set_reg_quad(vvtd, DMAR_IQH_REG, i << DMA_IQH_QH_SHIFT);
+    }
+
+    /*
+     * When IQE set, IQH references the desriptor associated with the error.
+     */
+    if ( ret )
+        vvtd_report_non_recoverable_fault(vvtd, DMA_FSTS_IQE_BIT);
+}
+
+static int vvtd_write_iqt(struct vvtd *vvtd, unsigned long val)
+{
+    uint64_t iqa;
+
+    if ( val & DMA_IQT_RSVD )
+    {
+        VVTD_DEBUG(VVTD_DBG_RW, "Attempt to set reserved bits in "
+                   "Invalidation Queue Tail.");
+        return X86EMUL_OKAY;
+    }
+
+    vvtd_get_reg_quad(vvtd, DMAR_IQA_REG, iqa);
+    if ( DMA_IQT_QT(val) >= DMA_IQA_ENTRY_PER_PAGE << DMA_IQA_QS(iqa) )
+    {
+        VVTD_DEBUG(VVTD_DBG_RW, "IQT: Value %lx exceeded supported max "
+                   "index.", val);
+        return X86EMUL_OKAY;
+    }
+
+    vvtd_set_reg_quad(vvtd, DMAR_IQT_REG, val);
+    vvtd_process_iq(vvtd);
+    return X86EMUL_OKAY;
+}
+
+static int vvtd_write_iqa(struct vvtd *vvtd, unsigned long val)
+{
+    if ( val & DMA_IQA_RSVD )
+    {
+        VVTD_DEBUG(VVTD_DBG_RW, "Attempt to set reserved bits in "
+                   "Invalidation Queue Address.");
+        return X86EMUL_OKAY;
+    }
+
+    vvtd_set_reg_quad(vvtd, DMAR_IQA_REG, val);
+    return X86EMUL_OKAY;
+}
+
+static int vvtd_write_ics(struct vvtd *vvtd, uint32_t val)
+{
+    if ( val & DMA_ICS_IWC )
+    {
+        __vvtd_clear_bit(vvtd, DMAR_ICS_REG, DMA_ICS_IWC_BIT);
+        /*When IWC field is cleared, the IP field needs to be cleared */
+        __vvtd_clear_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IP_BIT);
+    }
+    return X86EMUL_OKAY;
+}
+
 static int vvtd_write_frcd3(struct vvtd *vvtd, uint32_t val)
 {
     /* Writing a 1 means clear fault */
@@ -439,6 +618,29 @@ static int vvtd_write_frcd3(struct vvtd *vvtd, uint32_t val)
     return X86EMUL_OKAY;
 }
 
+static int vvtd_write_iectl(struct vvtd *vvtd, uint32_t val)
+{
+    /*
+     * Only DMA_IECTL_IM bit is writable. Generate pending event when unmask.
+     */
+    if ( !(val & DMA_IECTL_IM) )
+    {
+        /* Clear IM and clear IP */
+        __vvtd_clear_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IM_BIT);
+        if ( vvtd_test_and_clear_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IP_BIT) )
+        {
+            uint32_t ie_data, ie_addr;
+            ie_data = vvtd_get_reg(vvtd, DMAR_IEDATA_REG);
+            ie_addr = vvtd_get_reg(vvtd, DMAR_IEADDR_REG);
+            vvtd_generate_interrupt(vvtd, ie_addr, ie_data);
+        }
+    }
+    else
+        __vvtd_set_bit(vvtd, DMAR_IECTL_REG, DMA_IECTL_IM_BIT);
+
+    return X86EMUL_OKAY;
+}
+
 static int vvtd_write_fectl(struct vvtd *vvtd, uint32_t val)
 {
     /*
@@ -481,6 +683,10 @@ static int vvtd_write_fsts(struct vvtd *vvtd, uint32_t val)
     if ( !((vvtd_get_reg(vvtd, DMAR_FSTS_REG) & DMA_FSTS_FAULTS)) )
         __vvtd_clear_bit(vvtd, DMAR_FECTL_REG, DMA_FECTL_IP_BIT);
 
+    /* Continue to deal invalidation when IQE is clear */
+    if ( !vvtd_test_bit(vvtd, DMAR_FSTS_REG, DMA_FSTS_IQE_BIT) )
+        vvtd_process_iq(vvtd);
+
     return X86EMUL_OKAY;
 }
 
@@ -639,6 +845,36 @@ static int vvtd_write(struct vcpu *v, unsigned long addr,
             ret = vvtd_write_frcd3(vvtd, val);
             break;
 
+        case DMAR_IECTL_REG:
+            ret = vvtd_write_iectl(vvtd, val);
+            break;
+
+        case DMAR_ICS_REG:
+            ret = vvtd_write_ics(vvtd, val);
+            break;
+
+        case DMAR_IQT_REG:
+            ret = vvtd_write_iqt(vvtd, (uint32_t)val);
+            break;
+
+        case DMAR_IQA_REG:
+        {
+            uint32_t iqa_hi;
+
+            iqa_hi = vvtd_get_reg(vvtd, DMAR_IQA_REG_HI);
+            ret = vvtd_write_iqa(vvtd, (uint32_t)val | ((uint64_t)iqa_hi << 32));
+            break;
+        }
+
+        case DMAR_IQA_REG_HI:
+        {
+            uint32_t iqa_lo;
+
+            iqa_lo = vvtd_get_reg(vvtd, DMAR_IQA_REG);
+            ret = vvtd_write_iqa(vvtd, (val << 32) | iqa_lo);
+            break;
+        }
+
         case DMAR_IEDATA_REG:
         case DMAR_IEADDR_REG:
         case DMAR_IEUADDR_REG:
@@ -668,6 +904,14 @@ static int vvtd_write(struct vcpu *v, unsigned long addr,
             ret = vvtd_write_frcd3(vvtd, val >> 32);
             break;
 
+        case DMAR_IQT_REG:
+            ret = vvtd_write_iqt(vvtd, val);
+            break;
+
+        case DMAR_IQA_REG:
+            ret = vvtd_write_iqa(vvtd, val);
+            break;
+
         default:
             ret = X86EMUL_UNHANDLEABLE;
             break;
-- 
1.8.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

  parent reply	other threads:[~2017-06-29  5:50 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-29  5:50 [PATCH 00/25] xen/vIOMMU: Add vIOMMU support with irq remapping fucntion of virtual vtd Lan Tianyu
2017-06-29  5:50 ` [PATCH 1/25] VIOMMU: Add vIOMMU helper functions to create, destroy and query capabilities Lan Tianyu
2017-06-30 13:05   ` Wei Liu
2017-07-04  1:46     ` Lan Tianyu
2017-07-04  7:34       ` Julien Grall
2017-07-04  7:53         ` Lan Tianyu
2017-07-04  7:57         ` Jan Beulich
2017-07-04 10:16           ` Julien Grall
2017-07-04 10:18             ` Julien Grall
2017-07-04  7:55       ` Jan Beulich
2017-07-04  8:45         ` Lan Tianyu
2017-07-04 10:03           ` Jan Beulich
2017-06-29  5:50 ` [PATCH 2/25] DOMCTL: Introduce new DOMCTL commands for vIOMMU support Lan Tianyu
2017-06-30 13:07   ` Wei Liu
2017-06-29  5:50 ` [PATCH 3/25] VIOMMU: Add irq request callback to deal with irq remapping Lan Tianyu
2017-06-29  5:50 ` [PATCH 4/25] VIOMMU: Add get irq info callback to convert irq remapping request Lan Tianyu
2017-06-29  5:50 ` [PATCH 5/25] Xen/doc: Add Xen virtual IOMMU doc Lan Tianyu
2017-07-04 10:39   ` Julien Grall
2017-07-05  3:15     ` Lan Tianyu
2017-07-05 13:25       ` Julien Grall
2017-07-06  3:10         ` Lan Tianyu
2017-07-07 16:08           ` Julien Grall
2017-07-12  3:09             ` Lan Tianyu
2017-07-12  7:26               ` Julien Grall
2017-07-12 11:44                 ` Lan Tianyu
2017-07-06  6:20         ` Lan Tianyu
2017-07-07 16:16           ` Julien Grall
2017-07-12  5:34             ` Lan Tianyu
2017-06-29  5:50 ` [PATCH 6/25] Tools/libxc: Add viommu operations in libxc Lan Tianyu
2017-06-30 13:44   ` Wei Liu
2017-06-29  5:50 ` [PATCH 7/25] Tools/libacpi: Add DMA remapping reporting (DMAR) ACPI table structures Lan Tianyu
2017-06-29  5:50 ` [PATCH 8/25] Tools/libacpi: Add new fields in acpi_config to build DMAR table Lan Tianyu
2017-06-29  5:50 ` [PATCH 9/25] Tools/libacpi: Add a user configurable parameter to control vIOMMU attributes Lan Tianyu
2017-06-30 13:44   ` Wei Liu
2017-06-29  5:50 ` [PATCH 10/25] libxl: create vIOMMU during domain construction Lan Tianyu
2017-06-30 13:45   ` Wei Liu
2017-07-04 10:46   ` Julien Grall
2017-07-04 11:03     ` Wei Liu
2017-07-05 10:53       ` Lan Tianyu
2017-07-05 11:19         ` Wei Liu
2017-07-05 11:32           ` Lan Tianyu
2017-07-05 11:39             ` Wei Liu
2017-06-29  5:50 ` [PATCH 11/25] x86/hvm: Introduce a emulated VTD for HVM Lan Tianyu
2017-06-29  5:50 ` [PATCH 12/25] X86/vvtd: Add MMIO handler for VVTD Lan Tianyu
2017-06-30 13:46   ` Wei Liu
2017-06-29  5:50 ` [PATCH 13/25] X86/vvtd: Set Interrupt Remapping Table Pointer through GCMD Lan Tianyu
2017-06-29  5:50 ` [PATCH 14/25] X86/vvtd: Process interrupt remapping request Lan Tianyu
2017-06-29  5:50 ` [PATCH 15/25] x86/vvtd: decode interrupt attribute from IRTE Lan Tianyu
2017-06-29  5:50 ` [PATCH 16/25] x86/vioapic: Hook interrupt delivery of vIOAPIC Lan Tianyu
2017-06-29  5:50 ` [PATCH 17/25] X86/vvtd: Enable Queued Invalidation through GCMD Lan Tianyu
2017-06-29  5:50 ` [PATCH 18/25] X86/vvtd: Enable Interrupt Remapping " Lan Tianyu
2017-06-29  5:50 ` [PATCH 19/25] x86/vioapic: introduce a function to get vector from pin Lan Tianyu
2017-06-29  5:50 ` [PATCH 20/25] passthrough: move some fields of hvm_gmsi_info to a sub-structure Lan Tianyu
2017-06-29  5:50 ` [PATCH 21/25] Tools/libxc: Add a new interface to bind remapping format msi with pirq Lan Tianyu
2017-06-30 13:48   ` Wei Liu
2017-06-29  5:50 ` [PATCH 22/25] x86/vmsi: Hook delivering remapping format msi to guest Lan Tianyu
2017-06-29  5:50 ` [PATCH 23/25] x86/vvtd: Handle interrupt translation faults Lan Tianyu
2017-06-29  5:50 ` Lan Tianyu [this message]
2017-06-29  5:50 ` [PATCH 25/25] x86/vvtd: save and restore emulated VT-d Lan Tianyu

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=1498715457-16565-25-git-send-email-tianyu.lan@intel.com \
    --to=tianyu.lan@intel.com \
    --cc=chao.gao@intel.com \
    --cc=kevin.tian@intel.com \
    --cc=xen-devel@lists.xen.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.