Author: kib
Date: Mon Apr  3 09:41:43 2017
New Revision: 316449
URL: https://svnweb.freebsd.org/changeset/base/316449

Log:
  MFC r316011:
  Timeout DMAR commands.

Modified:
  stable/11/sys/x86/iommu/intel_dmar.h
  stable/11/sys/x86/iommu/intel_drv.c
  stable/11/sys/x86/iommu/intel_qi.c
  stable/11/sys/x86/iommu/intel_utils.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/x86/iommu/intel_dmar.h
==============================================================================
--- stable/11/sys/x86/iommu/intel_dmar.h        Mon Apr  3 09:36:44 2017        
(r316448)
+++ stable/11/sys/x86/iommu/intel_dmar.h        Mon Apr  3 09:41:43 2017        
(r316449)
@@ -290,6 +290,8 @@ int dmar_enable_ir(struct dmar_unit *uni
 int dmar_disable_ir(struct dmar_unit *unit);
 bool dmar_barrier_enter(struct dmar_unit *dmar, u_int barrier_id);
 void dmar_barrier_exit(struct dmar_unit *dmar, u_int barrier_id);
+uint64_t dmar_get_timeout(void);
+void dmar_update_timeout(uint64_t newval);
 
 int dmar_fault_intr(void *arg);
 void dmar_enable_fault_intr(struct dmar_unit *unit);
@@ -507,6 +509,36 @@ dmar_test_boundary(dmar_gaddr_t start, d
        return (start + size <= ((start + boundary) & ~(boundary - 1)));
 }
 
+extern struct timespec dmar_hw_timeout;
+
+#define        DMAR_WAIT_UNTIL(cond)                                   \
+{                                                              \
+       struct timespec last, curr;                             \
+       bool forever;                                           \
+                                                               \
+       if (dmar_hw_timeout.tv_sec == 0 &&                      \
+           dmar_hw_timeout.tv_nsec == 0) {                     \
+               forever = true;                                 \
+       } else {                                                \
+               forever = false;                                \
+               nanouptime(&curr);                              \
+               last = curr;                                    \
+               timespecadd(&last, &dmar_hw_timeout);           \
+       }                                                       \
+       for (;;) {                                              \
+               if (cond) {                                     \
+                       error = 0;                              \
+                       break;                                  \
+               }                                               \
+               nanouptime(&curr);                              \
+               if (!forever && timespeccmp(&last, &curr, <)) { \
+                       error = ETIMEDOUT;                      \
+                       break;                                  \
+               }                                               \
+               cpu_spinwait();                                 \
+       }                                                       \
+}
+
 #ifdef INVARIANTS
 #define        TD_PREP_PINNED_ASSERT                                           
\
        int old_td_pinned;                                              \

Modified: stable/11/sys/x86/iommu/intel_drv.c
==============================================================================
--- stable/11/sys/x86/iommu/intel_drv.c Mon Apr  3 09:36:44 2017        
(r316448)
+++ stable/11/sys/x86/iommu/intel_drv.c Mon Apr  3 09:41:43 2017        
(r316449)
@@ -402,6 +402,7 @@ dmar_attach(device_t dev)
 {
        struct dmar_unit *unit;
        ACPI_DMAR_HARDWARE_UNIT *dmaru;
+       uint64_t timeout;
        int i, error;
 
        unit = device_get_softc(dev);
@@ -426,6 +427,10 @@ dmar_attach(device_t dev)
                dmar_print_caps(dev, unit, dmaru);
        dmar_quirks_post_ident(unit);
 
+       timeout = dmar_get_timeout();
+       TUNABLE_UINT64_FETCH("hw.dmar.timeout", &timeout);
+       dmar_update_timeout(timeout);
+
        for (i = 0; i < DMAR_INTR_TOTAL; i++)
                unit->intrs[i].irq = -1;
 

Modified: stable/11/sys/x86/iommu/intel_qi.c
==============================================================================
--- stable/11/sys/x86/iommu/intel_qi.c  Mon Apr  3 09:36:44 2017        
(r316448)
+++ stable/11/sys/x86/iommu/intel_qi.c  Mon Apr  3 09:41:43 2017        
(r316449)
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <sys/rman.h>
 #include <sys/taskqueue.h>
+#include <sys/time.h>
 #include <sys/tree.h>
 #include <sys/vmem.h>
 #include <machine/bus.h>
@@ -70,27 +71,27 @@ dmar_qi_seq_processed(const struct dmar_
 static int
 dmar_enable_qi(struct dmar_unit *unit)
 {
+       int error;
 
        DMAR_ASSERT_LOCKED(unit);
        unit->hw_gcmd |= DMAR_GCMD_QIE;
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_QIES) == 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_QIES)
+           != 0));
+       return (error);
 }
 
 static int
 dmar_disable_qi(struct dmar_unit *unit)
 {
+       int error;
 
        DMAR_ASSERT_LOCKED(unit);
        unit->hw_gcmd &= ~DMAR_GCMD_QIE;
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_QIES) != 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_QIES)
+           == 0));
+       return (error);
 }
 
 static void

Modified: stable/11/sys/x86/iommu/intel_utils.c
==============================================================================
--- stable/11/sys/x86/iommu/intel_utils.c       Mon Apr  3 09:36:44 2017        
(r316448)
+++ stable/11/sys/x86/iommu/intel_utils.c       Mon Apr  3 09:41:43 2017        
(r316449)
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/taskqueue.h>
+#include <sys/time.h>
 #include <sys/tree.h>
 #include <sys/vmem.h>
 #include <dev/pci/pcivar.h>
@@ -401,6 +402,7 @@ int
 dmar_load_root_entry_ptr(struct dmar_unit *unit)
 {
        vm_page_t root_entry;
+       int error;
 
        /*
         * Access to the GCMD register must be serialized while the
@@ -413,10 +415,9 @@ dmar_load_root_entry_ptr(struct dmar_uni
        VM_OBJECT_RUNLOCK(unit->ctx_obj);
        dmar_write8(unit, DMAR_RTADDR_REG, VM_PAGE_TO_PHYS(root_entry));
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd | DMAR_GCMD_SRTP);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_RTPS) == 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_RTPS)
+           != 0));
+       return (error);
 }
 
 /*
@@ -426,6 +427,7 @@ dmar_load_root_entry_ptr(struct dmar_uni
 int
 dmar_inv_ctx_glob(struct dmar_unit *unit)
 {
+       int error;
 
        /*
         * Access to the CCMD register must be serialized while the
@@ -441,10 +443,9 @@ dmar_inv_ctx_glob(struct dmar_unit *unit
         * writes the upper dword last.
         */
        dmar_write8(unit, DMAR_CCMD_REG, DMAR_CCMD_ICC | DMAR_CCMD_CIRG_GLOB);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_CCMD_REG + 4) & DMAR_CCMD_ICC32) != 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_CCMD_REG + 4) & DMAR_CCMD_ICC32)
+           == 0));
+       return (error);
 }
 
 /*
@@ -453,7 +454,7 @@ dmar_inv_ctx_glob(struct dmar_unit *unit
 int
 dmar_inv_iotlb_glob(struct dmar_unit *unit)
 {
-       int reg;
+       int error, reg;
 
        DMAR_ASSERT_LOCKED(unit);
        KASSERT(!unit->qi_enabled, ("QI enabled"));
@@ -462,11 +463,9 @@ dmar_inv_iotlb_glob(struct dmar_unit *un
        /* See a comment about DMAR_CCMD_ICC in dmar_inv_ctx_glob. */
        dmar_write8(unit, reg + DMAR_IOTLB_REG_OFF, DMAR_IOTLB_IVT |
            DMAR_IOTLB_IIRG_GLB | DMAR_IOTLB_DR | DMAR_IOTLB_DW);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, reg + DMAR_IOTLB_REG_OFF + 4) &
-           DMAR_IOTLB_IVT32) != 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, reg + DMAR_IOTLB_REG_OFF + 4) &
+           DMAR_IOTLB_IVT32) == 0));
+       return (error);
 }
 
 /*
@@ -476,6 +475,7 @@ dmar_inv_iotlb_glob(struct dmar_unit *un
 int
 dmar_flush_write_bufs(struct dmar_unit *unit)
 {
+       int error;
 
        DMAR_ASSERT_LOCKED(unit);
 
@@ -486,42 +486,42 @@ dmar_flush_write_bufs(struct dmar_unit *
            ("dmar%d: no RWBF", unit->unit));
 
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd | DMAR_GCMD_WBF);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_WBFS) == 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_WBFS)
+           != 0));
+       return (error);
 }
 
 int
 dmar_enable_translation(struct dmar_unit *unit)
 {
+       int error;
 
        DMAR_ASSERT_LOCKED(unit);
        unit->hw_gcmd |= DMAR_GCMD_TE;
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_TES) == 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_TES)
+           != 0));
+       return (error);
 }
 
 int
 dmar_disable_translation(struct dmar_unit *unit)
 {
+       int error;
 
        DMAR_ASSERT_LOCKED(unit);
        unit->hw_gcmd &= ~DMAR_GCMD_TE;
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_TES) != 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_TES)
+           == 0));
+       return (error);
 }
 
 int
 dmar_load_irt_ptr(struct dmar_unit *unit)
 {
        uint64_t irta, s;
+       int error;
 
        DMAR_ASSERT_LOCKED(unit);
        irta = unit->irt_phys;
@@ -534,37 +534,36 @@ dmar_load_irt_ptr(struct dmar_unit *unit
        irta |= s;
        dmar_write8(unit, DMAR_IRTA_REG, irta);
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd | DMAR_GCMD_SIRTP);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_IRTPS) == 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_IRTPS)
+           != 0));
+       return (error);
 }
 
 int
 dmar_enable_ir(struct dmar_unit *unit)
 {
+       int error;
 
        DMAR_ASSERT_LOCKED(unit);
        unit->hw_gcmd |= DMAR_GCMD_IRE;
        unit->hw_gcmd &= ~DMAR_GCMD_CFI;
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_IRES) == 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_IRES)
+           != 0));
+       return (error);
 }
 
 int
 dmar_disable_ir(struct dmar_unit *unit)
 {
+       int error;
 
        DMAR_ASSERT_LOCKED(unit);
        unit->hw_gcmd &= ~DMAR_GCMD_IRE;
        dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd);
-       /* XXXKIB should have a timeout */
-       while ((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_IRES) != 0)
-               cpu_spinwait();
-       return (0);
+       DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_IRES)
+           == 0));
+       return (error);
 }
 
 #define BARRIER_F                              \
@@ -619,6 +618,43 @@ dmar_barrier_exit(struct dmar_unit *dmar
 
 int dmar_match_verbose;
 int dmar_batch_coalesce = 100;
+struct timespec dmar_hw_timeout = {
+       .tv_sec = 0,
+       .tv_nsec = 1000000
+};
+
+static const uint64_t d = 1000000000;
+
+void
+dmar_update_timeout(uint64_t newval)
+{
+
+       /* XXXKIB not atomic */
+       dmar_hw_timeout.tv_sec = newval / d;
+       dmar_hw_timeout.tv_nsec = newval % d;
+}
+
+uint64_t
+dmar_get_timeout(void)
+{
+
+       return ((uint64_t)dmar_hw_timeout.tv_sec * d +
+           dmar_hw_timeout.tv_nsec);
+}
+
+static int
+dmar_timeout_sysctl(SYSCTL_HANDLER_ARGS)
+{
+       uint64_t val;
+       int error;
+
+       val = dmar_get_timeout();
+       error = sysctl_handle_long(oidp, &val, 0, req);
+       if (error != 0 || req->newptr == NULL)
+               return (error);
+       dmar_update_timeout(val);
+       return (error);
+}
 
 static SYSCTL_NODE(_hw, OID_AUTO, dmar, CTLFLAG_RD, NULL, "");
 SYSCTL_INT(_hw_dmar, OID_AUTO, tbl_pagecnt, CTLFLAG_RD,
@@ -630,6 +666,10 @@ SYSCTL_INT(_hw_dmar, OID_AUTO, match_ver
 SYSCTL_INT(_hw_dmar, OID_AUTO, batch_coalesce, CTLFLAG_RWTUN,
     &dmar_batch_coalesce, 0,
     "Number of qi batches between interrupt");
+SYSCTL_PROC(_hw_dmar, OID_AUTO, timeout,
+    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 0,
+    dmar_timeout_sysctl, "QU",
+    "Timeout for command wait, in nanoseconds");
 #ifdef INVARIANTS
 int dmar_check_free;
 SYSCTL_INT(_hw_dmar, OID_AUTO, check_free, CTLFLAG_RWTUN,
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to