svn commit: r316449 - stable/11/sys/x86/iommu
Konstantin Belousov
kib at FreeBSD.org
Mon Apr 3 09:41:45 UTC 2017
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,
More information about the svn-src-stable-11
mailing list