From owner-svn-src-stable-11@freebsd.org Mon Apr 3 09:41:45 2017 Return-Path: Delivered-To: svn-src-stable-11@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 943CBD2A34C; Mon, 3 Apr 2017 09:41:45 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 526AB1B3; Mon, 3 Apr 2017 09:41:45 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v339fi7G002167; Mon, 3 Apr 2017 09:41:44 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v339fib0002163; Mon, 3 Apr 2017 09:41:44 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201704030941.v339fib0002163@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Mon, 3 Apr 2017 09:41:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r316449 - stable/11/sys/x86/iommu X-SVN-Group: stable-11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-11@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for only the 11-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 03 Apr 2017 09:41:45 -0000 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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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,