Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Nov 2015 18:51:17 +0000 (UTC)
From:      "Conrad E. Meyer" <cem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r291263 - head/sys/dev/ntb/ntb_hw
Message-ID:  <201511241851.tAOIpHRK066859@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: cem
Date: Tue Nov 24 18:51:17 2015
New Revision: 291263
URL: https://svnweb.freebsd.org/changeset/base/291263

Log:
  ntb: Add MW tunable for MMR Xeon errata workaround
  
  Adds a new tunable, ntb.hw.b2b_mw_idx, which specifies the offset (from the
  total number of memory windows) to use for register access on hardware with
  the SDOORBELL_LOCKUP errata.  The default is -1, i.e., the last memory
  window.
  
  We map BARs before the b2b_mw_idx is selected, so map them all as memory
  windows initially.  The register memory window should not be write-combined,
  so we explicitly disable WC on the selected MW later.
  
  This introduces a layer of abstraction between consumer memory window
  indices, which exclude any exclusive errata-workaround BARs, and internal
  memory window indices, which include such BARs.  An internal routine,
  ntb_user_mw_to_idx(), converts the former to the latter.  Public APIs have
  been updated to use this instead of assuming the exclusive workaround BAR is
  the last available MW.
  
  Sponsored by:	EMC / Isilon Storage Division

Modified:
  head/sys/dev/ntb/ntb_hw/ntb_hw.c

Modified: head/sys/dev/ntb/ntb_hw/ntb_hw.c
==============================================================================
--- head/sys/dev/ntb/ntb_hw/ntb_hw.c	Tue Nov 24 16:10:21 2015	(r291262)
+++ head/sys/dev/ntb/ntb_hw/ntb_hw.c	Tue Nov 24 18:51:17 2015	(r291263)
@@ -264,11 +264,13 @@ bus_space_write_8(bus_space_tag_t tag, b
 static int ntb_probe(device_t device);
 static int ntb_attach(device_t device);
 static int ntb_detach(device_t device);
+static unsigned ntb_user_mw_to_idx(struct ntb_softc *, unsigned uidx);
 static inline enum ntb_bar ntb_mw_to_bar(struct ntb_softc *, unsigned mw);
 static inline bool bar_is_64bit(struct ntb_softc *, enum ntb_bar);
 static inline void bar_get_xlat_params(struct ntb_softc *, enum ntb_bar,
     uint32_t *base, uint32_t *xlat, uint32_t *lmt);
 static int ntb_map_pci_bars(struct ntb_softc *ntb);
+static int ntb_mw_set_wc_internal(struct ntb_softc *, unsigned idx, bool wc);
 static void print_map_success(struct ntb_softc *, struct ntb_pci_bar_info *,
     const char *);
 static int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar);
@@ -332,6 +334,14 @@ static unsigned g_ntb_enable_wc = 1;
 SYSCTL_UINT(_hw_ntb, OID_AUTO, enable_writecombine, CTLFLAG_RDTUN,
     &g_ntb_enable_wc, 0, "Set to 1 to map memory windows write combining");
 
+static int g_ntb_mw_idx = -1;
+SYSCTL_INT(_hw_ntb, OID_AUTO, b2b_mw_idx, CTLFLAG_RDTUN, &g_ntb_mw_idx,
+    0, "Use this memory window to access the peer NTB registers.  A "
+    "non-negative value starts from the first MW index; a negative value "
+    "starts from the last MW index.  The default is -1, i.e., the last "
+    "available memory window.  Both sides of the NTB MUST set the same "
+    "value here!  (Applies on Xeon platforms with SDOORBELL_LOCKUP errata.)");
+
 static struct ntb_hw_info pci_ids[] = {
 	/* XXX: PS/SS IDs left out until they are supported. */
 	{ 0x0C4E8086, "BWD Atom Processor S1200 Non-Transparent Bridge B2B",
@@ -579,11 +589,6 @@ ntb_detach(device_t device)
 	mtx_destroy(&ntb->db_mask_lock);
 	mtx_destroy(&ntb->ctx_lock);
 
-	/*
-	 * Redetect total MWs so we unmap properly -- in case we lowered the
-	 * maximum to work around Xeon errata.
-	 */
-	ntb_detect_max_mw(ntb);
 	ntb_unmap_pci_bar(ntb);
 
 	return (0);
@@ -596,8 +601,7 @@ static inline enum ntb_bar
 ntb_mw_to_bar(struct ntb_softc *ntb, unsigned mw)
 {
 
-	KASSERT(mw < ntb->mw_count ||
-	    (mw != B2B_MW_DISABLED && mw == ntb->b2b_mw_idx),
+	KASSERT(mw < ntb->mw_count,
 	    ("%s: mw:%u > count:%u", __func__, mw, (unsigned)ntb->mw_count));
 	KASSERT(ntb->reg->mw_bar[mw] != 0, ("invalid mw"));
 
@@ -668,11 +672,9 @@ ntb_map_pci_bars(struct ntb_softc *ntb)
 	ntb->bar_info[NTB_B2B_BAR_1].pbarxlat_off = XEON_PBAR2XLAT_OFFSET;
 
 	ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4);
-	/* XXX Are shared MW B2Bs write-combining? */
-	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP) && !HAS_FEATURE(NTB_SPLIT_BAR))
-		rc = map_mmr_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_2]);
-	else
-		rc = map_memory_window_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_2]);
+	rc = map_memory_window_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_2]);
+	if (rc != 0)
+		goto out;
 	ntb->bar_info[NTB_B2B_BAR_2].psz_off = XEON_PBAR4SZ_OFFSET;
 	ntb->bar_info[NTB_B2B_BAR_2].ssz_off = XEON_SBAR4SZ_OFFSET;
 	ntb->bar_info[NTB_B2B_BAR_2].pbarxlat_off = XEON_PBAR4XLAT_OFFSET;
@@ -681,10 +683,7 @@ ntb_map_pci_bars(struct ntb_softc *ntb)
 		goto out;
 
 	ntb->bar_info[NTB_B2B_BAR_3].pci_resource_id = PCIR_BAR(5);
-	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
-		rc = map_mmr_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_3]);
-	else
-		rc = map_memory_window_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_3]);
+	rc = map_memory_window_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_3]);
 	ntb->bar_info[NTB_B2B_BAR_3].psz_off = XEON_PBAR5SZ_OFFSET;
 	ntb->bar_info[NTB_B2B_BAR_3].ssz_off = XEON_SBAR5SZ_OFFSET;
 	ntb->bar_info[NTB_B2B_BAR_3].pbarxlat_off = XEON_PBAR5XLAT_OFFSET;
@@ -1264,14 +1263,18 @@ ntb_xeon_init_dev(struct ntb_softc *ntb)
 	/*
 	 * There is a Xeon hardware errata related to writes to SDOORBELL or
 	 * B2BDOORBELL in conjunction with inbound access to NTB MMIO space,
-	 * which may hang the system.  To workaround this use the second memory
+	 * which may hang the system.  To workaround this, use a memory
 	 * window to access the interrupt and scratch pad registers on the
 	 * remote system.
 	 */
-	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
-		/* Use the last MW for mapping remote spad */
-		ntb->b2b_mw_idx = ntb->mw_count - 1;
-	else if (HAS_FEATURE(NTB_B2BDOORBELL_BIT14))
+	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) {
+		ntb->b2b_mw_idx = (ntb->mw_count + g_ntb_mw_idx) %
+		    ntb->mw_count;
+		ntb_printf(2, "Setting up b2b mw idx %d means %u\n",
+		    g_ntb_mw_idx, ntb->b2b_mw_idx);
+		rc = ntb_mw_set_wc_internal(ntb, ntb->b2b_mw_idx, false);
+		KASSERT(rc == 0, ("shouldn't fail"));
+	} else if (HAS_FEATURE(NTB_B2BDOORBELL_BIT14))
 		/*
 		 * HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
 		 * mirrored to the remote system.  Shrink the number of bits by one,
@@ -1481,7 +1484,6 @@ xeon_setup_b2b_mw(struct ntb_softc *ntb,
 			ntb->b2b_off = bar_size >> 1;
 		else if (bar_size >= XEON_B2B_MIN_SIZE) {
 			ntb->b2b_off = 0;
-			ntb->mw_count--;
 		} else {
 			device_printf(ntb->device,
 			    "B2B bar size is too small!\n");
@@ -1999,7 +2001,7 @@ ntb_sysctl_init(struct ntb_softc *ntb)
 	    "A", "Link status");
 
 	SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "mw_count", CTLFLAG_RD,
-	    &ntb->mw_count, 0, "MW count (excl. non-shared B2B register BAR)");
+	    &ntb->mw_count, 0, "MW count");
 	SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "spad_count", CTLFLAG_RD,
 	    &ntb->spad_count, 0, "Scratchpad count");
 	SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "db_count", CTLFLAG_RD,
@@ -2341,6 +2343,16 @@ sysctl_handle_register(SYSCTL_HANDLER_AR
 	return (EINVAL);
 }
 
+static unsigned
+ntb_user_mw_to_idx(struct ntb_softc *ntb, unsigned uidx)
+{
+
+	if (ntb->b2b_mw_idx != B2B_MW_DISABLED && ntb->b2b_off == 0 &&
+	    uidx >= ntb->b2b_mw_idx)
+		return (uidx + 1);
+	return (uidx);
+}
+
 /*
  * Public API to the rest of the OS
  */
@@ -2361,10 +2373,18 @@ ntb_get_max_spads(struct ntb_softc *ntb)
 	return (ntb->spad_count);
 }
 
+/*
+ * ntb_mw_count() - Get the number of memory windows available for KPI
+ * consumers.
+ *
+ * (Excludes any MW wholly reserved for register access.)
+ */
 uint8_t
 ntb_mw_count(struct ntb_softc *ntb)
 {
 
+	if (ntb->b2b_mw_idx != B2B_MW_DISABLED && ntb->b2b_off == 0)
+		return (ntb->mw_count - 1);
 	return (ntb->mw_count);
 }
 
@@ -2495,6 +2515,7 @@ ntb_mw_get_range(struct ntb_softc *ntb, 
 
 	if (mw_idx >= ntb_mw_count(ntb))
 		return (EINVAL);
+	mw_idx = ntb_user_mw_to_idx(ntb, mw_idx);
 
 	bar_num = ntb_mw_to_bar(ntb, mw_idx);
 	bar = &ntb->bar_info[bar_num];
@@ -2553,6 +2574,7 @@ ntb_mw_set_trans(struct ntb_softc *ntb, 
 
 	if (idx >= ntb_mw_count(ntb))
 		return (EINVAL);
+	idx = ntb_user_mw_to_idx(ntb, idx);
 
 	bar_num = ntb_mw_to_bar(ntb, idx);
 	bar = &ntb->bar_info[bar_num];
@@ -2658,6 +2680,7 @@ ntb_mw_get_wc(struct ntb_softc *ntb, uns
 
 	if (idx >= ntb_mw_count(ntb))
 		return (EINVAL);
+	idx = ntb_user_mw_to_idx(ntb, idx);
 
 	bar = &ntb->bar_info[ntb_mw_to_bar(ntb, idx)];
 	*wc = bar->mapped_wc;
@@ -2676,13 +2699,21 @@ ntb_mw_get_wc(struct ntb_softc *ntb, uns
 int
 ntb_mw_set_wc(struct ntb_softc *ntb, unsigned idx, bool wc)
 {
-	struct ntb_pci_bar_info *bar;
-	vm_memattr_t attr;
-	int rc;
 
 	if (idx >= ntb_mw_count(ntb))
 		return (EINVAL);
 
+	idx = ntb_user_mw_to_idx(ntb, idx);
+	return (ntb_mw_set_wc_internal(ntb, idx, wc));
+}
+
+static int
+ntb_mw_set_wc_internal(struct ntb_softc *ntb, unsigned idx, bool wc)
+{
+	struct ntb_pci_bar_info *bar;
+	vm_memattr_t attr;
+	int rc;
+
 	bar = &ntb->bar_info[ntb_mw_to_bar(ntb, idx)];
 	if (bar->mapped_wc == wc)
 		return (0);
@@ -2741,9 +2772,6 @@ ntb_get_peer_db_addr(struct ntb_softc *n
 		bar = &ntb->bar_info[NTB_CONFIG_BAR];
 		regoff = ntb->peer_reg->db_bell;
 	} else {
-		KASSERT((HAS_FEATURE(NTB_SPLIT_BAR) && ntb->mw_count == 2) ||
-		    (!HAS_FEATURE(NTB_SPLIT_BAR) && ntb->mw_count == 1),
-		    ("mw_count invalid after setup"));
 		KASSERT(ntb->b2b_mw_idx != B2B_MW_DISABLED,
 		    ("invalid b2b idx"));
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201511241851.tAOIpHRK066859>