All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/16] ntb: NTB Abstraction Layer
@ 2015-05-20 15:41 Allen Hubbe
  2015-05-20 15:41 ` [PATCH 01/16] Move files in preparation for NTB Abstraction Allen Hubbe
                   ` (15 more replies)
  0 siblings, 16 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

The NTB drivers currently support only one hardware driver, and one client
type.  This patch set adds an abstraction layer, enabling different hardware
drivers by other vendors, and clients other than ntb_transport.

The commits in this set may also be pulled from:
github.com/allenbh/linux
in the branch ntb-abh, or tag ntb-abh-v1

Allen Hubbe (12):
  Move files in preparation for NTB Abstraction
  NTB Abstraction Layer
  Intel NTB params for snb b2b addresses
  NTB Pingpong Client
  NTB Tool Client
  ntb_transport: rate limit ntb_qp_link_work
  ntb_transport: differentiate link down messages
  ntb_transport: don't advance rx on link down
  ntb_transport: reset qp link stats on down
  ntb_transport: numa aware memory and dma chan
  ntb_hw_intel: numa aware memory allocation
  ntb_transport: fix small code format issues

Dave Jiang (4):
  ntb: Enable link training for RP mode in the driver probe
  Check the DID for certain workaround error flags to be set.
  ntb: performance improvement by write combining
  ntb: default to cpu memcpy for performance

 Documentation/ntb.txt               |  127 ++
 MAINTAINERS                         |   16 +-
 drivers/net/ntb_netdev.c            |   58 +-
 drivers/ntb/Kconfig                 |   22 +-
 drivers/ntb/Makefile                |    4 +-
 drivers/ntb/hw/Kconfig              |    1 +
 drivers/ntb/hw/Makefile             |    1 +
 drivers/ntb/hw/intel/Kconfig        |    8 +
 drivers/ntb/hw/intel/Makefile       |    1 +
 drivers/ntb/hw/intel/ntb_hw_intel.c | 2222 +++++++++++++++++++++++++++++++++++
 drivers/ntb/hw/intel/ntb_hw_intel.h |  342 ++++++
 drivers/ntb/ntb.c                   |  251 ++++
 drivers/ntb/ntb_hw.c                | 1896 ------------------------------
 drivers/ntb/ntb_hw.h                |  256 ----
 drivers/ntb/ntb_regs.h              |  177 ---
 drivers/ntb/ntb_transport.c         | 1018 +++++++++-------
 drivers/ntb/test/Kconfig            |   21 +
 drivers/ntb/test/Makefile           |    2 +
 drivers/ntb/test/ntb_pingpong.c     |  251 ++++
 drivers/ntb/test/ntb_tool.c         |  557 +++++++++
 include/linux/ntb.h                 |  969 ++++++++++++++-
 include/linux/ntb_transport.h       |   85 ++
 22 files changed, 5486 insertions(+), 2799 deletions(-)
 create mode 100644 Documentation/ntb.txt
 create mode 100644 drivers/ntb/hw/Kconfig
 create mode 100644 drivers/ntb/hw/Makefile
 create mode 100644 drivers/ntb/hw/intel/Kconfig
 create mode 100644 drivers/ntb/hw/intel/Makefile
 create mode 100644 drivers/ntb/hw/intel/ntb_hw_intel.c
 create mode 100644 drivers/ntb/hw/intel/ntb_hw_intel.h
 create mode 100644 drivers/ntb/ntb.c
 delete mode 100644 drivers/ntb/ntb_hw.c
 delete mode 100644 drivers/ntb/ntb_hw.h
 delete mode 100644 drivers/ntb/ntb_regs.h
 create mode 100644 drivers/ntb/test/Kconfig
 create mode 100644 drivers/ntb/test/Makefile
 create mode 100644 drivers/ntb/test/ntb_pingpong.c
 create mode 100644 drivers/ntb/test/ntb_tool.c
 create mode 100644 include/linux/ntb_transport.h

-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 01/16] Move files in preparation for NTB Abstraction
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 02/16] NTB Abstraction Layer Allen Hubbe
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

This patch only serves the purpose to move files to their new locations,
before applying the next patch adding the NTB Abstraction layer.
Splitting this patch from the next is intended make distinct the which
code is changed only due to moving the files, versus which are
substantial code changes in adding the NTB Abstraction layer.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/net/ntb_netdev.c            |    2 +-
 drivers/ntb/Makefile                |    2 +-
 drivers/ntb/hw/intel/ntb_hw_intel.c | 1895 ++++++++++++++++++++++++++++++++++
 drivers/ntb/hw/intel/ntb_hw_intel.h |  385 +++++++
 drivers/ntb/ntb_hw.c                | 1896 -----------------------------------
 drivers/ntb/ntb_hw.h                |  256 -----
 drivers/ntb/ntb_regs.h              |  177 ----
 drivers/ntb/ntb_transport.c         |    2 +-
 include/linux/ntb.h                 |   88 --
 include/linux/ntb_transport.h       |   88 ++
 10 files changed, 2371 insertions(+), 2420 deletions(-)
 create mode 100644 drivers/ntb/hw/intel/ntb_hw_intel.c
 create mode 100644 drivers/ntb/hw/intel/ntb_hw_intel.h
 delete mode 100644 drivers/ntb/ntb_hw.c
 delete mode 100644 drivers/ntb/ntb_hw.h
 delete mode 100644 drivers/ntb/ntb_regs.h
 delete mode 100644 include/linux/ntb.h
 create mode 100644 include/linux/ntb_transport.h

diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index 5a7e639..dcf8000 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -49,7 +49,7 @@
 #include <linux/ethtool.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/ntb.h>
+#include <linux/ntb_transport.h>
 
 #define NTB_NETDEV_VER	"0.7"
 
diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile
index 15cb59f..17f0309 100644
--- a/drivers/ntb/Makefile
+++ b/drivers/ntb/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_NTB) += ntb.o
 
-ntb-objs := ntb_hw.o ntb_transport.o
+ntb-objs := hw/intel/ntb_hw_intel.o ntb_transport.o
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
new file mode 100644
index 0000000..9ce4148
--- /dev/null
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -0,0 +1,1895 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Intel PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Jon Mason <jon.mason@intel.com>
+ */
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include "ntb_hw_intel.h"
+
+#define NTB_NAME	"Intel(R) PCI-E Non-Transparent Bridge Driver"
+#define NTB_VER		"1.0"
+
+MODULE_DESCRIPTION(NTB_NAME);
+MODULE_VERSION(NTB_VER);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+
+enum {
+	NTB_CONN_TRANSPARENT = 0,
+	NTB_CONN_B2B,
+	NTB_CONN_RP,
+};
+
+enum {
+	NTB_DEV_USD = 0,
+	NTB_DEV_DSD,
+};
+
+enum {
+	SNB_HW = 0,
+	BWD_HW,
+};
+
+static struct dentry *debugfs_dir;
+
+#define BWD_LINK_RECOVERY_TIME	500
+
+/* Translate memory window 0,1,2 to BAR 2,4,5 */
+#define MW_TO_BAR(mw)	(mw == 0 ? 2 : (mw == 1 ? 4 : 5))
+
+static const struct pci_device_id ntb_pci_tbl[] = {
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)},
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, ntb_pci_tbl);
+
+static int is_ntb_xeon(struct ntb_device *ndev)
+{
+	switch (ndev->pdev->device) {
+	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+		return 1;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int is_ntb_atom(struct ntb_device *ndev)
+{
+	switch (ndev->pdev->device) {
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD:
+		return 1;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static void ntb_set_errata_flags(struct ntb_device *ndev)
+{
+	switch (ndev->pdev->device) {
+	/*
+	 * this workaround applies to all platform up to IvyBridge
+	 * Haswell has splitbar support and use a different workaround
+	 */
+	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+		ndev->wa_flags |= WA_SNB_ERR;
+		break;
+	}
+}
+
+/**
+ * ntb_register_event_callback() - register event callback
+ * @ndev: pointer to ntb_device instance
+ * @func: callback function to register
+ *
+ * This function registers a callback for any HW driver events such as link
+ * up/down, power management notices and etc.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_register_event_callback(struct ntb_device *ndev,
+				void (*func)(void *handle,
+					     enum ntb_hw_event event))
+{
+	if (ndev->event_cb)
+		return -EINVAL;
+
+	ndev->event_cb = func;
+
+	return 0;
+}
+
+/**
+ * ntb_unregister_event_callback() - unregisters the event callback
+ * @ndev: pointer to ntb_device instance
+ *
+ * This function unregisters the existing callback from transport
+ */
+void ntb_unregister_event_callback(struct ntb_device *ndev)
+{
+	ndev->event_cb = NULL;
+}
+
+static void ntb_irq_work(unsigned long data)
+{
+	struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data;
+	int rc;
+
+	rc = db_cb->callback(db_cb->data, db_cb->db_num);
+	if (rc)
+		tasklet_schedule(&db_cb->irq_work);
+	else {
+		struct ntb_device *ndev = db_cb->ndev;
+		unsigned long mask;
+
+		mask = readw(ndev->reg_ofs.ldb_mask);
+		clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
+		writew(mask, ndev->reg_ofs.ldb_mask);
+	}
+}
+
+/**
+ * ntb_register_db_callback() - register a callback for doorbell interrupt
+ * @ndev: pointer to ntb_device instance
+ * @idx: doorbell index to register callback, zero based
+ * @data: pointer to be returned to caller with every callback
+ * @func: callback function to register
+ *
+ * This function registers a callback function for the doorbell interrupt
+ * on the primary side. The function will unmask the doorbell as well to
+ * allow interrupt.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
+			     void *data, int (*func)(void *data, int db_num))
+{
+	unsigned long mask;
+
+	if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) {
+		dev_warn(&ndev->pdev->dev, "Invalid Index.\n");
+		return -EINVAL;
+	}
+
+	ndev->db_cb[idx].callback = func;
+	ndev->db_cb[idx].data = data;
+	ndev->db_cb[idx].ndev = ndev;
+
+	tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work,
+		     (unsigned long) &ndev->db_cb[idx]);
+
+	/* unmask interrupt */
+	mask = readw(ndev->reg_ofs.ldb_mask);
+	clear_bit(idx * ndev->bits_per_vector, &mask);
+	writew(mask, ndev->reg_ofs.ldb_mask);
+
+	return 0;
+}
+
+/**
+ * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt
+ * @ndev: pointer to ntb_device instance
+ * @idx: doorbell index to register callback, zero based
+ *
+ * This function unregisters a callback function for the doorbell interrupt
+ * on the primary side. The function will also mask the said doorbell.
+ */
+void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx)
+{
+	unsigned long mask;
+
+	if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback)
+		return;
+
+	mask = readw(ndev->reg_ofs.ldb_mask);
+	set_bit(idx * ndev->bits_per_vector, &mask);
+	writew(mask, ndev->reg_ofs.ldb_mask);
+
+	tasklet_disable(&ndev->db_cb[idx].irq_work);
+
+	ndev->db_cb[idx].callback = NULL;
+}
+
+/**
+ * ntb_find_transport() - find the transport pointer
+ * @transport: pointer to pci device
+ *
+ * Given the pci device pointer, return the transport pointer passed in when
+ * the transport attached when it was inited.
+ *
+ * RETURNS: pointer to transport.
+ */
+void *ntb_find_transport(struct pci_dev *pdev)
+{
+	struct ntb_device *ndev = pci_get_drvdata(pdev);
+	return ndev->ntb_transport;
+}
+
+/**
+ * ntb_register_transport() - Register NTB transport with NTB HW driver
+ * @transport: transport identifier
+ *
+ * This function allows a transport to reserve the hardware driver for
+ * NTB usage.
+ *
+ * RETURNS: pointer to ntb_device, NULL on error.
+ */
+struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport)
+{
+	struct ntb_device *ndev = pci_get_drvdata(pdev);
+
+	if (ndev->ntb_transport)
+		return NULL;
+
+	ndev->ntb_transport = transport;
+	return ndev;
+}
+
+/**
+ * ntb_unregister_transport() - Unregister the transport with the NTB HW driver
+ * @ndev - ntb_device of the transport to be freed
+ *
+ * This function unregisters the transport from the HW driver and performs any
+ * necessary cleanups.
+ */
+void ntb_unregister_transport(struct ntb_device *ndev)
+{
+	int i;
+
+	if (!ndev->ntb_transport)
+		return;
+
+	for (i = 0; i < ndev->max_cbs; i++)
+		ntb_unregister_db_callback(ndev, i);
+
+	ntb_unregister_event_callback(ndev);
+	ndev->ntb_transport = NULL;
+}
+
+/**
+ * ntb_write_local_spad() - write to the secondary scratchpad register
+ * @ndev: pointer to ntb_device instance
+ * @idx: index to the scratchpad register, 0 based
+ * @val: the data value to put into the register
+ *
+ * This function allows writing of a 32bit value to the indexed scratchpad
+ * register. This writes over the data mirrored to the local scratchpad register
+ * by the remote system.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val)
+{
+	if (idx >= ndev->limits.max_spads)
+		return -EINVAL;
+
+	dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n",
+		val, idx);
+	writel(val, ndev->reg_ofs.spad_read + idx * 4);
+
+	return 0;
+}
+
+/**
+ * ntb_read_local_spad() - read from the primary scratchpad register
+ * @ndev: pointer to ntb_device instance
+ * @idx: index to scratchpad register, 0 based
+ * @val: pointer to 32bit integer for storing the register value
+ *
+ * This function allows reading of the 32bit scratchpad register on
+ * the primary (internal) side.  This allows the local system to read data
+ * written and mirrored to the scratchpad register by the remote system.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
+{
+	if (idx >= ndev->limits.max_spads)
+		return -EINVAL;
+
+	*val = readl(ndev->reg_ofs.spad_write + idx * 4);
+	dev_dbg(&ndev->pdev->dev,
+		"Reading %x from local scratch pad index %d\n", *val, idx);
+
+	return 0;
+}
+
+/**
+ * ntb_write_remote_spad() - write to the secondary scratchpad register
+ * @ndev: pointer to ntb_device instance
+ * @idx: index to the scratchpad register, 0 based
+ * @val: the data value to put into the register
+ *
+ * This function allows writing of a 32bit value to the indexed scratchpad
+ * register. The register resides on the secondary (external) side.  This allows
+ * the local system to write data to be mirrored to the remote systems
+ * scratchpad register.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val)
+{
+	if (idx >= ndev->limits.max_spads)
+		return -EINVAL;
+
+	dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n",
+		val, idx);
+	writel(val, ndev->reg_ofs.spad_write + idx * 4);
+
+	return 0;
+}
+
+/**
+ * ntb_read_remote_spad() - read from the primary scratchpad register
+ * @ndev: pointer to ntb_device instance
+ * @idx: index to scratchpad register, 0 based
+ * @val: pointer to 32bit integer for storing the register value
+ *
+ * This function allows reading of the 32bit scratchpad register on
+ * the primary (internal) side.  This alloows the local system to read the data
+ * it wrote to be mirrored on the remote system.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
+{
+	if (idx >= ndev->limits.max_spads)
+		return -EINVAL;
+
+	*val = readl(ndev->reg_ofs.spad_read + idx * 4);
+	dev_dbg(&ndev->pdev->dev,
+		"Reading %x from remote scratch pad index %d\n", *val, idx);
+
+	return 0;
+}
+
+/**
+ * ntb_get_mw_base() - get addr for the NTB memory window
+ * @ndev: pointer to ntb_device instance
+ * @mw: memory window number
+ *
+ * This function provides the base address of the memory window specified.
+ *
+ * RETURNS: address, or NULL on error.
+ */
+resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw)
+{
+	if (mw >= ntb_max_mw(ndev))
+		return 0;
+
+	return pci_resource_start(ndev->pdev, MW_TO_BAR(mw));
+}
+
+/**
+ * ntb_get_mw_vbase() - get virtual addr for the NTB memory window
+ * @ndev: pointer to ntb_device instance
+ * @mw: memory window number
+ *
+ * This function provides the base virtual address of the memory window
+ * specified.
+ *
+ * RETURNS: pointer to virtual address, or NULL on error.
+ */
+void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw)
+{
+	if (mw >= ntb_max_mw(ndev))
+		return NULL;
+
+	return ndev->mw[mw].vbase;
+}
+
+/**
+ * ntb_get_mw_size() - return size of NTB memory window
+ * @ndev: pointer to ntb_device instance
+ * @mw: memory window number
+ *
+ * This function provides the physical size of the memory window specified
+ *
+ * RETURNS: the size of the memory window or zero on error
+ */
+u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
+{
+	if (mw >= ntb_max_mw(ndev))
+		return 0;
+
+	return ndev->mw[mw].bar_sz;
+}
+
+/**
+ * ntb_set_mw_addr - set the memory window address
+ * @ndev: pointer to ntb_device instance
+ * @mw: memory window number
+ * @addr: base address for data
+ *
+ * This function sets the base physical address of the memory window.  This
+ * memory address is where data from the remote system will be transfered into
+ * or out of depending on how the transport is configured.
+ */
+void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
+{
+	if (mw >= ntb_max_mw(ndev))
+		return;
+
+	dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr,
+		MW_TO_BAR(mw));
+
+	ndev->mw[mw].phys_addr = addr;
+
+	switch (MW_TO_BAR(mw)) {
+	case NTB_BAR_23:
+		writeq(addr, ndev->reg_ofs.bar2_xlat);
+		break;
+	case NTB_BAR_4:
+		if (ndev->split_bar)
+			writel(addr, ndev->reg_ofs.bar4_xlat);
+		else
+			writeq(addr, ndev->reg_ofs.bar4_xlat);
+		break;
+	case NTB_BAR_5:
+		writel(addr, ndev->reg_ofs.bar5_xlat);
+		break;
+	}
+}
+
+/**
+ * ntb_ring_doorbell() - Set the doorbell on the secondary/external side
+ * @ndev: pointer to ntb_device instance
+ * @db: doorbell to ring
+ *
+ * This function allows triggering of a doorbell on the secondary/external
+ * side that will initiate an interrupt on the remote host
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db)
+{
+	dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db);
+
+	if (ndev->hw_type == BWD_HW)
+		writeq((u64) 1 << db, ndev->reg_ofs.rdb);
+	else
+		writew(((1 << ndev->bits_per_vector) - 1) <<
+		       (db * ndev->bits_per_vector), ndev->reg_ofs.rdb);
+}
+
+static void bwd_recover_link(struct ntb_device *ndev)
+{
+	u32 status;
+
+	/* Driver resets the NTB ModPhy lanes - magic! */
+	writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6);
+	writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4);
+	writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4);
+	writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6);
+
+	/* Driver waits 100ms to allow the NTB ModPhy to settle */
+	msleep(100);
+
+	/* Clear AER Errors, write to clear */
+	status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET);
+	dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status);
+	status &= PCI_ERR_COR_REP_ROLL;
+	writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET);
+
+	/* Clear unexpected electrical idle event in LTSSM, write to clear */
+	status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET);
+	dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status);
+	status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI;
+	writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET);
+
+	/* Clear DeSkew Buffer error, write to clear */
+	status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET);
+	dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status);
+	status |= BWD_DESKEWSTS_DBERR;
+	writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET);
+
+	status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
+	dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status);
+	status &= BWD_IBIST_ERR_OFLOW;
+	writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
+
+	/* Releases the NTB state machine to allow the link to retrain */
+	status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
+	dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status);
+	status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT;
+	writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
+}
+
+static void ntb_link_event(struct ntb_device *ndev, int link_state)
+{
+	unsigned int event;
+
+	if (ndev->link_status == link_state)
+		return;
+
+	if (link_state == NTB_LINK_UP) {
+		u16 status;
+
+		dev_info(&ndev->pdev->dev, "Link Up\n");
+		ndev->link_status = NTB_LINK_UP;
+		event = NTB_EVENT_HW_LINK_UP;
+
+		if (is_ntb_atom(ndev) ||
+		    ndev->conn_type == NTB_CONN_TRANSPARENT)
+			status = readw(ndev->reg_ofs.lnk_stat);
+		else {
+			int rc = pci_read_config_word(ndev->pdev,
+						      SNB_LINK_STATUS_OFFSET,
+						      &status);
+			if (rc)
+				return;
+		}
+
+		ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4;
+		ndev->link_speed = (status & NTB_LINK_SPEED_MASK);
+		dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n",
+			 ndev->link_width, ndev->link_speed);
+	} else {
+		dev_info(&ndev->pdev->dev, "Link Down\n");
+		ndev->link_status = NTB_LINK_DOWN;
+		event = NTB_EVENT_HW_LINK_DOWN;
+		/* Don't modify link width/speed, we need it in link recovery */
+	}
+
+	/* notify the upper layer if we have an event change */
+	if (ndev->event_cb)
+		ndev->event_cb(ndev->ntb_transport, event);
+}
+
+static int ntb_link_status(struct ntb_device *ndev)
+{
+	int link_state;
+
+	if (is_ntb_atom(ndev)) {
+		u32 ntb_cntl;
+
+		ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
+		if (ntb_cntl & BWD_CNTL_LINK_DOWN)
+			link_state = NTB_LINK_DOWN;
+		else
+			link_state = NTB_LINK_UP;
+	} else {
+		u16 status;
+		int rc;
+
+		rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET,
+					  &status);
+		if (rc)
+			return rc;
+
+		if (status & NTB_LINK_STATUS_ACTIVE)
+			link_state = NTB_LINK_UP;
+		else
+			link_state = NTB_LINK_DOWN;
+	}
+
+	ntb_link_event(ndev, link_state);
+
+	return 0;
+}
+
+static void bwd_link_recovery(struct work_struct *work)
+{
+	struct ntb_device *ndev = container_of(work, struct ntb_device,
+					       lr_timer.work);
+	u32 status32;
+
+	bwd_recover_link(ndev);
+	/* There is a potential race between the 2 NTB devices recovering at the
+	 * same time.  If the times are the same, the link will not recover and
+	 * the driver will be stuck in this loop forever.  Add a random interval
+	 * to the recovery time to prevent this race.
+	 */
+	msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME);
+
+	status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
+	if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT)
+		goto retry;
+
+	status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
+	if (status32 & BWD_IBIST_ERR_OFLOW)
+		goto retry;
+
+	status32 = readl(ndev->reg_ofs.lnk_cntl);
+	if (!(status32 & BWD_CNTL_LINK_DOWN)) {
+		unsigned char speed, width;
+		u16 status16;
+
+		status16 = readw(ndev->reg_ofs.lnk_stat);
+		width = (status16 & NTB_LINK_WIDTH_MASK) >> 4;
+		speed = (status16 & NTB_LINK_SPEED_MASK);
+		if (ndev->link_width != width || ndev->link_speed != speed)
+			goto retry;
+	}
+
+	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
+	return;
+
+retry:
+	schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT);
+}
+
+/* BWD doesn't have link status interrupt, poll on that platform */
+static void bwd_link_poll(struct work_struct *work)
+{
+	struct ntb_device *ndev = container_of(work, struct ntb_device,
+					       hb_timer.work);
+	unsigned long ts = jiffies;
+
+	/* If we haven't gotten an interrupt in a while, check the BWD link
+	 * status bit
+	 */
+	if (ts > ndev->last_ts + NTB_HB_TIMEOUT) {
+		int rc = ntb_link_status(ndev);
+		if (rc)
+			dev_err(&ndev->pdev->dev,
+				"Error determining link status\n");
+
+		/* Check to see if a link error is the cause of the link down */
+		if (ndev->link_status == NTB_LINK_DOWN) {
+			u32 status32 = readl(ndev->reg_base +
+					     BWD_LTSSMSTATEJMP_OFFSET);
+			if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) {
+				schedule_delayed_work(&ndev->lr_timer, 0);
+				return;
+			}
+		}
+	}
+
+	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
+}
+
+static int ntb_xeon_setup(struct ntb_device *ndev)
+{
+	switch (ndev->conn_type) {
+	case NTB_CONN_B2B:
+		ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
+		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
+		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
+		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
+		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
+		if (ndev->split_bar)
+			ndev->reg_ofs.bar5_xlat =
+				ndev->reg_base + SNB_SBAR5XLAT_OFFSET;
+		ndev->limits.max_spads = SNB_MAX_B2B_SPADS;
+
+		/* 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 window to access the interrupt and
+		 * scratch pad registers on the remote system.
+		 */
+		if (ndev->wa_flags & WA_SNB_ERR) {
+			if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz)
+				return -EINVAL;
+
+			ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
+			ndev->reg_ofs.spad_write =
+				ndev->mw[ndev->limits.max_mw - 1].vbase +
+				SNB_SPAD_OFFSET;
+			ndev->reg_ofs.rdb =
+				ndev->mw[ndev->limits.max_mw - 1].vbase +
+				SNB_PDOORBELL_OFFSET;
+
+			/* Set the Limit register to 4k, the minimum size, to
+			 * prevent an illegal access
+			 */
+			writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base +
+			       SNB_PBAR4LMT_OFFSET);
+			/* HW errata on the Limit registers.  They can only be
+			 * written when the base register is 4GB aligned and
+			 * < 32bit.  This should already be the case based on
+			 * the driver defaults, but write the Limit registers
+			 * first just in case.
+			 */
+
+			ndev->limits.max_mw = SNB_ERRATA_MAX_MW;
+		} else {
+			/* HW Errata on bit 14 of b2bdoorbell register.  Writes
+			 * will not be mirrored to the remote system.  Shrink
+			 * the number of bits by one, since bit 14 is the last
+			 * bit.
+			 */
+			ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1;
+			ndev->reg_ofs.spad_write = ndev->reg_base +
+						   SNB_B2B_SPAD_OFFSET;
+			ndev->reg_ofs.rdb = ndev->reg_base +
+					    SNB_B2B_DOORBELL_OFFSET;
+
+			/* Disable the Limit register, just incase it is set to
+			 * something silly. A 64bit write should handle it
+			 * regardless of whether it has a split BAR or not.
+			 */
+			writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET);
+			/* HW errata on the Limit registers.  They can only be
+			 * written when the base register is 4GB aligned and
+			 * < 32bit.  This should already be the case based on
+			 * the driver defaults, but write the Limit registers
+			 * first just in case.
+			 */
+			if (ndev->split_bar)
+				ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
+			else
+				ndev->limits.max_mw = SNB_MAX_MW;
+		}
+
+		/* The Xeon errata workaround requires setting SBAR Base
+		 * addresses to known values, so that the PBAR XLAT can be
+		 * pointed at SBAR0 of the remote system.
+		 */
+		if (ndev->dev_type == NTB_DEV_USD) {
+			writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base +
+			       SNB_PBAR2XLAT_OFFSET);
+			if (ndev->wa_flags & WA_SNB_ERR)
+				writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base +
+				       SNB_PBAR4XLAT_OFFSET);
+			else {
+				if (ndev->split_bar) {
+					writel(SNB_MBAR4_DSD_ADDR,
+					       ndev->reg_base +
+					       SNB_PBAR4XLAT_OFFSET);
+					writel(SNB_MBAR5_DSD_ADDR,
+					       ndev->reg_base +
+					       SNB_PBAR5XLAT_OFFSET);
+				} else
+					writeq(SNB_MBAR4_DSD_ADDR,
+					       ndev->reg_base +
+					       SNB_PBAR4XLAT_OFFSET);
+
+				/* B2B_XLAT_OFFSET is a 64bit register, but can
+				 * only take 32bit writes
+				 */
+				writel(SNB_MBAR01_DSD_ADDR & 0xffffffff,
+				       ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
+				writel(SNB_MBAR01_DSD_ADDR >> 32,
+				       ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
+			}
+
+			writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base +
+			       SNB_SBAR0BASE_OFFSET);
+			writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base +
+			       SNB_SBAR2BASE_OFFSET);
+			if (ndev->split_bar) {
+				writel(SNB_MBAR4_USD_ADDR, ndev->reg_base +
+				       SNB_SBAR4BASE_OFFSET);
+				writel(SNB_MBAR5_USD_ADDR, ndev->reg_base +
+				       SNB_SBAR5BASE_OFFSET);
+			} else
+				writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base +
+				       SNB_SBAR4BASE_OFFSET);
+		} else {
+			writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base +
+			       SNB_PBAR2XLAT_OFFSET);
+			if (ndev->wa_flags & WA_SNB_ERR)
+				writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base +
+				       SNB_PBAR4XLAT_OFFSET);
+			else {
+				if (ndev->split_bar) {
+					writel(SNB_MBAR4_USD_ADDR,
+					       ndev->reg_base +
+					       SNB_PBAR4XLAT_OFFSET);
+					writel(SNB_MBAR5_USD_ADDR,
+					       ndev->reg_base +
+					       SNB_PBAR5XLAT_OFFSET);
+				} else
+					writeq(SNB_MBAR4_USD_ADDR,
+					       ndev->reg_base +
+					       SNB_PBAR4XLAT_OFFSET);
+
+				/*
+				 * B2B_XLAT_OFFSET is a 64bit register, but can
+				 * only take 32bit writes
+				 */
+				writel(SNB_MBAR01_USD_ADDR & 0xffffffff,
+				       ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
+				writel(SNB_MBAR01_USD_ADDR >> 32,
+				       ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
+			}
+			writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base +
+			       SNB_SBAR0BASE_OFFSET);
+			writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base +
+			       SNB_SBAR2BASE_OFFSET);
+			if (ndev->split_bar) {
+				writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base +
+				       SNB_SBAR4BASE_OFFSET);
+				writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base +
+				       SNB_SBAR5BASE_OFFSET);
+			} else
+				writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base +
+				       SNB_SBAR4BASE_OFFSET);
+
+		}
+		break;
+	case NTB_CONN_RP:
+		if (ndev->wa_flags & WA_SNB_ERR) {
+			dev_err(&ndev->pdev->dev,
+				"NTB-RP disabled due to hardware errata.\n");
+			return -EINVAL;
+		}
+
+		/* Scratch pads need to have exclusive access from the primary
+		 * or secondary side.  Halve the num spads so that each side can
+		 * have an equal amount.
+		 */
+		ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2;
+		ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
+		/* Note: The SDOORBELL is the cause of the errata.  You REALLY
+		 * don't want to touch it.
+		 */
+		ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
+		ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
+		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
+		/* Offset the start of the spads to correspond to whether it is
+		 * primary or secondary
+		 */
+		ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET +
+					   ndev->limits.max_spads * 4;
+		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
+		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
+		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
+		if (ndev->split_bar) {
+			ndev->reg_ofs.bar5_xlat =
+				ndev->reg_base + SNB_SBAR5XLAT_OFFSET;
+			ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
+		} else
+			ndev->limits.max_mw = SNB_MAX_MW;
+		break;
+	case NTB_CONN_TRANSPARENT:
+		if (ndev->wa_flags & WA_SNB_ERR) {
+			dev_err(&ndev->pdev->dev,
+				"NTB-TRANSPARENT disabled due to hardware errata.\n");
+			return -EINVAL;
+		}
+
+		/* Scratch pads need to have exclusive access from the primary
+		 * or secondary side.  Halve the num spads so that each side can
+		 * have an equal amount.
+		 */
+		ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2;
+		ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
+		ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
+		ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
+		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET;
+		ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET;
+		/* Offset the start of the spads to correspond to whether it is
+		 * primary or secondary
+		 */
+		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET +
+					  ndev->limits.max_spads * 4;
+		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET;
+		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET;
+
+		if (ndev->split_bar) {
+			ndev->reg_ofs.bar5_xlat =
+				ndev->reg_base + SNB_PBAR5XLAT_OFFSET;
+			ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
+		} else
+			ndev->limits.max_mw = SNB_MAX_MW;
+		break;
+	default:
+		/*
+		 * we should never hit this. the detect function should've
+		 * take cared of everything.
+		 */
+		return -EINVAL;
+	}
+
+	ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET;
+	ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET;
+	ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET;
+
+	ndev->limits.msix_cnt = SNB_MSIX_CNT;
+	ndev->bits_per_vector = SNB_DB_BITS_PER_VEC;
+
+	return 0;
+}
+
+static int ntb_bwd_setup(struct ntb_device *ndev)
+{
+	int rc;
+	u32 val;
+
+	ndev->hw_type = BWD_HW;
+
+	rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val);
+	if (rc)
+		return rc;
+
+	switch ((val & BWD_PPD_CONN_TYPE) >> 8) {
+	case NTB_CONN_B2B:
+		ndev->conn_type = NTB_CONN_B2B;
+		break;
+	case NTB_CONN_RP:
+	default:
+		dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n");
+		return -EINVAL;
+	}
+
+	if (val & BWD_PPD_DEV_TYPE)
+		ndev->dev_type = NTB_DEV_DSD;
+	else
+		ndev->dev_type = NTB_DEV_USD;
+
+	/* Initiate PCI-E link training */
+	rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET,
+				    val | BWD_PPD_INIT_LINK);
+	if (rc)
+		return rc;
+
+	ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET;
+	ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET;
+	ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET;
+	ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET;
+	ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET;
+	ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET;
+	ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET;
+	ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET;
+	ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET;
+	ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET;
+	ndev->limits.max_mw = BWD_MAX_MW;
+	ndev->limits.max_spads = BWD_MAX_SPADS;
+	ndev->limits.max_db_bits = BWD_MAX_DB_BITS;
+	ndev->limits.msix_cnt = BWD_MSIX_CNT;
+	ndev->bits_per_vector = BWD_DB_BITS_PER_VEC;
+
+	/* Since bwd doesn't have a link interrupt, setup a poll timer */
+	INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll);
+	INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery);
+	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
+
+	return 0;
+}
+
+static int ntb_device_setup(struct ntb_device *ndev)
+{
+	int rc;
+
+	if (is_ntb_xeon(ndev))
+		rc = ntb_xeon_setup(ndev);
+	else if (is_ntb_atom(ndev))
+		rc = ntb_bwd_setup(ndev);
+	else
+		rc = -ENODEV;
+
+	if (rc)
+		return rc;
+
+	if (ndev->conn_type == NTB_CONN_B2B)
+		/* Enable Bus Master and Memory Space on the secondary side */
+		writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+		       ndev->reg_ofs.spci_cmd);
+
+	return 0;
+}
+
+static void ntb_device_free(struct ntb_device *ndev)
+{
+	if (is_ntb_atom(ndev)) {
+		cancel_delayed_work_sync(&ndev->hb_timer);
+		cancel_delayed_work_sync(&ndev->lr_timer);
+	}
+}
+
+static irqreturn_t bwd_callback_msix_irq(int irq, void *data)
+{
+	struct ntb_db_cb *db_cb = data;
+	struct ntb_device *ndev = db_cb->ndev;
+	unsigned long mask;
+
+	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
+		db_cb->db_num);
+
+	mask = readw(ndev->reg_ofs.ldb_mask);
+	set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
+	writew(mask, ndev->reg_ofs.ldb_mask);
+
+	tasklet_schedule(&db_cb->irq_work);
+
+	/* No need to check for the specific HB irq, any interrupt means
+	 * we're connected.
+	 */
+	ndev->last_ts = jiffies;
+
+	writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
+{
+	struct ntb_db_cb *db_cb = data;
+	struct ntb_device *ndev = db_cb->ndev;
+	unsigned long mask;
+
+	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
+		db_cb->db_num);
+
+	mask = readw(ndev->reg_ofs.ldb_mask);
+	set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
+	writew(mask, ndev->reg_ofs.ldb_mask);
+
+	tasklet_schedule(&db_cb->irq_work);
+
+	/* On Sandybridge, there are 16 bits in the interrupt register
+	 * but only 4 vectors.  So, 5 bits are assigned to the first 3
+	 * vectors, with the 4th having a single bit for link
+	 * interrupts.
+	 */
+	writew(((1 << ndev->bits_per_vector) - 1) <<
+	       (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb);
+
+	return IRQ_HANDLED;
+}
+
+/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */
+static irqreturn_t xeon_event_msix_irq(int irq, void *dev)
+{
+	struct ntb_device *ndev = dev;
+	int rc;
+
+	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq);
+
+	rc = ntb_link_status(ndev);
+	if (rc)
+		dev_err(&ndev->pdev->dev, "Error determining link status\n");
+
+	/* bit 15 is always the link bit */
+	writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t ntb_interrupt(int irq, void *dev)
+{
+	struct ntb_device *ndev = dev;
+	unsigned int i = 0;
+
+	if (is_ntb_atom(ndev)) {
+		u64 ldb = readq(ndev->reg_ofs.ldb);
+
+		dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb);
+
+		while (ldb) {
+			i = __ffs(ldb);
+			ldb &= ldb - 1;
+			bwd_callback_msix_irq(irq, &ndev->db_cb[i]);
+		}
+	} else {
+		u16 ldb = readw(ndev->reg_ofs.ldb);
+
+		dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb);
+
+		if (ldb & SNB_DB_HW_LINK) {
+			xeon_event_msix_irq(irq, dev);
+			ldb &= ~SNB_DB_HW_LINK;
+		}
+
+		while (ldb) {
+			i = __ffs(ldb);
+			ldb &= ldb - 1;
+			xeon_callback_msix_irq(irq, &ndev->db_cb[i]);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries)
+{
+	struct pci_dev *pdev = ndev->pdev;
+	struct msix_entry *msix;
+	int rc, i;
+
+	if (msix_entries < ndev->limits.msix_cnt)
+		return -ENOSPC;
+
+	rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries);
+	if (rc < 0)
+		return rc;
+
+	for (i = 0; i < msix_entries; i++) {
+		msix = &ndev->msix_entries[i];
+		WARN_ON(!msix->vector);
+
+		if (i == msix_entries - 1) {
+			rc = request_irq(msix->vector,
+					 xeon_event_msix_irq, 0,
+					 "ntb-event-msix", ndev);
+			if (rc)
+				goto err;
+		} else {
+			rc = request_irq(msix->vector,
+					 xeon_callback_msix_irq, 0,
+					 "ntb-callback-msix",
+					 &ndev->db_cb[i]);
+			if (rc)
+				goto err;
+		}
+	}
+
+	ndev->num_msix = msix_entries;
+	ndev->max_cbs = msix_entries - 1;
+
+	return 0;
+
+err:
+	while (--i >= 0) {
+		/* Code never reaches here for entry nr 'ndev->num_msix - 1' */
+		msix = &ndev->msix_entries[i];
+		free_irq(msix->vector, &ndev->db_cb[i]);
+	}
+
+	pci_disable_msix(pdev);
+	ndev->num_msix = 0;
+
+	return rc;
+}
+
+static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries)
+{
+	struct pci_dev *pdev = ndev->pdev;
+	struct msix_entry *msix;
+	int rc, i;
+
+	msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries,
+					     1, msix_entries);
+	if (msix_entries < 0)
+		return msix_entries;
+
+	for (i = 0; i < msix_entries; i++) {
+		msix = &ndev->msix_entries[i];
+		WARN_ON(!msix->vector);
+
+		rc = request_irq(msix->vector, bwd_callback_msix_irq, 0,
+				 "ntb-callback-msix", &ndev->db_cb[i]);
+		if (rc)
+			goto err;
+	}
+
+	ndev->num_msix = msix_entries;
+	ndev->max_cbs = msix_entries;
+
+	return 0;
+
+err:
+	while (--i >= 0)
+		free_irq(msix->vector, &ndev->db_cb[i]);
+
+	pci_disable_msix(pdev);
+	ndev->num_msix = 0;
+
+	return rc;
+}
+
+static int ntb_setup_msix(struct ntb_device *ndev)
+{
+	struct pci_dev *pdev = ndev->pdev;
+	int msix_entries;
+	int rc, i;
+
+	msix_entries = pci_msix_vec_count(pdev);
+	if (msix_entries < 0) {
+		rc = msix_entries;
+		goto err;
+	} else if (msix_entries > ndev->limits.msix_cnt) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries,
+				     GFP_KERNEL);
+	if (!ndev->msix_entries) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < msix_entries; i++)
+		ndev->msix_entries[i].entry = i;
+
+	if (is_ntb_atom(ndev))
+		rc = ntb_setup_bwd_msix(ndev, msix_entries);
+	else
+		rc = ntb_setup_snb_msix(ndev, msix_entries);
+	if (rc)
+		goto err1;
+
+	return 0;
+
+err1:
+	kfree(ndev->msix_entries);
+err:
+	dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n");
+	return rc;
+}
+
+static int ntb_setup_msi(struct ntb_device *ndev)
+{
+	struct pci_dev *pdev = ndev->pdev;
+	int rc;
+
+	rc = pci_enable_msi(pdev);
+	if (rc)
+		return rc;
+
+	rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev);
+	if (rc) {
+		pci_disable_msi(pdev);
+		dev_err(&pdev->dev, "Error allocating MSI interrupt\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int ntb_setup_intx(struct ntb_device *ndev)
+{
+	struct pci_dev *pdev = ndev->pdev;
+	int rc;
+
+	pci_msi_off(pdev);
+
+	/* Verify intx is enabled */
+	pci_intx(pdev, 1);
+
+	rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx",
+			 ndev);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int ntb_setup_interrupts(struct ntb_device *ndev)
+{
+	int rc;
+
+	/* On BWD, disable all interrupts.  On SNB, disable all but Link
+	 * Interrupt.  The rest will be unmasked as callbacks are registered.
+	 */
+	if (is_ntb_atom(ndev))
+		writeq(~0, ndev->reg_ofs.ldb_mask);
+	else {
+		u16 var = 1 << SNB_LINK_DB;
+		writew(~var, ndev->reg_ofs.ldb_mask);
+	}
+
+	rc = ntb_setup_msix(ndev);
+	if (!rc)
+		goto done;
+
+	ndev->bits_per_vector = 1;
+	ndev->max_cbs = ndev->limits.max_db_bits;
+
+	rc = ntb_setup_msi(ndev);
+	if (!rc)
+		goto done;
+
+	rc = ntb_setup_intx(ndev);
+	if (rc) {
+		dev_err(&ndev->pdev->dev, "no usable interrupts\n");
+		return rc;
+	}
+
+done:
+	return 0;
+}
+
+static void ntb_free_interrupts(struct ntb_device *ndev)
+{
+	struct pci_dev *pdev = ndev->pdev;
+
+	/* mask interrupts */
+	if (is_ntb_atom(ndev))
+		writeq(~0, ndev->reg_ofs.ldb_mask);
+	else
+		writew(~0, ndev->reg_ofs.ldb_mask);
+
+	if (ndev->num_msix) {
+		struct msix_entry *msix;
+		u32 i;
+
+		for (i = 0; i < ndev->num_msix; i++) {
+			msix = &ndev->msix_entries[i];
+			if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1)
+				free_irq(msix->vector, ndev);
+			else
+				free_irq(msix->vector, &ndev->db_cb[i]);
+		}
+		pci_disable_msix(pdev);
+		kfree(ndev->msix_entries);
+	} else {
+		free_irq(pdev->irq, ndev);
+
+		if (pci_dev_msi_enabled(pdev))
+			pci_disable_msi(pdev);
+	}
+}
+
+static int ntb_create_callbacks(struct ntb_device *ndev)
+{
+	int i;
+
+	/* Chicken-egg issue.  We won't know how many callbacks are necessary
+	 * until we see how many MSI-X vectors we get, but these pointers need
+	 * to be passed into the MSI-X register function.  So, we allocate the
+	 * max, knowing that they might not all be used, to work around this.
+	 */
+	ndev->db_cb = kcalloc(ndev->limits.max_db_bits,
+			      sizeof(struct ntb_db_cb),
+			      GFP_KERNEL);
+	if (!ndev->db_cb)
+		return -ENOMEM;
+
+	for (i = 0; i < ndev->limits.max_db_bits; i++) {
+		ndev->db_cb[i].db_num = i;
+		ndev->db_cb[i].ndev = ndev;
+	}
+
+	return 0;
+}
+
+static void ntb_free_callbacks(struct ntb_device *ndev)
+{
+	int i;
+
+	for (i = 0; i < ndev->limits.max_db_bits; i++)
+		ntb_unregister_db_callback(ndev, i);
+
+	kfree(ndev->db_cb);
+}
+
+static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf,
+				size_t count, loff_t *offp)
+{
+	struct ntb_device *ndev;
+	char *buf;
+	ssize_t ret, offset, out_count;
+
+	out_count = 500;
+
+	buf = kmalloc(out_count, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ndev = filp->private_data;
+	offset = 0;
+	offset += snprintf(buf + offset, out_count - offset,
+			   "NTB Device Information:\n");
+	offset += snprintf(buf + offset, out_count - offset,
+			   "Connection Type - \t\t%s\n",
+			   ndev->conn_type == NTB_CONN_TRANSPARENT ?
+			   "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ?
+			   "Back to back" : "Root Port");
+	offset += snprintf(buf + offset, out_count - offset,
+			   "Device Type - \t\t\t%s\n",
+			   ndev->dev_type == NTB_DEV_USD ?
+			   "DSD/USP" : "USD/DSP");
+	offset += snprintf(buf + offset, out_count - offset,
+			   "Max Number of Callbacks - \t%u\n",
+			   ntb_max_cbs(ndev));
+	offset += snprintf(buf + offset, out_count - offset,
+			   "Link Status - \t\t\t%s\n",
+			   ntb_hw_link_status(ndev) ? "Up" : "Down");
+	if (ntb_hw_link_status(ndev)) {
+		offset += snprintf(buf + offset, out_count - offset,
+				   "Link Speed - \t\t\tPCI-E Gen %u\n",
+				   ndev->link_speed);
+		offset += snprintf(buf + offset, out_count - offset,
+				   "Link Width - \t\t\tx%u\n",
+				   ndev->link_width);
+	}
+
+	if (is_ntb_xeon(ndev)) {
+		u32 status32;
+		u16 status16;
+		int rc;
+
+		offset += snprintf(buf + offset, out_count - offset,
+				   "\nNTB Device Statistics:\n");
+		offset += snprintf(buf + offset, out_count - offset,
+				   "Upstream Memory Miss - \t%u\n",
+				   readw(ndev->reg_base +
+					 SNB_USMEMMISS_OFFSET));
+
+		offset += snprintf(buf + offset, out_count - offset,
+				   "\nNTB Hardware Errors:\n");
+
+		rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET,
+					  &status16);
+		if (!rc)
+			offset += snprintf(buf + offset, out_count - offset,
+					   "DEVSTS - \t%#06x\n", status16);
+
+		rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET,
+					  &status16);
+		if (!rc)
+			offset += snprintf(buf + offset, out_count - offset,
+					   "LNKSTS - \t%#06x\n", status16);
+
+		rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET,
+					   &status32);
+		if (!rc)
+			offset += snprintf(buf + offset, out_count - offset,
+					   "UNCERRSTS - \t%#010x\n", status32);
+
+		rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET,
+					   &status32);
+		if (!rc)
+			offset += snprintf(buf + offset, out_count - offset,
+					   "CORERRSTS - \t%#010x\n", status32);
+	}
+
+	if (offset > out_count)
+		offset = out_count;
+
+	ret = simple_read_from_buffer(ubuf, count, offp, buf, offset);
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations ntb_debugfs_info = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = ntb_debugfs_read,
+};
+
+static void ntb_setup_debugfs(struct ntb_device *ndev)
+{
+	if (!debugfs_initialized())
+		return;
+
+	if (!debugfs_dir)
+		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+	ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev),
+					       debugfs_dir);
+	if (ndev->debugfs_dir)
+		ndev->debugfs_info = debugfs_create_file("info", S_IRUSR,
+							 ndev->debugfs_dir,
+							 ndev,
+							 &ntb_debugfs_info);
+}
+
+static void ntb_free_debugfs(struct ntb_device *ndev)
+{
+	debugfs_remove_recursive(ndev->debugfs_dir);
+
+	if (debugfs_dir && simple_empty(debugfs_dir)) {
+		debugfs_remove_recursive(debugfs_dir);
+		debugfs_dir = NULL;
+	}
+}
+
+static void ntb_hw_link_up(struct ntb_device *ndev)
+{
+	if (ndev->conn_type == NTB_CONN_TRANSPARENT)
+		ntb_link_event(ndev, NTB_LINK_UP);
+	else {
+		u32 ntb_cntl;
+
+		/* Let's bring the NTB link up */
+		ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
+		ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK);
+		ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP;
+		ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP;
+		if (ndev->split_bar)
+			ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP |
+				    NTB_CNTL_S2P_BAR5_SNOOP;
+
+		writel(ntb_cntl, ndev->reg_ofs.lnk_cntl);
+	}
+}
+
+static void ntb_hw_link_down(struct ntb_device *ndev)
+{
+	u32 ntb_cntl;
+
+	if (ndev->conn_type == NTB_CONN_TRANSPARENT) {
+		ntb_link_event(ndev, NTB_LINK_DOWN);
+		return;
+	}
+
+	/* Bring NTB link down */
+	ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
+	ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP);
+	ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP);
+	if (ndev->split_bar)
+		ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP |
+			      NTB_CNTL_S2P_BAR5_SNOOP);
+	ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK;
+	writel(ntb_cntl, ndev->reg_ofs.lnk_cntl);
+}
+
+static void ntb_max_mw_detect(struct ntb_device *ndev)
+{
+	if (ndev->split_bar)
+		ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
+	else
+		ndev->limits.max_mw = SNB_MAX_MW;
+}
+
+static int ntb_xeon_detect(struct ntb_device *ndev)
+{
+	int rc, bars_mask;
+	u32 bars;
+	u8 ppd;
+
+	ndev->hw_type = SNB_HW;
+
+	rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd);
+	if (rc)
+		return -EIO;
+
+	if (ppd & SNB_PPD_DEV_TYPE)
+		ndev->dev_type = NTB_DEV_USD;
+	else
+		ndev->dev_type = NTB_DEV_DSD;
+
+	ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0;
+
+	switch (ppd & SNB_PPD_CONN_TYPE) {
+	case NTB_CONN_B2B:
+		dev_info(&ndev->pdev->dev, "Conn Type = B2B\n");
+		ndev->conn_type = NTB_CONN_B2B;
+		break;
+	case NTB_CONN_RP:
+		dev_info(&ndev->pdev->dev, "Conn Type = RP\n");
+		ndev->conn_type = NTB_CONN_RP;
+		break;
+	case NTB_CONN_TRANSPARENT:
+		dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n");
+		ndev->conn_type = NTB_CONN_TRANSPARENT;
+		/*
+		 * This mode is default to USD/DSP. HW does not report
+		 * properly in transparent mode as it has no knowledge of
+		 * NTB. We will just force correct here.
+		 */
+		ndev->dev_type = NTB_DEV_USD;
+
+		/*
+		 * This is a way for transparent BAR to figure out if we
+		 * are doing split BAR or not. There is no way for the hw
+		 * on the transparent side to know and set the PPD.
+		 */
+		bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM);
+		bars = hweight32(bars_mask);
+		if (bars == (HSX_SPLITBAR_MAX_MW + 1))
+			ndev->split_bar = 1;
+
+		break;
+	default:
+		dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd);
+		return -ENODEV;
+	}
+
+	ntb_max_mw_detect(ndev);
+
+	return 0;
+}
+
+static int ntb_atom_detect(struct ntb_device *ndev)
+{
+	int rc;
+	u32 ppd;
+
+	ndev->hw_type = BWD_HW;
+
+	rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd);
+	if (rc)
+		return rc;
+
+	switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) {
+	case NTB_CONN_B2B:
+		dev_info(&ndev->pdev->dev, "Conn Type = B2B\n");
+		ndev->conn_type = NTB_CONN_B2B;
+		break;
+	case NTB_CONN_RP:
+	default:
+		dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n");
+		return -EINVAL;
+	}
+
+	if (ppd & BWD_PPD_DEV_TYPE)
+		ndev->dev_type = NTB_DEV_DSD;
+	else
+		ndev->dev_type = NTB_DEV_USD;
+
+	return 0;
+}
+
+static int ntb_device_detect(struct ntb_device *ndev)
+{
+	int rc;
+
+	if (is_ntb_xeon(ndev))
+		rc = ntb_xeon_detect(ndev);
+	else if (is_ntb_atom(ndev))
+		rc = ntb_atom_detect(ndev);
+	else
+		rc = -ENODEV;
+
+	dev_info(&ndev->pdev->dev, "Device Type = %s\n",
+		 ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP");
+
+	return 0;
+}
+
+static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct ntb_device *ndev;
+	int rc, i;
+
+	ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL);
+	if (!ndev)
+		return -ENOMEM;
+
+	ndev->pdev = pdev;
+
+	ntb_set_errata_flags(ndev);
+
+	ndev->link_status = NTB_LINK_DOWN;
+	pci_set_drvdata(pdev, ndev);
+	ntb_setup_debugfs(ndev);
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err;
+
+	pci_set_master(ndev->pdev);
+
+	rc = ntb_device_detect(ndev);
+	if (rc)
+		goto err;
+
+	ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw),
+			   GFP_KERNEL);
+	if (!ndev->mw) {
+		rc = -ENOMEM;
+		goto err1;
+	}
+
+	if (ndev->split_bar)
+		rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK,
+						  KBUILD_MODNAME);
+	else
+		rc = pci_request_selected_regions(pdev, NTB_BAR_MASK,
+						  KBUILD_MODNAME);
+
+	if (rc)
+		goto err2;
+
+	ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO);
+	if (!ndev->reg_base) {
+		dev_warn(&pdev->dev, "Cannot remap BAR 0\n");
+		rc = -EIO;
+		goto err3;
+	}
+
+	for (i = 0; i < ndev->limits.max_mw; i++) {
+		ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i));
+
+		/*
+		 * with the errata we need to steal last of the memory
+		 * windows for workarounds and they point to MMIO registers.
+		 */
+		if ((ndev->wa_flags & WA_SNB_ERR) &&
+		    (i == (ndev->limits.max_mw - 1))) {
+			ndev->mw[i].vbase =
+				ioremap_nocache(pci_resource_start(pdev,
+							MW_TO_BAR(i)),
+						ndev->mw[i].bar_sz);
+		} else {
+			ndev->mw[i].vbase =
+				ioremap_wc(pci_resource_start(pdev,
+							MW_TO_BAR(i)),
+					   ndev->mw[i].bar_sz);
+		}
+
+		dev_info(&pdev->dev, "MW %d size %llu\n", i,
+			 (unsigned long long) ndev->mw[i].bar_sz);
+		if (!ndev->mw[i].vbase) {
+			dev_warn(&pdev->dev, "Cannot remap BAR %d\n",
+				 MW_TO_BAR(i));
+			rc = -EIO;
+			goto err3;
+		}
+	}
+
+	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (rc) {
+		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc)
+			goto err4;
+
+		dev_warn(&pdev->dev, "Cannot DMA highmem\n");
+	}
+
+	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (rc) {
+		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc)
+			goto err4;
+
+		dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n");
+	}
+
+	rc = ntb_device_setup(ndev);
+	if (rc)
+		goto err4;
+
+	rc = ntb_create_callbacks(ndev);
+	if (rc)
+		goto err5;
+
+	rc = ntb_setup_interrupts(ndev);
+	if (rc)
+		goto err6;
+
+	/* The scratchpad registers keep the values between rmmod/insmod,
+	 * blast them now
+	 */
+	for (i = 0; i < ndev->limits.max_spads; i++) {
+		ntb_write_local_spad(ndev, i, 0);
+		ntb_write_remote_spad(ndev, i, 0);
+	}
+
+	rc = ntb_transport_init(pdev);
+	if (rc)
+		goto err7;
+
+	ntb_hw_link_up(ndev);
+
+	return 0;
+
+err7:
+	ntb_free_interrupts(ndev);
+err6:
+	ntb_free_callbacks(ndev);
+err5:
+	ntb_device_free(ndev);
+err4:
+	for (i--; i >= 0; i--)
+		iounmap(ndev->mw[i].vbase);
+	iounmap(ndev->reg_base);
+err3:
+	if (ndev->split_bar)
+		pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK);
+	else
+		pci_release_selected_regions(pdev, NTB_BAR_MASK);
+err2:
+	kfree(ndev->mw);
+err1:
+	pci_disable_device(pdev);
+err:
+	ntb_free_debugfs(ndev);
+	kfree(ndev);
+
+	dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME);
+	return rc;
+}
+
+static void ntb_pci_remove(struct pci_dev *pdev)
+{
+	struct ntb_device *ndev = pci_get_drvdata(pdev);
+	int i;
+
+	ntb_hw_link_down(ndev);
+
+	ntb_transport_free(ndev->ntb_transport);
+
+	ntb_free_interrupts(ndev);
+	ntb_free_callbacks(ndev);
+	ntb_device_free(ndev);
+
+	/* need to reset max_mw limits so we can unmap properly */
+	if (ndev->hw_type == SNB_HW)
+		ntb_max_mw_detect(ndev);
+
+	for (i = 0; i < ndev->limits.max_mw; i++)
+		iounmap(ndev->mw[i].vbase);
+
+	kfree(ndev->mw);
+	iounmap(ndev->reg_base);
+	if (ndev->split_bar)
+		pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK);
+	else
+		pci_release_selected_regions(pdev, NTB_BAR_MASK);
+	pci_disable_device(pdev);
+	ntb_free_debugfs(ndev);
+	kfree(ndev);
+}
+
+static struct pci_driver ntb_pci_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = ntb_pci_tbl,
+	.probe = ntb_pci_probe,
+	.remove = ntb_pci_remove,
+};
+
+module_pci_driver(ntb_pci_driver);
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
new file mode 100644
index 0000000..9356104
--- /dev/null
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
@@ -0,0 +1,385 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Intel PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Jon Mason <jon.mason@intel.com>
+ */
+#include <linux/ntb_transport.h>
+
+#define NTB_LINK_STATUS_ACTIVE	0x2000
+#define NTB_LINK_SPEED_MASK	0x000f
+#define NTB_LINK_WIDTH_MASK	0x03f0
+
+#define SNB_MSIX_CNT		4
+#define SNB_MAX_B2B_SPADS	16
+#define SNB_MAX_COMPAT_SPADS	16
+/* Reserve the uppermost bit for link interrupt */
+#define SNB_MAX_DB_BITS		15
+#define SNB_LINK_DB		15
+#define SNB_DB_BITS_PER_VEC	5
+#define HSX_SPLITBAR_MAX_MW	3
+#define SNB_MAX_MW		2
+#define SNB_ERRATA_MAX_MW	1
+
+#define SNB_DB_HW_LINK		0x8000
+
+#define SNB_UNCERRSTS_OFFSET	0x014C
+#define SNB_CORERRSTS_OFFSET	0x0158
+#define SNB_LINK_STATUS_OFFSET	0x01A2
+#define SNB_PCICMD_OFFSET	0x0504
+#define SNB_DEVCTRL_OFFSET	0x0598
+#define SNB_DEVSTS_OFFSET	0x059A
+#define SNB_SLINK_STATUS_OFFSET	0x05A2
+
+#define SNB_PBAR2LMT_OFFSET	0x0000
+#define SNB_PBAR4LMT_OFFSET	0x0008
+#define SNB_PBAR5LMT_OFFSET	0x000C
+#define SNB_PBAR2XLAT_OFFSET	0x0010
+#define SNB_PBAR4XLAT_OFFSET	0x0018
+#define SNB_PBAR5XLAT_OFFSET	0x001C
+#define SNB_SBAR2LMT_OFFSET	0x0020
+#define SNB_SBAR4LMT_OFFSET	0x0028
+#define SNB_SBAR5LMT_OFFSET	0x002C
+#define SNB_SBAR2XLAT_OFFSET	0x0030
+#define SNB_SBAR4XLAT_OFFSET	0x0038
+#define SNB_SBAR5XLAT_OFFSET	0x003C
+#define SNB_SBAR0BASE_OFFSET	0x0040
+#define SNB_SBAR2BASE_OFFSET	0x0048
+#define SNB_SBAR4BASE_OFFSET	0x0050
+#define SNB_SBAR5BASE_OFFSET	0x0054
+#define SNB_NTBCNTL_OFFSET	0x0058
+#define SNB_SBDF_OFFSET		0x005C
+#define SNB_PDOORBELL_OFFSET	0x0060
+#define SNB_PDBMSK_OFFSET	0x0062
+#define SNB_SDOORBELL_OFFSET	0x0064
+#define SNB_SDBMSK_OFFSET	0x0066
+#define SNB_USMEMMISS_OFFSET	0x0070
+#define SNB_SPAD_OFFSET		0x0080
+#define SNB_SPADSEMA4_OFFSET	0x00c0
+#define SNB_WCCNTRL_OFFSET	0x00e0
+#define SNB_B2B_SPAD_OFFSET	0x0100
+#define SNB_B2B_DOORBELL_OFFSET	0x0140
+#define SNB_B2B_XLAT_OFFSETL	0x0144
+#define SNB_B2B_XLAT_OFFSETU	0x0148
+
+/*
+ * The addresses are setup so the 32bit BARs can function. Thus
+ * the addresses are all in 32bit space
+ */
+#define SNB_MBAR01_USD_ADDR	0x000000002100000CULL
+#define SNB_MBAR23_USD_ADDR	0x000000004100000CULL
+#define SNB_MBAR4_USD_ADDR	0x000000008100000CULL
+#define SNB_MBAR5_USD_ADDR	0x00000000A100000CULL
+#define SNB_MBAR01_DSD_ADDR	0x000000002000000CULL
+#define SNB_MBAR23_DSD_ADDR	0x000000004000000CULL
+#define SNB_MBAR4_DSD_ADDR	0x000000008000000CULL
+#define SNB_MBAR5_DSD_ADDR	0x00000000A000000CULL
+
+#define BWD_MSIX_CNT		34
+#define BWD_MAX_SPADS		16
+#define BWD_MAX_DB_BITS		34
+#define BWD_DB_BITS_PER_VEC	1
+#define BWD_MAX_MW		2
+
+#define BWD_PCICMD_OFFSET	0xb004
+#define BWD_MBAR23_OFFSET	0xb018
+#define BWD_MBAR45_OFFSET	0xb020
+#define BWD_DEVCTRL_OFFSET	0xb048
+#define BWD_LINK_STATUS_OFFSET	0xb052
+#define BWD_ERRCORSTS_OFFSET	0xb110
+
+#define BWD_SBAR2XLAT_OFFSET	0x0008
+#define BWD_SBAR4XLAT_OFFSET	0x0010
+#define BWD_PDOORBELL_OFFSET	0x0020
+#define BWD_PDBMSK_OFFSET	0x0028
+#define BWD_NTBCNTL_OFFSET	0x0060
+#define BWD_EBDF_OFFSET		0x0064
+#define BWD_SPAD_OFFSET		0x0080
+#define BWD_SPADSEMA_OFFSET	0x00c0
+#define BWD_STKYSPAD_OFFSET	0x00c4
+#define BWD_PBAR2XLAT_OFFSET	0x8008
+#define BWD_PBAR4XLAT_OFFSET	0x8010
+#define BWD_B2B_DOORBELL_OFFSET	0x8020
+#define BWD_B2B_SPAD_OFFSET	0x8080
+#define BWD_B2B_SPADSEMA_OFFSET	0x80c0
+#define BWD_B2B_STKYSPAD_OFFSET	0x80c4
+
+#define BWD_MODPHY_PCSREG4	0x1c004
+#define BWD_MODPHY_PCSREG6	0x1c006
+
+#define BWD_IP_BASE		0xC000
+#define BWD_DESKEWSTS_OFFSET	(BWD_IP_BASE + 0x3024)
+#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180)
+#define BWD_LTSSMSTATEJMP_OFFSET	(BWD_IP_BASE + 0x3040)
+#define BWD_IBSTERRRCRVSTS0_OFFSET	(BWD_IP_BASE + 0x3324)
+
+#define BWD_DESKEWSTS_DBERR	(1 << 15)
+#define BWD_LTSSMERRSTS0_UNEXPECTEDEI	(1 << 20)
+#define BWD_LTSSMSTATEJMP_FORCEDETECT	(1 << 2)
+#define BWD_IBIST_ERR_OFLOW	0x7FFF7FFF
+
+#define NTB_CNTL_CFG_LOCK		(1 << 0)
+#define NTB_CNTL_LINK_DISABLE		(1 << 1)
+#define NTB_CNTL_S2P_BAR23_SNOOP	(1 << 2)
+#define NTB_CNTL_P2S_BAR23_SNOOP	(1 << 4)
+#define NTB_CNTL_S2P_BAR4_SNOOP	(1 << 6)
+#define NTB_CNTL_P2S_BAR4_SNOOP	(1 << 8)
+#define NTB_CNTL_S2P_BAR5_SNOOP	(1 << 12)
+#define NTB_CNTL_P2S_BAR5_SNOOP	(1 << 14)
+#define BWD_CNTL_LINK_DOWN		(1 << 16)
+
+#define NTB_PPD_OFFSET		0x00D4
+#define SNB_PPD_CONN_TYPE	0x0003
+#define SNB_PPD_DEV_TYPE	0x0010
+#define SNB_PPD_SPLIT_BAR	(1 << 6)
+#define BWD_PPD_INIT_LINK	0x0008
+#define BWD_PPD_CONN_TYPE	0x0300
+#define BWD_PPD_DEV_TYPE	0x1000
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF		0x3725
+#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF		0x3726
+#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF		0x3727
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB		0x3C0D
+#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB		0x3C0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB		0x3C0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT		0x0E0D
+#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT		0x0E0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT		0x0E0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX		0x2F0D
+#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX		0x2F0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX		0x2F0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD		0x0C4E
+
+#ifndef readq
+static inline u64 readq(void __iomem *addr)
+{
+	return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+	writel(val & 0xffffffff, addr);
+	writel(val >> 32, addr + 4);
+}
+#endif
+
+#define NTB_BAR_MMIO		0
+#define NTB_BAR_23		2
+#define NTB_BAR_4		4
+#define NTB_BAR_5		5
+
+#define NTB_BAR_MASK		((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
+				 (1 << NTB_BAR_4))
+#define NTB_SPLITBAR_MASK	((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
+				 (1 << NTB_BAR_4) | (1 << NTB_BAR_5))
+
+#define NTB_HB_TIMEOUT		msecs_to_jiffies(1000)
+
+enum ntb_hw_event {
+	NTB_EVENT_SW_EVENT0 = 0,
+	NTB_EVENT_SW_EVENT1,
+	NTB_EVENT_SW_EVENT2,
+	NTB_EVENT_HW_ERROR,
+	NTB_EVENT_HW_LINK_UP,
+	NTB_EVENT_HW_LINK_DOWN,
+};
+
+struct ntb_mw {
+	dma_addr_t phys_addr;
+	void __iomem *vbase;
+	resource_size_t bar_sz;
+};
+
+struct ntb_db_cb {
+	int (*callback)(void *data, int db_num);
+	unsigned int db_num;
+	void *data;
+	struct ntb_device *ndev;
+	struct tasklet_struct irq_work;
+};
+
+#define WA_SNB_ERR	0x00000001
+
+struct ntb_device {
+	struct pci_dev *pdev;
+	struct msix_entry *msix_entries;
+	void __iomem *reg_base;
+	struct ntb_mw *mw;
+	struct {
+		unsigned char max_mw;
+		unsigned char max_spads;
+		unsigned char max_db_bits;
+		unsigned char msix_cnt;
+	} limits;
+	struct {
+		void __iomem *ldb;
+		void __iomem *ldb_mask;
+		void __iomem *rdb;
+		void __iomem *bar2_xlat;
+		void __iomem *bar4_xlat;
+		void __iomem *bar5_xlat;
+		void __iomem *spad_write;
+		void __iomem *spad_read;
+		void __iomem *lnk_cntl;
+		void __iomem *lnk_stat;
+		void __iomem *spci_cmd;
+	} reg_ofs;
+	struct ntb_transport *ntb_transport;
+	void (*event_cb)(void *handle, enum ntb_hw_event event);
+
+	struct ntb_db_cb *db_cb;
+	unsigned char hw_type;
+	unsigned char conn_type;
+	unsigned char dev_type;
+	unsigned char num_msix;
+	unsigned char bits_per_vector;
+	unsigned char max_cbs;
+	unsigned char link_width;
+	unsigned char link_speed;
+	unsigned char link_status;
+	unsigned char split_bar;
+
+	struct delayed_work hb_timer;
+	unsigned long last_ts;
+
+	struct delayed_work lr_timer;
+
+	struct dentry *debugfs_dir;
+	struct dentry *debugfs_info;
+
+	unsigned int wa_flags;
+};
+
+/**
+ * ntb_max_cbs() - return the max callbacks
+ * @ndev: pointer to ntb_device instance
+ *
+ * Given the ntb pointer, return the maximum number of callbacks
+ *
+ * RETURNS: the maximum number of callbacks
+ */
+static inline unsigned char ntb_max_cbs(struct ntb_device *ndev)
+{
+	return ndev->max_cbs;
+}
+
+/**
+ * ntb_max_mw() - return the max number of memory windows
+ * @ndev: pointer to ntb_device instance
+ *
+ * Given the ntb pointer, return the maximum number of memory windows
+ *
+ * RETURNS: the maximum number of memory windows
+ */
+static inline unsigned char ntb_max_mw(struct ntb_device *ndev)
+{
+	return ndev->limits.max_mw;
+}
+
+/**
+ * ntb_hw_link_status() - return the hardware link status
+ * @ndev: pointer to ntb_device instance
+ *
+ * Returns true if the hardware is connected to the remote system
+ *
+ * RETURNS: true or false based on the hardware link state
+ */
+static inline bool ntb_hw_link_status(struct ntb_device *ndev)
+{
+	return ndev->link_status == NTB_LINK_UP;
+}
+
+/**
+ * ntb_query_pdev() - return the pci_dev pointer
+ * @ndev: pointer to ntb_device instance
+ *
+ * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device
+ *
+ * RETURNS: a pointer to the ntb pci_dev
+ */
+static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev)
+{
+	return ndev->pdev;
+}
+
+/**
+ * ntb_query_debugfs() - return the debugfs pointer
+ * @ndev: pointer to ntb_device instance
+ *
+ * Given the ntb pointer, return the debugfs directory pointer for the NTB
+ * hardware device
+ *
+ * RETURNS: a pointer to the debugfs directory
+ */
+static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev)
+{
+	return ndev->debugfs_dir;
+}
+
+struct ntb_device *ntb_register_transport(struct pci_dev *pdev,
+					  void *transport);
+void ntb_unregister_transport(struct ntb_device *ndev);
+void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr);
+int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
+			     void *data, int (*db_cb_func)(void *data,
+							   int db_num));
+void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx);
+int ntb_register_event_callback(struct ntb_device *ndev,
+				void (*event_cb_func)(void *handle,
+						      enum ntb_hw_event event));
+void ntb_unregister_event_callback(struct ntb_device *ndev);
+int ntb_get_max_spads(struct ntb_device *ndev);
+int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
+int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
+int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
+int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
+resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw);
+void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw);
+u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw);
+void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx);
+void *ntb_find_transport(struct pci_dev *pdev);
+
+int ntb_transport_init(struct pci_dev *pdev);
+void ntb_transport_free(void *transport);
diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c
deleted file mode 100644
index cd29b10..0000000
--- a/drivers/ntb/ntb_hw.c
+++ /dev/null
@@ -1,1896 +0,0 @@
-/*
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GPL LICENSE SUMMARY
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2 of the GNU General Public License as
- *   published by the Free Software Foundation.
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copy
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Intel PCIe NTB Linux driver
- *
- * Contact Information:
- * Jon Mason <jon.mason@intel.com>
- */
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include "ntb_hw.h"
-#include "ntb_regs.h"
-
-#define NTB_NAME	"Intel(R) PCI-E Non-Transparent Bridge Driver"
-#define NTB_VER		"1.0"
-
-MODULE_DESCRIPTION(NTB_NAME);
-MODULE_VERSION(NTB_VER);
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Intel Corporation");
-
-enum {
-	NTB_CONN_TRANSPARENT = 0,
-	NTB_CONN_B2B,
-	NTB_CONN_RP,
-};
-
-enum {
-	NTB_DEV_USD = 0,
-	NTB_DEV_DSD,
-};
-
-enum {
-	SNB_HW = 0,
-	BWD_HW,
-};
-
-static struct dentry *debugfs_dir;
-
-#define BWD_LINK_RECOVERY_TIME	500
-
-/* Translate memory window 0,1,2 to BAR 2,4,5 */
-#define MW_TO_BAR(mw)	(mw == 0 ? 2 : (mw == 1 ? 4 : 5))
-
-static const struct pci_device_id ntb_pci_tbl[] = {
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)},
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, ntb_pci_tbl);
-
-static int is_ntb_xeon(struct ntb_device *ndev)
-{
-	switch (ndev->pdev->device) {
-	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
-		return 1;
-	default:
-		return 0;
-	}
-
-	return 0;
-}
-
-static int is_ntb_atom(struct ntb_device *ndev)
-{
-	switch (ndev->pdev->device) {
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD:
-		return 1;
-	default:
-		return 0;
-	}
-
-	return 0;
-}
-
-static void ntb_set_errata_flags(struct ntb_device *ndev)
-{
-	switch (ndev->pdev->device) {
-	/*
-	 * this workaround applies to all platform up to IvyBridge
-	 * Haswell has splitbar support and use a different workaround
-	 */
-	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
-		ndev->wa_flags |= WA_SNB_ERR;
-		break;
-	}
-}
-
-/**
- * ntb_register_event_callback() - register event callback
- * @ndev: pointer to ntb_device instance
- * @func: callback function to register
- *
- * This function registers a callback for any HW driver events such as link
- * up/down, power management notices and etc.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_register_event_callback(struct ntb_device *ndev,
-				void (*func)(void *handle,
-					     enum ntb_hw_event event))
-{
-	if (ndev->event_cb)
-		return -EINVAL;
-
-	ndev->event_cb = func;
-
-	return 0;
-}
-
-/**
- * ntb_unregister_event_callback() - unregisters the event callback
- * @ndev: pointer to ntb_device instance
- *
- * This function unregisters the existing callback from transport
- */
-void ntb_unregister_event_callback(struct ntb_device *ndev)
-{
-	ndev->event_cb = NULL;
-}
-
-static void ntb_irq_work(unsigned long data)
-{
-	struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data;
-	int rc;
-
-	rc = db_cb->callback(db_cb->data, db_cb->db_num);
-	if (rc)
-		tasklet_schedule(&db_cb->irq_work);
-	else {
-		struct ntb_device *ndev = db_cb->ndev;
-		unsigned long mask;
-
-		mask = readw(ndev->reg_ofs.ldb_mask);
-		clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
-		writew(mask, ndev->reg_ofs.ldb_mask);
-	}
-}
-
-/**
- * ntb_register_db_callback() - register a callback for doorbell interrupt
- * @ndev: pointer to ntb_device instance
- * @idx: doorbell index to register callback, zero based
- * @data: pointer to be returned to caller with every callback
- * @func: callback function to register
- *
- * This function registers a callback function for the doorbell interrupt
- * on the primary side. The function will unmask the doorbell as well to
- * allow interrupt.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
-			     void *data, int (*func)(void *data, int db_num))
-{
-	unsigned long mask;
-
-	if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) {
-		dev_warn(&ndev->pdev->dev, "Invalid Index.\n");
-		return -EINVAL;
-	}
-
-	ndev->db_cb[idx].callback = func;
-	ndev->db_cb[idx].data = data;
-	ndev->db_cb[idx].ndev = ndev;
-
-	tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work,
-		     (unsigned long) &ndev->db_cb[idx]);
-
-	/* unmask interrupt */
-	mask = readw(ndev->reg_ofs.ldb_mask);
-	clear_bit(idx * ndev->bits_per_vector, &mask);
-	writew(mask, ndev->reg_ofs.ldb_mask);
-
-	return 0;
-}
-
-/**
- * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt
- * @ndev: pointer to ntb_device instance
- * @idx: doorbell index to register callback, zero based
- *
- * This function unregisters a callback function for the doorbell interrupt
- * on the primary side. The function will also mask the said doorbell.
- */
-void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx)
-{
-	unsigned long mask;
-
-	if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback)
-		return;
-
-	mask = readw(ndev->reg_ofs.ldb_mask);
-	set_bit(idx * ndev->bits_per_vector, &mask);
-	writew(mask, ndev->reg_ofs.ldb_mask);
-
-	tasklet_disable(&ndev->db_cb[idx].irq_work);
-
-	ndev->db_cb[idx].callback = NULL;
-}
-
-/**
- * ntb_find_transport() - find the transport pointer
- * @transport: pointer to pci device
- *
- * Given the pci device pointer, return the transport pointer passed in when
- * the transport attached when it was inited.
- *
- * RETURNS: pointer to transport.
- */
-void *ntb_find_transport(struct pci_dev *pdev)
-{
-	struct ntb_device *ndev = pci_get_drvdata(pdev);
-	return ndev->ntb_transport;
-}
-
-/**
- * ntb_register_transport() - Register NTB transport with NTB HW driver
- * @transport: transport identifier
- *
- * This function allows a transport to reserve the hardware driver for
- * NTB usage.
- *
- * RETURNS: pointer to ntb_device, NULL on error.
- */
-struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport)
-{
-	struct ntb_device *ndev = pci_get_drvdata(pdev);
-
-	if (ndev->ntb_transport)
-		return NULL;
-
-	ndev->ntb_transport = transport;
-	return ndev;
-}
-
-/**
- * ntb_unregister_transport() - Unregister the transport with the NTB HW driver
- * @ndev - ntb_device of the transport to be freed
- *
- * This function unregisters the transport from the HW driver and performs any
- * necessary cleanups.
- */
-void ntb_unregister_transport(struct ntb_device *ndev)
-{
-	int i;
-
-	if (!ndev->ntb_transport)
-		return;
-
-	for (i = 0; i < ndev->max_cbs; i++)
-		ntb_unregister_db_callback(ndev, i);
-
-	ntb_unregister_event_callback(ndev);
-	ndev->ntb_transport = NULL;
-}
-
-/**
- * ntb_write_local_spad() - write to the secondary scratchpad register
- * @ndev: pointer to ntb_device instance
- * @idx: index to the scratchpad register, 0 based
- * @val: the data value to put into the register
- *
- * This function allows writing of a 32bit value to the indexed scratchpad
- * register. This writes over the data mirrored to the local scratchpad register
- * by the remote system.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val)
-{
-	if (idx >= ndev->limits.max_spads)
-		return -EINVAL;
-
-	dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n",
-		val, idx);
-	writel(val, ndev->reg_ofs.spad_read + idx * 4);
-
-	return 0;
-}
-
-/**
- * ntb_read_local_spad() - read from the primary scratchpad register
- * @ndev: pointer to ntb_device instance
- * @idx: index to scratchpad register, 0 based
- * @val: pointer to 32bit integer for storing the register value
- *
- * This function allows reading of the 32bit scratchpad register on
- * the primary (internal) side.  This allows the local system to read data
- * written and mirrored to the scratchpad register by the remote system.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
-{
-	if (idx >= ndev->limits.max_spads)
-		return -EINVAL;
-
-	*val = readl(ndev->reg_ofs.spad_write + idx * 4);
-	dev_dbg(&ndev->pdev->dev,
-		"Reading %x from local scratch pad index %d\n", *val, idx);
-
-	return 0;
-}
-
-/**
- * ntb_write_remote_spad() - write to the secondary scratchpad register
- * @ndev: pointer to ntb_device instance
- * @idx: index to the scratchpad register, 0 based
- * @val: the data value to put into the register
- *
- * This function allows writing of a 32bit value to the indexed scratchpad
- * register. The register resides on the secondary (external) side.  This allows
- * the local system to write data to be mirrored to the remote systems
- * scratchpad register.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val)
-{
-	if (idx >= ndev->limits.max_spads)
-		return -EINVAL;
-
-	dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n",
-		val, idx);
-	writel(val, ndev->reg_ofs.spad_write + idx * 4);
-
-	return 0;
-}
-
-/**
- * ntb_read_remote_spad() - read from the primary scratchpad register
- * @ndev: pointer to ntb_device instance
- * @idx: index to scratchpad register, 0 based
- * @val: pointer to 32bit integer for storing the register value
- *
- * This function allows reading of the 32bit scratchpad register on
- * the primary (internal) side.  This alloows the local system to read the data
- * it wrote to be mirrored on the remote system.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
-{
-	if (idx >= ndev->limits.max_spads)
-		return -EINVAL;
-
-	*val = readl(ndev->reg_ofs.spad_read + idx * 4);
-	dev_dbg(&ndev->pdev->dev,
-		"Reading %x from remote scratch pad index %d\n", *val, idx);
-
-	return 0;
-}
-
-/**
- * ntb_get_mw_base() - get addr for the NTB memory window
- * @ndev: pointer to ntb_device instance
- * @mw: memory window number
- *
- * This function provides the base address of the memory window specified.
- *
- * RETURNS: address, or NULL on error.
- */
-resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw)
-{
-	if (mw >= ntb_max_mw(ndev))
-		return 0;
-
-	return pci_resource_start(ndev->pdev, MW_TO_BAR(mw));
-}
-
-/**
- * ntb_get_mw_vbase() - get virtual addr for the NTB memory window
- * @ndev: pointer to ntb_device instance
- * @mw: memory window number
- *
- * This function provides the base virtual address of the memory window
- * specified.
- *
- * RETURNS: pointer to virtual address, or NULL on error.
- */
-void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw)
-{
-	if (mw >= ntb_max_mw(ndev))
-		return NULL;
-
-	return ndev->mw[mw].vbase;
-}
-
-/**
- * ntb_get_mw_size() - return size of NTB memory window
- * @ndev: pointer to ntb_device instance
- * @mw: memory window number
- *
- * This function provides the physical size of the memory window specified
- *
- * RETURNS: the size of the memory window or zero on error
- */
-u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
-{
-	if (mw >= ntb_max_mw(ndev))
-		return 0;
-
-	return ndev->mw[mw].bar_sz;
-}
-
-/**
- * ntb_set_mw_addr - set the memory window address
- * @ndev: pointer to ntb_device instance
- * @mw: memory window number
- * @addr: base address for data
- *
- * This function sets the base physical address of the memory window.  This
- * memory address is where data from the remote system will be transfered into
- * or out of depending on how the transport is configured.
- */
-void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
-{
-	if (mw >= ntb_max_mw(ndev))
-		return;
-
-	dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr,
-		MW_TO_BAR(mw));
-
-	ndev->mw[mw].phys_addr = addr;
-
-	switch (MW_TO_BAR(mw)) {
-	case NTB_BAR_23:
-		writeq(addr, ndev->reg_ofs.bar2_xlat);
-		break;
-	case NTB_BAR_4:
-		if (ndev->split_bar)
-			writel(addr, ndev->reg_ofs.bar4_xlat);
-		else
-			writeq(addr, ndev->reg_ofs.bar4_xlat);
-		break;
-	case NTB_BAR_5:
-		writel(addr, ndev->reg_ofs.bar5_xlat);
-		break;
-	}
-}
-
-/**
- * ntb_ring_doorbell() - Set the doorbell on the secondary/external side
- * @ndev: pointer to ntb_device instance
- * @db: doorbell to ring
- *
- * This function allows triggering of a doorbell on the secondary/external
- * side that will initiate an interrupt on the remote host
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db)
-{
-	dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db);
-
-	if (ndev->hw_type == BWD_HW)
-		writeq((u64) 1 << db, ndev->reg_ofs.rdb);
-	else
-		writew(((1 << ndev->bits_per_vector) - 1) <<
-		       (db * ndev->bits_per_vector), ndev->reg_ofs.rdb);
-}
-
-static void bwd_recover_link(struct ntb_device *ndev)
-{
-	u32 status;
-
-	/* Driver resets the NTB ModPhy lanes - magic! */
-	writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6);
-	writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4);
-	writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4);
-	writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6);
-
-	/* Driver waits 100ms to allow the NTB ModPhy to settle */
-	msleep(100);
-
-	/* Clear AER Errors, write to clear */
-	status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status);
-	status &= PCI_ERR_COR_REP_ROLL;
-	writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET);
-
-	/* Clear unexpected electrical idle event in LTSSM, write to clear */
-	status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status);
-	status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI;
-	writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET);
-
-	/* Clear DeSkew Buffer error, write to clear */
-	status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status);
-	status |= BWD_DESKEWSTS_DBERR;
-	writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET);
-
-	status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status);
-	status &= BWD_IBIST_ERR_OFLOW;
-	writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
-
-	/* Releases the NTB state machine to allow the link to retrain */
-	status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status);
-	status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT;
-	writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
-}
-
-static void ntb_link_event(struct ntb_device *ndev, int link_state)
-{
-	unsigned int event;
-
-	if (ndev->link_status == link_state)
-		return;
-
-	if (link_state == NTB_LINK_UP) {
-		u16 status;
-
-		dev_info(&ndev->pdev->dev, "Link Up\n");
-		ndev->link_status = NTB_LINK_UP;
-		event = NTB_EVENT_HW_LINK_UP;
-
-		if (is_ntb_atom(ndev) ||
-		    ndev->conn_type == NTB_CONN_TRANSPARENT)
-			status = readw(ndev->reg_ofs.lnk_stat);
-		else {
-			int rc = pci_read_config_word(ndev->pdev,
-						      SNB_LINK_STATUS_OFFSET,
-						      &status);
-			if (rc)
-				return;
-		}
-
-		ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4;
-		ndev->link_speed = (status & NTB_LINK_SPEED_MASK);
-		dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n",
-			 ndev->link_width, ndev->link_speed);
-	} else {
-		dev_info(&ndev->pdev->dev, "Link Down\n");
-		ndev->link_status = NTB_LINK_DOWN;
-		event = NTB_EVENT_HW_LINK_DOWN;
-		/* Don't modify link width/speed, we need it in link recovery */
-	}
-
-	/* notify the upper layer if we have an event change */
-	if (ndev->event_cb)
-		ndev->event_cb(ndev->ntb_transport, event);
-}
-
-static int ntb_link_status(struct ntb_device *ndev)
-{
-	int link_state;
-
-	if (is_ntb_atom(ndev)) {
-		u32 ntb_cntl;
-
-		ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
-		if (ntb_cntl & BWD_CNTL_LINK_DOWN)
-			link_state = NTB_LINK_DOWN;
-		else
-			link_state = NTB_LINK_UP;
-	} else {
-		u16 status;
-		int rc;
-
-		rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET,
-					  &status);
-		if (rc)
-			return rc;
-
-		if (status & NTB_LINK_STATUS_ACTIVE)
-			link_state = NTB_LINK_UP;
-		else
-			link_state = NTB_LINK_DOWN;
-	}
-
-	ntb_link_event(ndev, link_state);
-
-	return 0;
-}
-
-static void bwd_link_recovery(struct work_struct *work)
-{
-	struct ntb_device *ndev = container_of(work, struct ntb_device,
-					       lr_timer.work);
-	u32 status32;
-
-	bwd_recover_link(ndev);
-	/* There is a potential race between the 2 NTB devices recovering at the
-	 * same time.  If the times are the same, the link will not recover and
-	 * the driver will be stuck in this loop forever.  Add a random interval
-	 * to the recovery time to prevent this race.
-	 */
-	msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME);
-
-	status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
-	if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT)
-		goto retry;
-
-	status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
-	if (status32 & BWD_IBIST_ERR_OFLOW)
-		goto retry;
-
-	status32 = readl(ndev->reg_ofs.lnk_cntl);
-	if (!(status32 & BWD_CNTL_LINK_DOWN)) {
-		unsigned char speed, width;
-		u16 status16;
-
-		status16 = readw(ndev->reg_ofs.lnk_stat);
-		width = (status16 & NTB_LINK_WIDTH_MASK) >> 4;
-		speed = (status16 & NTB_LINK_SPEED_MASK);
-		if (ndev->link_width != width || ndev->link_speed != speed)
-			goto retry;
-	}
-
-	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
-	return;
-
-retry:
-	schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT);
-}
-
-/* BWD doesn't have link status interrupt, poll on that platform */
-static void bwd_link_poll(struct work_struct *work)
-{
-	struct ntb_device *ndev = container_of(work, struct ntb_device,
-					       hb_timer.work);
-	unsigned long ts = jiffies;
-
-	/* If we haven't gotten an interrupt in a while, check the BWD link
-	 * status bit
-	 */
-	if (ts > ndev->last_ts + NTB_HB_TIMEOUT) {
-		int rc = ntb_link_status(ndev);
-		if (rc)
-			dev_err(&ndev->pdev->dev,
-				"Error determining link status\n");
-
-		/* Check to see if a link error is the cause of the link down */
-		if (ndev->link_status == NTB_LINK_DOWN) {
-			u32 status32 = readl(ndev->reg_base +
-					     BWD_LTSSMSTATEJMP_OFFSET);
-			if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) {
-				schedule_delayed_work(&ndev->lr_timer, 0);
-				return;
-			}
-		}
-	}
-
-	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
-}
-
-static int ntb_xeon_setup(struct ntb_device *ndev)
-{
-	switch (ndev->conn_type) {
-	case NTB_CONN_B2B:
-		ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
-		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
-		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
-		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
-		if (ndev->split_bar)
-			ndev->reg_ofs.bar5_xlat =
-				ndev->reg_base + SNB_SBAR5XLAT_OFFSET;
-		ndev->limits.max_spads = SNB_MAX_B2B_SPADS;
-
-		/* 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 window to access the interrupt and
-		 * scratch pad registers on the remote system.
-		 */
-		if (ndev->wa_flags & WA_SNB_ERR) {
-			if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz)
-				return -EINVAL;
-
-			ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
-			ndev->reg_ofs.spad_write =
-				ndev->mw[ndev->limits.max_mw - 1].vbase +
-				SNB_SPAD_OFFSET;
-			ndev->reg_ofs.rdb =
-				ndev->mw[ndev->limits.max_mw - 1].vbase +
-				SNB_PDOORBELL_OFFSET;
-
-			/* Set the Limit register to 4k, the minimum size, to
-			 * prevent an illegal access
-			 */
-			writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base +
-			       SNB_PBAR4LMT_OFFSET);
-			/* HW errata on the Limit registers.  They can only be
-			 * written when the base register is 4GB aligned and
-			 * < 32bit.  This should already be the case based on
-			 * the driver defaults, but write the Limit registers
-			 * first just in case.
-			 */
-
-			ndev->limits.max_mw = SNB_ERRATA_MAX_MW;
-		} else {
-			/* HW Errata on bit 14 of b2bdoorbell register.  Writes
-			 * will not be mirrored to the remote system.  Shrink
-			 * the number of bits by one, since bit 14 is the last
-			 * bit.
-			 */
-			ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1;
-			ndev->reg_ofs.spad_write = ndev->reg_base +
-						   SNB_B2B_SPAD_OFFSET;
-			ndev->reg_ofs.rdb = ndev->reg_base +
-					    SNB_B2B_DOORBELL_OFFSET;
-
-			/* Disable the Limit register, just incase it is set to
-			 * something silly. A 64bit write should handle it
-			 * regardless of whether it has a split BAR or not.
-			 */
-			writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET);
-			/* HW errata on the Limit registers.  They can only be
-			 * written when the base register is 4GB aligned and
-			 * < 32bit.  This should already be the case based on
-			 * the driver defaults, but write the Limit registers
-			 * first just in case.
-			 */
-			if (ndev->split_bar)
-				ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
-			else
-				ndev->limits.max_mw = SNB_MAX_MW;
-		}
-
-		/* The Xeon errata workaround requires setting SBAR Base
-		 * addresses to known values, so that the PBAR XLAT can be
-		 * pointed at SBAR0 of the remote system.
-		 */
-		if (ndev->dev_type == NTB_DEV_USD) {
-			writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base +
-			       SNB_PBAR2XLAT_OFFSET);
-			if (ndev->wa_flags & WA_SNB_ERR)
-				writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base +
-				       SNB_PBAR4XLAT_OFFSET);
-			else {
-				if (ndev->split_bar) {
-					writel(SNB_MBAR4_DSD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR4XLAT_OFFSET);
-					writel(SNB_MBAR5_DSD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR5XLAT_OFFSET);
-				} else
-					writeq(SNB_MBAR4_DSD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR4XLAT_OFFSET);
-
-				/* B2B_XLAT_OFFSET is a 64bit register, but can
-				 * only take 32bit writes
-				 */
-				writel(SNB_MBAR01_DSD_ADDR & 0xffffffff,
-				       ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
-				writel(SNB_MBAR01_DSD_ADDR >> 32,
-				       ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
-			}
-
-			writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base +
-			       SNB_SBAR0BASE_OFFSET);
-			writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base +
-			       SNB_SBAR2BASE_OFFSET);
-			if (ndev->split_bar) {
-				writel(SNB_MBAR4_USD_ADDR, ndev->reg_base +
-				       SNB_SBAR4BASE_OFFSET);
-				writel(SNB_MBAR5_USD_ADDR, ndev->reg_base +
-				       SNB_SBAR5BASE_OFFSET);
-			} else
-				writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base +
-				       SNB_SBAR4BASE_OFFSET);
-		} else {
-			writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base +
-			       SNB_PBAR2XLAT_OFFSET);
-			if (ndev->wa_flags & WA_SNB_ERR)
-				writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base +
-				       SNB_PBAR4XLAT_OFFSET);
-			else {
-				if (ndev->split_bar) {
-					writel(SNB_MBAR4_USD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR4XLAT_OFFSET);
-					writel(SNB_MBAR5_USD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR5XLAT_OFFSET);
-				} else
-					writeq(SNB_MBAR4_USD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR4XLAT_OFFSET);
-
-				/*
-				 * B2B_XLAT_OFFSET is a 64bit register, but can
-				 * only take 32bit writes
-				 */
-				writel(SNB_MBAR01_USD_ADDR & 0xffffffff,
-				       ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
-				writel(SNB_MBAR01_USD_ADDR >> 32,
-				       ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
-			}
-			writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base +
-			       SNB_SBAR0BASE_OFFSET);
-			writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base +
-			       SNB_SBAR2BASE_OFFSET);
-			if (ndev->split_bar) {
-				writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base +
-				       SNB_SBAR4BASE_OFFSET);
-				writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base +
-				       SNB_SBAR5BASE_OFFSET);
-			} else
-				writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base +
-				       SNB_SBAR4BASE_OFFSET);
-
-		}
-		break;
-	case NTB_CONN_RP:
-		if (ndev->wa_flags & WA_SNB_ERR) {
-			dev_err(&ndev->pdev->dev,
-				"NTB-RP disabled due to hardware errata.\n");
-			return -EINVAL;
-		}
-
-		/* Scratch pads need to have exclusive access from the primary
-		 * or secondary side.  Halve the num spads so that each side can
-		 * have an equal amount.
-		 */
-		ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2;
-		ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
-		/* Note: The SDOORBELL is the cause of the errata.  You REALLY
-		 * don't want to touch it.
-		 */
-		ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
-		/* Offset the start of the spads to correspond to whether it is
-		 * primary or secondary
-		 */
-		ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET +
-					   ndev->limits.max_spads * 4;
-		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
-		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
-		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
-		if (ndev->split_bar) {
-			ndev->reg_ofs.bar5_xlat =
-				ndev->reg_base + SNB_SBAR5XLAT_OFFSET;
-			ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
-		} else
-			ndev->limits.max_mw = SNB_MAX_MW;
-		break;
-	case NTB_CONN_TRANSPARENT:
-		if (ndev->wa_flags & WA_SNB_ERR) {
-			dev_err(&ndev->pdev->dev,
-				"NTB-TRANSPARENT disabled due to hardware errata.\n");
-			return -EINVAL;
-		}
-
-		/* Scratch pads need to have exclusive access from the primary
-		 * or secondary side.  Halve the num spads so that each side can
-		 * have an equal amount.
-		 */
-		ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2;
-		ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
-		ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET;
-		ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET;
-		/* Offset the start of the spads to correspond to whether it is
-		 * primary or secondary
-		 */
-		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET +
-					  ndev->limits.max_spads * 4;
-		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET;
-		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET;
-
-		if (ndev->split_bar) {
-			ndev->reg_ofs.bar5_xlat =
-				ndev->reg_base + SNB_PBAR5XLAT_OFFSET;
-			ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
-		} else
-			ndev->limits.max_mw = SNB_MAX_MW;
-		break;
-	default:
-		/*
-		 * we should never hit this. the detect function should've
-		 * take cared of everything.
-		 */
-		return -EINVAL;
-	}
-
-	ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET;
-	ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET;
-	ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET;
-
-	ndev->limits.msix_cnt = SNB_MSIX_CNT;
-	ndev->bits_per_vector = SNB_DB_BITS_PER_VEC;
-
-	return 0;
-}
-
-static int ntb_bwd_setup(struct ntb_device *ndev)
-{
-	int rc;
-	u32 val;
-
-	ndev->hw_type = BWD_HW;
-
-	rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val);
-	if (rc)
-		return rc;
-
-	switch ((val & BWD_PPD_CONN_TYPE) >> 8) {
-	case NTB_CONN_B2B:
-		ndev->conn_type = NTB_CONN_B2B;
-		break;
-	case NTB_CONN_RP:
-	default:
-		dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n");
-		return -EINVAL;
-	}
-
-	if (val & BWD_PPD_DEV_TYPE)
-		ndev->dev_type = NTB_DEV_DSD;
-	else
-		ndev->dev_type = NTB_DEV_USD;
-
-	/* Initiate PCI-E link training */
-	rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET,
-				    val | BWD_PPD_INIT_LINK);
-	if (rc)
-		return rc;
-
-	ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET;
-	ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET;
-	ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET;
-	ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET;
-	ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET;
-	ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET;
-	ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET;
-	ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET;
-	ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET;
-	ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET;
-	ndev->limits.max_mw = BWD_MAX_MW;
-	ndev->limits.max_spads = BWD_MAX_SPADS;
-	ndev->limits.max_db_bits = BWD_MAX_DB_BITS;
-	ndev->limits.msix_cnt = BWD_MSIX_CNT;
-	ndev->bits_per_vector = BWD_DB_BITS_PER_VEC;
-
-	/* Since bwd doesn't have a link interrupt, setup a poll timer */
-	INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll);
-	INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery);
-	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
-
-	return 0;
-}
-
-static int ntb_device_setup(struct ntb_device *ndev)
-{
-	int rc;
-
-	if (is_ntb_xeon(ndev))
-		rc = ntb_xeon_setup(ndev);
-	else if (is_ntb_atom(ndev))
-		rc = ntb_bwd_setup(ndev);
-	else
-		rc = -ENODEV;
-
-	if (rc)
-		return rc;
-
-	if (ndev->conn_type == NTB_CONN_B2B)
-		/* Enable Bus Master and Memory Space on the secondary side */
-		writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
-		       ndev->reg_ofs.spci_cmd);
-
-	return 0;
-}
-
-static void ntb_device_free(struct ntb_device *ndev)
-{
-	if (is_ntb_atom(ndev)) {
-		cancel_delayed_work_sync(&ndev->hb_timer);
-		cancel_delayed_work_sync(&ndev->lr_timer);
-	}
-}
-
-static irqreturn_t bwd_callback_msix_irq(int irq, void *data)
-{
-	struct ntb_db_cb *db_cb = data;
-	struct ntb_device *ndev = db_cb->ndev;
-	unsigned long mask;
-
-	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
-		db_cb->db_num);
-
-	mask = readw(ndev->reg_ofs.ldb_mask);
-	set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
-	writew(mask, ndev->reg_ofs.ldb_mask);
-
-	tasklet_schedule(&db_cb->irq_work);
-
-	/* No need to check for the specific HB irq, any interrupt means
-	 * we're connected.
-	 */
-	ndev->last_ts = jiffies;
-
-	writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
-{
-	struct ntb_db_cb *db_cb = data;
-	struct ntb_device *ndev = db_cb->ndev;
-	unsigned long mask;
-
-	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
-		db_cb->db_num);
-
-	mask = readw(ndev->reg_ofs.ldb_mask);
-	set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
-	writew(mask, ndev->reg_ofs.ldb_mask);
-
-	tasklet_schedule(&db_cb->irq_work);
-
-	/* On Sandybridge, there are 16 bits in the interrupt register
-	 * but only 4 vectors.  So, 5 bits are assigned to the first 3
-	 * vectors, with the 4th having a single bit for link
-	 * interrupts.
-	 */
-	writew(((1 << ndev->bits_per_vector) - 1) <<
-	       (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb);
-
-	return IRQ_HANDLED;
-}
-
-/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */
-static irqreturn_t xeon_event_msix_irq(int irq, void *dev)
-{
-	struct ntb_device *ndev = dev;
-	int rc;
-
-	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq);
-
-	rc = ntb_link_status(ndev);
-	if (rc)
-		dev_err(&ndev->pdev->dev, "Error determining link status\n");
-
-	/* bit 15 is always the link bit */
-	writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t ntb_interrupt(int irq, void *dev)
-{
-	struct ntb_device *ndev = dev;
-	unsigned int i = 0;
-
-	if (is_ntb_atom(ndev)) {
-		u64 ldb = readq(ndev->reg_ofs.ldb);
-
-		dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb);
-
-		while (ldb) {
-			i = __ffs(ldb);
-			ldb &= ldb - 1;
-			bwd_callback_msix_irq(irq, &ndev->db_cb[i]);
-		}
-	} else {
-		u16 ldb = readw(ndev->reg_ofs.ldb);
-
-		dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb);
-
-		if (ldb & SNB_DB_HW_LINK) {
-			xeon_event_msix_irq(irq, dev);
-			ldb &= ~SNB_DB_HW_LINK;
-		}
-
-		while (ldb) {
-			i = __ffs(ldb);
-			ldb &= ldb - 1;
-			xeon_callback_msix_irq(irq, &ndev->db_cb[i]);
-		}
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries)
-{
-	struct pci_dev *pdev = ndev->pdev;
-	struct msix_entry *msix;
-	int rc, i;
-
-	if (msix_entries < ndev->limits.msix_cnt)
-		return -ENOSPC;
-
-	rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries);
-	if (rc < 0)
-		return rc;
-
-	for (i = 0; i < msix_entries; i++) {
-		msix = &ndev->msix_entries[i];
-		WARN_ON(!msix->vector);
-
-		if (i == msix_entries - 1) {
-			rc = request_irq(msix->vector,
-					 xeon_event_msix_irq, 0,
-					 "ntb-event-msix", ndev);
-			if (rc)
-				goto err;
-		} else {
-			rc = request_irq(msix->vector,
-					 xeon_callback_msix_irq, 0,
-					 "ntb-callback-msix",
-					 &ndev->db_cb[i]);
-			if (rc)
-				goto err;
-		}
-	}
-
-	ndev->num_msix = msix_entries;
-	ndev->max_cbs = msix_entries - 1;
-
-	return 0;
-
-err:
-	while (--i >= 0) {
-		/* Code never reaches here for entry nr 'ndev->num_msix - 1' */
-		msix = &ndev->msix_entries[i];
-		free_irq(msix->vector, &ndev->db_cb[i]);
-	}
-
-	pci_disable_msix(pdev);
-	ndev->num_msix = 0;
-
-	return rc;
-}
-
-static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries)
-{
-	struct pci_dev *pdev = ndev->pdev;
-	struct msix_entry *msix;
-	int rc, i;
-
-	msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries,
-					     1, msix_entries);
-	if (msix_entries < 0)
-		return msix_entries;
-
-	for (i = 0; i < msix_entries; i++) {
-		msix = &ndev->msix_entries[i];
-		WARN_ON(!msix->vector);
-
-		rc = request_irq(msix->vector, bwd_callback_msix_irq, 0,
-				 "ntb-callback-msix", &ndev->db_cb[i]);
-		if (rc)
-			goto err;
-	}
-
-	ndev->num_msix = msix_entries;
-	ndev->max_cbs = msix_entries;
-
-	return 0;
-
-err:
-	while (--i >= 0)
-		free_irq(msix->vector, &ndev->db_cb[i]);
-
-	pci_disable_msix(pdev);
-	ndev->num_msix = 0;
-
-	return rc;
-}
-
-static int ntb_setup_msix(struct ntb_device *ndev)
-{
-	struct pci_dev *pdev = ndev->pdev;
-	int msix_entries;
-	int rc, i;
-
-	msix_entries = pci_msix_vec_count(pdev);
-	if (msix_entries < 0) {
-		rc = msix_entries;
-		goto err;
-	} else if (msix_entries > ndev->limits.msix_cnt) {
-		rc = -EINVAL;
-		goto err;
-	}
-
-	ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries,
-				     GFP_KERNEL);
-	if (!ndev->msix_entries) {
-		rc = -ENOMEM;
-		goto err;
-	}
-
-	for (i = 0; i < msix_entries; i++)
-		ndev->msix_entries[i].entry = i;
-
-	if (is_ntb_atom(ndev))
-		rc = ntb_setup_bwd_msix(ndev, msix_entries);
-	else
-		rc = ntb_setup_snb_msix(ndev, msix_entries);
-	if (rc)
-		goto err1;
-
-	return 0;
-
-err1:
-	kfree(ndev->msix_entries);
-err:
-	dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n");
-	return rc;
-}
-
-static int ntb_setup_msi(struct ntb_device *ndev)
-{
-	struct pci_dev *pdev = ndev->pdev;
-	int rc;
-
-	rc = pci_enable_msi(pdev);
-	if (rc)
-		return rc;
-
-	rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev);
-	if (rc) {
-		pci_disable_msi(pdev);
-		dev_err(&pdev->dev, "Error allocating MSI interrupt\n");
-		return rc;
-	}
-
-	return 0;
-}
-
-static int ntb_setup_intx(struct ntb_device *ndev)
-{
-	struct pci_dev *pdev = ndev->pdev;
-	int rc;
-
-	pci_msi_off(pdev);
-
-	/* Verify intx is enabled */
-	pci_intx(pdev, 1);
-
-	rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx",
-			 ndev);
-	if (rc)
-		return rc;
-
-	return 0;
-}
-
-static int ntb_setup_interrupts(struct ntb_device *ndev)
-{
-	int rc;
-
-	/* On BWD, disable all interrupts.  On SNB, disable all but Link
-	 * Interrupt.  The rest will be unmasked as callbacks are registered.
-	 */
-	if (is_ntb_atom(ndev))
-		writeq(~0, ndev->reg_ofs.ldb_mask);
-	else {
-		u16 var = 1 << SNB_LINK_DB;
-		writew(~var, ndev->reg_ofs.ldb_mask);
-	}
-
-	rc = ntb_setup_msix(ndev);
-	if (!rc)
-		goto done;
-
-	ndev->bits_per_vector = 1;
-	ndev->max_cbs = ndev->limits.max_db_bits;
-
-	rc = ntb_setup_msi(ndev);
-	if (!rc)
-		goto done;
-
-	rc = ntb_setup_intx(ndev);
-	if (rc) {
-		dev_err(&ndev->pdev->dev, "no usable interrupts\n");
-		return rc;
-	}
-
-done:
-	return 0;
-}
-
-static void ntb_free_interrupts(struct ntb_device *ndev)
-{
-	struct pci_dev *pdev = ndev->pdev;
-
-	/* mask interrupts */
-	if (is_ntb_atom(ndev))
-		writeq(~0, ndev->reg_ofs.ldb_mask);
-	else
-		writew(~0, ndev->reg_ofs.ldb_mask);
-
-	if (ndev->num_msix) {
-		struct msix_entry *msix;
-		u32 i;
-
-		for (i = 0; i < ndev->num_msix; i++) {
-			msix = &ndev->msix_entries[i];
-			if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1)
-				free_irq(msix->vector, ndev);
-			else
-				free_irq(msix->vector, &ndev->db_cb[i]);
-		}
-		pci_disable_msix(pdev);
-		kfree(ndev->msix_entries);
-	} else {
-		free_irq(pdev->irq, ndev);
-
-		if (pci_dev_msi_enabled(pdev))
-			pci_disable_msi(pdev);
-	}
-}
-
-static int ntb_create_callbacks(struct ntb_device *ndev)
-{
-	int i;
-
-	/* Chicken-egg issue.  We won't know how many callbacks are necessary
-	 * until we see how many MSI-X vectors we get, but these pointers need
-	 * to be passed into the MSI-X register function.  So, we allocate the
-	 * max, knowing that they might not all be used, to work around this.
-	 */
-	ndev->db_cb = kcalloc(ndev->limits.max_db_bits,
-			      sizeof(struct ntb_db_cb),
-			      GFP_KERNEL);
-	if (!ndev->db_cb)
-		return -ENOMEM;
-
-	for (i = 0; i < ndev->limits.max_db_bits; i++) {
-		ndev->db_cb[i].db_num = i;
-		ndev->db_cb[i].ndev = ndev;
-	}
-
-	return 0;
-}
-
-static void ntb_free_callbacks(struct ntb_device *ndev)
-{
-	int i;
-
-	for (i = 0; i < ndev->limits.max_db_bits; i++)
-		ntb_unregister_db_callback(ndev, i);
-
-	kfree(ndev->db_cb);
-}
-
-static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf,
-				size_t count, loff_t *offp)
-{
-	struct ntb_device *ndev;
-	char *buf;
-	ssize_t ret, offset, out_count;
-
-	out_count = 500;
-
-	buf = kmalloc(out_count, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	ndev = filp->private_data;
-	offset = 0;
-	offset += snprintf(buf + offset, out_count - offset,
-			   "NTB Device Information:\n");
-	offset += snprintf(buf + offset, out_count - offset,
-			   "Connection Type - \t\t%s\n",
-			   ndev->conn_type == NTB_CONN_TRANSPARENT ?
-			   "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ?
-			   "Back to back" : "Root Port");
-	offset += snprintf(buf + offset, out_count - offset,
-			   "Device Type - \t\t\t%s\n",
-			   ndev->dev_type == NTB_DEV_USD ?
-			   "DSD/USP" : "USD/DSP");
-	offset += snprintf(buf + offset, out_count - offset,
-			   "Max Number of Callbacks - \t%u\n",
-			   ntb_max_cbs(ndev));
-	offset += snprintf(buf + offset, out_count - offset,
-			   "Link Status - \t\t\t%s\n",
-			   ntb_hw_link_status(ndev) ? "Up" : "Down");
-	if (ntb_hw_link_status(ndev)) {
-		offset += snprintf(buf + offset, out_count - offset,
-				   "Link Speed - \t\t\tPCI-E Gen %u\n",
-				   ndev->link_speed);
-		offset += snprintf(buf + offset, out_count - offset,
-				   "Link Width - \t\t\tx%u\n",
-				   ndev->link_width);
-	}
-
-	if (is_ntb_xeon(ndev)) {
-		u32 status32;
-		u16 status16;
-		int rc;
-
-		offset += snprintf(buf + offset, out_count - offset,
-				   "\nNTB Device Statistics:\n");
-		offset += snprintf(buf + offset, out_count - offset,
-				   "Upstream Memory Miss - \t%u\n",
-				   readw(ndev->reg_base +
-					 SNB_USMEMMISS_OFFSET));
-
-		offset += snprintf(buf + offset, out_count - offset,
-				   "\nNTB Hardware Errors:\n");
-
-		rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET,
-					  &status16);
-		if (!rc)
-			offset += snprintf(buf + offset, out_count - offset,
-					   "DEVSTS - \t%#06x\n", status16);
-
-		rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET,
-					  &status16);
-		if (!rc)
-			offset += snprintf(buf + offset, out_count - offset,
-					   "LNKSTS - \t%#06x\n", status16);
-
-		rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET,
-					   &status32);
-		if (!rc)
-			offset += snprintf(buf + offset, out_count - offset,
-					   "UNCERRSTS - \t%#010x\n", status32);
-
-		rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET,
-					   &status32);
-		if (!rc)
-			offset += snprintf(buf + offset, out_count - offset,
-					   "CORERRSTS - \t%#010x\n", status32);
-	}
-
-	if (offset > out_count)
-		offset = out_count;
-
-	ret = simple_read_from_buffer(ubuf, count, offp, buf, offset);
-	kfree(buf);
-	return ret;
-}
-
-static const struct file_operations ntb_debugfs_info = {
-	.owner = THIS_MODULE,
-	.open = simple_open,
-	.read = ntb_debugfs_read,
-};
-
-static void ntb_setup_debugfs(struct ntb_device *ndev)
-{
-	if (!debugfs_initialized())
-		return;
-
-	if (!debugfs_dir)
-		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
-
-	ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev),
-					       debugfs_dir);
-	if (ndev->debugfs_dir)
-		ndev->debugfs_info = debugfs_create_file("info", S_IRUSR,
-							 ndev->debugfs_dir,
-							 ndev,
-							 &ntb_debugfs_info);
-}
-
-static void ntb_free_debugfs(struct ntb_device *ndev)
-{
-	debugfs_remove_recursive(ndev->debugfs_dir);
-
-	if (debugfs_dir && simple_empty(debugfs_dir)) {
-		debugfs_remove_recursive(debugfs_dir);
-		debugfs_dir = NULL;
-	}
-}
-
-static void ntb_hw_link_up(struct ntb_device *ndev)
-{
-	if (ndev->conn_type == NTB_CONN_TRANSPARENT)
-		ntb_link_event(ndev, NTB_LINK_UP);
-	else {
-		u32 ntb_cntl;
-
-		/* Let's bring the NTB link up */
-		ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
-		ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK);
-		ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP;
-		ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP;
-		if (ndev->split_bar)
-			ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP |
-				    NTB_CNTL_S2P_BAR5_SNOOP;
-
-		writel(ntb_cntl, ndev->reg_ofs.lnk_cntl);
-	}
-}
-
-static void ntb_hw_link_down(struct ntb_device *ndev)
-{
-	u32 ntb_cntl;
-
-	if (ndev->conn_type == NTB_CONN_TRANSPARENT) {
-		ntb_link_event(ndev, NTB_LINK_DOWN);
-		return;
-	}
-
-	/* Bring NTB link down */
-	ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
-	ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP);
-	ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP);
-	if (ndev->split_bar)
-		ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP |
-			      NTB_CNTL_S2P_BAR5_SNOOP);
-	ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK;
-	writel(ntb_cntl, ndev->reg_ofs.lnk_cntl);
-}
-
-static void ntb_max_mw_detect(struct ntb_device *ndev)
-{
-	if (ndev->split_bar)
-		ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
-	else
-		ndev->limits.max_mw = SNB_MAX_MW;
-}
-
-static int ntb_xeon_detect(struct ntb_device *ndev)
-{
-	int rc, bars_mask;
-	u32 bars;
-	u8 ppd;
-
-	ndev->hw_type = SNB_HW;
-
-	rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd);
-	if (rc)
-		return -EIO;
-
-	if (ppd & SNB_PPD_DEV_TYPE)
-		ndev->dev_type = NTB_DEV_USD;
-	else
-		ndev->dev_type = NTB_DEV_DSD;
-
-	ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0;
-
-	switch (ppd & SNB_PPD_CONN_TYPE) {
-	case NTB_CONN_B2B:
-		dev_info(&ndev->pdev->dev, "Conn Type = B2B\n");
-		ndev->conn_type = NTB_CONN_B2B;
-		break;
-	case NTB_CONN_RP:
-		dev_info(&ndev->pdev->dev, "Conn Type = RP\n");
-		ndev->conn_type = NTB_CONN_RP;
-		break;
-	case NTB_CONN_TRANSPARENT:
-		dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n");
-		ndev->conn_type = NTB_CONN_TRANSPARENT;
-		/*
-		 * This mode is default to USD/DSP. HW does not report
-		 * properly in transparent mode as it has no knowledge of
-		 * NTB. We will just force correct here.
-		 */
-		ndev->dev_type = NTB_DEV_USD;
-
-		/*
-		 * This is a way for transparent BAR to figure out if we
-		 * are doing split BAR or not. There is no way for the hw
-		 * on the transparent side to know and set the PPD.
-		 */
-		bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM);
-		bars = hweight32(bars_mask);
-		if (bars == (HSX_SPLITBAR_MAX_MW + 1))
-			ndev->split_bar = 1;
-
-		break;
-	default:
-		dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd);
-		return -ENODEV;
-	}
-
-	ntb_max_mw_detect(ndev);
-
-	return 0;
-}
-
-static int ntb_atom_detect(struct ntb_device *ndev)
-{
-	int rc;
-	u32 ppd;
-
-	ndev->hw_type = BWD_HW;
-
-	rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd);
-	if (rc)
-		return rc;
-
-	switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) {
-	case NTB_CONN_B2B:
-		dev_info(&ndev->pdev->dev, "Conn Type = B2B\n");
-		ndev->conn_type = NTB_CONN_B2B;
-		break;
-	case NTB_CONN_RP:
-	default:
-		dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n");
-		return -EINVAL;
-	}
-
-	if (ppd & BWD_PPD_DEV_TYPE)
-		ndev->dev_type = NTB_DEV_DSD;
-	else
-		ndev->dev_type = NTB_DEV_USD;
-
-	return 0;
-}
-
-static int ntb_device_detect(struct ntb_device *ndev)
-{
-	int rc;
-
-	if (is_ntb_xeon(ndev))
-		rc = ntb_xeon_detect(ndev);
-	else if (is_ntb_atom(ndev))
-		rc = ntb_atom_detect(ndev);
-	else
-		rc = -ENODEV;
-
-	dev_info(&ndev->pdev->dev, "Device Type = %s\n",
-		 ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP");
-
-	return 0;
-}
-
-static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	struct ntb_device *ndev;
-	int rc, i;
-
-	ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL);
-	if (!ndev)
-		return -ENOMEM;
-
-	ndev->pdev = pdev;
-
-	ntb_set_errata_flags(ndev);
-
-	ndev->link_status = NTB_LINK_DOWN;
-	pci_set_drvdata(pdev, ndev);
-	ntb_setup_debugfs(ndev);
-
-	rc = pci_enable_device(pdev);
-	if (rc)
-		goto err;
-
-	pci_set_master(ndev->pdev);
-
-	rc = ntb_device_detect(ndev);
-	if (rc)
-		goto err;
-
-	ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw),
-			   GFP_KERNEL);
-	if (!ndev->mw) {
-		rc = -ENOMEM;
-		goto err1;
-	}
-
-	if (ndev->split_bar)
-		rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK,
-						  KBUILD_MODNAME);
-	else
-		rc = pci_request_selected_regions(pdev, NTB_BAR_MASK,
-						  KBUILD_MODNAME);
-
-	if (rc)
-		goto err2;
-
-	ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO);
-	if (!ndev->reg_base) {
-		dev_warn(&pdev->dev, "Cannot remap BAR 0\n");
-		rc = -EIO;
-		goto err3;
-	}
-
-	for (i = 0; i < ndev->limits.max_mw; i++) {
-		ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i));
-
-		/*
-		 * with the errata we need to steal last of the memory
-		 * windows for workarounds and they point to MMIO registers.
-		 */
-		if ((ndev->wa_flags & WA_SNB_ERR) &&
-		    (i == (ndev->limits.max_mw - 1))) {
-			ndev->mw[i].vbase =
-				ioremap_nocache(pci_resource_start(pdev,
-							MW_TO_BAR(i)),
-						ndev->mw[i].bar_sz);
-		} else {
-			ndev->mw[i].vbase =
-				ioremap_wc(pci_resource_start(pdev,
-							MW_TO_BAR(i)),
-					   ndev->mw[i].bar_sz);
-		}
-
-		dev_info(&pdev->dev, "MW %d size %llu\n", i,
-			 (unsigned long long) ndev->mw[i].bar_sz);
-		if (!ndev->mw[i].vbase) {
-			dev_warn(&pdev->dev, "Cannot remap BAR %d\n",
-				 MW_TO_BAR(i));
-			rc = -EIO;
-			goto err3;
-		}
-	}
-
-	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-	if (rc) {
-		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc)
-			goto err4;
-
-		dev_warn(&pdev->dev, "Cannot DMA highmem\n");
-	}
-
-	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-	if (rc) {
-		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc)
-			goto err4;
-
-		dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n");
-	}
-
-	rc = ntb_device_setup(ndev);
-	if (rc)
-		goto err4;
-
-	rc = ntb_create_callbacks(ndev);
-	if (rc)
-		goto err5;
-
-	rc = ntb_setup_interrupts(ndev);
-	if (rc)
-		goto err6;
-
-	/* The scratchpad registers keep the values between rmmod/insmod,
-	 * blast them now
-	 */
-	for (i = 0; i < ndev->limits.max_spads; i++) {
-		ntb_write_local_spad(ndev, i, 0);
-		ntb_write_remote_spad(ndev, i, 0);
-	}
-
-	rc = ntb_transport_init(pdev);
-	if (rc)
-		goto err7;
-
-	ntb_hw_link_up(ndev);
-
-	return 0;
-
-err7:
-	ntb_free_interrupts(ndev);
-err6:
-	ntb_free_callbacks(ndev);
-err5:
-	ntb_device_free(ndev);
-err4:
-	for (i--; i >= 0; i--)
-		iounmap(ndev->mw[i].vbase);
-	iounmap(ndev->reg_base);
-err3:
-	if (ndev->split_bar)
-		pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK);
-	else
-		pci_release_selected_regions(pdev, NTB_BAR_MASK);
-err2:
-	kfree(ndev->mw);
-err1:
-	pci_disable_device(pdev);
-err:
-	ntb_free_debugfs(ndev);
-	kfree(ndev);
-
-	dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME);
-	return rc;
-}
-
-static void ntb_pci_remove(struct pci_dev *pdev)
-{
-	struct ntb_device *ndev = pci_get_drvdata(pdev);
-	int i;
-
-	ntb_hw_link_down(ndev);
-
-	ntb_transport_free(ndev->ntb_transport);
-
-	ntb_free_interrupts(ndev);
-	ntb_free_callbacks(ndev);
-	ntb_device_free(ndev);
-
-	/* need to reset max_mw limits so we can unmap properly */
-	if (ndev->hw_type == SNB_HW)
-		ntb_max_mw_detect(ndev);
-
-	for (i = 0; i < ndev->limits.max_mw; i++)
-		iounmap(ndev->mw[i].vbase);
-
-	kfree(ndev->mw);
-	iounmap(ndev->reg_base);
-	if (ndev->split_bar)
-		pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK);
-	else
-		pci_release_selected_regions(pdev, NTB_BAR_MASK);
-	pci_disable_device(pdev);
-	ntb_free_debugfs(ndev);
-	kfree(ndev);
-}
-
-static struct pci_driver ntb_pci_driver = {
-	.name = KBUILD_MODNAME,
-	.id_table = ntb_pci_tbl,
-	.probe = ntb_pci_probe,
-	.remove = ntb_pci_remove,
-};
-
-module_pci_driver(ntb_pci_driver);
diff --git a/drivers/ntb/ntb_hw.h b/drivers/ntb/ntb_hw.h
deleted file mode 100644
index 96de5fc..0000000
--- a/drivers/ntb/ntb_hw.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GPL LICENSE SUMMARY
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2 of the GNU General Public License as
- *   published by the Free Software Foundation.
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copy
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Intel PCIe NTB Linux driver
- *
- * Contact Information:
- * Jon Mason <jon.mason@intel.com>
- */
-#include <linux/ntb.h>
-
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF		0x3725
-#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF		0x3726
-#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF		0x3727
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB		0x3C0D
-#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB		0x3C0E
-#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB		0x3C0F
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT		0x0E0D
-#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT		0x0E0E
-#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT		0x0E0F
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX		0x2F0D
-#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX		0x2F0E
-#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX		0x2F0F
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD		0x0C4E
-
-#ifndef readq
-static inline u64 readq(void __iomem *addr)
-{
-	return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
-}
-#endif
-
-#ifndef writeq
-static inline void writeq(u64 val, void __iomem *addr)
-{
-	writel(val & 0xffffffff, addr);
-	writel(val >> 32, addr + 4);
-}
-#endif
-
-#define NTB_BAR_MMIO		0
-#define NTB_BAR_23		2
-#define NTB_BAR_4		4
-#define NTB_BAR_5		5
-
-#define NTB_BAR_MASK		((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
-				 (1 << NTB_BAR_4))
-#define NTB_SPLITBAR_MASK	((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
-				 (1 << NTB_BAR_4) | (1 << NTB_BAR_5))
-
-#define NTB_HB_TIMEOUT		msecs_to_jiffies(1000)
-
-enum ntb_hw_event {
-	NTB_EVENT_SW_EVENT0 = 0,
-	NTB_EVENT_SW_EVENT1,
-	NTB_EVENT_SW_EVENT2,
-	NTB_EVENT_HW_ERROR,
-	NTB_EVENT_HW_LINK_UP,
-	NTB_EVENT_HW_LINK_DOWN,
-};
-
-struct ntb_mw {
-	dma_addr_t phys_addr;
-	void __iomem *vbase;
-	resource_size_t bar_sz;
-};
-
-struct ntb_db_cb {
-	int (*callback)(void *data, int db_num);
-	unsigned int db_num;
-	void *data;
-	struct ntb_device *ndev;
-	struct tasklet_struct irq_work;
-};
-
-#define WA_SNB_ERR	0x00000001
-
-struct ntb_device {
-	struct pci_dev *pdev;
-	struct msix_entry *msix_entries;
-	void __iomem *reg_base;
-	struct ntb_mw *mw;
-	struct {
-		unsigned char max_mw;
-		unsigned char max_spads;
-		unsigned char max_db_bits;
-		unsigned char msix_cnt;
-	} limits;
-	struct {
-		void __iomem *ldb;
-		void __iomem *ldb_mask;
-		void __iomem *rdb;
-		void __iomem *bar2_xlat;
-		void __iomem *bar4_xlat;
-		void __iomem *bar5_xlat;
-		void __iomem *spad_write;
-		void __iomem *spad_read;
-		void __iomem *lnk_cntl;
-		void __iomem *lnk_stat;
-		void __iomem *spci_cmd;
-	} reg_ofs;
-	struct ntb_transport *ntb_transport;
-	void (*event_cb)(void *handle, enum ntb_hw_event event);
-
-	struct ntb_db_cb *db_cb;
-	unsigned char hw_type;
-	unsigned char conn_type;
-	unsigned char dev_type;
-	unsigned char num_msix;
-	unsigned char bits_per_vector;
-	unsigned char max_cbs;
-	unsigned char link_width;
-	unsigned char link_speed;
-	unsigned char link_status;
-	unsigned char split_bar;
-
-	struct delayed_work hb_timer;
-	unsigned long last_ts;
-
-	struct delayed_work lr_timer;
-
-	struct dentry *debugfs_dir;
-	struct dentry *debugfs_info;
-
-	unsigned int wa_flags;
-};
-
-/**
- * ntb_max_cbs() - return the max callbacks
- * @ndev: pointer to ntb_device instance
- *
- * Given the ntb pointer, return the maximum number of callbacks
- *
- * RETURNS: the maximum number of callbacks
- */
-static inline unsigned char ntb_max_cbs(struct ntb_device *ndev)
-{
-	return ndev->max_cbs;
-}
-
-/**
- * ntb_max_mw() - return the max number of memory windows
- * @ndev: pointer to ntb_device instance
- *
- * Given the ntb pointer, return the maximum number of memory windows
- *
- * RETURNS: the maximum number of memory windows
- */
-static inline unsigned char ntb_max_mw(struct ntb_device *ndev)
-{
-	return ndev->limits.max_mw;
-}
-
-/**
- * ntb_hw_link_status() - return the hardware link status
- * @ndev: pointer to ntb_device instance
- *
- * Returns true if the hardware is connected to the remote system
- *
- * RETURNS: true or false based on the hardware link state
- */
-static inline bool ntb_hw_link_status(struct ntb_device *ndev)
-{
-	return ndev->link_status == NTB_LINK_UP;
-}
-
-/**
- * ntb_query_pdev() - return the pci_dev pointer
- * @ndev: pointer to ntb_device instance
- *
- * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device
- *
- * RETURNS: a pointer to the ntb pci_dev
- */
-static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev)
-{
-	return ndev->pdev;
-}
-
-/**
- * ntb_query_debugfs() - return the debugfs pointer
- * @ndev: pointer to ntb_device instance
- *
- * Given the ntb pointer, return the debugfs directory pointer for the NTB
- * hardware device
- *
- * RETURNS: a pointer to the debugfs directory
- */
-static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev)
-{
-	return ndev->debugfs_dir;
-}
-
-struct ntb_device *ntb_register_transport(struct pci_dev *pdev,
-					  void *transport);
-void ntb_unregister_transport(struct ntb_device *ndev);
-void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr);
-int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
-			     void *data, int (*db_cb_func)(void *data,
-							   int db_num));
-void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx);
-int ntb_register_event_callback(struct ntb_device *ndev,
-				void (*event_cb_func)(void *handle,
-						      enum ntb_hw_event event));
-void ntb_unregister_event_callback(struct ntb_device *ndev);
-int ntb_get_max_spads(struct ntb_device *ndev);
-int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
-int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
-int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
-int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
-resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw);
-void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw);
-u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw);
-void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx);
-void *ntb_find_transport(struct pci_dev *pdev);
-
-int ntb_transport_init(struct pci_dev *pdev);
-void ntb_transport_free(void *transport);
diff --git a/drivers/ntb/ntb_regs.h b/drivers/ntb/ntb_regs.h
deleted file mode 100644
index f028ff8..0000000
--- a/drivers/ntb/ntb_regs.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GPL LICENSE SUMMARY
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2 of the GNU General Public License as
- *   published by the Free Software Foundation.
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copy
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Intel PCIe NTB Linux driver
- *
- * Contact Information:
- * Jon Mason <jon.mason@intel.com>
- */
-
-#define NTB_LINK_STATUS_ACTIVE	0x2000
-#define NTB_LINK_SPEED_MASK	0x000f
-#define NTB_LINK_WIDTH_MASK	0x03f0
-
-#define SNB_MSIX_CNT		4
-#define SNB_MAX_B2B_SPADS	16
-#define SNB_MAX_COMPAT_SPADS	16
-/* Reserve the uppermost bit for link interrupt */
-#define SNB_MAX_DB_BITS		15
-#define SNB_LINK_DB		15
-#define SNB_DB_BITS_PER_VEC	5
-#define HSX_SPLITBAR_MAX_MW	3
-#define SNB_MAX_MW		2
-#define SNB_ERRATA_MAX_MW	1
-
-#define SNB_DB_HW_LINK		0x8000
-
-#define SNB_UNCERRSTS_OFFSET	0x014C
-#define SNB_CORERRSTS_OFFSET	0x0158
-#define SNB_LINK_STATUS_OFFSET	0x01A2
-#define SNB_PCICMD_OFFSET	0x0504
-#define SNB_DEVCTRL_OFFSET	0x0598
-#define SNB_DEVSTS_OFFSET	0x059A
-#define SNB_SLINK_STATUS_OFFSET	0x05A2
-
-#define SNB_PBAR2LMT_OFFSET	0x0000
-#define SNB_PBAR4LMT_OFFSET	0x0008
-#define SNB_PBAR5LMT_OFFSET	0x000C
-#define SNB_PBAR2XLAT_OFFSET	0x0010
-#define SNB_PBAR4XLAT_OFFSET	0x0018
-#define SNB_PBAR5XLAT_OFFSET	0x001C
-#define SNB_SBAR2LMT_OFFSET	0x0020
-#define SNB_SBAR4LMT_OFFSET	0x0028
-#define SNB_SBAR5LMT_OFFSET	0x002C
-#define SNB_SBAR2XLAT_OFFSET	0x0030
-#define SNB_SBAR4XLAT_OFFSET	0x0038
-#define SNB_SBAR5XLAT_OFFSET	0x003C
-#define SNB_SBAR0BASE_OFFSET	0x0040
-#define SNB_SBAR2BASE_OFFSET	0x0048
-#define SNB_SBAR4BASE_OFFSET	0x0050
-#define SNB_SBAR5BASE_OFFSET	0x0054
-#define SNB_NTBCNTL_OFFSET	0x0058
-#define SNB_SBDF_OFFSET		0x005C
-#define SNB_PDOORBELL_OFFSET	0x0060
-#define SNB_PDBMSK_OFFSET	0x0062
-#define SNB_SDOORBELL_OFFSET	0x0064
-#define SNB_SDBMSK_OFFSET	0x0066
-#define SNB_USMEMMISS_OFFSET	0x0070
-#define SNB_SPAD_OFFSET		0x0080
-#define SNB_SPADSEMA4_OFFSET	0x00c0
-#define SNB_WCCNTRL_OFFSET	0x00e0
-#define SNB_B2B_SPAD_OFFSET	0x0100
-#define SNB_B2B_DOORBELL_OFFSET	0x0140
-#define SNB_B2B_XLAT_OFFSETL	0x0144
-#define SNB_B2B_XLAT_OFFSETU	0x0148
-
-/*
- * The addresses are setup so the 32bit BARs can function. Thus
- * the addresses are all in 32bit space
- */
-#define SNB_MBAR01_USD_ADDR	0x000000002100000CULL
-#define SNB_MBAR23_USD_ADDR	0x000000004100000CULL
-#define SNB_MBAR4_USD_ADDR	0x000000008100000CULL
-#define SNB_MBAR5_USD_ADDR	0x00000000A100000CULL
-#define SNB_MBAR01_DSD_ADDR	0x000000002000000CULL
-#define SNB_MBAR23_DSD_ADDR	0x000000004000000CULL
-#define SNB_MBAR4_DSD_ADDR	0x000000008000000CULL
-#define SNB_MBAR5_DSD_ADDR	0x00000000A000000CULL
-
-#define BWD_MSIX_CNT		34
-#define BWD_MAX_SPADS		16
-#define BWD_MAX_DB_BITS		34
-#define BWD_DB_BITS_PER_VEC	1
-#define BWD_MAX_MW		2
-
-#define BWD_PCICMD_OFFSET	0xb004
-#define BWD_MBAR23_OFFSET	0xb018
-#define BWD_MBAR45_OFFSET	0xb020
-#define BWD_DEVCTRL_OFFSET	0xb048
-#define BWD_LINK_STATUS_OFFSET	0xb052
-#define BWD_ERRCORSTS_OFFSET	0xb110
-
-#define BWD_SBAR2XLAT_OFFSET	0x0008
-#define BWD_SBAR4XLAT_OFFSET	0x0010
-#define BWD_PDOORBELL_OFFSET	0x0020
-#define BWD_PDBMSK_OFFSET	0x0028
-#define BWD_NTBCNTL_OFFSET	0x0060
-#define BWD_EBDF_OFFSET		0x0064
-#define BWD_SPAD_OFFSET		0x0080
-#define BWD_SPADSEMA_OFFSET	0x00c0
-#define BWD_STKYSPAD_OFFSET	0x00c4
-#define BWD_PBAR2XLAT_OFFSET	0x8008
-#define BWD_PBAR4XLAT_OFFSET	0x8010
-#define BWD_B2B_DOORBELL_OFFSET	0x8020
-#define BWD_B2B_SPAD_OFFSET	0x8080
-#define BWD_B2B_SPADSEMA_OFFSET	0x80c0
-#define BWD_B2B_STKYSPAD_OFFSET	0x80c4
-
-#define BWD_MODPHY_PCSREG4	0x1c004
-#define BWD_MODPHY_PCSREG6	0x1c006
-
-#define BWD_IP_BASE		0xC000
-#define BWD_DESKEWSTS_OFFSET	(BWD_IP_BASE + 0x3024)
-#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180)
-#define BWD_LTSSMSTATEJMP_OFFSET	(BWD_IP_BASE + 0x3040)
-#define BWD_IBSTERRRCRVSTS0_OFFSET	(BWD_IP_BASE + 0x3324)
-
-#define BWD_DESKEWSTS_DBERR	(1 << 15)
-#define BWD_LTSSMERRSTS0_UNEXPECTEDEI	(1 << 20)
-#define BWD_LTSSMSTATEJMP_FORCEDETECT	(1 << 2)
-#define BWD_IBIST_ERR_OFLOW	0x7FFF7FFF
-
-#define NTB_CNTL_CFG_LOCK		(1 << 0)
-#define NTB_CNTL_LINK_DISABLE		(1 << 1)
-#define NTB_CNTL_S2P_BAR23_SNOOP	(1 << 2)
-#define NTB_CNTL_P2S_BAR23_SNOOP	(1 << 4)
-#define NTB_CNTL_S2P_BAR4_SNOOP	(1 << 6)
-#define NTB_CNTL_P2S_BAR4_SNOOP	(1 << 8)
-#define NTB_CNTL_S2P_BAR5_SNOOP	(1 << 12)
-#define NTB_CNTL_P2S_BAR5_SNOOP	(1 << 14)
-#define BWD_CNTL_LINK_DOWN		(1 << 16)
-
-#define NTB_PPD_OFFSET		0x00D4
-#define SNB_PPD_CONN_TYPE	0x0003
-#define SNB_PPD_DEV_TYPE	0x0010
-#define SNB_PPD_SPLIT_BAR	(1 << 6)
-#define BWD_PPD_INIT_LINK	0x0008
-#define BWD_PPD_CONN_TYPE	0x0300
-#define BWD_PPD_DEV_TYPE	0x1000
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index e9bf2f4..b9d8e19 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -56,7 +56,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/types.h>
-#include "ntb_hw.h"
+#include "hw/intel/ntb_hw_intel.h"
 
 #define NTB_TRANSPORT_VERSION	3
 
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
deleted file mode 100644
index 9ac1a62..0000000
--- a/include/linux/ntb.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GPL LICENSE SUMMARY
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2 of the GNU General Public License as
- *   published by the Free Software Foundation.
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copy
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Intel PCIe NTB Linux driver
- *
- * Contact Information:
- * Jon Mason <jon.mason@intel.com>
- */
-
-struct ntb_transport_qp;
-
-struct ntb_client {
-	struct device_driver driver;
-	int (*probe)(struct pci_dev *pdev);
-	void (*remove)(struct pci_dev *pdev);
-};
-
-enum {
-	NTB_LINK_DOWN = 0,
-	NTB_LINK_UP,
-};
-
-int ntb_register_client(struct ntb_client *drvr);
-void ntb_unregister_client(struct ntb_client *drvr);
-int ntb_register_client_dev(char *device_name);
-void ntb_unregister_client_dev(char *device_name);
-
-struct ntb_queue_handlers {
-	void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
-			   void *data, int len);
-	void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data,
-			   void *data, int len);
-	void (*event_handler)(void *data, int status);
-};
-
-unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp);
-unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp);
-struct ntb_transport_qp *
-ntb_transport_create_queue(void *data, struct pci_dev *pdev,
-			   const struct ntb_queue_handlers *handlers);
-void ntb_transport_free_queue(struct ntb_transport_qp *qp);
-int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
-			     unsigned int len);
-int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
-			     unsigned int len);
-void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len);
-void ntb_transport_link_up(struct ntb_transport_qp *qp);
-void ntb_transport_link_down(struct ntb_transport_qp *qp);
-bool ntb_transport_link_query(struct ntb_transport_qp *qp);
diff --git a/include/linux/ntb_transport.h b/include/linux/ntb_transport.h
new file mode 100644
index 0000000..9ac1a62
--- /dev/null
+++ b/include/linux/ntb_transport.h
@@ -0,0 +1,88 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Intel PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Jon Mason <jon.mason@intel.com>
+ */
+
+struct ntb_transport_qp;
+
+struct ntb_client {
+	struct device_driver driver;
+	int (*probe)(struct pci_dev *pdev);
+	void (*remove)(struct pci_dev *pdev);
+};
+
+enum {
+	NTB_LINK_DOWN = 0,
+	NTB_LINK_UP,
+};
+
+int ntb_register_client(struct ntb_client *drvr);
+void ntb_unregister_client(struct ntb_client *drvr);
+int ntb_register_client_dev(char *device_name);
+void ntb_unregister_client_dev(char *device_name);
+
+struct ntb_queue_handlers {
+	void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
+			   void *data, int len);
+	void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data,
+			   void *data, int len);
+	void (*event_handler)(void *data, int status);
+};
+
+unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp);
+unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp);
+struct ntb_transport_qp *
+ntb_transport_create_queue(void *data, struct pci_dev *pdev,
+			   const struct ntb_queue_handlers *handlers);
+void ntb_transport_free_queue(struct ntb_transport_qp *qp);
+int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
+			     unsigned int len);
+int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
+			     unsigned int len);
+void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len);
+void ntb_transport_link_up(struct ntb_transport_qp *qp);
+void ntb_transport_link_down(struct ntb_transport_qp *qp);
+bool ntb_transport_link_query(struct ntb_transport_qp *qp);
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 02/16] NTB Abstraction Layer
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
  2015-05-20 15:41 ` [PATCH 01/16] Move files in preparation for NTB Abstraction Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-21  8:51   ` Paul Bolle
  2015-05-20 15:41 ` [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe Allen Hubbe
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

Abstract the ntb device behind a programming interface, so that it can
support different hardware.  Change the intel hardware driver to fit the
abstraction.

Expose the ntb hardware api to client drivers instead of tying it to
ntb_transport.  Make ntb_transport a client of the ntb hardware api.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 Documentation/ntb.txt               |   58 +
 MAINTAINERS                         |   14 +-
 drivers/net/ntb_netdev.c            |   58 +-
 drivers/ntb/Kconfig                 |   20 +-
 drivers/ntb/Makefile                |    4 +-
 drivers/ntb/hw/Kconfig              |    1 +
 drivers/ntb/hw/Makefile             |    1 +
 drivers/ntb/hw/intel/Kconfig        |    8 +
 drivers/ntb/hw/intel/Makefile       |    1 +
 drivers/ntb/hw/intel/ntb_hw_intel.c | 3108 +++++++++++++++++++----------------
 drivers/ntb/hw/intel/ntb_hw_intel.h |  591 +++----
 drivers/ntb/ntb.c                   |  251 +++
 drivers/ntb/ntb_transport.c         |  927 ++++++-----
 include/linux/ntb.h                 |  983 +++++++++++
 include/linux/ntb_transport.h       |   25 +-
 15 files changed, 3873 insertions(+), 2177 deletions(-)
 create mode 100644 Documentation/ntb.txt
 create mode 100644 drivers/ntb/hw/Kconfig
 create mode 100644 drivers/ntb/hw/Makefile
 create mode 100644 drivers/ntb/hw/intel/Kconfig
 create mode 100644 drivers/ntb/hw/intel/Makefile
 create mode 100644 drivers/ntb/ntb.c
 create mode 100644 include/linux/ntb.h

diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt
new file mode 100644
index 0000000..725ba1e
--- /dev/null
+++ b/Documentation/ntb.txt
@@ -0,0 +1,58 @@
+# NTB Drivers
+
+NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects
+the separate memory systems of two computers to the same PCI-Express fabric.
+Existing NTB hardware supports a common feature set, including scratchpad
+registers, doorbell registers, and memory translation windows.  Scratchpad
+registers are read-and-writable registers that are accessible from either side
+of the device, so that peers can exchange a small amount of information at a
+fixed address.  Doorbell registers provide a way for peers to send interrupt
+events.  Memory windows allow translated read and write access to the peer
+memory.
+
+## NTB Core Driver (ntb)
+
+The NTB core driver defines an api wrapping the common feature set, and allows
+clients interested in NTB features to discover NTB the devices supported by
+hardware drivers.  The term "client" is used here to mean an upper layer
+component making use of the NTB api.  The term "driver," or "hardware driver,"
+is used here to mean a driver for a specific vendor and model of NTB hardware.
+
+## NTB Client Drivers
+
+NTB client drivers should register with the NTB core driver.  After
+registering, the client probe and remove functions will be called appropriately
+as ntb hardware, or hardware drivers, are inserted and removed.  The
+registration uses the Linux Device framework, so it should feel familiar to
+anyone who has written a pci driver.
+
+### NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)
+
+The primary client for NTB is the Transport client, used in tandem with NTB
+Netdev.  These drivers function together to create a logical link to the peer,
+across the ntb, to exchange packets of network data.  The Transport client
+establishes a logical link to the peer, and creates queue pairs to exchange
+messages and data.  The NTB Netdev then creates an ethernet device using a
+Transport queue pair.  Network data is copied between socket buffers and the
+Transport queue pair buffer.  The Transport client may be used for other things
+besides Netdev, however no other applications have yet been written.
+
+## NTB Hardware Drivers
+
+NTB hardware drivers should register devices with the NTB core driver.  After
+registering, clients probe and remove functions will be called.
+
+### NTB Intel Hardware Driver (ntb\_hw\_intel)
+
+The Intel hardware driver supports NTB on Xeon and Atom CPUs.
+
+Module Parameters:
+
+* b2b\_mw\_idx - If the peer ntb is to be accessed via a memory window, then use
+	this memory window to access the peer ntb.  A value of zero or positive
+	starts from the first mw idx, and a negative value starts from the last
+	mw idx.  Both sides MUST set the same value here!  The default value is
+	`-1`.
+* b2b\_mw\_share - If the peer ntb is to be accessed via a memory window, and if
+	the memory window is large enough, still allow the client to use the
+	second half of the memory window for address translation to the peer.
diff --git a/MAINTAINERS b/MAINTAINERS
index 2e5bbc0..2560e18 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6943,7 +6943,7 @@ T:	git git://git.rocketboards.org/linux-socfpga-next.git
 S:	Maintained
 F:	arch/nios2/
 
-NTB DRIVER
+NTB DRIVER CORE
 M:	Jon Mason <jdmason@kudzu.us>
 M:	Dave Jiang <dave.jiang@intel.com>
 S:	Supported
@@ -6951,7 +6951,19 @@ W:	https://github.com/jonmason/ntb/wiki
 T:	git git://github.com/jonmason/ntb.git
 F:	drivers/ntb/
 F:	drivers/net/ntb_netdev.c
+F:	drivers/ntb/ntb.c
+F:	drivers/ntb/ntb_transport.c
 F:	include/linux/ntb.h
+F:	include/linux/ntb_transport.h
+
+NTB INTEL DRIVER
+M:	Jon Mason <jdmason@kudzu.us>
+M:	Dave Jiang <dave.jiang@intel.com>
+S:	Supported
+W:	https://github.com/jonmason/ntb/wiki
+T:	git git://github.com/jonmason/ntb.git
+F:	drivers/ntb/hw/intel/ntb_hw_intel.c
+F:	drivers/ntb/hw/intel/ntb_hw_intel.h
 
 NTFS FILESYSTEM
 M:	Anton Altaparmakov <anton@tuxera.com>
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index dcf8000..3cc316c 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -5,6 +5,7 @@
  *   GPL LICENSE SUMMARY
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
  *   BSD LICENSE
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -40,7 +42,7 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Intel PCIe NTB Network Linux driver
+ * PCIe NTB Network Linux driver
  *
  * Contact Information:
  * Jon Mason <jon.mason@intel.com>
@@ -49,6 +51,7 @@
 #include <linux/ethtool.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/ntb.h>
 #include <linux/ntb_transport.h>
 
 #define NTB_NETDEV_VER	"0.7"
@@ -70,26 +73,19 @@ struct ntb_netdev {
 
 static LIST_HEAD(dev_list);
 
-static void ntb_netdev_event_handler(void *data, int status)
+static void ntb_netdev_event_handler(void *data, int link_is_up)
 {
 	struct net_device *ndev = data;
 	struct ntb_netdev *dev = netdev_priv(ndev);
 
-	netdev_dbg(ndev, "Event %x, Link %x\n", status,
+	netdev_dbg(ndev, "Event %x, Link %x\n", link_is_up,
 		   ntb_transport_link_query(dev->qp));
 
-	switch (status) {
-	case NTB_LINK_DOWN:
+	if (link_is_up) {
+		if (ntb_transport_link_query(dev->qp))
+			netif_carrier_on(ndev);
+	} else {
 		netif_carrier_off(ndev);
-		break;
-	case NTB_LINK_UP:
-		if (!ntb_transport_link_query(dev->qp))
-			return;
-
-		netif_carrier_on(ndev);
-		break;
-	default:
-		netdev_warn(ndev, "Unsupported event type %d\n", status);
 	}
 }
 
@@ -160,8 +156,6 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
 	struct ntb_netdev *dev = netdev_priv(ndev);
 	int rc;
 
-	netdev_dbg(ndev, "%s: skb len %d\n", __func__, skb->len);
-
 	rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);
 	if (rc)
 		goto err;
@@ -322,20 +316,26 @@ static const struct ntb_queue_handlers ntb_netdev_handlers = {
 	.event_handler = ntb_netdev_event_handler,
 };
 
-static int ntb_netdev_probe(struct pci_dev *pdev)
+static int ntb_netdev_probe(struct device *client_dev)
 {
+	struct ntb_dev *ntb;
 	struct net_device *ndev;
+	struct pci_dev *pdev;
 	struct ntb_netdev *dev;
 	int rc;
 
-	ndev = alloc_etherdev(sizeof(struct ntb_netdev));
+	ntb = dev_ntb(client_dev->parent);
+	pdev = ntb->pdev;
+	if (!pdev)
+		return -ENODEV;
+
+	ndev = alloc_etherdev(sizeof(*dev));
 	if (!ndev)
 		return -ENOMEM;
 
 	dev = netdev_priv(ndev);
 	dev->ndev = ndev;
 	dev->pdev = pdev;
-	BUG_ON(!dev->pdev);
 	ndev->features = NETIF_F_HIGHDMA;
 
 	ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
@@ -349,7 +349,8 @@ static int ntb_netdev_probe(struct pci_dev *pdev)
 	ndev->netdev_ops = &ntb_netdev_ops;
 	ndev->ethtool_ops = &ntb_ethtool_ops;
 
-	dev->qp = ntb_transport_create_queue(ndev, pdev, &ntb_netdev_handlers);
+	dev->qp = ntb_transport_create_queue(ndev, client_dev,
+					     &ntb_netdev_handlers);
 	if (!dev->qp) {
 		rc = -EIO;
 		goto err;
@@ -372,12 +373,17 @@ err:
 	return rc;
 }
 
-static void ntb_netdev_remove(struct pci_dev *pdev)
+static void ntb_netdev_remove(struct device *client_dev)
 {
+	struct ntb_dev *ntb;
 	struct net_device *ndev;
+	struct pci_dev *pdev;
 	struct ntb_netdev *dev;
 	bool found = false;
 
+	ntb = dev_ntb(client_dev->parent);
+	pdev = ntb->pdev;
+
 	list_for_each_entry(dev, &dev_list, list) {
 		if (dev->pdev == pdev) {
 			found = true;
@@ -396,7 +402,7 @@ static void ntb_netdev_remove(struct pci_dev *pdev)
 	free_netdev(ndev);
 }
 
-static struct ntb_client ntb_netdev_client = {
+static struct ntb_transport_client ntb_netdev_client = {
 	.driver.name = KBUILD_MODNAME,
 	.driver.owner = THIS_MODULE,
 	.probe = ntb_netdev_probe,
@@ -407,16 +413,16 @@ static int __init ntb_netdev_init_module(void)
 {
 	int rc;
 
-	rc = ntb_register_client_dev(KBUILD_MODNAME);
+	rc = ntb_transport_register_client_dev(KBUILD_MODNAME);
 	if (rc)
 		return rc;
-	return ntb_register_client(&ntb_netdev_client);
+	return ntb_transport_register_client(&ntb_netdev_client);
 }
 module_init(ntb_netdev_init_module);
 
 static void __exit ntb_netdev_exit_module(void)
 {
-	ntb_unregister_client(&ntb_netdev_client);
-	ntb_unregister_client_dev(KBUILD_MODNAME);
+	ntb_transport_unregister_client(&ntb_netdev_client);
+	ntb_transport_unregister_client_dev(KBUILD_MODNAME);
 }
 module_exit(ntb_netdev_exit_module);
diff --git a/drivers/ntb/Kconfig b/drivers/ntb/Kconfig
index f69df793..988b03d 100644
--- a/drivers/ntb/Kconfig
+++ b/drivers/ntb/Kconfig
@@ -1,7 +1,6 @@
-config NTB
-       tristate "Intel Non-Transparent Bridge support"
+menuconfig NTB
+       tristate "Non-Transparent Bridge support"
        depends on PCI
-       depends on X86
        help
         The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus
         connecting 2 systems.  When configured, writes to the device's PCI
@@ -11,3 +10,18 @@ config NTB
 
         If unsure, say N.
 
+if NTB
+
+source "drivers/ntb/hw/Kconfig"
+
+config NTB_TRANSPORT
+       tristate "NTB Transport Client"
+       depends on NTB
+       help
+        This is a transport driver that enables connected systems to exchange
+        messages over the ntb hardware.  The transport exposes a queue pair api
+        to client drivers.
+
+        If unsure, say N.
+
+endif # NTB
diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile
index 17f0309..671c4e6 100644
--- a/drivers/ntb/Makefile
+++ b/drivers/ntb/Makefile
@@ -1,3 +1,3 @@
+obj-y += hw/
 obj-$(CONFIG_NTB) += ntb.o
-
-ntb-objs := hw/intel/ntb_hw_intel.o ntb_transport.o
+obj-$(CONFIG_NTB_TRANSPORT) += ntb_transport.o
diff --git a/drivers/ntb/hw/Kconfig b/drivers/ntb/hw/Kconfig
new file mode 100644
index 0000000..4d5535c
--- /dev/null
+++ b/drivers/ntb/hw/Kconfig
@@ -0,0 +1 @@
+source "drivers/ntb/hw/intel/Kconfig"
diff --git a/drivers/ntb/hw/Makefile b/drivers/ntb/hw/Makefile
new file mode 100644
index 0000000..175d7c9
--- /dev/null
+++ b/drivers/ntb/hw/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_NTB_INTEL)	+= intel/
diff --git a/drivers/ntb/hw/intel/Kconfig b/drivers/ntb/hw/intel/Kconfig
new file mode 100644
index 0000000..85de2e8
--- /dev/null
+++ b/drivers/ntb/hw/intel/Kconfig
@@ -0,0 +1,8 @@
+config NTB_INTEL
+       tristate "Intel Non-Transparent Bridge support"
+       depends on NTB
+       depends on X86
+       help
+        This driver supports Intel NTB on capable Xeon and Atom hardware.
+
+        If unsure, say N.
diff --git a/drivers/ntb/hw/intel/Makefile b/drivers/ntb/hw/intel/Makefile
new file mode 100644
index 0000000..1b43456
--- /dev/null
+++ b/drivers/ntb/hw/intel/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_NTB_INTEL) += ntb_hw_intel.o
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 9ce4148..05c4b77 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -5,6 +5,7 @@
  *   GPL LICENSE SUMMARY
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
  *   BSD LICENSE
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -45,6 +47,7 @@
  * Contact Information:
  * Jon Mason <jon.mason@intel.com>
  */
+
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -53,99 +56,97 @@
 #include <linux/pci.h>
 #include <linux/random.h>
 #include <linux/slab.h>
+#include <linux/ntb.h>
+
 #include "ntb_hw_intel.h"
 
-#define NTB_NAME	"Intel(R) PCI-E Non-Transparent Bridge Driver"
-#define NTB_VER		"1.0"
+#define NTB_NAME	"ntb_hw_intel"
+#define NTB_DESC	"Intel(R) PCI-E Non-Transparent Bridge Driver"
+#define NTB_VER		"2.0"
 
-MODULE_DESCRIPTION(NTB_NAME);
+MODULE_DESCRIPTION(NTB_DESC);
 MODULE_VERSION(NTB_VER);
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Intel Corporation");
 
-enum {
-	NTB_CONN_TRANSPARENT = 0,
-	NTB_CONN_B2B,
-	NTB_CONN_RP,
-};
-
-enum {
-	NTB_DEV_USD = 0,
-	NTB_DEV_DSD,
-};
-
-enum {
-	SNB_HW = 0,
-	BWD_HW,
-};
-
+#define bar0_off(base, bar) ((base) + ((bar) << 2))
+#define bar2_off(base, bar) bar0_off(base, (bar) - 2)
+
+static int b2b_mw_idx = -1;
+module_param(b2b_mw_idx, int, 0644);
+MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb.  A "
+		 "value of zero or positive starts from first mw idx, and a "
+		 "negative value starts from last mw idx.  Both sides MUST "
+		 "set the same value here!");
+
+static unsigned int b2b_mw_share;
+module_param(b2b_mw_share, uint, 0644);
+MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the "
+		 "ntb so that the peer ntb only occupies the first half of "
+		 "the mw, so the second half can still be used as a mw.  Both "
+		 "sides MUST set the same value here!");
+
+static const struct intel_ntb_reg bwd_reg;
+static const struct intel_ntb_alt_reg bwd_pri_reg;
+static const struct intel_ntb_alt_reg bwd_sec_reg;
+static const struct intel_ntb_alt_reg bwd_b2b_reg;
+static const struct intel_ntb_xlat_reg bwd_pri_xlat;
+static const struct intel_ntb_xlat_reg bwd_sec_xlat;
+static const struct intel_ntb_reg snb_reg;
+static const struct intel_ntb_alt_reg snb_pri_reg;
+static const struct intel_ntb_alt_reg snb_sec_reg;
+static const struct intel_ntb_alt_reg snb_b2b_reg;
+static const struct intel_ntb_xlat_reg snb_pri_xlat;
+static const struct intel_ntb_xlat_reg snb_sec_xlat;
+static const struct intel_b2b_addr snb_b2b_usd_addr;
+static const struct intel_b2b_addr snb_b2b_dsd_addr;
+
+static const struct ntb_dev_ops intel_ntb_ops;
+
+static const struct file_operations intel_ntb_debugfs_info;
 static struct dentry *debugfs_dir;
 
-#define BWD_LINK_RECOVERY_TIME	500
-
-/* Translate memory window 0,1,2 to BAR 2,4,5 */
-#define MW_TO_BAR(mw)	(mw == 0 ? 2 : (mw == 1 ? 4 : 5))
-
-static const struct pci_device_id ntb_pci_tbl[] = {
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)},
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, ntb_pci_tbl);
-
-static int is_ntb_xeon(struct ntb_device *ndev)
+#ifndef ioread64
+#ifdef readq
+#define ioread64 readq
+#else
+#define ioread64 _ioread64
+static inline u64 _ioread64(void __iomem *mmio)
 {
-	switch (ndev->pdev->device) {
-	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
-		return 1;
-	default:
-		return 0;
-	}
+	u64 low, high;
 
-	return 0;
+	low = ioread32(mmio);
+	high = ioread32(mmio + sizeof(u32));
+	return low | (high << 32);
+}
+#endif
+#endif
+
+#ifndef iowrite64
+#ifdef writeq
+#define iowrite64 writeq
+#else
+#define iowrite64 _iowrite64
+static inline void _iowrite64(u64 val, void __iomem *mmio)
+{
+	iowrite32(val, mmio);
+	iowrite32(val >> 32, mmio + sizeof(u32));
 }
+#endif
+#endif
 
-static int is_ntb_atom(struct ntb_device *ndev)
+static inline int pdev_is_bwd(struct pci_dev *pdev)
 {
-	switch (ndev->pdev->device) {
+	switch (pdev->device) {
 	case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD:
 		return 1;
-	default:
-		return 0;
 	}
-
 	return 0;
 }
 
-static void ntb_set_errata_flags(struct ntb_device *ndev)
+static inline int pdev_is_snb(struct pci_dev *pdev)
 {
-	switch (ndev->pdev->device) {
-	/*
-	 * this workaround applies to all platform up to IvyBridge
-	 * Haswell has splitbar support and use a different workaround
-	 */
+	switch (pdev->device) {
 	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
 	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
 	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
@@ -158,1738 +159,1995 @@ static void ntb_set_errata_flags(struct ntb_device *ndev)
 	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
 	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
 	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
-		ndev->wa_flags |= WA_SNB_ERR;
-		break;
+		return 1;
 	}
+	return 0;
 }
 
-/**
- * ntb_register_event_callback() - register event callback
- * @ndev: pointer to ntb_device instance
- * @func: callback function to register
- *
- * This function registers a callback for any HW driver events such as link
- * up/down, power management notices and etc.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_register_event_callback(struct ntb_device *ndev,
-				void (*func)(void *handle,
-					     enum ntb_hw_event event))
+static inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev)
 {
-	if (ndev->event_cb)
-		return -EINVAL;
-
-	ndev->event_cb = func;
-
-	return 0;
+	ndev->unsafe_flags = 0;
+	ndev->unsafe_flags_ignore = 0;
+
+	/* Only B2B has a workaround to avoid SDOORBELL */
+	if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP)
+		if (!ntb_topo_is_b2b(ndev->ntb.topo))
+			ndev->unsafe_flags |= NTB_UNSAFE_DB;
+
+	/* No low level workaround to avoid SB01BASE */
+	if (ndev->hwerr_flags & NTB_HWERR_SB01BASE_LOCKUP) {
+		ndev->unsafe_flags |= NTB_UNSAFE_DB;
+		ndev->unsafe_flags |= NTB_UNSAFE_SPAD;
+	}
 }
 
-/**
- * ntb_unregister_event_callback() - unregisters the event callback
- * @ndev: pointer to ntb_device instance
- *
- * This function unregisters the existing callback from transport
- */
-void ntb_unregister_event_callback(struct ntb_device *ndev)
+static inline int ndev_is_unsafe(struct intel_ntb_dev *ndev,
+				 unsigned long flag)
 {
-	ndev->event_cb = NULL;
+	return !!(flag & ndev->unsafe_flags & ~ndev->unsafe_flags_ignore);
 }
 
-static void ntb_irq_work(unsigned long data)
+static inline int ndev_ignore_unsafe(struct intel_ntb_dev *ndev,
+				     unsigned long flag)
 {
-	struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data;
-	int rc;
+	flag &= ndev->unsafe_flags;
+	ndev->unsafe_flags_ignore |= flag;
 
-	rc = db_cb->callback(db_cb->data, db_cb->db_num);
-	if (rc)
-		tasklet_schedule(&db_cb->irq_work);
-	else {
-		struct ntb_device *ndev = db_cb->ndev;
-		unsigned long mask;
-
-		mask = readw(ndev->reg_ofs.ldb_mask);
-		clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
-		writew(mask, ndev->reg_ofs.ldb_mask);
-	}
+	return !!flag;
 }
 
-/**
- * ntb_register_db_callback() - register a callback for doorbell interrupt
- * @ndev: pointer to ntb_device instance
- * @idx: doorbell index to register callback, zero based
- * @data: pointer to be returned to caller with every callback
- * @func: callback function to register
- *
- * This function registers a callback function for the doorbell interrupt
- * on the primary side. The function will unmask the doorbell as well to
- * allow interrupt.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
-			     void *data, int (*func)(void *data, int db_num))
+static int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx)
 {
-	unsigned long mask;
-
-	if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) {
-		dev_warn(&ndev->pdev->dev, "Invalid Index.\n");
+	if (idx < 0 || idx > ndev->mw_count)
 		return -EINVAL;
-	}
+	return ndev->reg->mw_bar[idx];
+}
 
-	ndev->db_cb[idx].callback = func;
-	ndev->db_cb[idx].data = data;
-	ndev->db_cb[idx].ndev = ndev;
+static inline int ndev_db_addr(struct intel_ntb_dev *ndev,
+			       phys_addr_t *db_addr, resource_size_t *db_size,
+			       phys_addr_t reg_addr, unsigned long reg)
+{
+	WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB));
 
-	tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work,
-		     (unsigned long) &ndev->db_cb[idx]);
+	if (db_addr) {
+		*db_addr = reg_addr + reg;
+		dev_dbg(ndev_dev(ndev), "Peer db addr %llx\n", *db_addr);
+	}
 
-	/* unmask interrupt */
-	mask = readw(ndev->reg_ofs.ldb_mask);
-	clear_bit(idx * ndev->bits_per_vector, &mask);
-	writew(mask, ndev->reg_ofs.ldb_mask);
+	if (db_size) {
+		*db_size = ndev->reg->db_size;
+		dev_dbg(ndev_dev(ndev), "Peer db size %llx\n", *db_size);
+	}
 
 	return 0;
 }
 
-/**
- * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt
- * @ndev: pointer to ntb_device instance
- * @idx: doorbell index to register callback, zero based
- *
- * This function unregisters a callback function for the doorbell interrupt
- * on the primary side. The function will also mask the said doorbell.
- */
-void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx)
+static inline u64 ndev_db_read(struct intel_ntb_dev *ndev,
+			       void __iomem *mmio)
 {
-	unsigned long mask;
+	WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB));
 
-	if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback)
-		return;
+	return ndev->reg->db_ioread(mmio);
+}
+
+static inline int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits,
+				void __iomem *mmio)
+{
+	WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB));
 
-	mask = readw(ndev->reg_ofs.ldb_mask);
-	set_bit(idx * ndev->bits_per_vector, &mask);
-	writew(mask, ndev->reg_ofs.ldb_mask);
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
 
-	tasklet_disable(&ndev->db_cb[idx].irq_work);
+	ndev->reg->db_iowrite(db_bits, mmio);
 
-	ndev->db_cb[idx].callback = NULL;
+	return 0;
 }
 
-/**
- * ntb_find_transport() - find the transport pointer
- * @transport: pointer to pci device
- *
- * Given the pci device pointer, return the transport pointer passed in when
- * the transport attached when it was inited.
- *
- * RETURNS: pointer to transport.
- */
-void *ntb_find_transport(struct pci_dev *pdev)
+static inline int ndev_db_set_mask(struct intel_ntb_dev *ndev, u64 db_bits,
+				   void __iomem *mmio)
 {
-	struct ntb_device *ndev = pci_get_drvdata(pdev);
-	return ndev->ntb_transport;
-}
+	unsigned long irqflags;
 
-/**
- * ntb_register_transport() - Register NTB transport with NTB HW driver
- * @transport: transport identifier
- *
- * This function allows a transport to reserve the hardware driver for
- * NTB usage.
- *
- * RETURNS: pointer to ntb_device, NULL on error.
- */
-struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport)
-{
-	struct ntb_device *ndev = pci_get_drvdata(pdev);
+	WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB));
+
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
 
-	if (ndev->ntb_transport)
-		return NULL;
+	spin_lock_irqsave(&ndev->db_mask_lock, irqflags);
+	{
+		ndev->db_mask |= db_bits;
+		ndev->reg->db_iowrite(ndev->db_mask, mmio);
+	}
+	spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags);
 
-	ndev->ntb_transport = transport;
-	return ndev;
+	return 0;
 }
 
-/**
- * ntb_unregister_transport() - Unregister the transport with the NTB HW driver
- * @ndev - ntb_device of the transport to be freed
- *
- * This function unregisters the transport from the HW driver and performs any
- * necessary cleanups.
- */
-void ntb_unregister_transport(struct ntb_device *ndev)
+static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits,
+				     void __iomem *mmio)
 {
-	int i;
+	unsigned long irqflags;
 
-	if (!ndev->ntb_transport)
-		return;
+	WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB));
+
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
 
-	for (i = 0; i < ndev->max_cbs; i++)
-		ntb_unregister_db_callback(ndev, i);
+	spin_lock_irqsave(&ndev->db_mask_lock, irqflags);
+	{
+		ndev->db_mask &= ~db_bits;
+		ndev->reg->db_iowrite(ndev->db_mask, mmio);
+	}
+	spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags);
 
-	ntb_unregister_event_callback(ndev);
-	ndev->ntb_transport = NULL;
+	return 0;
 }
 
-/**
- * ntb_write_local_spad() - write to the secondary scratchpad register
- * @ndev: pointer to ntb_device instance
- * @idx: index to the scratchpad register, 0 based
- * @val: the data value to put into the register
- *
- * This function allows writing of a 32bit value to the indexed scratchpad
- * register. This writes over the data mirrored to the local scratchpad register
- * by the remote system.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val)
+static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
 {
-	if (idx >= ndev->limits.max_spads)
-		return -EINVAL;
+	u64 shift, mask;
 
-	dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n",
-		val, idx);
-	writel(val, ndev->reg_ofs.spad_read + idx * 4);
+	shift = ndev->db_vec_shift;
+	mask = BIT_ULL(shift) - 1;
 
-	return 0;
+	return mask << (shift * db_vector);
 }
 
-/**
- * ntb_read_local_spad() - read from the primary scratchpad register
- * @ndev: pointer to ntb_device instance
- * @idx: index to scratchpad register, 0 based
- * @val: pointer to 32bit integer for storing the register value
- *
- * This function allows reading of the 32bit scratchpad register on
- * the primary (internal) side.  This allows the local system to read data
- * written and mirrored to the scratchpad register by the remote system.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
+static inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx,
+				 phys_addr_t *spad_addr, phys_addr_t reg_addr,
+				 unsigned long reg)
 {
-	if (idx >= ndev->limits.max_spads)
+	WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB));
+
+	if (idx < 0 || idx >= ndev->spad_count)
 		return -EINVAL;
 
-	*val = readl(ndev->reg_ofs.spad_write + idx * 4);
-	dev_dbg(&ndev->pdev->dev,
-		"Reading %x from local scratch pad index %d\n", *val, idx);
+	if (spad_addr) {
+		*spad_addr = reg_addr + reg + (idx << 2);
+		dev_dbg(ndev_dev(ndev), "Peer spad addr %llx\n", *spad_addr);
+	}
 
 	return 0;
 }
 
-/**
- * ntb_write_remote_spad() - write to the secondary scratchpad register
- * @ndev: pointer to ntb_device instance
- * @idx: index to the scratchpad register, 0 based
- * @val: the data value to put into the register
- *
- * This function allows writing of a 32bit value to the indexed scratchpad
- * register. The register resides on the secondary (external) side.  This allows
- * the local system to write data to be mirrored to the remote systems
- * scratchpad register.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val)
+static inline u32 ndev_spad_read(struct intel_ntb_dev *ndev, int idx,
+				 void __iomem *mmio)
 {
-	if (idx >= ndev->limits.max_spads)
-		return -EINVAL;
+	WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD));
 
-	dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n",
-		val, idx);
-	writel(val, ndev->reg_ofs.spad_write + idx * 4);
+	if (idx < 0 || idx >= ndev->spad_count)
+		return 0;
 
-	return 0;
+	return ioread32(mmio + (idx << 2));
 }
 
-/**
- * ntb_read_remote_spad() - read from the primary scratchpad register
- * @ndev: pointer to ntb_device instance
- * @idx: index to scratchpad register, 0 based
- * @val: pointer to 32bit integer for storing the register value
- *
- * This function allows reading of the 32bit scratchpad register on
- * the primary (internal) side.  This alloows the local system to read the data
- * it wrote to be mirrored on the remote system.
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
+static inline int ndev_spad_write(struct intel_ntb_dev *ndev, int idx, u32 val,
+				  void __iomem *mmio)
 {
-	if (idx >= ndev->limits.max_spads)
+	WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD));
+
+	if (idx < 0 || idx >= ndev->spad_count)
 		return -EINVAL;
 
-	*val = readl(ndev->reg_ofs.spad_read + idx * 4);
-	dev_dbg(&ndev->pdev->dev,
-		"Reading %x from remote scratch pad index %d\n", *val, idx);
+	iowrite32(val, mmio + (idx << 2));
 
 	return 0;
 }
 
-/**
- * ntb_get_mw_base() - get addr for the NTB memory window
- * @ndev: pointer to ntb_device instance
- * @mw: memory window number
- *
- * This function provides the base address of the memory window specified.
- *
- * RETURNS: address, or NULL on error.
- */
-resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw)
+static irqreturn_t ndev_interrupt(struct intel_ntb_dev *ndev, int vec)
 {
-	if (mw >= ntb_max_mw(ndev))
-		return 0;
+	u64 vec_mask;
+
+	vec_mask = ndev_vec_mask(ndev, vec);
+
+	dev_dbg(ndev_dev(ndev), "vec %d vec_mask %llx\n", vec, vec_mask);
 
-	return pci_resource_start(ndev->pdev, MW_TO_BAR(mw));
+	ndev->last_ts = jiffies;
+
+	if (vec_mask & ndev->db_link_mask) {
+		if (ndev->reg->poll_link(ndev))
+			ntb_link_event(&ndev->ntb);
+	}
+
+	if (vec_mask & ndev->db_valid_mask)
+		ntb_db_event(&ndev->ntb, vec);
+
+	return IRQ_HANDLED;
 }
 
-/**
- * ntb_get_mw_vbase() - get virtual addr for the NTB memory window
- * @ndev: pointer to ntb_device instance
- * @mw: memory window number
- *
- * This function provides the base virtual address of the memory window
- * specified.
- *
- * RETURNS: pointer to virtual address, or NULL on error.
- */
-void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw)
+static irqreturn_t ndev_vec_isr(int irq, void *dev)
 {
-	if (mw >= ntb_max_mw(ndev))
-		return NULL;
+	struct intel_ntb_vec *nvec = dev;
 
-	return ndev->mw[mw].vbase;
+	return ndev_interrupt(nvec->ndev, nvec->num);
 }
 
-/**
- * ntb_get_mw_size() - return size of NTB memory window
- * @ndev: pointer to ntb_device instance
- * @mw: memory window number
- *
- * This function provides the physical size of the memory window specified
- *
- * RETURNS: the size of the memory window or zero on error
- */
-u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
+static irqreturn_t ndev_irq_isr(int irq, void *dev)
 {
-	if (mw >= ntb_max_mw(ndev))
-		return 0;
+	struct intel_ntb_dev *ndev = dev;
 
-	return ndev->mw[mw].bar_sz;
+	return ndev_interrupt(ndev, irq - ndev_pdev(ndev)->irq);
 }
 
-/**
- * ntb_set_mw_addr - set the memory window address
- * @ndev: pointer to ntb_device instance
- * @mw: memory window number
- * @addr: base address for data
- *
- * This function sets the base physical address of the memory window.  This
- * memory address is where data from the remote system will be transfered into
- * or out of depending on how the transport is configured.
- */
-void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
+static int ndev_init_isr(struct intel_ntb_dev *ndev,
+			 int msix_min, int msix_max,
+			 int msix_shift, int total_shift)
 {
-	if (mw >= ntb_max_mw(ndev))
-		return;
+	struct pci_dev *pdev;
+	int rc, i, msix_count;
 
-	dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr,
-		MW_TO_BAR(mw));
+	pdev = ndev_pdev(ndev);
 
-	ndev->mw[mw].phys_addr = addr;
+	/* Mask all doorbell interrupts */
+	ndev->db_mask = ndev->db_valid_mask;
+	ndev->reg->db_iowrite(ndev->db_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_mask);
 
-	switch (MW_TO_BAR(mw)) {
-	case NTB_BAR_23:
-		writeq(addr, ndev->reg_ofs.bar2_xlat);
-		break;
-	case NTB_BAR_4:
-		if (ndev->split_bar)
-			writel(addr, ndev->reg_ofs.bar4_xlat);
-		else
-			writeq(addr, ndev->reg_ofs.bar4_xlat);
-		break;
-	case NTB_BAR_5:
-		writel(addr, ndev->reg_ofs.bar5_xlat);
-		break;
+	/* Try to set up msix irq */
+
+	ndev->vec = kcalloc(msix_max, sizeof(*ndev->vec), GFP_KERNEL);
+	if (!ndev->vec)
+		goto err_msix_vec_alloc;
+
+	ndev->msix = kcalloc(msix_max, sizeof(*ndev->msix), GFP_KERNEL);
+	if (!ndev->msix)
+		goto err_msix_alloc;
+
+	for (i = 0; i < msix_max; ++i)
+		ndev->msix[i].entry = i;
+
+	msix_count = pci_enable_msix_range(pdev, ndev->msix,
+					   msix_min, msix_max);
+	if (msix_count < 0)
+		goto err_msix_enable;
+
+	for (i = 0; i < msix_count; ++i) {
+		ndev->vec[i].ndev = ndev;
+		ndev->vec[i].num = i;
+		rc = request_irq(ndev->msix[i].vector, ndev_vec_isr, 0,
+				 "ndev_vec_isr", &ndev->vec[i]);
+		if (rc)
+			goto err_msix_request;
 	}
-}
 
-/**
- * ntb_ring_doorbell() - Set the doorbell on the secondary/external side
- * @ndev: pointer to ntb_device instance
- * @db: doorbell to ring
- *
- * This function allows triggering of a doorbell on the secondary/external
- * side that will initiate an interrupt on the remote host
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db)
-{
-	dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db);
+	dev_dbg(ndev_dev(ndev), "Using msix interrupts\n");
+	ndev->db_vec_count = msix_count;
+	ndev->db_vec_shift = msix_shift;
+	return 0;
 
-	if (ndev->hw_type == BWD_HW)
-		writeq((u64) 1 << db, ndev->reg_ofs.rdb);
-	else
-		writew(((1 << ndev->bits_per_vector) - 1) <<
-		       (db * ndev->bits_per_vector), ndev->reg_ofs.rdb);
-}
+err_msix_request:
+	while (i-- > 0)
+		free_irq(ndev->msix[i].vector, ndev);
+	pci_disable_msix(pdev);
+err_msix_enable:
+	kfree(ndev->msix);
+err_msix_alloc:
+	kfree(ndev->vec);
+err_msix_vec_alloc:
+	ndev->msix = NULL;
+	ndev->vec = NULL;
 
-static void bwd_recover_link(struct ntb_device *ndev)
-{
-	u32 status;
+	/* Try to set up msi irq */
 
-	/* Driver resets the NTB ModPhy lanes - magic! */
-	writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6);
-	writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4);
-	writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4);
-	writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6);
+	rc = pci_enable_msi(pdev);
+	if (rc)
+		goto err_msi_enable;
 
-	/* Driver waits 100ms to allow the NTB ModPhy to settle */
-	msleep(100);
+	rc = request_irq(pdev->irq, ndev_irq_isr, 0,
+			 "ndev_irq_isr", ndev);
+	if (rc)
+		goto err_msi_request;
 
-	/* Clear AER Errors, write to clear */
-	status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status);
-	status &= PCI_ERR_COR_REP_ROLL;
-	writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET);
+	dev_dbg(ndev_dev(ndev), "Using msi interrupts\n");
+	ndev->db_vec_count = 1;
+	ndev->db_vec_shift = total_shift;
+	return 0;
 
-	/* Clear unexpected electrical idle event in LTSSM, write to clear */
-	status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status);
-	status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI;
-	writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET);
+err_msi_request:
+	pci_disable_msi(pdev);
+err_msi_enable:
 
-	/* Clear DeSkew Buffer error, write to clear */
-	status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status);
-	status |= BWD_DESKEWSTS_DBERR;
-	writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET);
+	/* Try to set up intx irq */
+
+	pci_msi_off(pdev);
+	pci_intx(pdev, 1);
 
-	status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status);
-	status &= BWD_IBIST_ERR_OFLOW;
-	writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
+	rc = request_irq(pdev->irq, ndev_irq_isr, IRQF_SHARED,
+			 "ndev_irq_isr", ndev);
+	if (rc)
+		goto err_intx_request;
 
-	/* Releases the NTB state machine to allow the link to retrain */
-	status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
-	dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status);
-	status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT;
-	writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
+	dev_dbg(ndev_dev(ndev), "Using intx interrupts\n");
+	ndev->db_vec_count = 1;
+	ndev->db_vec_shift = total_shift;
+	return 0;
+
+err_intx_request:
+	return rc;
 }
 
-static void ntb_link_event(struct ntb_device *ndev, int link_state)
+static void ndev_deinit_isr(struct intel_ntb_dev *ndev)
 {
-	unsigned int event;
+	struct pci_dev *pdev;
+	int i;
 
-	if (ndev->link_status == link_state)
-		return;
+	pdev = ndev_pdev(ndev);
 
-	if (link_state == NTB_LINK_UP) {
-		u16 status;
-
-		dev_info(&ndev->pdev->dev, "Link Up\n");
-		ndev->link_status = NTB_LINK_UP;
-		event = NTB_EVENT_HW_LINK_UP;
-
-		if (is_ntb_atom(ndev) ||
-		    ndev->conn_type == NTB_CONN_TRANSPARENT)
-			status = readw(ndev->reg_ofs.lnk_stat);
-		else {
-			int rc = pci_read_config_word(ndev->pdev,
-						      SNB_LINK_STATUS_OFFSET,
-						      &status);
-			if (rc)
-				return;
-		}
+	/* Mask all doorbell interrupts */
+	ndev->db_mask = ndev->db_valid_mask;
+	ndev->reg->db_iowrite(ndev->db_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_mask);
 
-		ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4;
-		ndev->link_speed = (status & NTB_LINK_SPEED_MASK);
-		dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n",
-			 ndev->link_width, ndev->link_speed);
+	if (ndev->msix) {
+		i = ndev->db_vec_count;
+		while (i--)
+			free_irq(ndev->msix[i].vector, &ndev->vec[i]);
+		pci_disable_msix(pdev);
+		kfree(ndev->msix);
+		kfree(ndev->vec);
 	} else {
-		dev_info(&ndev->pdev->dev, "Link Down\n");
-		ndev->link_status = NTB_LINK_DOWN;
-		event = NTB_EVENT_HW_LINK_DOWN;
-		/* Don't modify link width/speed, we need it in link recovery */
+		free_irq(pdev->irq, ndev);
+		if (pci_dev_msi_enabled(pdev))
+			pci_disable_msi(pdev);
 	}
-
-	/* notify the upper layer if we have an event change */
-	if (ndev->event_cb)
-		ndev->event_cb(ndev->ntb_transport, event);
 }
 
-static int ntb_link_status(struct ntb_device *ndev)
+static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
+				 size_t count, loff_t *offp)
 {
-	int link_state;
+	struct intel_ntb_dev *ndev;
+	void __iomem *mmio;
+	char *buf;
+	size_t buf_size;
+	ssize_t ret, off;
+	union { u64 v64; u32 v32; u16 v16; } u;
+	unsigned long reg;
+
+	ndev = filp->private_data;
+	mmio = ndev->self_mmio;
 
-	if (is_ntb_atom(ndev)) {
-		u32 ntb_cntl;
+	buf_size = min(count, 0x800ul);
 
-		ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
-		if (ntb_cntl & BWD_CNTL_LINK_DOWN)
-			link_state = NTB_LINK_DOWN;
-		else
-			link_state = NTB_LINK_UP;
-	} else {
-		u16 status;
-		int rc;
+	buf = kmalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
 
-		rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET,
-					  &status);
-		if (rc)
-			return rc;
+	off = 0;
 
-		if (status & NTB_LINK_STATUS_ACTIVE)
-			link_state = NTB_LINK_UP;
-		else
-			link_state = NTB_LINK_DOWN;
-	}
+	off += scnprintf(buf + off, buf_size - off,
+			 "NTB Device Information:\n");
 
-	ntb_link_event(ndev, link_state);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Connection Topology -\t%s\n",
+			 ntb_topo_string(ndev->ntb.topo));
 
-	return 0;
-}
+	off += scnprintf(buf + off, buf_size - off,
+			 "B2B Offset -\t\t%#lx\n", ndev->b2b_off);
+	off += scnprintf(buf + off, buf_size - off,
+			 "B2B MW Idx -\t\t%d\n", ndev->b2b_idx);
+	off += scnprintf(buf + off, buf_size - off,
+			 "BAR4 Split -\t\t%s\n",
+			 ndev->bar4_split ? "yes" : "no");
 
-static void bwd_link_recovery(struct work_struct *work)
-{
-	struct ntb_device *ndev = container_of(work, struct ntb_device,
-					       lr_timer.work);
-	u32 status32;
+	off += scnprintf(buf + off, buf_size - off,
+			 "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl);
+	off += scnprintf(buf + off, buf_size - off,
+			 "LNK STA -\t\t%#06x\n", ndev->lnk_sta);
 
-	bwd_recover_link(ndev);
-	/* There is a potential race between the 2 NTB devices recovering at the
-	 * same time.  If the times are the same, the link will not recover and
-	 * the driver will be stuck in this loop forever.  Add a random interval
-	 * to the recovery time to prevent this race.
-	 */
-	msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME);
-
-	status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
-	if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT)
-		goto retry;
-
-	status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
-	if (status32 & BWD_IBIST_ERR_OFLOW)
-		goto retry;
-
-	status32 = readl(ndev->reg_ofs.lnk_cntl);
-	if (!(status32 & BWD_CNTL_LINK_DOWN)) {
-		unsigned char speed, width;
-		u16 status16;
-
-		status16 = readw(ndev->reg_ofs.lnk_stat);
-		width = (status16 & NTB_LINK_WIDTH_MASK) >> 4;
-		speed = (status16 & NTB_LINK_SPEED_MASK);
-		if (ndev->link_width != width || ndev->link_speed != speed)
-			goto retry;
+	if (!ndev->reg->link_is_up(ndev)) {
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Satus -\t\tDown\n");
+	} else {
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Satus -\t\tUp\n");
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Speed -\t\tPCI-E Gen %u\n",
+				 NTB_LNK_STA_SPEED(ndev->lnk_sta));
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Width -\t\tx%u\n",
+				 NTB_LNK_STA_WIDTH(ndev->lnk_sta));
 	}
 
-	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
-	return;
+	off += scnprintf(buf + off, buf_size - off,
+			 "Memory Window Count -\t%u\n", ndev->mw_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Scratchpad Count -\t%u\n", ndev->spad_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Count -\t%u\n", ndev->db_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Vector Count -\t%u\n", ndev->db_vec_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
+
+	reg = ndev->self_reg->db_mask;
+	u.v64 = ndev_db_read(ndev, mmio + reg);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Mask -\t\t%#llx\n", u.v64);
+
+	reg = ndev->self_reg->db_bell;
+	u.v64 = ndev_db_read(ndev, mmio + reg);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Bell -\t\t%#llx\n", u.v64);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "\nNTB Incoming XLAT:\n");
+
+	reg = bar2_off(ndev->xlat_reg->bar2_xlat, 2);
+	u.v64 = ioread64(mmio + reg);
+	off += scnprintf(buf + off, buf_size - off,
+			 "XLAT23 -\t\t%#018llx\n", u.v64);
+
+	reg = bar2_off(ndev->xlat_reg->bar2_xlat, 4);
+	u.v64 = ioread64(mmio + reg);
+	off += scnprintf(buf + off, buf_size - off,
+			 "XLAT45 -\t\t%#018llx\n", u.v64);
+
+	reg = bar2_off(ndev->xlat_reg->bar2_limit, 2);
+	u.v64 = ioread64(mmio + reg);
+	off += scnprintf(buf + off, buf_size - off,
+			 "LMT23 -\t\t\t%#018llx\n", u.v64);
+
+	reg = bar2_off(ndev->xlat_reg->bar2_limit, 4);
+	u.v64 = ioread64(mmio + reg);
+	off += scnprintf(buf + off, buf_size - off,
+			 "LMT45 -\t\t\t%#018llx\n", u.v64);
+
+	if (pdev_is_snb(ndev->ntb.pdev)) {
+		if (ntb_topo_is_b2b(ndev->ntb.topo)) {
+			off += scnprintf(buf + off, buf_size - off,
+					 "\nNTB Outgoing B2B XLAT:\n");
+
+			reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 2);
+			u.v64 = ioread64(mmio + reg);
+			off += scnprintf(buf + off, buf_size - off,
+					 "B2B XLAT23 -\t\t%#018llx\n", u.v64);
+
+			reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 4);
+			u.v64 = ioread64(mmio + reg);
+			off += scnprintf(buf + off, buf_size - off,
+					 "B2B XLAT45 -\t\t%#018llx\n", u.v64);
+
+			reg = bar2_off(SNB_PBAR2LMT_OFFSET, 2);
+			u.v64 = ioread64(mmio + reg);
+			off += scnprintf(buf + off, buf_size - off,
+					 "B2B LMT23 -\t\t%#018llx\n", u.v64);
+
+			reg = bar2_off(SNB_PBAR2LMT_OFFSET, 4);
+			u.v64 = ioread64(mmio + reg);
+			off += scnprintf(buf + off, buf_size - off,
+					 "B2B LMT45 -\t\t%#018llx\n", u.v64);
+
+			off += scnprintf(buf + off, buf_size - off,
+					 "\nNTB Secondary BAR:\n");
+
+			reg = bar0_off(SNB_SBAR0BASE_OFFSET, 0);
+			u.v64 = ioread64(mmio + reg);
+			off += scnprintf(buf + off, buf_size - off,
+					 "SBAR01 -\t\t%#018llx\n", u.v64);
+
+			reg = bar0_off(SNB_SBAR0BASE_OFFSET, 2);
+			u.v64 = ioread64(mmio + reg);
+			off += scnprintf(buf + off, buf_size - off,
+					 "SBAR23 -\t\t%#018llx\n", u.v64);
+
+			reg = bar0_off(SNB_SBAR0BASE_OFFSET, 4);
+			u.v64 = ioread64(mmio + reg);
+			off += scnprintf(buf + off, buf_size - off,
+					 "SBAR45 -\t\t%#018llx\n", u.v64);
+		}
+
+		off += scnprintf(buf + off, buf_size - off,
+				 "\nSNB NTB Statistics:\n");
+
+		reg = SNB_USMEMMISS_OFFSET;
+		u.v16 = ioread16(mmio + reg);
+		off += scnprintf(buf + off, buf_size - off,
+				 "Upstream Memory Miss -\t%u\n", u.v16);
+
+		off += scnprintf(buf + off, buf_size - off,
+				 "\nSNB NTB Hardware Errors:\n");
+
+		reg = SNB_DEVSTS_OFFSET;
+		if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
+			off += scnprintf(buf + off, buf_size - off,
+					 "DEVSTS -\t\t%#06x\n", u.v16);
 
-retry:
-	schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT);
+		reg = SNB_LINK_STATUS_OFFSET;
+		if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
+			off += scnprintf(buf + off, buf_size - off,
+					 "LNKSTS -\t\t%#06x\n", u.v16);
+
+		reg = SNB_UNCERRSTS_OFFSET;
+		if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
+			off += scnprintf(buf + off, buf_size - off,
+					 "UNCERRSTS -\t\t%#06x\n", u.v32);
+
+		reg = SNB_CORERRSTS_OFFSET;
+		if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
+			off += scnprintf(buf + off, buf_size - off,
+					 "CORERRSTS -\t\t%#06x\n", u.v32);
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
+	kfree(buf);
+	return ret;
 }
 
-/* BWD doesn't have link status interrupt, poll on that platform */
-static void bwd_link_poll(struct work_struct *work)
+static void ndev_init_debugfs(struct intel_ntb_dev *ndev)
 {
-	struct ntb_device *ndev = container_of(work, struct ntb_device,
-					       hb_timer.work);
-	unsigned long ts = jiffies;
-
-	/* If we haven't gotten an interrupt in a while, check the BWD link
-	 * status bit
-	 */
-	if (ts > ndev->last_ts + NTB_HB_TIMEOUT) {
-		int rc = ntb_link_status(ndev);
-		if (rc)
-			dev_err(&ndev->pdev->dev,
-				"Error determining link status\n");
-
-		/* Check to see if a link error is the cause of the link down */
-		if (ndev->link_status == NTB_LINK_DOWN) {
-			u32 status32 = readl(ndev->reg_base +
-					     BWD_LTSSMSTATEJMP_OFFSET);
-			if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) {
-				schedule_delayed_work(&ndev->lr_timer, 0);
-				return;
-			}
-		}
+	if (!debugfs_dir) {
+		ndev->debugfs_dir = NULL;
+		ndev->debugfs_info = NULL;
+	} else {
+		ndev->debugfs_dir =
+			debugfs_create_dir(ndev_name(ndev), debugfs_dir);
+		if (!ndev->debugfs_dir)
+			ndev->debugfs_info = NULL;
+		else
+			ndev->debugfs_info =
+				debugfs_create_file("info", S_IRUSR,
+						    ndev->debugfs_dir, ndev,
+						    &intel_ntb_debugfs_info);
 	}
+}
 
-	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
+static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
+{
+	debugfs_remove_recursive(ndev->debugfs_dir);
 }
 
-static int ntb_xeon_setup(struct ntb_device *ndev)
+static int intel_ntb_mw_count(struct ntb_dev *ntb)
 {
-	switch (ndev->conn_type) {
-	case NTB_CONN_B2B:
-		ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
-		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
-		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
-		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
-		if (ndev->split_bar)
-			ndev->reg_ofs.bar5_xlat =
-				ndev->reg_base + SNB_SBAR5XLAT_OFFSET;
-		ndev->limits.max_spads = SNB_MAX_B2B_SPADS;
+	return ntb_ndev(ntb)->mw_count;
+}
 
-		/* 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 window to access the interrupt and
-		 * scratch pad registers on the remote system.
-		 */
-		if (ndev->wa_flags & WA_SNB_ERR) {
-			if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz)
-				return -EINVAL;
-
-			ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
-			ndev->reg_ofs.spad_write =
-				ndev->mw[ndev->limits.max_mw - 1].vbase +
-				SNB_SPAD_OFFSET;
-			ndev->reg_ofs.rdb =
-				ndev->mw[ndev->limits.max_mw - 1].vbase +
-				SNB_PDOORBELL_OFFSET;
-
-			/* Set the Limit register to 4k, the minimum size, to
-			 * prevent an illegal access
-			 */
-			writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base +
-			       SNB_PBAR4LMT_OFFSET);
-			/* HW errata on the Limit registers.  They can only be
-			 * written when the base register is 4GB aligned and
-			 * < 32bit.  This should already be the case based on
-			 * the driver defaults, but write the Limit registers
-			 * first just in case.
-			 */
-
-			ndev->limits.max_mw = SNB_ERRATA_MAX_MW;
-		} else {
-			/* HW Errata on bit 14 of b2bdoorbell register.  Writes
-			 * will not be mirrored to the remote system.  Shrink
-			 * the number of bits by one, since bit 14 is the last
-			 * bit.
-			 */
-			ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1;
-			ndev->reg_ofs.spad_write = ndev->reg_base +
-						   SNB_B2B_SPAD_OFFSET;
-			ndev->reg_ofs.rdb = ndev->reg_base +
-					    SNB_B2B_DOORBELL_OFFSET;
-
-			/* Disable the Limit register, just incase it is set to
-			 * something silly. A 64bit write should handle it
-			 * regardless of whether it has a split BAR or not.
-			 */
-			writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET);
-			/* HW errata on the Limit registers.  They can only be
-			 * written when the base register is 4GB aligned and
-			 * < 32bit.  This should already be the case based on
-			 * the driver defaults, but write the Limit registers
-			 * first just in case.
-			 */
-			if (ndev->split_bar)
-				ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
-			else
-				ndev->limits.max_mw = SNB_MAX_MW;
-		}
+static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
+				  phys_addr_t *base,
+				  resource_size_t *size,
+				  resource_size_t *align,
+				  resource_size_t *align_size)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+	int bar;
 
-		/* The Xeon errata workaround requires setting SBAR Base
-		 * addresses to known values, so that the PBAR XLAT can be
-		 * pointed at SBAR0 of the remote system.
-		 */
-		if (ndev->dev_type == NTB_DEV_USD) {
-			writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base +
-			       SNB_PBAR2XLAT_OFFSET);
-			if (ndev->wa_flags & WA_SNB_ERR)
-				writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base +
-				       SNB_PBAR4XLAT_OFFSET);
-			else {
-				if (ndev->split_bar) {
-					writel(SNB_MBAR4_DSD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR4XLAT_OFFSET);
-					writel(SNB_MBAR5_DSD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR5XLAT_OFFSET);
-				} else
-					writeq(SNB_MBAR4_DSD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR4XLAT_OFFSET);
-
-				/* B2B_XLAT_OFFSET is a 64bit register, but can
-				 * only take 32bit writes
-				 */
-				writel(SNB_MBAR01_DSD_ADDR & 0xffffffff,
-				       ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
-				writel(SNB_MBAR01_DSD_ADDR >> 32,
-				       ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
-			}
-
-			writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base +
-			       SNB_SBAR0BASE_OFFSET);
-			writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base +
-			       SNB_SBAR2BASE_OFFSET);
-			if (ndev->split_bar) {
-				writel(SNB_MBAR4_USD_ADDR, ndev->reg_base +
-				       SNB_SBAR4BASE_OFFSET);
-				writel(SNB_MBAR5_USD_ADDR, ndev->reg_base +
-				       SNB_SBAR5BASE_OFFSET);
-			} else
-				writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base +
-				       SNB_SBAR4BASE_OFFSET);
-		} else {
-			writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base +
-			       SNB_PBAR2XLAT_OFFSET);
-			if (ndev->wa_flags & WA_SNB_ERR)
-				writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base +
-				       SNB_PBAR4XLAT_OFFSET);
-			else {
-				if (ndev->split_bar) {
-					writel(SNB_MBAR4_USD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR4XLAT_OFFSET);
-					writel(SNB_MBAR5_USD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR5XLAT_OFFSET);
-				} else
-					writeq(SNB_MBAR4_USD_ADDR,
-					       ndev->reg_base +
-					       SNB_PBAR4XLAT_OFFSET);
-
-				/*
-				 * B2B_XLAT_OFFSET is a 64bit register, but can
-				 * only take 32bit writes
-				 */
-				writel(SNB_MBAR01_USD_ADDR & 0xffffffff,
-				       ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
-				writel(SNB_MBAR01_USD_ADDR >> 32,
-				       ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
-			}
-			writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base +
-			       SNB_SBAR0BASE_OFFSET);
-			writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base +
-			       SNB_SBAR2BASE_OFFSET);
-			if (ndev->split_bar) {
-				writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base +
-				       SNB_SBAR4BASE_OFFSET);
-				writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base +
-				       SNB_SBAR5BASE_OFFSET);
-			} else
-				writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base +
-				       SNB_SBAR4BASE_OFFSET);
+	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+		idx += 1;
 
-		}
-		break;
-	case NTB_CONN_RP:
-		if (ndev->wa_flags & WA_SNB_ERR) {
-			dev_err(&ndev->pdev->dev,
-				"NTB-RP disabled due to hardware errata.\n");
-			return -EINVAL;
-		}
+	bar = ndev_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
 
-		/* Scratch pads need to have exclusive access from the primary
-		 * or secondary side.  Halve the num spads so that each side can
-		 * have an equal amount.
-		 */
-		ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2;
-		ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
-		/* Note: The SDOORBELL is the cause of the errata.  You REALLY
-		 * don't want to touch it.
-		 */
-		ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
-		/* Offset the start of the spads to correspond to whether it is
-		 * primary or secondary
-		 */
-		ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET +
-					   ndev->limits.max_spads * 4;
-		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
-		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
-		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
-		if (ndev->split_bar) {
-			ndev->reg_ofs.bar5_xlat =
-				ndev->reg_base + SNB_SBAR5XLAT_OFFSET;
-			ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
-		} else
-			ndev->limits.max_mw = SNB_MAX_MW;
-		break;
-	case NTB_CONN_TRANSPARENT:
-		if (ndev->wa_flags & WA_SNB_ERR) {
-			dev_err(&ndev->pdev->dev,
-				"NTB-TRANSPARENT disabled due to hardware errata.\n");
-			return -EINVAL;
-		}
+	if (base)
+		*base = pci_resource_start(ndev->ntb.pdev, bar) +
+			(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
 
-		/* Scratch pads need to have exclusive access from the primary
-		 * or secondary side.  Halve the num spads so that each side can
-		 * have an equal amount.
-		 */
-		ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2;
-		ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
-		ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
-		ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET;
-		ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET;
-		/* Offset the start of the spads to correspond to whether it is
-		 * primary or secondary
-		 */
-		ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET +
-					  ndev->limits.max_spads * 4;
-		ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET;
-		ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET;
-
-		if (ndev->split_bar) {
-			ndev->reg_ofs.bar5_xlat =
-				ndev->reg_base + SNB_PBAR5XLAT_OFFSET;
-			ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
-		} else
-			ndev->limits.max_mw = SNB_MAX_MW;
-		break;
-	default:
-		/*
-		 * we should never hit this. the detect function should've
-		 * take cared of everything.
-		 */
-		return -EINVAL;
-	}
+	if (size)
+		*size = pci_resource_len(ndev->ntb.pdev, bar) -
+			(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
 
-	ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET;
-	ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET;
-	ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET;
+	if (align)
+		*align = pci_resource_len(ndev->ntb.pdev, bar);
 
-	ndev->limits.msix_cnt = SNB_MSIX_CNT;
-	ndev->bits_per_vector = SNB_DB_BITS_PER_VEC;
+	if (align_size)
+		*align_size = 1;
 
 	return 0;
 }
 
-static int ntb_bwd_setup(struct ntb_device *ndev)
+static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+				  dma_addr_t addr, resource_size_t size)
 {
-	int rc;
-	u32 val;
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+	unsigned long base_reg, xlat_reg, limit_reg;
+	resource_size_t bar_size, mw_size;
+	void __iomem *mmio;
+	u64 base, limit, reg_val;
+	int bar;
 
-	ndev->hw_type = BWD_HW;
+	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+		idx += 1;
 
-	rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val);
-	if (rc)
-		return rc;
+	bar = ndev_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
 
-	switch ((val & BWD_PPD_CONN_TYPE) >> 8) {
-	case NTB_CONN_B2B:
-		ndev->conn_type = NTB_CONN_B2B;
-		break;
-	case NTB_CONN_RP:
-	default:
-		dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n");
+	bar_size = pci_resource_len(ndev->ntb.pdev, bar);
+
+	if (idx == ndev->b2b_idx)
+		mw_size = bar_size - ndev->b2b_off;
+	else
+		mw_size = bar_size;
+
+	/* hardware requires that addr is aligned to bar size */
+	if (addr & (bar_size - 1))
 		return -EINVAL;
+
+	/* make sure the range fits in the usable mw size */
+	if (size > mw_size)
+		return -EINVAL;
+
+	mmio = ndev->self_mmio;
+	base_reg = bar0_off(ndev->xlat_reg->bar0_base, bar);
+	xlat_reg = bar2_off(ndev->xlat_reg->bar2_xlat, bar);
+	limit_reg = bar2_off(ndev->xlat_reg->bar2_limit, bar);
+
+	if (bar < 4 || !ndev->bar4_split) {
+		base = ioread64(mmio + base_reg);
+
+		/* Set the limit if supported, if size is not mw_size */
+		if (limit_reg && size != mw_size)
+			limit = base + size;
+		else
+			limit = 0;
+
+		/* set and verify setting the translation address */
+		iowrite64(addr, mmio + xlat_reg);
+		reg_val = ioread64(mmio + xlat_reg);
+		if (reg_val != addr) {
+			iowrite64(0, mmio + xlat_reg);
+			return -EIO;
+		}
+
+		/* set and verify setting the limit */
+		iowrite64(limit, mmio + limit_reg);
+		reg_val = ioread64(mmio + limit_reg);
+		if (reg_val != limit) {
+			iowrite64(base, mmio + limit_reg);
+			iowrite64(0, mmio + xlat_reg);
+			return -EIO;
+		}
+	} else {
+		/* split bar addr range must all be 32 bit */
+		if (addr & (~0ull << 32))
+			return -EINVAL;
+		if ((addr + size) & (~0ull << 32))
+			return -EINVAL;
+
+		base = ioread32(mmio + base_reg);
+
+		/* Set the limit if supported, if size is not mw_size */
+		if (limit_reg && size != mw_size)
+			limit = base + size;
+		else
+			limit = 0;
+
+		/* set and verify setting the translation address */
+		iowrite32(addr, mmio + xlat_reg);
+		reg_val = ioread32(mmio + xlat_reg);
+		if (reg_val != addr) {
+			iowrite32(0, mmio + xlat_reg);
+			return -EIO;
+		}
+
+		/* set and verify setting the limit */
+		iowrite32(limit, mmio + limit_reg);
+		reg_val = ioread32(mmio + limit_reg);
+		if (reg_val != limit) {
+			iowrite32(base, mmio + limit_reg);
+			iowrite32(0, mmio + xlat_reg);
+			return -EIO;
+		}
 	}
 
-	if (val & BWD_PPD_DEV_TYPE)
-		ndev->dev_type = NTB_DEV_DSD;
-	else
-		ndev->dev_type = NTB_DEV_USD;
+	return 0;
+}
 
-	/* Initiate PCI-E link training */
-	rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET,
-				    val | BWD_PPD_INIT_LINK);
-	if (rc)
-		return rc;
+static int intel_ntb_link_is_up(struct ntb_dev *ntb,
+				enum ntb_speed *speed,
+				enum ntb_width *width)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET;
-	ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET;
-	ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET;
-	ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET;
-	ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET;
-	ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET;
-	ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET;
-	ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET;
-	ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET;
-	ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET;
-	ndev->limits.max_mw = BWD_MAX_MW;
-	ndev->limits.max_spads = BWD_MAX_SPADS;
-	ndev->limits.max_db_bits = BWD_MAX_DB_BITS;
-	ndev->limits.msix_cnt = BWD_MSIX_CNT;
-	ndev->bits_per_vector = BWD_DB_BITS_PER_VEC;
-
-	/* Since bwd doesn't have a link interrupt, setup a poll timer */
-	INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll);
-	INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery);
-	schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
+	if (ndev->reg->link_is_up(ndev)) {
+		if (speed)
+			*speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
+		if (width)
+			*width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
+		return 1;
+	} else {
+		/* TODO MAYBE: is it possible to observe the link speed and
+		 * width while link is training? */
+		if (speed)
+			*speed = NTB_SPEED_NONE;
+		if (width)
+			*width = NTB_WIDTH_NONE;
+		return 0;
+	}
+}
+
+static int intel_ntb_link_enable(struct ntb_dev *ntb,
+				 enum ntb_speed max_speed,
+				 enum ntb_width max_width)
+{
+	struct intel_ntb_dev *ndev;
+	u32 ntb_ctl;
+
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+	if (ndev->ntb.topo == NTB_TOPO_SEC)
+		return -EINVAL;
+
+	dev_dbg(ndev_dev(ndev),
+		"Enabling link with max_speed %d max_width %d\n",
+		max_speed, max_width);
+	if (max_speed != NTB_SPEED_AUTO)
+		dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
+	if (max_width != NTB_WIDTH_AUTO)
+		dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
+
+	ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+	ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
+	ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+	ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+	if (ndev->bar4_split)
+		ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
+	iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
 
 	return 0;
 }
 
-static int ntb_device_setup(struct ntb_device *ndev)
+static int intel_ntb_link_disable(struct ntb_dev *ntb)
 {
-	int rc;
+	struct intel_ntb_dev *ndev;
+	u32 ntb_cntl;
 
-	if (is_ntb_xeon(ndev))
-		rc = ntb_xeon_setup(ndev);
-	else if (is_ntb_atom(ndev))
-		rc = ntb_bwd_setup(ndev);
-	else
-		rc = -ENODEV;
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
 
-	if (rc)
-		return rc;
+	if (ndev->ntb.topo == NTB_TOPO_SEC)
+		return -EINVAL;
 
-	if (ndev->conn_type == NTB_CONN_B2B)
-		/* Enable Bus Master and Memory Space on the secondary side */
-		writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
-		       ndev->reg_ofs.spci_cmd);
+	dev_dbg(ndev_dev(ndev), "Disabling link\n");
+
+	/* Bring NTB link down */
+	ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+	ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
+	ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
+	if (ndev->bar4_split)
+		ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
+	ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
+	iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
 
 	return 0;
 }
 
-static void ntb_device_free(struct ntb_device *ndev)
+static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
 {
-	if (is_ntb_atom(ndev)) {
-		cancel_delayed_work_sync(&ndev->hb_timer);
-		cancel_delayed_work_sync(&ndev->lr_timer);
-	}
+	return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
 }
 
-static irqreturn_t bwd_callback_msix_irq(int irq, void *data)
+static u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb)
 {
-	struct ntb_db_cb *db_cb = data;
-	struct ntb_device *ndev = db_cb->ndev;
-	unsigned long mask;
+	return ntb_ndev(ntb)->db_valid_mask;
+}
 
-	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
-		db_cb->db_num);
+static int intel_ntb_db_vector_count(struct ntb_dev *ntb)
+{
+	struct intel_ntb_dev *ndev;
 
-	mask = readw(ndev->reg_ofs.ldb_mask);
-	set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
-	writew(mask, ndev->reg_ofs.ldb_mask);
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
 
-	tasklet_schedule(&db_cb->irq_work);
+	return ndev->db_vec_count;
+}
 
-	/* No need to check for the specific HB irq, any interrupt means
-	 * we're connected.
-	 */
-	ndev->last_ts = jiffies;
+static u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb);
+	if (db_vector < 0 || db_vector > ndev->db_vec_count)
+		return 0;
 
-	return IRQ_HANDLED;
+	return ndev->db_valid_mask & ndev_vec_mask(ndev, db_vector);
 }
 
-static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
+static u64 intel_ntb_db_read(struct ntb_dev *ntb)
 {
-	struct ntb_db_cb *db_cb = data;
-	struct ntb_device *ndev = db_cb->ndev;
-	unsigned long mask;
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
-		db_cb->db_num);
+	return ndev_db_read(ndev,
+			    ndev->self_mmio +
+			    ndev->self_reg->db_bell);
+}
 
-	mask = readw(ndev->reg_ofs.ldb_mask);
-	set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
-	writew(mask, ndev->reg_ofs.ldb_mask);
+static int intel_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	tasklet_schedule(&db_cb->irq_work);
+	return ndev_db_write(ndev, db_bits,
+			     ndev->self_mmio +
+			     ndev->self_reg->db_bell);
+}
 
-	/* On Sandybridge, there are 16 bits in the interrupt register
-	 * but only 4 vectors.  So, 5 bits are assigned to the first 3
-	 * vectors, with the 4th having a single bit for link
-	 * interrupts.
-	 */
-	writew(((1 << ndev->bits_per_vector) - 1) <<
-	       (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb);
+static int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	return IRQ_HANDLED;
+	return ndev_db_set_mask(ndev, db_bits,
+				ndev->self_mmio +
+				ndev->self_reg->db_mask);
 }
 
-/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */
-static irqreturn_t xeon_event_msix_irq(int irq, void *dev)
+static int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
 {
-	struct ntb_device *ndev = dev;
-	int rc;
-
-	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq);
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	rc = ntb_link_status(ndev);
-	if (rc)
-		dev_err(&ndev->pdev->dev, "Error determining link status\n");
+	return ndev_db_clear_mask(ndev, db_bits,
+				  ndev->self_mmio +
+				  ndev->self_reg->db_mask);
+}
 
-	/* bit 15 is always the link bit */
-	writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb);
+static int intel_ntb_peer_db_addr(struct ntb_dev *ntb,
+				  phys_addr_t *db_addr,
+				  resource_size_t *db_size)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	return IRQ_HANDLED;
+	return ndev_db_addr(ndev, db_addr, db_size, ndev->peer_addr,
+			    ndev->peer_reg->db_bell);
 }
 
-static irqreturn_t ntb_interrupt(int irq, void *dev)
+static int intel_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
 {
-	struct ntb_device *ndev = dev;
-	unsigned int i = 0;
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	if (is_ntb_atom(ndev)) {
-		u64 ldb = readq(ndev->reg_ofs.ldb);
+	return ndev_db_write(ndev, db_bits,
+			     ndev->peer_mmio +
+			     ndev->peer_reg->db_bell);
+}
 
-		dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb);
+static int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb)
+{
+	return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_SPAD);
+}
 
-		while (ldb) {
-			i = __ffs(ldb);
-			ldb &= ldb - 1;
-			bwd_callback_msix_irq(irq, &ndev->db_cb[i]);
-		}
-	} else {
-		u16 ldb = readw(ndev->reg_ofs.ldb);
+static int intel_ntb_spad_count(struct ntb_dev *ntb)
+{
+	struct intel_ntb_dev *ndev;
 
-		dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb);
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
 
-		if (ldb & SNB_DB_HW_LINK) {
-			xeon_event_msix_irq(irq, dev);
-			ldb &= ~SNB_DB_HW_LINK;
-		}
+	return ndev->spad_count;
+}
 
-		while (ldb) {
-			i = __ffs(ldb);
-			ldb &= ldb - 1;
-			xeon_callback_msix_irq(irq, &ndev->db_cb[i]);
-		}
-	}
+static u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	return IRQ_HANDLED;
+	return ndev_spad_read(ndev, idx,
+			      ndev->self_mmio +
+			      ndev->self_reg->spad);
 }
 
-static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries)
+static int intel_ntb_spad_write(struct ntb_dev *ntb,
+				int idx, u32 val)
 {
-	struct pci_dev *pdev = ndev->pdev;
-	struct msix_entry *msix;
-	int rc, i;
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	if (msix_entries < ndev->limits.msix_cnt)
-		return -ENOSPC;
+	return ndev_spad_write(ndev, idx, val,
+			       ndev->self_mmio +
+			       ndev->self_reg->spad);
+}
 
-	rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries);
-	if (rc < 0)
-		return rc;
+static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+				    phys_addr_t *spad_addr)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	for (i = 0; i < msix_entries; i++) {
-		msix = &ndev->msix_entries[i];
-		WARN_ON(!msix->vector);
+	return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr,
+			      ndev->peer_reg->spad);
+}
 
-		if (i == msix_entries - 1) {
-			rc = request_irq(msix->vector,
-					 xeon_event_msix_irq, 0,
-					 "ntb-event-msix", ndev);
-			if (rc)
-				goto err;
-		} else {
-			rc = request_irq(msix->vector,
-					 xeon_callback_msix_irq, 0,
-					 "ntb-callback-msix",
-					 &ndev->db_cb[i]);
-			if (rc)
-				goto err;
-		}
-	}
+static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-	ndev->num_msix = msix_entries;
-	ndev->max_cbs = msix_entries - 1;
+	return ndev_spad_read(ndev, idx,
+			      ndev->peer_mmio +
+			      ndev->peer_reg->spad);
+}
 
-	return 0;
+static int intel_ntb_peer_spad_write(struct ntb_dev *ntb,
+				     int idx, u32 val)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-err:
-	while (--i >= 0) {
-		/* Code never reaches here for entry nr 'ndev->num_msix - 1' */
-		msix = &ndev->msix_entries[i];
-		free_irq(msix->vector, &ndev->db_cb[i]);
-	}
+	return ndev_spad_write(ndev, idx, val,
+			       ndev->peer_mmio +
+			       ndev->peer_reg->spad);
+}
 
-	pci_disable_msix(pdev);
-	ndev->num_msix = 0;
+/* BWD */
 
-	return rc;
+static u64 bwd_db_ioread(void __iomem *mmio)
+{
+	return ioread64(mmio);
 }
 
-static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries)
+static void bwd_db_iowrite(u64 bits, void __iomem *mmio)
 {
-	struct pci_dev *pdev = ndev->pdev;
-	struct msix_entry *msix;
-	int rc, i;
+	iowrite64(bits, mmio);
+}
 
-	msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries,
-					     1, msix_entries);
-	if (msix_entries < 0)
-		return msix_entries;
+static int bwd_poll_link(struct intel_ntb_dev *ndev)
+{
+	u32 ntb_ctl;
 
-	for (i = 0; i < msix_entries; i++) {
-		msix = &ndev->msix_entries[i];
-		WARN_ON(!msix->vector);
+	ntb_ctl = ioread32(ndev->self_mmio + BWD_NTBCNTL_OFFSET);
 
-		rc = request_irq(msix->vector, bwd_callback_msix_irq, 0,
-				 "ntb-callback-msix", &ndev->db_cb[i]);
-		if (rc)
-			goto err;
-	}
+	if (ntb_ctl == ndev->ntb_ctl)
+		return 0;
 
-	ndev->num_msix = msix_entries;
-	ndev->max_cbs = msix_entries;
+	ndev->ntb_ctl = ntb_ctl;
 
-	return 0;
+	ndev->lnk_sta = ioread32(ndev->self_mmio + BWD_LINK_STATUS_OFFSET);
 
-err:
-	while (--i >= 0)
-		free_irq(msix->vector, &ndev->db_cb[i]);
+	return 1;
+}
 
-	pci_disable_msix(pdev);
-	ndev->num_msix = 0;
+static int bwd_link_is_up(struct intel_ntb_dev *ndev)
+{
+	return BWD_NTB_CTL_ACTIVE(ndev->ntb_ctl);
+}
 
-	return rc;
+static int bwd_link_is_err(struct intel_ntb_dev *ndev)
+{
+	if (ioread32(ndev->self_mmio + BWD_LTSSMSTATEJMP_OFFSET)
+	    & BWD_LTSSMSTATEJMP_FORCEDETECT)
+		return 1;
+
+	if (ioread32(ndev->self_mmio + BWD_IBSTERRRCRVSTS0_OFFSET)
+	    & BWD_IBIST_ERR_OFLOW)
+		return 1;
+
+	return 0;
 }
 
-static int ntb_setup_msix(struct ntb_device *ndev)
+static inline enum ntb_topo bwd_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd)
 {
-	struct pci_dev *pdev = ndev->pdev;
-	int msix_entries;
-	int rc, i;
+	switch (ppd & BWD_PPD_TOPO_MASK) {
+	case BWD_PPD_TOPO_B2B_USD:
+		dev_dbg(ndev_dev(ndev), "PPD %d B2B USD\n", ppd);
+		return NTB_TOPO_B2B_USD;
+
+	case BWD_PPD_TOPO_B2B_DSD:
+		dev_dbg(ndev_dev(ndev), "PPD %d B2B DSD\n", ppd);
+		return NTB_TOPO_B2B_DSD;
+
+	case BWD_PPD_TOPO_PRI_USD:
+	case BWD_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */
+	case BWD_PPD_TOPO_SEC_USD:
+	case BWD_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */
+		dev_dbg(ndev_dev(ndev), "PPD %d non B2B disabled\n", ppd);
+		return NTB_TOPO_NONE;
+	}
 
-	msix_entries = pci_msix_vec_count(pdev);
-	if (msix_entries < 0) {
-		rc = msix_entries;
-		goto err;
-	} else if (msix_entries > ndev->limits.msix_cnt) {
-		rc = -EINVAL;
-		goto err;
+	dev_dbg(ndev_dev(ndev), "PPD %d invalid\n", ppd);
+	return NTB_TOPO_NONE;
+}
+
+static void bwd_link_hb(struct work_struct *work)
+{
+	struct intel_ntb_dev *ndev = hb_ndev(work);
+	unsigned long poll_ts;
+	void __iomem *mmio;
+	u32 status32;
+
+	poll_ts = ndev->last_ts + BWD_LINK_HB_TIMEOUT;
+
+	/* Delay polling the link status if an interrupt was received,
+	 * unless the cached link status says the link is down.
+	 */
+	if (time_after(poll_ts, jiffies) && bwd_link_is_up(ndev)) {
+		schedule_delayed_work(&ndev->hb_timer, poll_ts - jiffies);
+		return;
 	}
 
-	ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries,
-				     GFP_KERNEL);
-	if (!ndev->msix_entries) {
-		rc = -ENOMEM;
-		goto err;
+	if (bwd_poll_link(ndev))
+		ntb_link_event(&ndev->ntb);
+
+	if (bwd_link_is_up(ndev) || !bwd_link_is_err(ndev)) {
+		schedule_delayed_work(&ndev->hb_timer, BWD_LINK_HB_TIMEOUT);
+		return;
 	}
 
-	for (i = 0; i < msix_entries; i++)
-		ndev->msix_entries[i].entry = i;
+	/* Link is down with error: recover the link! */
 
-	if (is_ntb_atom(ndev))
-		rc = ntb_setup_bwd_msix(ndev, msix_entries);
-	else
-		rc = ntb_setup_snb_msix(ndev, msix_entries);
-	if (rc)
-		goto err1;
+	mmio = ndev->self_mmio;
 
-	return 0;
+	/* Driver resets the NTB ModPhy lanes - magic! */
+	iowrite8(0xe0, mmio + BWD_MODPHY_PCSREG6);
+	iowrite8(0x40, mmio + BWD_MODPHY_PCSREG4);
+	iowrite8(0x60, mmio + BWD_MODPHY_PCSREG4);
+	iowrite8(0x60, mmio + BWD_MODPHY_PCSREG6);
 
-err1:
-	kfree(ndev->msix_entries);
-err:
-	dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n");
-	return rc;
+	/* Driver waits 100ms to allow the NTB ModPhy to settle */
+	msleep(100);
+
+	/* Clear AER Errors, write to clear */
+	status32 = ioread32(mmio + BWD_ERRCORSTS_OFFSET);
+	dev_dbg(ndev_dev(ndev), "ERRCORSTS = %x\n", status32);
+	status32 &= PCI_ERR_COR_REP_ROLL;
+	iowrite32(status32, mmio + BWD_ERRCORSTS_OFFSET);
+
+	/* Clear unexpected electrical idle event in LTSSM, write to clear */
+	status32 = ioread32(mmio + BWD_LTSSMERRSTS0_OFFSET);
+	dev_dbg(ndev_dev(ndev), "LTSSMERRSTS0 = %x\n", status32);
+	status32 |= BWD_LTSSMERRSTS0_UNEXPECTEDEI;
+	iowrite32(status32, mmio + BWD_LTSSMERRSTS0_OFFSET);
+
+	/* Clear DeSkew Buffer error, write to clear */
+	status32 = ioread32(mmio + BWD_DESKEWSTS_OFFSET);
+	dev_dbg(ndev_dev(ndev), "DESKEWSTS = %x\n", status32);
+	status32 |= BWD_DESKEWSTS_DBERR;
+	iowrite32(status32, mmio + BWD_DESKEWSTS_OFFSET);
+
+	status32 = ioread32(mmio + BWD_IBSTERRRCRVSTS0_OFFSET);
+	dev_dbg(ndev_dev(ndev), "IBSTERRRCRVSTS0 = %x\n", status32);
+	status32 &= BWD_IBIST_ERR_OFLOW;
+	iowrite32(status32, mmio + BWD_IBSTERRRCRVSTS0_OFFSET);
+
+	/* Releases the NTB state machine to allow the link to retrain */
+	status32 = ioread32(mmio + BWD_LTSSMSTATEJMP_OFFSET);
+	dev_dbg(ndev_dev(ndev), "LTSSMSTATEJMP = %x\n", status32);
+	status32 &= ~BWD_LTSSMSTATEJMP_FORCEDETECT;
+	iowrite32(status32, mmio + BWD_LTSSMSTATEJMP_OFFSET);
+
+	/* There is a potential race between the 2 NTB devices recovering at the
+	 * same time.  If the times are the same, the link will not recover and
+	 * the driver will be stuck in this loop forever.  Add a random interval
+	 * to the recovery time to prevent this race.
+	 */
+	schedule_delayed_work(&ndev->hb_timer, BWD_LINK_RECOVERY_TIME
+			      + prandom_u32() % BWD_LINK_RECOVERY_TIME);
 }
 
-static int ntb_setup_msi(struct ntb_device *ndev)
+static int bwd_init_isr(struct intel_ntb_dev *ndev)
 {
-	struct pci_dev *pdev = ndev->pdev;
 	int rc;
 
-	rc = pci_enable_msi(pdev);
+	rc = ndev_init_isr(ndev, 1, BWD_DB_MSIX_VECTOR_COUNT,
+			   BWD_DB_MSIX_VECTOR_SHIFT, BWD_DB_TOTAL_SHIFT);
 	if (rc)
 		return rc;
 
-	rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev);
-	if (rc) {
-		pci_disable_msi(pdev);
-		dev_err(&pdev->dev, "Error allocating MSI interrupt\n");
-		return rc;
-	}
+	/* BWD doesn't have link status interrupt, poll on that platform */
+	ndev->last_ts = jiffies;
+	INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_hb);
+	schedule_delayed_work(&ndev->hb_timer, BWD_LINK_HB_TIMEOUT);
 
 	return 0;
 }
 
-static int ntb_setup_intx(struct ntb_device *ndev)
+static void bwd_deinit_isr(struct intel_ntb_dev *ndev)
 {
-	struct pci_dev *pdev = ndev->pdev;
-	int rc;
+	cancel_delayed_work_sync(&ndev->hb_timer);
+	ndev_deinit_isr(ndev);
+}
 
-	pci_msi_off(pdev);
+static int bwd_init_ntb(struct intel_ntb_dev *ndev)
+{
+	ndev->mw_count = BWD_MW_COUNT;
+	ndev->spad_count = BWD_SPAD_COUNT;
+	ndev->db_count = BWD_DB_COUNT;
 
-	/* Verify intx is enabled */
-	pci_intx(pdev, 1);
+	switch (ndev->ntb.topo) {
+	case NTB_TOPO_B2B_USD:
+	case NTB_TOPO_B2B_DSD:
+		ndev->self_reg = &bwd_pri_reg;
+		ndev->peer_reg = &bwd_b2b_reg;
+		ndev->xlat_reg = &bwd_sec_xlat;
 
-	rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx",
-			 ndev);
-	if (rc)
-		return rc;
+		/* Enable Bus Master and Memory Space on the secondary side */
+		iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+			  ndev->self_mmio + BWD_SPCICMD_OFFSET);
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
 
 	return 0;
 }
 
-static int ntb_setup_interrupts(struct ntb_device *ndev)
+static int bwd_init_dev(struct intel_ntb_dev *ndev)
 {
+	u32 ppd;
 	int rc;
 
-	/* On BWD, disable all interrupts.  On SNB, disable all but Link
-	 * Interrupt.  The rest will be unmasked as callbacks are registered.
-	 */
-	if (is_ntb_atom(ndev))
-		writeq(~0, ndev->reg_ofs.ldb_mask);
-	else {
-		u16 var = 1 << SNB_LINK_DB;
-		writew(~var, ndev->reg_ofs.ldb_mask);
-	}
-
-	rc = ntb_setup_msix(ndev);
-	if (!rc)
-		goto done;
+	rc = pci_read_config_dword(ndev->ntb.pdev, BWD_PPD_OFFSET, &ppd);
+	if (rc)
+		return -EIO;
 
-	ndev->bits_per_vector = 1;
-	ndev->max_cbs = ndev->limits.max_db_bits;
+	ndev->ntb.topo = bwd_ppd_topo(ndev, ppd);
+	if (ndev->ntb.topo == NTB_TOPO_NONE)
+		return -EINVAL;
 
-	rc = ntb_setup_msi(ndev);
-	if (!rc)
-		goto done;
+	rc = bwd_init_ntb(ndev);
+	if (rc)
+		return rc;
 
-	rc = ntb_setup_intx(ndev);
-	if (rc) {
-		dev_err(&ndev->pdev->dev, "no usable interrupts\n");
+	rc = bwd_init_isr(ndev);
+	if (rc)
 		return rc;
+
+	if (ndev->ntb.topo != NTB_TOPO_SEC) {
+		/* Initiate PCI-E link training */
+		rc = pci_write_config_dword(ndev->ntb.pdev, BWD_PPD_OFFSET,
+					    ppd | BWD_PPD_INIT_LINK);
+		if (rc)
+			return rc;
 	}
 
-done:
 	return 0;
 }
 
-static void ntb_free_interrupts(struct ntb_device *ndev)
+static void bwd_deinit_dev(struct intel_ntb_dev *ndev)
 {
-	struct pci_dev *pdev = ndev->pdev;
+	bwd_deinit_isr(ndev);
+}
 
-	/* mask interrupts */
-	if (is_ntb_atom(ndev))
-		writeq(~0, ndev->reg_ofs.ldb_mask);
-	else
-		writew(~0, ndev->reg_ofs.ldb_mask);
+/* SNB */
 
-	if (ndev->num_msix) {
-		struct msix_entry *msix;
-		u32 i;
+static u64 snb_db_ioread(void __iomem *mmio)
+{
+	return (u64)ioread16(mmio);
+}
 
-		for (i = 0; i < ndev->num_msix; i++) {
-			msix = &ndev->msix_entries[i];
-			if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1)
-				free_irq(msix->vector, ndev);
-			else
-				free_irq(msix->vector, &ndev->db_cb[i]);
-		}
-		pci_disable_msix(pdev);
-		kfree(ndev->msix_entries);
-	} else {
-		free_irq(pdev->irq, ndev);
+static void snb_db_iowrite(u64 bits, void __iomem *mmio)
+{
+	iowrite16((u16)bits, mmio);
+}
 
-		if (pci_dev_msi_enabled(pdev))
-			pci_disable_msi(pdev);
-	}
+static int snb_poll_link(struct intel_ntb_dev *ndev)
+{
+	u16 reg_val;
+	int rc;
+
+	ndev->reg->db_iowrite(ndev->db_link_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_bell);
+
+	rc = pci_read_config_word(ndev->ntb.pdev,
+				  SNB_LINK_STATUS_OFFSET, &reg_val);
+	if (rc)
+		return 0;
+
+	if (reg_val == ndev->lnk_sta)
+		return 0;
+
+	ndev->lnk_sta = reg_val;
+
+	return 1;
 }
 
-static int ntb_create_callbacks(struct ntb_device *ndev)
+static int snb_link_is_up(struct intel_ntb_dev *ndev)
 {
-	int i;
+	return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
+}
 
-	/* Chicken-egg issue.  We won't know how many callbacks are necessary
-	 * until we see how many MSI-X vectors we get, but these pointers need
-	 * to be passed into the MSI-X register function.  So, we allocate the
-	 * max, knowing that they might not all be used, to work around this.
-	 */
-	ndev->db_cb = kcalloc(ndev->limits.max_db_bits,
-			      sizeof(struct ntb_db_cb),
-			      GFP_KERNEL);
-	if (!ndev->db_cb)
-		return -ENOMEM;
+static inline enum ntb_topo snb_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd)
+{
+	switch (ppd & SNB_PPD_TOPO_MASK) {
+	case SNB_PPD_TOPO_B2B_USD:
+		return NTB_TOPO_B2B_USD;
+
+	case SNB_PPD_TOPO_B2B_DSD:
+		return NTB_TOPO_B2B_DSD;
 
-	for (i = 0; i < ndev->limits.max_db_bits; i++) {
-		ndev->db_cb[i].db_num = i;
-		ndev->db_cb[i].ndev = ndev;
+	case SNB_PPD_TOPO_PRI_USD:
+	case SNB_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */
+		return NTB_TOPO_PRI;
+
+	case SNB_PPD_TOPO_SEC_USD:
+	case SNB_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */
+		return NTB_TOPO_SEC;
 	}
 
-	return 0;
+	return NTB_TOPO_NONE;
 }
 
-static void ntb_free_callbacks(struct ntb_device *ndev)
+static inline int snb_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd)
 {
-	int i;
+	if (ppd & SNB_PPD_SPLIT_BAR_MASK) {
+		dev_dbg(ndev_dev(ndev), "PPD %d split bar\n", ppd);
+		return 1;
+	}
+	return 0;
+}
 
-	for (i = 0; i < ndev->limits.max_db_bits; i++)
-		ntb_unregister_db_callback(ndev, i);
+static int snb_init_isr(struct intel_ntb_dev *ndev)
+{
+	return ndev_init_isr(ndev, SNB_DB_MSIX_VECTOR_COUNT,
+			     SNB_DB_MSIX_VECTOR_COUNT,
+			     SNB_DB_MSIX_VECTOR_SHIFT,
+			     SNB_DB_TOTAL_SHIFT);
+}
 
-	kfree(ndev->db_cb);
+static void snb_deinit_isr(struct intel_ntb_dev *ndev)
+{
+	ndev_deinit_isr(ndev);
 }
 
-static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf,
-				size_t count, loff_t *offp)
+static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
+			    const struct intel_b2b_addr *addr,
+			    const struct intel_b2b_addr *peer_addr)
 {
-	struct ntb_device *ndev;
-	char *buf;
-	ssize_t ret, offset, out_count;
+	struct pci_dev *pdev;
+	void __iomem *mmio;
+	unsigned long off;
+	resource_size_t bar_size;
+	phys_addr_t bar_addr;
+	int b2b_bar;
+	u8 bar_sz;
+
+	pdev = ndev_pdev(ndev);
+	mmio = ndev->self_mmio;
+
+	if (ndev->b2b_idx >= ndev->mw_count) {
+		dev_dbg(ndev_dev(ndev), "not using b2b mw\n");
+		b2b_bar = 0;
+		ndev->b2b_off = 0;
+	} else {
+		b2b_bar = ndev_mw_to_bar(ndev, ndev->b2b_idx);
+		if (b2b_bar < 0)
+			return -EIO;
 
-	out_count = 500;
+		dev_dbg(ndev_dev(ndev), "using b2b mw bar %d\n", b2b_bar);
 
-	buf = kmalloc(out_count, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
+		bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar);
 
-	ndev = filp->private_data;
-	offset = 0;
-	offset += snprintf(buf + offset, out_count - offset,
-			   "NTB Device Information:\n");
-	offset += snprintf(buf + offset, out_count - offset,
-			   "Connection Type - \t\t%s\n",
-			   ndev->conn_type == NTB_CONN_TRANSPARENT ?
-			   "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ?
-			   "Back to back" : "Root Port");
-	offset += snprintf(buf + offset, out_count - offset,
-			   "Device Type - \t\t\t%s\n",
-			   ndev->dev_type == NTB_DEV_USD ?
-			   "DSD/USP" : "USD/DSP");
-	offset += snprintf(buf + offset, out_count - offset,
-			   "Max Number of Callbacks - \t%u\n",
-			   ntb_max_cbs(ndev));
-	offset += snprintf(buf + offset, out_count - offset,
-			   "Link Status - \t\t\t%s\n",
-			   ntb_hw_link_status(ndev) ? "Up" : "Down");
-	if (ntb_hw_link_status(ndev)) {
-		offset += snprintf(buf + offset, out_count - offset,
-				   "Link Speed - \t\t\tPCI-E Gen %u\n",
-				   ndev->link_speed);
-		offset += snprintf(buf + offset, out_count - offset,
-				   "Link Width - \t\t\tx%u\n",
-				   ndev->link_width);
-	}
+		dev_dbg(ndev_dev(ndev), "b2b bar size %#llx\n", bar_size);
 
-	if (is_ntb_xeon(ndev)) {
-		u32 status32;
-		u16 status16;
-		int rc;
-
-		offset += snprintf(buf + offset, out_count - offset,
-				   "\nNTB Device Statistics:\n");
-		offset += snprintf(buf + offset, out_count - offset,
-				   "Upstream Memory Miss - \t%u\n",
-				   readw(ndev->reg_base +
-					 SNB_USMEMMISS_OFFSET));
-
-		offset += snprintf(buf + offset, out_count - offset,
-				   "\nNTB Hardware Errors:\n");
-
-		rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET,
-					  &status16);
-		if (!rc)
-			offset += snprintf(buf + offset, out_count - offset,
-					   "DEVSTS - \t%#06x\n", status16);
-
-		rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET,
-					  &status16);
-		if (!rc)
-			offset += snprintf(buf + offset, out_count - offset,
-					   "LNKSTS - \t%#06x\n", status16);
-
-		rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET,
-					   &status32);
-		if (!rc)
-			offset += snprintf(buf + offset, out_count - offset,
-					   "UNCERRSTS - \t%#010x\n", status32);
-
-		rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET,
-					   &status32);
-		if (!rc)
-			offset += snprintf(buf + offset, out_count - offset,
-					   "CORERRSTS - \t%#010x\n", status32);
+		if (b2b_mw_share && SNB_B2B_MIN_SIZE <= bar_size >> 1) {
+			dev_dbg(ndev_dev(ndev),
+				"b2b using first half of bar\n");
+			ndev->b2b_off = bar_size >> 1;
+		} else if (SNB_B2B_MIN_SIZE <= bar_size) {
+			dev_dbg(ndev_dev(ndev),
+				"b2b using whole bar\n");
+			ndev->b2b_off = 0;
+			--ndev->mw_count;
+		} else {
+			dev_dbg(ndev_dev(ndev),
+				"b2b bar size is too small\n");
+			return -EIO;
+		}
 	}
 
-	if (offset > out_count)
-		offset = out_count;
+	/* Reset the secondary bar sizes to match the primary bar sizes,
+	 * except disable or halve the size of the b2b secondary bar.
+	 *
+	 * Note: code for each specific bar size register, because the register
+	 * offsets are not in a consistent order (bar5sz comes after ppd, odd).
+	 */
+	pci_read_config_byte(pdev, SNB_PBAR23SZ_OFFSET, &bar_sz);
+	dev_dbg(ndev_dev(ndev), "PBAR23SZ %#x\n", bar_sz);
+	if (b2b_bar == 2) {
+		if (ndev->b2b_off)
+			bar_sz -= 1;
+		else
+			bar_sz = 0;
+	}
+	pci_write_config_byte(pdev, SNB_SBAR23SZ_OFFSET, bar_sz);
+	pci_read_config_byte(pdev, SNB_SBAR23SZ_OFFSET, &bar_sz);
+	dev_dbg(ndev_dev(ndev), "SBAR23SZ %#x\n", bar_sz);
+
+	if (!ndev->bar4_split) {
+		pci_read_config_byte(pdev, SNB_PBAR45SZ_OFFSET, &bar_sz);
+		dev_dbg(ndev_dev(ndev), "PBAR45SZ %#x\n", bar_sz);
+		if (b2b_bar == 4) {
+			if (ndev->b2b_off)
+				bar_sz -= 1;
+			else
+				bar_sz = 0;
+		}
+		pci_write_config_byte(pdev, SNB_SBAR45SZ_OFFSET, bar_sz);
+		pci_read_config_byte(pdev, SNB_SBAR45SZ_OFFSET, &bar_sz);
+		dev_dbg(ndev_dev(ndev), "SBAR45SZ %#x\n", bar_sz);
+	} else {
+		pci_read_config_byte(pdev, SNB_PBAR4SZ_OFFSET, &bar_sz);
+		dev_dbg(ndev_dev(ndev), "PBAR4SZ %#x\n", bar_sz);
+		if (b2b_bar == 4) {
+			if (ndev->b2b_off)
+				bar_sz -= 1;
+			else
+				bar_sz = 0;
+		}
+		pci_write_config_byte(pdev, SNB_SBAR4SZ_OFFSET, bar_sz);
+		pci_read_config_byte(pdev, SNB_SBAR4SZ_OFFSET, &bar_sz);
+		dev_dbg(ndev_dev(ndev), "SBAR4SZ %#x\n", bar_sz);
+
+		pci_read_config_byte(pdev, SNB_PBAR5SZ_OFFSET, &bar_sz);
+		dev_dbg(ndev_dev(ndev), "PBAR5SZ %#x\n", bar_sz);
+		if (b2b_bar == 5) {
+			if (ndev->b2b_off)
+				bar_sz -= 1;
+			else
+				bar_sz = 0;
+		}
+		pci_write_config_byte(pdev, SNB_SBAR5SZ_OFFSET, bar_sz);
+		pci_read_config_byte(pdev, SNB_SBAR5SZ_OFFSET, &bar_sz);
+		dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz);
+	}
 
-	ret = simple_read_from_buffer(ubuf, count, offp, buf, offset);
-	kfree(buf);
-	return ret;
-}
+	/* setup incoming bar base addresses */
+	off = SNB_SBAR0BASE_OFFSET;
+
+	/* SBAR01 hit by first part of the b2b bar */
+	if (b2b_bar == 0) {
+		bar_addr = addr->bar0_addr;
+	} else if (b2b_bar == 2) {
+		bar_addr = addr->bar2_addr64;
+	} else if (b2b_bar == 4 && !ndev->bar4_split) {
+		bar_addr = addr->bar4_addr64;
+	} else if (b2b_bar == 4) {
+		bar_addr = addr->bar4_addr32;
+	} else if (b2b_bar == 5) {
+		bar_addr = addr->bar5_addr32;
+	} else {
+		bar_addr = 0;
+		BUG();
+	}
 
-static const struct file_operations ntb_debugfs_info = {
-	.owner = THIS_MODULE,
-	.open = simple_open,
-	.read = ntb_debugfs_read,
-};
+	dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr);
+	iowrite64(bar_addr, mmio + bar0_off(off, 0));
 
-static void ntb_setup_debugfs(struct ntb_device *ndev)
-{
-	if (!debugfs_initialized())
-		return;
+	/* Other SBAR are normally hit by the PBAR xlat, except for b2b bar.
+	 * The b2b bar is either disabled above, or configured half-size, and
+	 * it starts at the PBAR xlat + offset.
+	 */
 
-	if (!debugfs_dir)
-		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
+	iowrite64(bar_addr, mmio + bar0_off(off, 2));
+	bar_addr = ioread64(mmio + bar0_off(off, 2));
+	dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr);
+
+	if (!ndev->bar4_split) {
+		bar_addr = addr->bar4_addr64 +
+			(b2b_bar == 4 ? ndev->b2b_off : 0);
+		iowrite64(bar_addr, mmio + bar0_off(off, 4));
+		bar_addr = ioread64(mmio + bar0_off(off, 4));
+		dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr);
+	} else {
+		bar_addr = addr->bar4_addr32 +
+			(b2b_bar == 4 ? ndev->b2b_off : 0);
+		iowrite32(bar_addr, mmio + bar0_off(off, 4));
+		bar_addr = ioread32(mmio + bar0_off(off, 4));
+		dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr);
+
+		bar_addr = addr->bar5_addr32 +
+			(b2b_bar == 5 ? ndev->b2b_off : 0);
+		iowrite32(bar_addr, mmio + bar0_off(off, 5));
+		bar_addr = ioread32(mmio + bar0_off(off, 5));
+		dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr);
+	}
 
-	ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev),
-					       debugfs_dir);
-	if (ndev->debugfs_dir)
-		ndev->debugfs_info = debugfs_create_file("info", S_IRUSR,
-							 ndev->debugfs_dir,
-							 ndev,
-							 &ntb_debugfs_info);
-}
+	/* setup incoming bar limits == base addrs (zero length windows) */
+	off = SNB_SBAR2LMT_OFFSET;
 
-static void ntb_free_debugfs(struct ntb_device *ndev)
-{
-	debugfs_remove_recursive(ndev->debugfs_dir);
+	bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
+	iowrite64(bar_addr, mmio + bar2_off(off, 2));
+	bar_addr = ioread64(mmio + bar2_off(off, 2));
+	dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr);
 
-	if (debugfs_dir && simple_empty(debugfs_dir)) {
-		debugfs_remove_recursive(debugfs_dir);
-		debugfs_dir = NULL;
+	if (!ndev->bar4_split) {
+		bar_addr = addr->bar4_addr64 +
+			(b2b_bar == 4 ? ndev->b2b_off : 0);
+		iowrite64(bar_addr, mmio + bar2_off(off, 4));
+		bar_addr = ioread64(mmio + bar2_off(off, 4));
+		dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr);
+	} else {
+		bar_addr = addr->bar4_addr32 +
+			(b2b_bar == 4 ? ndev->b2b_off : 0);
+		iowrite32(bar_addr, mmio + bar2_off(off, 4));
+		bar_addr = ioread32(mmio + bar2_off(off, 4));
+		dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr);
+
+		bar_addr = addr->bar5_addr32 +
+			(b2b_bar == 5 ? ndev->b2b_off : 0);
+		iowrite32(bar_addr, mmio + bar2_off(off, 5));
+		bar_addr = ioread32(mmio + bar2_off(off, 5));
+		dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr);
 	}
-}
 
-static void ntb_hw_link_up(struct ntb_device *ndev)
-{
-	if (ndev->conn_type == NTB_CONN_TRANSPARENT)
-		ntb_link_event(ndev, NTB_LINK_UP);
-	else {
-		u32 ntb_cntl;
+	/* zero incoming translation addrs */
+	off = SNB_SBAR2XLAT_OFFSET;
 
-		/* Let's bring the NTB link up */
-		ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
-		ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK);
-		ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP;
-		ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP;
-		if (ndev->split_bar)
-			ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP |
-				    NTB_CNTL_S2P_BAR5_SNOOP;
+	iowrite64(0, mmio + bar2_off(off, 2));
 
-		writel(ntb_cntl, ndev->reg_ofs.lnk_cntl);
+	if (!ndev->bar4_split) {
+		iowrite64(0, mmio + bar2_off(off, 4));
+	} else {
+		iowrite32(0, mmio + bar2_off(off, 4));
+		iowrite32(0, mmio + bar2_off(off, 5));
 	}
-}
 
-static void ntb_hw_link_down(struct ntb_device *ndev)
-{
-	u32 ntb_cntl;
+	/* zero outgoing translation limits (whole bar size windows) */
+	off = SNB_PBAR2LMT_OFFSET;
+	iowrite64(0, mmio + bar2_off(off, 2));
+	if (!ndev->bar4_split) {
+		iowrite64(0, mmio + bar2_off(off, 4));
+	} else {
+		iowrite32(0, mmio + bar2_off(off, 4));
+		iowrite32(0, mmio + bar2_off(off, 5));
+	}
 
-	if (ndev->conn_type == NTB_CONN_TRANSPARENT) {
-		ntb_link_event(ndev, NTB_LINK_DOWN);
-		return;
+	/* set outgoing translation offsets */
+	off = SNB_PBAR2XLAT_OFFSET;
+
+	bar_addr = peer_addr->bar2_addr64;
+	iowrite64(bar_addr, mmio + bar2_off(off, 2));
+	bar_addr = ioread64(mmio + bar2_off(off, 2));
+	dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr);
+
+	if (!ndev->bar4_split) {
+		bar_addr = peer_addr->bar4_addr64;
+		iowrite64(bar_addr, mmio + bar2_off(off, 4));
+		bar_addr = ioread64(mmio + bar2_off(off, 4));
+		dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr);
+	} else {
+		bar_addr = peer_addr->bar2_addr64;
+		iowrite32(bar_addr, mmio + bar2_off(off, 4));
+		bar_addr = ioread32(mmio + bar2_off(off, 4));
+		dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr);
+
+		bar_addr = peer_addr->bar2_addr64;
+		iowrite32(bar_addr, mmio + bar2_off(off, 5));
+		bar_addr = ioread32(mmio + bar2_off(off, 5));
+		dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr);
 	}
 
-	/* Bring NTB link down */
-	ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
-	ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP);
-	ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP);
-	if (ndev->split_bar)
-		ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP |
-			      NTB_CNTL_S2P_BAR5_SNOOP);
-	ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK;
-	writel(ntb_cntl, ndev->reg_ofs.lnk_cntl);
-}
+	/* set the translation offset for b2b registers */
+	if (b2b_bar == 0) {
+		bar_addr = peer_addr->bar0_addr;
+	} else if (b2b_bar == 2) {
+		bar_addr = peer_addr->bar2_addr64;
+	} else if (b2b_bar == 4 && !ndev->bar4_split) {
+		bar_addr = peer_addr->bar4_addr64;
+	} else if (b2b_bar == 4) {
+		bar_addr = peer_addr->bar4_addr32;
+	} else if (b2b_bar == 5) {
+		bar_addr = peer_addr->bar5_addr32;
+	} else {
+		bar_addr = 0;
+		BUG();
+	}
+	/* B2B_XLAT_OFFSET is 64bit, but can only take 32bit writes */
+	dev_dbg(ndev_dev(ndev), "B2BXLAT %#018llx\n", bar_addr);
+	iowrite32(bar_addr, mmio + SNB_B2B_XLAT_OFFSETL);
+	iowrite32(bar_addr >> 32, mmio + SNB_B2B_XLAT_OFFSETU);
+
+	if (b2b_bar) {
+		/* map peer ntb mmio config space registers */
+		ndev->peer_mmio = pci_iomap(pdev, b2b_bar,
+					    SNB_B2B_MIN_SIZE);
+		if (!ndev->peer_mmio)
+			return -EIO;
+	}
 
-static void ntb_max_mw_detect(struct ntb_device *ndev)
-{
-	if (ndev->split_bar)
-		ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
-	else
-		ndev->limits.max_mw = SNB_MAX_MW;
+	return 0;
 }
 
-static int ntb_xeon_detect(struct ntb_device *ndev)
+static int snb_init_ntb(struct intel_ntb_dev *ndev)
 {
-	int rc, bars_mask;
-	u32 bars;
-	u8 ppd;
-
-	ndev->hw_type = SNB_HW;
-
-	rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd);
-	if (rc)
-		return -EIO;
+	int rc;
 
-	if (ppd & SNB_PPD_DEV_TYPE)
-		ndev->dev_type = NTB_DEV_USD;
+	if (ndev->bar4_split)
+		ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
 	else
-		ndev->dev_type = NTB_DEV_DSD;
+		ndev->mw_count = SNB_MW_COUNT;
 
-	ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0;
+	ndev->spad_count = SNB_SPAD_COUNT;
+	ndev->db_count = SNB_DB_COUNT;
+	ndev->db_link_mask = SNB_DB_LINK_BIT;
 
-	switch (ppd & SNB_PPD_CONN_TYPE) {
-	case NTB_CONN_B2B:
-		dev_info(&ndev->pdev->dev, "Conn Type = B2B\n");
-		ndev->conn_type = NTB_CONN_B2B;
+	switch (ndev->ntb.topo) {
+	case NTB_TOPO_PRI:
+		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
+			dev_err(ndev_dev(ndev), "NTB Primary config disabled\n");
+			return -EINVAL;
+		}
+		/* use half the spads for the peer */
+		ndev->spad_count >>= 1;
+		ndev->self_reg = &snb_pri_reg;
+		ndev->peer_reg = &snb_sec_reg;
+		ndev->xlat_reg = &snb_sec_xlat;
 		break;
-	case NTB_CONN_RP:
-		dev_info(&ndev->pdev->dev, "Conn Type = RP\n");
-		ndev->conn_type = NTB_CONN_RP;
+
+	case NTB_TOPO_SEC:
+		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
+			dev_err(ndev_dev(ndev), "NTB Secondary config disabled\n");
+			return -EINVAL;
+		}
+		/* use half the spads for the peer */
+		ndev->spad_count >>= 1;
+		ndev->self_reg = &snb_sec_reg;
+		ndev->peer_reg = &snb_pri_reg;
+		ndev->xlat_reg = &snb_pri_xlat;
 		break;
-	case NTB_CONN_TRANSPARENT:
-		dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n");
-		ndev->conn_type = NTB_CONN_TRANSPARENT;
-		/*
-		 * This mode is default to USD/DSP. HW does not report
-		 * properly in transparent mode as it has no knowledge of
-		 * NTB. We will just force correct here.
-		 */
-		ndev->dev_type = NTB_DEV_USD;
 
-		/*
-		 * This is a way for transparent BAR to figure out if we
-		 * are doing split BAR or not. There is no way for the hw
-		 * on the transparent side to know and set the PPD.
-		 */
-		bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM);
-		bars = hweight32(bars_mask);
-		if (bars == (HSX_SPLITBAR_MAX_MW + 1))
-			ndev->split_bar = 1;
+	case NTB_TOPO_B2B_USD:
+	case NTB_TOPO_B2B_DSD:
+		ndev->self_reg = &snb_pri_reg;
+		ndev->peer_reg = &snb_b2b_reg;
+		ndev->xlat_reg = &snb_sec_xlat;
 
-		break;
-	default:
-		dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd);
-		return -ENODEV;
-	}
+		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
+			ndev->peer_reg = &snb_pri_reg;
 
-	ntb_max_mw_detect(ndev);
+			if (b2b_mw_idx < 0)
+				ndev->b2b_idx = b2b_mw_idx + ndev->mw_count;
+			else
+				ndev->b2b_idx = b2b_mw_idx;
 
-	return 0;
-}
+			dev_dbg(ndev_dev(ndev),
+				"setting up b2b mw idx %d means %d\n",
+				b2b_mw_idx, ndev->b2b_idx);
 
-static int ntb_atom_detect(struct ntb_device *ndev)
-{
-	int rc;
-	u32 ppd;
+		} else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) {
+			dev_warn(ndev_dev(ndev), "Reduce doorbell count by 1\n");
+			ndev->db_count -= 1;
+		}
 
-	ndev->hw_type = BWD_HW;
+		if (ndev->ntb.topo == NTB_TOPO_B2B_USD) {
+			rc = snb_setup_b2b_mw(ndev,
+					      &snb_b2b_dsd_addr,
+					      &snb_b2b_usd_addr);
+		} else {
+			rc = snb_setup_b2b_mw(ndev,
+					      &snb_b2b_usd_addr,
+					      &snb_b2b_dsd_addr);
+		}
+		if (rc)
+			return rc;
 
-	rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd);
-	if (rc)
-		return rc;
+		/* Enable Bus Master and Memory Space on the secondary side */
+		iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+			  ndev->self_mmio + SNB_SPCICMD_OFFSET);
 
-	switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) {
-	case NTB_CONN_B2B:
-		dev_info(&ndev->pdev->dev, "Conn Type = B2B\n");
-		ndev->conn_type = NTB_CONN_B2B;
 		break;
-	case NTB_CONN_RP:
+
 	default:
-		dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n");
 		return -EINVAL;
 	}
 
-	if (ppd & BWD_PPD_DEV_TYPE)
-		ndev->dev_type = NTB_DEV_DSD;
-	else
-		ndev->dev_type = NTB_DEV_USD;
+	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
+
+	ndev->reg->db_iowrite(ndev->db_valid_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_mask);
 
 	return 0;
 }
 
-static int ntb_device_detect(struct ntb_device *ndev)
+static int snb_init_dev(struct intel_ntb_dev *ndev)
 {
-	int rc;
+	struct pci_dev *pdev;
+	u8 ppd;
+	int rc, mem;
 
-	if (is_ntb_xeon(ndev))
-		rc = ntb_xeon_detect(ndev);
-	else if (is_ntb_atom(ndev))
-		rc = ntb_atom_detect(ndev);
-	else
-		rc = -ENODEV;
+	/* 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
+	 * window to access the interrupt and scratch pad registers on the
+	 * remote system.
+	 */
+	ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
 
-	dev_info(&ndev->pdev->dev, "Device Type = %s\n",
-		 ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP");
+	/* There is a hardware errata related to accessing any register in
+	 * SB01BASE in the presence of bidirectional traffic crossing the NTB.
+	 */
+	ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
 
-	return 0;
-}
+	/* HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
+	 * mirrored to the remote system.  Shrink the number of bits by one,
+	 * since bit 14 is the last bit.
+	 */
+	ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
 
-static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	struct ntb_device *ndev;
-	int rc, i;
+	ndev->reg = &snb_reg;
 
-	ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL);
-	if (!ndev)
-		return -ENOMEM;
+	pdev = ndev_pdev(ndev);
 
-	ndev->pdev = pdev;
+	rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd);
+	if (rc)
+		return -EIO;
 
-	ntb_set_errata_flags(ndev);
+	ndev->ntb.topo = snb_ppd_topo(ndev, ppd);
+	dev_dbg(ndev_dev(ndev), "ppd %#x topo %s\n", ppd,
+		ntb_topo_string(ndev->ntb.topo));
+	if (ndev->ntb.topo == NTB_TOPO_NONE)
+		return -EINVAL;
 
-	ndev->link_status = NTB_LINK_DOWN;
-	pci_set_drvdata(pdev, ndev);
-	ntb_setup_debugfs(ndev);
+	if (ndev->ntb.topo != NTB_TOPO_PRI) {
+		ndev->bar4_split = snb_ppd_bar4_split(ndev, ppd);
+		dev_dbg(ndev_dev(ndev), "ppd %#x bar4_split %d\n",
+			ppd, ndev->bar4_split);
+	} else {
+		/* This is a way for transparent BAR to figure out if we are
+		 * doing split BAR or not. There is no way for the hw on the
+		 * transparent side to know and set the PPD.
+		 */
+		mem = pci_select_bars(pdev, IORESOURCE_MEM);
+		ndev->bar4_split = hweight32(mem) ==
+			HSX_SPLIT_BAR_MW_COUNT + 1;
+		dev_dbg(ndev_dev(ndev), "mem %#x bar4_split %d\n",
+			mem, ndev->bar4_split);
+	}
 
-	rc = pci_enable_device(pdev);
+	rc = snb_init_ntb(ndev);
 	if (rc)
-		goto err;
-
-	pci_set_master(ndev->pdev);
+		return rc;
 
-	rc = ntb_device_detect(ndev);
+	rc = snb_init_isr(ndev);
 	if (rc)
-		goto err;
+		return rc;
 
-	ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw),
-			   GFP_KERNEL);
-	if (!ndev->mw) {
-		rc = -ENOMEM;
-		goto err1;
-	}
+	return 0;
+}
 
-	if (ndev->split_bar)
-		rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK,
-						  KBUILD_MODNAME);
-	else
-		rc = pci_request_selected_regions(pdev, NTB_BAR_MASK,
-						  KBUILD_MODNAME);
+static void snb_deinit_dev(struct intel_ntb_dev *ndev)
+{
+	snb_deinit_isr(ndev);
+}
 
-	if (rc)
-		goto err2;
+static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev)
+{
+	int rc;
 
-	ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO);
-	if (!ndev->reg_base) {
-		dev_warn(&pdev->dev, "Cannot remap BAR 0\n");
-		rc = -EIO;
-		goto err3;
-	}
+	pci_set_drvdata(pdev, ndev);
 
-	for (i = 0; i < ndev->limits.max_mw; i++) {
-		ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i));
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_pci_enable;
 
-		/*
-		 * with the errata we need to steal last of the memory
-		 * windows for workarounds and they point to MMIO registers.
-		 */
-		if ((ndev->wa_flags & WA_SNB_ERR) &&
-		    (i == (ndev->limits.max_mw - 1))) {
-			ndev->mw[i].vbase =
-				ioremap_nocache(pci_resource_start(pdev,
-							MW_TO_BAR(i)),
-						ndev->mw[i].bar_sz);
-		} else {
-			ndev->mw[i].vbase =
-				ioremap_wc(pci_resource_start(pdev,
-							MW_TO_BAR(i)),
-					   ndev->mw[i].bar_sz);
-		}
+	rc = pci_request_regions(pdev, NTB_NAME);
+	if (rc)
+		goto err_pci_regions;
 
-		dev_info(&pdev->dev, "MW %d size %llu\n", i,
-			 (unsigned long long) ndev->mw[i].bar_sz);
-		if (!ndev->mw[i].vbase) {
-			dev_warn(&pdev->dev, "Cannot remap BAR %d\n",
-				 MW_TO_BAR(i));
-			rc = -EIO;
-			goto err3;
-		}
-	}
+	pci_set_master(pdev);
 
 	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
 	if (rc) {
 		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 		if (rc)
-			goto err4;
-
-		dev_warn(&pdev->dev, "Cannot DMA highmem\n");
+			goto err_dma_mask;
+		dev_warn(ndev_dev(ndev), "Cannot DMA highmem\n");
 	}
 
 	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
 	if (rc) {
 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 		if (rc)
-			goto err4;
+			goto err_dma_mask;
+		dev_warn(ndev_dev(ndev), "Cannot DMA consistent highmem\n");
+	}
 
-		dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n");
+	ndev->self_mmio = pci_iomap(pdev, 0, 0);
+	if (!ndev->self_mmio) {
+		rc = -EIO;
+		goto err_mmio;
 	}
+	ndev->peer_mmio = ndev->self_mmio;
 
-	rc = ntb_device_setup(ndev);
-	if (rc)
-		goto err4;
+	return 0;
 
-	rc = ntb_create_callbacks(ndev);
-	if (rc)
-		goto err5;
+err_mmio:
+err_dma_mask:
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+err_pci_regions:
+	pci_disable_device(pdev);
+err_pci_enable:
+	pci_set_drvdata(pdev, NULL);
+	return rc;
+}
 
-	rc = ntb_setup_interrupts(ndev);
-	if (rc)
-		goto err6;
+static void intel_ntb_deinit_pci(struct intel_ntb_dev *ndev)
+{
+	struct pci_dev *pdev = ndev_pdev(ndev);
 
-	/* The scratchpad registers keep the values between rmmod/insmod,
-	 * blast them now
-	 */
-	for (i = 0; i < ndev->limits.max_spads; i++) {
-		ntb_write_local_spad(ndev, i, 0);
-		ntb_write_remote_spad(ndev, i, 0);
+	if (ndev->peer_mmio && ndev->peer_mmio != ndev->self_mmio)
+		pci_iounmap(pdev, ndev->peer_mmio);
+	pci_iounmap(pdev, ndev->self_mmio);
+
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static inline void ndev_init_struct(struct intel_ntb_dev *ndev,
+				    struct pci_dev *pdev)
+{
+	ndev->ntb.pdev = pdev;
+	ndev->ntb.topo = NTB_TOPO_NONE;
+	ndev->ntb.ops = &intel_ntb_ops;
+
+	ndev->b2b_off = 0;
+	ndev->b2b_idx = INT_MAX;
+
+	ndev->bar4_split = 0;
+
+	ndev->mw_count = 0;
+	ndev->spad_count = 0;
+	ndev->db_count = 0;
+	ndev->db_vec_count = 0;
+	ndev->db_vec_shift = 0;
+
+	ndev->ntb_ctl = 0;
+	ndev->lnk_sta = 0;
+
+	ndev->db_valid_mask = 0;
+	ndev->db_link_mask = 0;
+	ndev->db_mask = 0;
+
+	spin_lock_init(&ndev->db_mask_lock);
+}
+
+static int intel_ntb_pci_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *id)
+{
+	struct intel_ntb_dev *ndev;
+	int rc;
+
+	if (pdev_is_bwd(pdev)) {
+		ndev = kmalloc(sizeof(*ndev), GFP_KERNEL);
+		if (!ndev) {
+			rc = -ENOMEM;
+			goto err_ndev;
+		}
+
+		ndev_init_struct(ndev, pdev);
+
+		rc = intel_ntb_init_pci(ndev, pdev);
+		if (rc)
+			goto err_init_pci;
+
+		rc = bwd_init_dev(ndev);
+		if (rc)
+			goto err_init_dev;
+
+	} else if (pdev_is_snb(pdev)) {
+		ndev = kmalloc(sizeof(*ndev), GFP_KERNEL);
+		if (!ndev) {
+			rc = -ENOMEM;
+			goto err_ndev;
+		}
+
+		ndev_init_struct(ndev, pdev);
+
+		rc = intel_ntb_init_pci(ndev, pdev);
+		if (rc)
+			goto err_init_pci;
+
+		rc = snb_init_dev(ndev);
+		if (rc)
+			goto err_init_dev;
+
+	} else {
+		rc = -EINVAL;
+		goto err_ndev;
 	}
 
-	rc = ntb_transport_init(pdev);
-	if (rc)
-		goto err7;
+	ndev_reset_unsafe_flags(ndev);
+
+	ndev->reg->poll_link(ndev);
 
-	ntb_hw_link_up(ndev);
+	ndev_init_debugfs(ndev);
+
+	rc = ntb_register_device(&ndev->ntb);
+	if (rc)
+		goto err_register;
 
 	return 0;
 
-err7:
-	ntb_free_interrupts(ndev);
-err6:
-	ntb_free_callbacks(ndev);
-err5:
-	ntb_device_free(ndev);
-err4:
-	for (i--; i >= 0; i--)
-		iounmap(ndev->mw[i].vbase);
-	iounmap(ndev->reg_base);
-err3:
-	if (ndev->split_bar)
-		pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK);
+err_register:
+	ndev_deinit_debugfs(ndev);
+	if (pdev_is_bwd(pdev))
+		bwd_deinit_dev(ndev);
+	else if (pdev_is_snb(pdev))
+		snb_deinit_dev(ndev);
 	else
-		pci_release_selected_regions(pdev, NTB_BAR_MASK);
-err2:
-	kfree(ndev->mw);
-err1:
-	pci_disable_device(pdev);
-err:
-	ntb_free_debugfs(ndev);
+		BUG();
+err_init_dev:
+	intel_ntb_deinit_pci(ndev);
+err_init_pci:
 	kfree(ndev);
-
-	dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME);
+err_ndev:
 	return rc;
 }
 
-static void ntb_pci_remove(struct pci_dev *pdev)
+static void intel_ntb_pci_remove(struct pci_dev *pdev)
 {
-	struct ntb_device *ndev = pci_get_drvdata(pdev);
-	int i;
+	struct intel_ntb_dev *ndev = pci_get_drvdata(pdev);
+
+	ntb_unregister_device(&ndev->ntb);
+	ndev_deinit_debugfs(ndev);
+	if (pdev_is_bwd(pdev))
+		bwd_deinit_dev(ndev);
+	else if (pdev_is_snb(pdev))
+		snb_deinit_dev(ndev);
+	else
+		BUG();
 
-	ntb_hw_link_down(ndev);
+	intel_ntb_deinit_pci(ndev);
+	kfree(ndev);
+}
 
-	ntb_transport_free(ndev->ntb_transport);
+static const struct intel_ntb_reg bwd_reg = {
+	.poll_link		= bwd_poll_link,
+	.link_is_up		= bwd_link_is_up,
+	.db_ioread		= bwd_db_ioread,
+	.db_iowrite		= bwd_db_iowrite,
+	.db_size		= sizeof(u64),
+	.ntb_ctl		= BWD_NTBCNTL_OFFSET,
+	.mw_bar			= {2, 4},
+};
 
-	ntb_free_interrupts(ndev);
-	ntb_free_callbacks(ndev);
-	ntb_device_free(ndev);
+static const struct intel_ntb_alt_reg bwd_pri_reg = {
+	.db_bell		= BWD_PDOORBELL_OFFSET,
+	.db_mask		= BWD_PDBMSK_OFFSET,
+	.spad			= BWD_SPAD_OFFSET,
+};
 
-	/* need to reset max_mw limits so we can unmap properly */
-	if (ndev->hw_type == SNB_HW)
-		ntb_max_mw_detect(ndev);
+static const struct intel_ntb_alt_reg bwd_b2b_reg = {
+	.db_bell		= BWD_B2B_DOORBELL_OFFSET,
+	.spad			= BWD_B2B_SPAD_OFFSET,
+};
 
-	for (i = 0; i < ndev->limits.max_mw; i++)
-		iounmap(ndev->mw[i].vbase);
+static const struct intel_ntb_xlat_reg bwd_sec_xlat = {
+	/* FIXME : .bar0_base	= BWD_SBAR0BASE_OFFSET, */
+	/* FIXME : .bar2_limit	= BWD_SBAR2LMT_OFFSET, */
+	.bar2_xlat		= BWD_SBAR2XLAT_OFFSET,
+};
 
-	kfree(ndev->mw);
-	iounmap(ndev->reg_base);
-	if (ndev->split_bar)
-		pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK);
-	else
-		pci_release_selected_regions(pdev, NTB_BAR_MASK);
-	pci_disable_device(pdev);
-	ntb_free_debugfs(ndev);
-	kfree(ndev);
-}
+static const struct intel_ntb_reg snb_reg = {
+	.poll_link		= snb_poll_link,
+	.link_is_up		= snb_link_is_up,
+	.db_ioread		= snb_db_ioread,
+	.db_iowrite		= snb_db_iowrite,
+	.db_size		= sizeof(u32),
+	.ntb_ctl		= SNB_NTBCNTL_OFFSET,
+	.mw_bar			= {2, 4, 5},
+};
+
+static const struct intel_ntb_alt_reg snb_pri_reg = {
+	.db_bell		= SNB_PDOORBELL_OFFSET,
+	.db_mask		= SNB_PDBMSK_OFFSET,
+	.spad			= SNB_SPAD_OFFSET,
+};
+
+static const struct intel_ntb_alt_reg snb_sec_reg = {
+	.db_bell		= SNB_SDOORBELL_OFFSET,
+	.db_mask		= SNB_SDBMSK_OFFSET,
+	/* second half of the scratchpads */
+	.spad			= SNB_SPAD_OFFSET + (SNB_SPAD_COUNT << 1),
+};
+
+static const struct intel_ntb_alt_reg snb_b2b_reg = {
+	.db_bell		= SNB_B2B_DOORBELL_OFFSET,
+	.spad			= SNB_B2B_SPAD_OFFSET,
+};
+
+static const struct intel_ntb_xlat_reg snb_pri_xlat = {
+	/* Note: no primary .bar0_base visible to the secondary side.
+	 *
+	 * The secondary side cannot get the base address stored in primary
+	 * bars.  The base address is necessary to set the limit register to
+	 * any value other than zero, or unlimited.
+	 *
+	 * WITHOUT THE BASE ADDRESS, THE SECONDARY SIDE CANNOT DISABLE the
+	 * window by setting the limit equal to base, nor can it limit the size
+	 * of the memory window by setting the limit to base + size.
+	 */
+	.bar2_limit		= SNB_PBAR2LMT_OFFSET,
+	.bar2_xlat		= SNB_PBAR2XLAT_OFFSET,
+};
+
+static const struct intel_ntb_xlat_reg snb_sec_xlat = {
+	.bar0_base		= SNB_SBAR0BASE_OFFSET,
+	.bar2_limit		= SNB_SBAR2LMT_OFFSET,
+	.bar2_xlat		= SNB_SBAR2XLAT_OFFSET,
+};
+
+static const struct intel_b2b_addr snb_b2b_usd_addr = {
+	.bar2_addr64		= SNB_B2B_BAR2_USD_ADDR64,
+	.bar4_addr64		= SNB_B2B_BAR4_USD_ADDR64,
+	.bar4_addr32		= SNB_B2B_BAR4_USD_ADDR32,
+	.bar5_addr32		= SNB_B2B_BAR5_USD_ADDR32,
+};
+
+static const struct intel_b2b_addr snb_b2b_dsd_addr = {
+	.bar2_addr64		= SNB_B2B_BAR2_DSD_ADDR64,
+	.bar4_addr64		= SNB_B2B_BAR4_DSD_ADDR64,
+	.bar4_addr32		= SNB_B2B_BAR4_DSD_ADDR32,
+	.bar5_addr32		= SNB_B2B_BAR5_DSD_ADDR32,
+};
+
+/* operations for primary side of local ntb */
+static const struct ntb_dev_ops intel_ntb_ops = {
+	.mw_count		= intel_ntb_mw_count,
+	.mw_get_range		= intel_ntb_mw_get_range,
+	.mw_set_trans		= intel_ntb_mw_set_trans,
+	.link_is_up		= intel_ntb_link_is_up,
+	.link_enable		= intel_ntb_link_enable,
+	.link_disable		= intel_ntb_link_disable,
+	.db_is_unsafe		= intel_ntb_db_is_unsafe,
+	.db_valid_mask		= intel_ntb_db_valid_mask,
+	.db_vector_count	= intel_ntb_db_vector_count,
+	.db_vector_mask		= intel_ntb_db_vector_mask,
+	.db_read		= intel_ntb_db_read,
+	.db_clear		= intel_ntb_db_clear,
+	.db_set_mask		= intel_ntb_db_set_mask,
+	.db_clear_mask		= intel_ntb_db_clear_mask,
+	.peer_db_addr		= intel_ntb_peer_db_addr,
+	.peer_db_set		= intel_ntb_peer_db_set,
+	.spad_is_unsafe		= intel_ntb_spad_is_unsafe,
+	.spad_count		= intel_ntb_spad_count,
+	.spad_read		= intel_ntb_spad_read,
+	.spad_write		= intel_ntb_spad_write,
+	.peer_spad_addr		= intel_ntb_peer_spad_addr,
+	.peer_spad_read		= intel_ntb_peer_spad_read,
+	.peer_spad_write	= intel_ntb_peer_spad_write,
+};
 
-static struct pci_driver ntb_pci_driver = {
+static const struct file_operations intel_ntb_debugfs_info = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = ndev_debugfs_read,
+};
+
+static const struct pci_device_id intel_ntb_pci_tbl[] = {
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)},
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl);
+
+static struct pci_driver intel_ntb_pci_driver = {
 	.name = KBUILD_MODNAME,
-	.id_table = ntb_pci_tbl,
-	.probe = ntb_pci_probe,
-	.remove = ntb_pci_remove,
+	.id_table = intel_ntb_pci_tbl,
+	.probe = intel_ntb_pci_probe,
+	.remove = intel_ntb_pci_remove,
 };
 
-module_pci_driver(ntb_pci_driver);
+static int __init intel_ntb_pci_driver_init(void)
+{
+	if (debugfs_initialized())
+		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+	return pci_register_driver(&intel_ntb_pci_driver);
+}
+module_init(intel_ntb_pci_driver_init);
+
+static void __exit intel_ntb_pci_driver_exit(void)
+{
+	pci_unregister_driver(&intel_ntb_pci_driver);
+
+	debugfs_remove_recursive(debugfs_dir);
+}
+module_exit(intel_ntb_pci_driver_exit);
+
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
index 9356104..0224b1a 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.h
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
@@ -5,6 +5,7 @@
  *   GPL LICENSE SUMMARY
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
  *   BSD LICENSE
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -45,341 +47,280 @@
  * Contact Information:
  * Jon Mason <jon.mason@intel.com>
  */
-#include <linux/ntb_transport.h>
-
-#define NTB_LINK_STATUS_ACTIVE	0x2000
-#define NTB_LINK_SPEED_MASK	0x000f
-#define NTB_LINK_WIDTH_MASK	0x03f0
-
-#define SNB_MSIX_CNT		4
-#define SNB_MAX_B2B_SPADS	16
-#define SNB_MAX_COMPAT_SPADS	16
-/* Reserve the uppermost bit for link interrupt */
-#define SNB_MAX_DB_BITS		15
-#define SNB_LINK_DB		15
-#define SNB_DB_BITS_PER_VEC	5
-#define HSX_SPLITBAR_MAX_MW	3
-#define SNB_MAX_MW		2
-#define SNB_ERRATA_MAX_MW	1
-
-#define SNB_DB_HW_LINK		0x8000
-
-#define SNB_UNCERRSTS_OFFSET	0x014C
-#define SNB_CORERRSTS_OFFSET	0x0158
-#define SNB_LINK_STATUS_OFFSET	0x01A2
-#define SNB_PCICMD_OFFSET	0x0504
-#define SNB_DEVCTRL_OFFSET	0x0598
-#define SNB_DEVSTS_OFFSET	0x059A
-#define SNB_SLINK_STATUS_OFFSET	0x05A2
-
-#define SNB_PBAR2LMT_OFFSET	0x0000
-#define SNB_PBAR4LMT_OFFSET	0x0008
-#define SNB_PBAR5LMT_OFFSET	0x000C
-#define SNB_PBAR2XLAT_OFFSET	0x0010
-#define SNB_PBAR4XLAT_OFFSET	0x0018
-#define SNB_PBAR5XLAT_OFFSET	0x001C
-#define SNB_SBAR2LMT_OFFSET	0x0020
-#define SNB_SBAR4LMT_OFFSET	0x0028
-#define SNB_SBAR5LMT_OFFSET	0x002C
-#define SNB_SBAR2XLAT_OFFSET	0x0030
-#define SNB_SBAR4XLAT_OFFSET	0x0038
-#define SNB_SBAR5XLAT_OFFSET	0x003C
-#define SNB_SBAR0BASE_OFFSET	0x0040
-#define SNB_SBAR2BASE_OFFSET	0x0048
-#define SNB_SBAR4BASE_OFFSET	0x0050
-#define SNB_SBAR5BASE_OFFSET	0x0054
-#define SNB_NTBCNTL_OFFSET	0x0058
-#define SNB_SBDF_OFFSET		0x005C
-#define SNB_PDOORBELL_OFFSET	0x0060
-#define SNB_PDBMSK_OFFSET	0x0062
-#define SNB_SDOORBELL_OFFSET	0x0064
-#define SNB_SDBMSK_OFFSET	0x0066
-#define SNB_USMEMMISS_OFFSET	0x0070
-#define SNB_SPAD_OFFSET		0x0080
-#define SNB_SPADSEMA4_OFFSET	0x00c0
-#define SNB_WCCNTRL_OFFSET	0x00e0
-#define SNB_B2B_SPAD_OFFSET	0x0100
-#define SNB_B2B_DOORBELL_OFFSET	0x0140
-#define SNB_B2B_XLAT_OFFSETL	0x0144
-#define SNB_B2B_XLAT_OFFSETU	0x0148
 
-/*
- * The addresses are setup so the 32bit BARs can function. Thus
- * the addresses are all in 32bit space
- */
-#define SNB_MBAR01_USD_ADDR	0x000000002100000CULL
-#define SNB_MBAR23_USD_ADDR	0x000000004100000CULL
-#define SNB_MBAR4_USD_ADDR	0x000000008100000CULL
-#define SNB_MBAR5_USD_ADDR	0x00000000A100000CULL
-#define SNB_MBAR01_DSD_ADDR	0x000000002000000CULL
-#define SNB_MBAR23_DSD_ADDR	0x000000004000000CULL
-#define SNB_MBAR4_DSD_ADDR	0x000000008000000CULL
-#define SNB_MBAR5_DSD_ADDR	0x00000000A000000CULL
-
-#define BWD_MSIX_CNT		34
-#define BWD_MAX_SPADS		16
-#define BWD_MAX_DB_BITS		34
-#define BWD_DB_BITS_PER_VEC	1
-#define BWD_MAX_MW		2
-
-#define BWD_PCICMD_OFFSET	0xb004
-#define BWD_MBAR23_OFFSET	0xb018
-#define BWD_MBAR45_OFFSET	0xb020
-#define BWD_DEVCTRL_OFFSET	0xb048
-#define BWD_LINK_STATUS_OFFSET	0xb052
-#define BWD_ERRCORSTS_OFFSET	0xb110
-
-#define BWD_SBAR2XLAT_OFFSET	0x0008
-#define BWD_SBAR4XLAT_OFFSET	0x0010
-#define BWD_PDOORBELL_OFFSET	0x0020
-#define BWD_PDBMSK_OFFSET	0x0028
-#define BWD_NTBCNTL_OFFSET	0x0060
-#define BWD_EBDF_OFFSET		0x0064
-#define BWD_SPAD_OFFSET		0x0080
-#define BWD_SPADSEMA_OFFSET	0x00c0
-#define BWD_STKYSPAD_OFFSET	0x00c4
-#define BWD_PBAR2XLAT_OFFSET	0x8008
-#define BWD_PBAR4XLAT_OFFSET	0x8010
-#define BWD_B2B_DOORBELL_OFFSET	0x8020
-#define BWD_B2B_SPAD_OFFSET	0x8080
-#define BWD_B2B_SPADSEMA_OFFSET	0x80c0
-#define BWD_B2B_STKYSPAD_OFFSET	0x80c4
-
-#define BWD_MODPHY_PCSREG4	0x1c004
-#define BWD_MODPHY_PCSREG6	0x1c006
-
-#define BWD_IP_BASE		0xC000
-#define BWD_DESKEWSTS_OFFSET	(BWD_IP_BASE + 0x3024)
-#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180)
+#ifndef NTB_HW_INTEL_H
+#define NTB_HW_INTEL_H
+
+#include <linux/ntb.h>
+#include <linux/pci.h>
+
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF	0x3725
+#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF	0x3726
+#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF	0x3727
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB	0x3C0D
+#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB	0x3C0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB	0x3C0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT	0x0E0D
+#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT	0x0E0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT	0x0E0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX	0x2F0D
+#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX	0x2F0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX	0x2F0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD	0x0C4E
+
+/* SNB hardware (and JSF, IVT, HSX) */
+
+#define SNB_PBAR2LMT_OFFSET		0x0000
+#define SNB_PBAR2XLAT_OFFSET		0x0010
+#define SNB_SBAR2LMT_OFFSET		0x0020
+#define SNB_SBAR2XLAT_OFFSET		0x0030
+#define SNB_SBAR0BASE_OFFSET		0x0040
+#define SNB_SBDF_OFFSET			0x005c
+#define SNB_NTBCNTL_OFFSET		0x0058
+#define SNB_PDOORBELL_OFFSET		0x0060
+#define SNB_PDBMSK_OFFSET		0x0062
+#define SNB_SDOORBELL_OFFSET		0x0064
+#define SNB_SDBMSK_OFFSET		0x0066
+#define SNB_USMEMMISS_OFFSET		0x0070
+#define SNB_SPAD_OFFSET			0x0080
+#define SNB_PBAR23SZ_OFFSET		0x00d0
+#define SNB_PBAR45SZ_OFFSET		0x00d1
+#define SNB_PBAR4SZ_OFFSET		0x00d1
+#define SNB_SBAR23SZ_OFFSET		0x00d2
+#define SNB_SBAR45SZ_OFFSET		0x00d3
+#define SNB_SBAR4SZ_OFFSET		0x00d3
+#define SNB_PPD_OFFSET			0x00d4
+#define SNB_PBAR5SZ_OFFSET		0x00d5
+#define SNB_SBAR5SZ_OFFSET		0x00d6
+#define SNB_WCCNTRL_OFFSET		0x00e0
+#define SNB_UNCERRSTS_OFFSET		0x014c
+#define SNB_CORERRSTS_OFFSET		0x0158
+#define SNB_LINK_STATUS_OFFSET		0x01a2
+#define SNB_SPCICMD_OFFSET		0x0504
+#define SNB_DEVCTRL_OFFSET		0x0598
+#define SNB_DEVSTS_OFFSET		0x059a
+#define SNB_SLINK_STATUS_OFFSET		0x05a2
+#define SNB_B2B_SPAD_OFFSET		0x0100
+#define SNB_B2B_DOORBELL_OFFSET		0x0140
+#define SNB_B2B_XLAT_OFFSETL		0x0144
+#define SNB_B2B_XLAT_OFFSETU		0x0148
+#define SNB_PPD_CONN_MASK		0x03
+#define SNB_PPD_CONN_TRANSPARENT	0x00
+#define SNB_PPD_CONN_B2B		0x01
+#define SNB_PPD_CONN_RP			0x02
+#define SNB_PPD_DEV_MASK		0x10
+#define SNB_PPD_DEV_USD			0x00
+#define SNB_PPD_DEV_DSD			0x10
+#define SNB_PPD_SPLIT_BAR_MASK		0x40
+
+#define SNB_PPD_TOPO_MASK	(SNB_PPD_CONN_MASK | SNB_PPD_DEV_MASK)
+#define SNB_PPD_TOPO_PRI_USD	(SNB_PPD_CONN_RP | SNB_PPD_DEV_USD)
+#define SNB_PPD_TOPO_PRI_DSD	(SNB_PPD_CONN_RP | SNB_PPD_DEV_DSD)
+#define SNB_PPD_TOPO_SEC_USD	(SNB_PPD_CONN_TRANSPARENT | SNB_PPD_DEV_USD)
+#define SNB_PPD_TOPO_SEC_DSD	(SNB_PPD_CONN_TRANSPARENT | SNB_PPD_DEV_DSD)
+#define SNB_PPD_TOPO_B2B_USD	(SNB_PPD_CONN_B2B | SNB_PPD_DEV_USD)
+#define SNB_PPD_TOPO_B2B_DSD	(SNB_PPD_CONN_B2B | SNB_PPD_DEV_DSD)
+
+#define SNB_MW_COUNT			2
+#define HSX_SPLIT_BAR_MW_COUNT		3
+#define SNB_DB_COUNT			15
+#define SNB_DB_LINK			15
+#define SNB_DB_LINK_BIT			BIT_ULL(SNB_DB_LINK)
+#define SNB_DB_MSIX_VECTOR_COUNT	4
+#define SNB_DB_MSIX_VECTOR_SHIFT	5
+#define SNB_DB_TOTAL_SHIFT		16
+#define SNB_SPAD_COUNT			16
+
+/* BWD hardware */
+
+#define BWD_SBAR2XLAT_OFFSET		0x0008
+#define BWD_PDOORBELL_OFFSET		0x0020
+#define BWD_PDBMSK_OFFSET		0x0028
+#define BWD_NTBCNTL_OFFSET		0x0060
+#define BWD_SPAD_OFFSET			0x0080
+#define BWD_PPD_OFFSET			0x00d4
+#define BWD_PBAR2XLAT_OFFSET		0x8008
+#define BWD_B2B_DOORBELL_OFFSET		0x8020
+#define BWD_B2B_SPAD_OFFSET		0x8080
+#define BWD_SPCICMD_OFFSET		0xb004
+#define BWD_LINK_STATUS_OFFSET		0xb052
+#define BWD_ERRCORSTS_OFFSET		0xb110
+#define BWD_IP_BASE			0xc000
+#define BWD_DESKEWSTS_OFFSET		(BWD_IP_BASE + 0x3024)
+#define BWD_LTSSMERRSTS0_OFFSET		(BWD_IP_BASE + 0x3180)
 #define BWD_LTSSMSTATEJMP_OFFSET	(BWD_IP_BASE + 0x3040)
 #define BWD_IBSTERRRCRVSTS0_OFFSET	(BWD_IP_BASE + 0x3324)
+#define BWD_MODPHY_PCSREG4		0x1c004
+#define BWD_MODPHY_PCSREG6		0x1c006
+
+#define BWD_PPD_INIT_LINK		0x0008
+#define BWD_PPD_CONN_MASK		0x0300
+#define BWD_PPD_CONN_TRANSPARENT	0x0000
+#define BWD_PPD_CONN_B2B		0x0100
+#define BWD_PPD_CONN_RP			0x0200
+#define BWD_PPD_DEV_MASK		0x1000
+#define BWD_PPD_DEV_USD			0x0000
+#define BWD_PPD_DEV_DSD			0x1000
+#define BWD_PPD_TOPO_MASK	(BWD_PPD_CONN_MASK | BWD_PPD_DEV_MASK)
+#define BWD_PPD_TOPO_PRI_USD	(BWD_PPD_CONN_TRANSPARENT | BWD_PPD_DEV_USD)
+#define BWD_PPD_TOPO_PRI_DSD	(BWD_PPD_CONN_TRANSPARENT | BWD_PPD_DEV_DSD)
+#define BWD_PPD_TOPO_SEC_USD	(BWD_PPD_CONN_RP | BWD_PPD_DEV_USD)
+#define BWD_PPD_TOPO_SEC_DSD	(BWD_PPD_CONN_RP | BWD_PPD_DEV_DSD)
+#define BWD_PPD_TOPO_B2B_USD	(BWD_PPD_CONN_B2B | BWD_PPD_DEV_USD)
+#define BWD_PPD_TOPO_B2B_DSD	(BWD_PPD_CONN_B2B | BWD_PPD_DEV_DSD)
+
+#define BWD_MW_COUNT			2
+#define BWD_DB_COUNT			34
+#define BWD_DB_VALID_MASK		(BIT_ULL(BWD_DB_COUNT) - 1)
+#define BWD_DB_MSIX_VECTOR_COUNT	34
+#define BWD_DB_MSIX_VECTOR_SHIFT	1
+#define BWD_DB_TOTAL_SHIFT		34
+#define BWD_SPAD_COUNT			16
+
+#define BWD_NTB_CTL_DOWN_BIT		BIT(16)
+#define BWD_NTB_CTL_ACTIVE(x)		!(x & BWD_NTB_CTL_DOWN_BIT)
+
+#define BWD_DESKEWSTS_DBERR		BIT(15)
+#define BWD_LTSSMERRSTS0_UNEXPECTEDEI	BIT(20)
+#define BWD_LTSSMSTATEJMP_FORCEDETECT	BIT(2)
+#define BWD_IBIST_ERR_OFLOW		0x7FFF7FFF
+
+#define BWD_LINK_HB_TIMEOUT		msecs_to_jiffies(1000)
+#define BWD_LINK_RECOVERY_TIME		msecs_to_jiffies(500)
+
+/* Ntb control and link status */
+
+#define NTB_CTL_CFG_LOCK		BIT(0)
+#define NTB_CTL_DISABLE			BIT(1)
+#define NTB_CTL_S2P_BAR2_SNOOP		BIT(2)
+#define NTB_CTL_P2S_BAR2_SNOOP		BIT(4)
+#define NTB_CTL_S2P_BAR4_SNOOP		BIT(6)
+#define NTB_CTL_P2S_BAR4_SNOOP		BIT(8)
+#define NTB_CTL_S2P_BAR5_SNOOP		BIT(12)
+#define NTB_CTL_P2S_BAR5_SNOOP		BIT(14)
+
+#define NTB_LNK_STA_ACTIVE_BIT		0x2000
+#define NTB_LNK_STA_SPEED_MASK		0x000f
+#define NTB_LNK_STA_WIDTH_MASK		0x03f0
+#define NTB_LNK_STA_ACTIVE(x)		(!!((x) & NTB_LNK_STA_ACTIVE_BIT))
+#define NTB_LNK_STA_SPEED(x)		((x) & NTB_LNK_STA_SPEED_MASK)
+#define NTB_LNK_STA_WIDTH(x)		(((x) & NTB_LNK_STA_WIDTH_MASK) >> 4)
+
+/* Use the following addresses for translation between b2b ntb devices in case
+ * the hardware default values are not reliable. */
+#define SNB_B2B_BAR0_USD_ADDR		0x1000000000000000ull
+#define SNB_B2B_BAR2_USD_ADDR64		0x2000000000000000ull
+#define SNB_B2B_BAR4_USD_ADDR64		0x4000000000000000ull
+#define SNB_B2B_BAR4_USD_ADDR32		0x20000000u
+#define SNB_B2B_BAR5_USD_ADDR32		0x40000000u
+#define SNB_B2B_BAR0_DSD_ADDR		0x9000000000000000ull
+#define SNB_B2B_BAR2_DSD_ADDR64		0xa000000000000000ull
+#define SNB_B2B_BAR4_DSD_ADDR64		0xc000000000000000ull
+#define SNB_B2B_BAR4_DSD_ADDR32		0xa0000000u
+#define SNB_B2B_BAR5_DSD_ADDR32		0xc0000000u
+
+/* The peer ntb secondary config space is 32KB fixed size */
+#define SNB_B2B_MIN_SIZE		0x8000
+
+/* flags to indicate hardware errata */
+#define NTB_HWERR_SDOORBELL_LOCKUP	BIT_ULL(0)
+#define NTB_HWERR_SB01BASE_LOCKUP	BIT_ULL(1)
+#define NTB_HWERR_B2BDOORBELL_BIT14	BIT_ULL(2)
+
+/* flags to indicate unsafe api */
+#define NTB_UNSAFE_DB			BIT_ULL(0)
+#define NTB_UNSAFE_SPAD			BIT_ULL(1)
+
+struct intel_ntb_dev;
+
+struct intel_ntb_reg {
+	int (*poll_link)(struct intel_ntb_dev *ndev);
+	int (*link_is_up)(struct intel_ntb_dev *ndev);
+	u64 (*db_ioread)(void __iomem *mmio);
+	void (*db_iowrite)(u64 db_bits, void __iomem *mmio);
+	unsigned long			ntb_ctl;
+	resource_size_t			db_size;
+	int				mw_bar[];
+};
 
-#define BWD_DESKEWSTS_DBERR	(1 << 15)
-#define BWD_LTSSMERRSTS0_UNEXPECTEDEI	(1 << 20)
-#define BWD_LTSSMSTATEJMP_FORCEDETECT	(1 << 2)
-#define BWD_IBIST_ERR_OFLOW	0x7FFF7FFF
-
-#define NTB_CNTL_CFG_LOCK		(1 << 0)
-#define NTB_CNTL_LINK_DISABLE		(1 << 1)
-#define NTB_CNTL_S2P_BAR23_SNOOP	(1 << 2)
-#define NTB_CNTL_P2S_BAR23_SNOOP	(1 << 4)
-#define NTB_CNTL_S2P_BAR4_SNOOP	(1 << 6)
-#define NTB_CNTL_P2S_BAR4_SNOOP	(1 << 8)
-#define NTB_CNTL_S2P_BAR5_SNOOP	(1 << 12)
-#define NTB_CNTL_P2S_BAR5_SNOOP	(1 << 14)
-#define BWD_CNTL_LINK_DOWN		(1 << 16)
-
-#define NTB_PPD_OFFSET		0x00D4
-#define SNB_PPD_CONN_TYPE	0x0003
-#define SNB_PPD_DEV_TYPE	0x0010
-#define SNB_PPD_SPLIT_BAR	(1 << 6)
-#define BWD_PPD_INIT_LINK	0x0008
-#define BWD_PPD_CONN_TYPE	0x0300
-#define BWD_PPD_DEV_TYPE	0x1000
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF		0x3725
-#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF		0x3726
-#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF		0x3727
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB		0x3C0D
-#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB		0x3C0E
-#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB		0x3C0F
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT		0x0E0D
-#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT		0x0E0E
-#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT		0x0E0F
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX		0x2F0D
-#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX		0x2F0E
-#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX		0x2F0F
-#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD		0x0C4E
-
-#ifndef readq
-static inline u64 readq(void __iomem *addr)
-{
-	return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
-}
-#endif
-
-#ifndef writeq
-static inline void writeq(u64 val, void __iomem *addr)
-{
-	writel(val & 0xffffffff, addr);
-	writel(val >> 32, addr + 4);
-}
-#endif
+struct intel_ntb_alt_reg {
+	unsigned long			db_bell;
+	unsigned long			db_mask;
+	unsigned long			spad;
+};
 
-#define NTB_BAR_MMIO		0
-#define NTB_BAR_23		2
-#define NTB_BAR_4		4
-#define NTB_BAR_5		5
-
-#define NTB_BAR_MASK		((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
-				 (1 << NTB_BAR_4))
-#define NTB_SPLITBAR_MASK	((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
-				 (1 << NTB_BAR_4) | (1 << NTB_BAR_5))
-
-#define NTB_HB_TIMEOUT		msecs_to_jiffies(1000)
-
-enum ntb_hw_event {
-	NTB_EVENT_SW_EVENT0 = 0,
-	NTB_EVENT_SW_EVENT1,
-	NTB_EVENT_SW_EVENT2,
-	NTB_EVENT_HW_ERROR,
-	NTB_EVENT_HW_LINK_UP,
-	NTB_EVENT_HW_LINK_DOWN,
+struct intel_ntb_xlat_reg {
+	unsigned long			bar0_base;
+	unsigned long			bar2_xlat;
+	unsigned long			bar2_limit;
 };
 
-struct ntb_mw {
-	dma_addr_t phys_addr;
-	void __iomem *vbase;
-	resource_size_t bar_sz;
+struct intel_b2b_addr {
+	phys_addr_t			bar0_addr;
+	phys_addr_t			bar2_addr64;
+	phys_addr_t			bar4_addr64;
+	phys_addr_t			bar4_addr32;
+	phys_addr_t			bar5_addr32;
 };
 
-struct ntb_db_cb {
-	int (*callback)(void *data, int db_num);
-	unsigned int db_num;
-	void *data;
-	struct ntb_device *ndev;
-	struct tasklet_struct irq_work;
+struct intel_ntb_vec {
+	struct intel_ntb_dev		*ndev;
+	int				num;
 };
 
-#define WA_SNB_ERR	0x00000001
-
-struct ntb_device {
-	struct pci_dev *pdev;
-	struct msix_entry *msix_entries;
-	void __iomem *reg_base;
-	struct ntb_mw *mw;
-	struct {
-		unsigned char max_mw;
-		unsigned char max_spads;
-		unsigned char max_db_bits;
-		unsigned char msix_cnt;
-	} limits;
-	struct {
-		void __iomem *ldb;
-		void __iomem *ldb_mask;
-		void __iomem *rdb;
-		void __iomem *bar2_xlat;
-		void __iomem *bar4_xlat;
-		void __iomem *bar5_xlat;
-		void __iomem *spad_write;
-		void __iomem *spad_read;
-		void __iomem *lnk_cntl;
-		void __iomem *lnk_stat;
-		void __iomem *spci_cmd;
-	} reg_ofs;
-	struct ntb_transport *ntb_transport;
-	void (*event_cb)(void *handle, enum ntb_hw_event event);
-
-	struct ntb_db_cb *db_cb;
-	unsigned char hw_type;
-	unsigned char conn_type;
-	unsigned char dev_type;
-	unsigned char num_msix;
-	unsigned char bits_per_vector;
-	unsigned char max_cbs;
-	unsigned char link_width;
-	unsigned char link_speed;
-	unsigned char link_status;
-	unsigned char split_bar;
-
-	struct delayed_work hb_timer;
-	unsigned long last_ts;
-
-	struct delayed_work lr_timer;
-
-	struct dentry *debugfs_dir;
-	struct dentry *debugfs_info;
-
-	unsigned int wa_flags;
+struct intel_ntb_dev {
+	struct ntb_dev			ntb;
+
+	/* offset of peer bar0 in b2b bar */
+	unsigned long			b2b_off;
+	/* mw idx used to access peer bar0 */
+	unsigned int			b2b_idx;
+
+	/* BAR45 is split into BAR4 and BAR5 */
+	bool				bar4_split;
+
+	u32				ntb_ctl;
+	u32				lnk_sta;
+
+	unsigned char			mw_count;
+	unsigned char			spad_count;
+	unsigned char			db_count;
+	unsigned char			db_vec_count;
+	unsigned char			db_vec_shift;
+
+	u64				db_valid_mask;
+	u64				db_link_mask;
+	u64				db_mask;
+
+	/* synchronize rmw access of db_mask and hw reg */
+	spinlock_t			db_mask_lock;
+
+	struct msix_entry		*msix;
+	struct intel_ntb_vec		*vec;
+
+	const struct intel_ntb_reg	*reg;
+	const struct intel_ntb_alt_reg	*self_reg;
+	const struct intel_ntb_alt_reg	*peer_reg;
+	const struct intel_ntb_xlat_reg	*xlat_reg;
+	void				__iomem *self_mmio;
+	void				__iomem *peer_mmio;
+	phys_addr_t			peer_addr;
+
+	unsigned long			last_ts;
+	struct delayed_work		hb_timer;
+
+	unsigned long			hwerr_flags;
+	unsigned long			unsafe_flags;
+	unsigned long			unsafe_flags_ignore;
+
+	struct dentry			*debugfs_dir;
+	struct dentry			*debugfs_info;
 };
 
-/**
- * ntb_max_cbs() - return the max callbacks
- * @ndev: pointer to ntb_device instance
- *
- * Given the ntb pointer, return the maximum number of callbacks
- *
- * RETURNS: the maximum number of callbacks
- */
-static inline unsigned char ntb_max_cbs(struct ntb_device *ndev)
-{
-	return ndev->max_cbs;
-}
-
-/**
- * ntb_max_mw() - return the max number of memory windows
- * @ndev: pointer to ntb_device instance
- *
- * Given the ntb pointer, return the maximum number of memory windows
- *
- * RETURNS: the maximum number of memory windows
- */
-static inline unsigned char ntb_max_mw(struct ntb_device *ndev)
-{
-	return ndev->limits.max_mw;
-}
-
-/**
- * ntb_hw_link_status() - return the hardware link status
- * @ndev: pointer to ntb_device instance
- *
- * Returns true if the hardware is connected to the remote system
- *
- * RETURNS: true or false based on the hardware link state
- */
-static inline bool ntb_hw_link_status(struct ntb_device *ndev)
-{
-	return ndev->link_status == NTB_LINK_UP;
-}
-
-/**
- * ntb_query_pdev() - return the pci_dev pointer
- * @ndev: pointer to ntb_device instance
- *
- * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device
- *
- * RETURNS: a pointer to the ntb pci_dev
- */
-static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev)
-{
-	return ndev->pdev;
-}
-
-/**
- * ntb_query_debugfs() - return the debugfs pointer
- * @ndev: pointer to ntb_device instance
- *
- * Given the ntb pointer, return the debugfs directory pointer for the NTB
- * hardware device
- *
- * RETURNS: a pointer to the debugfs directory
- */
-static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev)
-{
-	return ndev->debugfs_dir;
-}
-
-struct ntb_device *ntb_register_transport(struct pci_dev *pdev,
-					  void *transport);
-void ntb_unregister_transport(struct ntb_device *ndev);
-void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr);
-int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
-			     void *data, int (*db_cb_func)(void *data,
-							   int db_num));
-void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx);
-int ntb_register_event_callback(struct ntb_device *ndev,
-				void (*event_cb_func)(void *handle,
-						      enum ntb_hw_event event));
-void ntb_unregister_event_callback(struct ntb_device *ndev);
-int ntb_get_max_spads(struct ntb_device *ndev);
-int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
-int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
-int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
-int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
-resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw);
-void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw);
-u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw);
-void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx);
-void *ntb_find_transport(struct pci_dev *pdev);
-
-int ntb_transport_init(struct pci_dev *pdev);
-void ntb_transport_free(void *transport);
+#define ndev_pdev(ndev) ((ndev)->ntb.pdev)
+#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
+#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
+#define ntb_ndev(ntb) container_of(ntb, struct intel_ntb_dev, ntb)
+#define hb_ndev(work) container_of(work, struct intel_ntb_dev, hb_timer.work)
+
+#endif
diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
new file mode 100644
index 0000000..0e27745
--- /dev/null
+++ b/drivers/ntb/ntb.c
@@ -0,0 +1,251 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Allen Hubbe <Allen.Hubbe@emc.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/ntb.h>
+#include <linux/pci.h>
+
+#define DRIVER_NAME			"ntb"
+#define DRIVER_DESCRIPTION		"PCIe NTB Driver Framework"
+
+#define DRIVER_LICENSE			"Dual BSD/GPL"
+#define DRIVER_VERSION			"1.0"
+#define DRIVER_RELDATE			"24 March 2015"
+#define DRIVER_AUTHOR			"Allen Hubbe <Allen.Hubbe@emc.com>"
+
+MODULE_LICENSE(DRIVER_LICENSE);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+
+static struct bus_type ntb_bus;
+static void ntb_dev_release(struct device *dev);
+
+int ntb_register_client(struct ntb_client *client)
+{
+	if (!client)
+		return -EINVAL;
+	if (!client->name)
+		return -EINVAL;
+	if (!ntb_client_ops_is_valid(&client->ops))
+		return -EINVAL;
+
+	memset(&client->drv, 0, sizeof(client->drv));
+	client->drv.bus = &ntb_bus;
+	client->drv.name = client->name;
+
+	return driver_register(&client->drv);
+}
+EXPORT_SYMBOL(ntb_register_client);
+
+void ntb_unregister_client(struct ntb_client *client)
+{
+	driver_unregister(&client->drv);
+}
+EXPORT_SYMBOL(ntb_unregister_client);
+
+int ntb_register_device(struct ntb_dev *ntb)
+{
+	if (!ntb)
+		return -EINVAL;
+	if (!ntb->pdev)
+		return -EINVAL;
+	if (!ntb->ops)
+		return -EINVAL;
+	if (!ntb_dev_ops_is_valid(ntb->ops))
+		return -EINVAL;
+
+	init_completion(&ntb->released);
+
+	memset(&ntb->dev, 0, sizeof(ntb->dev));
+	ntb->dev.bus = &ntb_bus;
+	ntb->dev.parent = &ntb->pdev->dev;
+	ntb->dev.release = ntb_dev_release;
+	dev_set_name(&ntb->dev, pci_name(ntb->pdev));
+
+	ntb->ctx = NULL;
+	ntb->ctx_ops = NULL;
+	spin_lock_init(&ntb->ctx_lock);
+
+	return device_register(&ntb->dev);
+}
+EXPORT_SYMBOL(ntb_register_device);
+
+void ntb_unregister_device(struct ntb_dev *ntb)
+{
+	device_unregister(&ntb->dev);
+	wait_for_completion(&ntb->released);
+}
+EXPORT_SYMBOL(ntb_unregister_device);
+
+int ntb_set_ctx(struct ntb_dev *ntb, void *ctx,
+		const struct ntb_ctx_ops *ctx_ops)
+{
+	unsigned long irqflags;
+
+	if (!ntb_ctx_ops_is_valid(ctx_ops))
+		return -EINVAL;
+	if (ntb->ctx_ops)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+	{
+		ntb->ctx = ctx;
+		ntb->ctx_ops = ctx_ops;
+	}
+	spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ntb_set_ctx);
+
+void ntb_clear_ctx(struct ntb_dev *ntb)
+{
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+	{
+		ntb->ctx_ops = NULL;
+		ntb->ctx = NULL;
+	}
+	spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+}
+EXPORT_SYMBOL(ntb_clear_ctx);
+
+void ntb_link_event(struct ntb_dev *ntb)
+{
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+	{
+		if (ntb->ctx_ops && ntb->ctx_ops->link_event)
+			ntb->ctx_ops->link_event(ntb->ctx);
+	}
+	spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+}
+EXPORT_SYMBOL(ntb_link_event);
+
+void ntb_db_event(struct ntb_dev *ntb, int vector)
+{
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+	{
+		if (ntb->ctx_ops && ntb->ctx_ops->db_event)
+			ntb->ctx_ops->db_event(ntb->ctx, vector);
+	}
+	spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+}
+EXPORT_SYMBOL(ntb_db_event);
+
+static int ntb_probe(struct device *dev)
+{
+	struct ntb_dev *ntb;
+	struct ntb_client *client;
+	int rc;
+
+	get_device(dev);
+	ntb = dev_ntb(dev);
+	client = drv_ntb_client(dev->driver);
+
+	rc = client->ops.probe(client, ntb);
+	if (rc)
+		put_device(dev);
+
+	return rc;
+}
+
+static int ntb_remove(struct device *dev)
+{
+	struct ntb_dev *ntb;
+	struct ntb_client *client;
+
+	if (dev->driver) {
+		ntb = dev_ntb(dev);
+		client = drv_ntb_client(dev->driver);
+
+		client->ops.remove(client, ntb);
+		put_device(dev);
+	}
+
+	return 0;
+}
+
+static void ntb_dev_release(struct device *dev)
+{
+	struct ntb_dev *ntb = dev_ntb(dev);
+
+	complete(&ntb->released);
+}
+
+static struct bus_type ntb_bus = {
+	.name = "ntb",
+	.probe = ntb_probe,
+	.remove = ntb_remove,
+};
+
+static int __init ntb_driver_init(void)
+{
+	return bus_register(&ntb_bus);
+}
+module_init(ntb_driver_init);
+
+static void __exit ntb_driver_exit(void)
+{
+	bus_unregister(&ntb_bus);
+}
+module_exit(ntb_driver_exit);
+
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index b9d8e19..f1ed1b7 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -5,6 +5,7 @@
  *   GPL LICENSE SUMMARY
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
  *   BSD LICENSE
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -40,7 +42,7 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Intel PCIe NTB Linux driver
+ * PCIe NTB Transport Linux driver
  *
  * Contact Information:
  * Jon Mason <jon.mason@intel.com>
@@ -56,9 +58,22 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/types.h>
-#include "hw/intel/ntb_hw_intel.h"
+#include "linux/ntb.h"
+#include "linux/ntb_transport.h"
 
-#define NTB_TRANSPORT_VERSION	3
+#define NTB_TRANSPORT_VERSION	4
+#define NTB_TRANSPORT_VER	"4"
+#define NTB_TRANSPORT_NAME	"ntb_transport"
+#define NTB_TRANSPORT_DESC	"Software Queue-Pair Transport over NTB"
+
+MODULE_DESCRIPTION(NTB_TRANSPORT_DESC);
+MODULE_VERSION(NTB_TRANSPORT_VER);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+
+static unsigned long max_mw_size;
+module_param(max_mw_size, ulong, 0644);
+MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows");
 
 static unsigned int transport_mtu = 0x401E;
 module_param(transport_mtu, uint, 0644);
@@ -72,6 +87,8 @@ static unsigned int copy_bytes = 1024;
 module_param(copy_bytes, uint, 0644);
 MODULE_PARM_DESC(copy_bytes, "Threshold under which NTB will use the CPU to copy instead of DMA");
 
+static struct dentry *nt_debugfs_dir;
+
 struct ntb_queue_entry {
 	/* ntb_queue list reference */
 	struct list_head entry;
@@ -94,14 +111,16 @@ struct ntb_rx_info {
 };
 
 struct ntb_transport_qp {
-	struct ntb_transport *transport;
-	struct ntb_device *ndev;
+	struct ntb_transport_ctx *transport;
+	struct ntb_dev *ndev;
 	void *cb_data;
 	struct dma_chan *dma_chan;
 
 	bool client_ready;
-	bool qp_link;
+	bool link_is_up;
+
 	u8 qp_num;	/* Only 64 QP's are allowed.  0-63 */
+	u64 qp_bit;
 
 	struct ntb_rx_info __iomem *rx_info;
 	struct ntb_rx_info *remote_rx_info;
@@ -153,33 +172,45 @@ struct ntb_transport_qp {
 };
 
 struct ntb_transport_mw {
-	size_t size;
+	phys_addr_t phys_addr;
+	resource_size_t phys_size;
+	resource_size_t xlat_align;
+	resource_size_t xlat_align_size;
+	void __iomem *vbase;
+	size_t xlat_size;
+	size_t buff_size;
 	void *virt_addr;
 	dma_addr_t dma_addr;
 };
 
 struct ntb_transport_client_dev {
 	struct list_head entry;
+	struct ntb_transport_ctx *nt;
 	struct device dev;
 };
 
-struct ntb_transport {
+struct ntb_transport_ctx {
 	struct list_head entry;
 	struct list_head client_devs;
 
-	struct ntb_device *ndev;
-	struct ntb_transport_mw *mw;
-	struct ntb_transport_qp *qps;
-	unsigned int max_qps;
-	unsigned long qp_bitmap;
-	bool transport_link;
+	struct ntb_dev *ndev;
+
+	struct ntb_transport_mw *mw_vec;
+	struct ntb_transport_qp *qp_vec;
+	unsigned int mw_count;
+	unsigned int qp_count;
+	u64 qp_bitmap;
+	u64 qp_bitmap_free;
+
+	bool link_is_up;
 	struct delayed_work link_work;
+	struct work_struct db_work;
 	struct work_struct link_cleanup;
 };
 
 enum {
-	DESC_DONE_FLAG = 1 << 0,
-	LINK_DOWN_FLAG = 1 << 1,
+	DESC_DONE_FLAG = BIT(0),
+	LINK_DOWN_FLAG = BIT(1),
 };
 
 struct ntb_payload_header {
@@ -200,68 +231,69 @@ enum {
 	MAX_SPAD,
 };
 
-#define QP_TO_MW(ndev, qp)	((qp) % ntb_max_mw(ndev))
+#define dev_client_dev(__dev) \
+	container_of((__dev), struct ntb_transport_client_dev, dev)
+
+#define drv_client(__drv) \
+	container_of((__drv), struct ntb_transport_client, driver)
+
+#define QP_TO_MW(nt, qp)	((qp) % nt->mw_count)
 #define NTB_QP_DEF_NUM_ENTRIES	100
 #define NTB_LINK_DOWN_TIMEOUT	10
 
-static int ntb_match_bus(struct device *dev, struct device_driver *drv)
+static void ntb_transport_doorbell_work(struct work_struct *ws);
+static const struct ntb_ctx_ops ntb_transport_ops;
+static struct ntb_client ntb_transport_client;
+
+static int ntb_transport_bus_match(struct device *dev,
+				   struct device_driver *drv)
 {
 	return !strncmp(dev_name(dev), drv->name, strlen(drv->name));
 }
 
-static int ntb_client_probe(struct device *dev)
+static int ntb_transport_bus_probe(struct device *dev)
 {
-	const struct ntb_client *drv = container_of(dev->driver,
-						    struct ntb_client, driver);
-	struct pci_dev *pdev = container_of(dev->parent, struct pci_dev, dev);
+	const struct ntb_transport_client *client;
 	int rc = -EINVAL;
 
 	get_device(dev);
-	if (drv && drv->probe)
-		rc = drv->probe(pdev);
+
+	client = drv_client(dev->driver);
+	rc = client->probe(dev);
 	if (rc)
 		put_device(dev);
 
 	return rc;
 }
 
-static int ntb_client_remove(struct device *dev)
+static int ntb_transport_bus_remove(struct device *dev)
 {
-	const struct ntb_client *drv = container_of(dev->driver,
-						    struct ntb_client, driver);
-	struct pci_dev *pdev = container_of(dev->parent, struct pci_dev, dev);
+	const struct ntb_transport_client *client;
 
-	if (drv && drv->remove)
-		drv->remove(pdev);
+	client = drv_client(dev->driver);
+	client->remove(dev);
 
 	put_device(dev);
 
 	return 0;
 }
 
-static struct bus_type ntb_bus_type = {
-	.name = "ntb_bus",
-	.match = ntb_match_bus,
-	.probe = ntb_client_probe,
-	.remove = ntb_client_remove,
+static struct bus_type ntb_transport_bus = {
+	.name = "ntb_transport",
+	.match = ntb_transport_bus_match,
+	.probe = ntb_transport_bus_probe,
+	.remove = ntb_transport_bus_remove,
 };
 
 static LIST_HEAD(ntb_transport_list);
 
-static int ntb_bus_init(struct ntb_transport *nt)
+static int ntb_bus_init(struct ntb_transport_ctx *nt)
 {
-	if (list_empty(&ntb_transport_list)) {
-		int rc = bus_register(&ntb_bus_type);
-		if (rc)
-			return rc;
-	}
-
 	list_add(&nt->entry, &ntb_transport_list);
-
 	return 0;
 }
 
-static void ntb_bus_remove(struct ntb_transport *nt)
+static void ntb_bus_remove(struct ntb_transport_ctx *nt)
 {
 	struct ntb_transport_client_dev *client_dev, *cd;
 
@@ -273,29 +305,26 @@ static void ntb_bus_remove(struct ntb_transport *nt)
 	}
 
 	list_del(&nt->entry);
-
-	if (list_empty(&ntb_transport_list))
-		bus_unregister(&ntb_bus_type);
 }
 
-static void ntb_client_release(struct device *dev)
+static void ntb_transport_client_release(struct device *dev)
 {
 	struct ntb_transport_client_dev *client_dev;
-	client_dev = container_of(dev, struct ntb_transport_client_dev, dev);
 
+	client_dev = dev_client_dev(dev);
 	kfree(client_dev);
 }
 
 /**
- * ntb_unregister_client_dev - Unregister NTB client device
+ * ntb_transport_unregister_client_dev - Unregister NTB client device
  * @device_name: Name of NTB client device
  *
  * Unregister an NTB client device with the NTB transport layer
  */
-void ntb_unregister_client_dev(char *device_name)
+void ntb_transport_unregister_client_dev(char *device_name)
 {
 	struct ntb_transport_client_dev *client, *cd;
-	struct ntb_transport *nt;
+	struct ntb_transport_ctx *nt;
 
 	list_for_each_entry(nt, &ntb_transport_list, entry)
 		list_for_each_entry_safe(client, cd, &nt->client_devs, entry)
@@ -305,18 +334,18 @@ void ntb_unregister_client_dev(char *device_name)
 				device_unregister(&client->dev);
 			}
 }
-EXPORT_SYMBOL_GPL(ntb_unregister_client_dev);
+EXPORT_SYMBOL_GPL(ntb_transport_unregister_client_dev);
 
 /**
- * ntb_register_client_dev - Register NTB client device
+ * ntb_transport_register_client_dev - Register NTB client device
  * @device_name: Name of NTB client device
  *
  * Register an NTB client device with the NTB transport layer
  */
-int ntb_register_client_dev(char *device_name)
+int ntb_transport_register_client_dev(char *device_name)
 {
 	struct ntb_transport_client_dev *client_dev;
-	struct ntb_transport *nt;
+	struct ntb_transport_ctx *nt;
 	int rc, i = 0;
 
 	if (list_empty(&ntb_transport_list))
@@ -325,7 +354,7 @@ int ntb_register_client_dev(char *device_name)
 	list_for_each_entry(nt, &ntb_transport_list, entry) {
 		struct device *dev;
 
-		client_dev = kzalloc(sizeof(struct ntb_transport_client_dev),
+		client_dev = kzalloc(sizeof(*client_dev),
 				     GFP_KERNEL);
 		if (!client_dev) {
 			rc = -ENOMEM;
@@ -336,9 +365,9 @@ int ntb_register_client_dev(char *device_name)
 
 		/* setup and register client devices */
 		dev_set_name(dev, "%s%d", device_name, i);
-		dev->bus = &ntb_bus_type;
-		dev->release = ntb_client_release;
-		dev->parent = &ntb_query_pdev(nt->ndev)->dev;
+		dev->bus = &ntb_transport_bus;
+		dev->release = ntb_transport_client_release;
+		dev->parent = &nt->ndev->dev;
 
 		rc = device_register(dev);
 		if (rc) {
@@ -353,44 +382,44 @@ int ntb_register_client_dev(char *device_name)
 	return 0;
 
 err:
-	ntb_unregister_client_dev(device_name);
+	ntb_transport_unregister_client_dev(device_name);
 
 	return rc;
 }
-EXPORT_SYMBOL_GPL(ntb_register_client_dev);
+EXPORT_SYMBOL_GPL(ntb_transport_register_client_dev);
 
 /**
- * ntb_register_client - Register NTB client driver
+ * ntb_transport_register_client - Register NTB client driver
  * @drv: NTB client driver to be registered
  *
  * Register an NTB client driver with the NTB transport layer
  *
  * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
  */
-int ntb_register_client(struct ntb_client *drv)
+int ntb_transport_register_client(struct ntb_transport_client *drv)
 {
-	drv->driver.bus = &ntb_bus_type;
+	drv->driver.bus = &ntb_transport_bus;
 
 	if (list_empty(&ntb_transport_list))
 		return -ENODEV;
 
 	return driver_register(&drv->driver);
 }
-EXPORT_SYMBOL_GPL(ntb_register_client);
+EXPORT_SYMBOL_GPL(ntb_transport_register_client);
 
 /**
- * ntb_unregister_client - Unregister NTB client driver
+ * ntb_transport_unregister_client - Unregister NTB client driver
  * @drv: NTB client driver to be unregistered
  *
  * Unregister an NTB client driver with the NTB transport layer
  *
  * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
  */
-void ntb_unregister_client(struct ntb_client *drv)
+void ntb_transport_unregister_client(struct ntb_transport_client *drv)
 {
 	driver_unregister(&drv->driver);
 }
-EXPORT_SYMBOL_GPL(ntb_unregister_client);
+EXPORT_SYMBOL_GPL(ntb_transport_unregister_client);
 
 static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
 			    loff_t *offp)
@@ -452,8 +481,7 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
 			       "tx_max_entry - \t%u\n", qp->tx_max_entry);
 
 	out_offset += snprintf(buf + out_offset, out_count - out_offset,
-			       "\nQP Link %s\n", (qp->qp_link == NTB_LINK_UP) ?
-			       "Up" : "Down");
+			"\nQP Link %s\n", qp->link_is_up ? "Up" : "Down");
 	if (out_offset > out_count)
 		out_offset = out_count;
 
@@ -497,26 +525,31 @@ out:
 	return entry;
 }
 
-static void ntb_transport_setup_qp_mw(struct ntb_transport *nt,
-				      unsigned int qp_num)
+static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
+				     unsigned int qp_num)
 {
-	struct ntb_transport_qp *qp = &nt->qps[qp_num];
+	struct ntb_transport_qp *qp = &nt->qp_vec[qp_num];
+	struct ntb_transport_mw *mw;
 	unsigned int rx_size, num_qps_mw;
-	u8 mw_num, mw_max;
+	unsigned int mw_num, mw_count, qp_count;
 	unsigned int i;
 
-	mw_max = ntb_max_mw(nt->ndev);
-	mw_num = QP_TO_MW(nt->ndev, qp_num);
+	mw_count = nt->mw_count;
+	qp_count = nt->qp_count;
 
-	WARN_ON(nt->mw[mw_num].virt_addr == NULL);
+	mw_num = QP_TO_MW(nt, qp_num);
+	mw = &nt->mw_vec[mw_num];
+
+	if (!mw->virt_addr)
+		return -ENOMEM;
 
-	if (nt->max_qps % mw_max && mw_num + 1 < nt->max_qps / mw_max)
-		num_qps_mw = nt->max_qps / mw_max + 1;
+	if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
+		num_qps_mw = qp_count / mw_count + 1;
 	else
-		num_qps_mw = nt->max_qps / mw_max;
+		num_qps_mw = qp_count / mw_count;
 
-	rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw;
-	qp->rx_buff = nt->mw[mw_num].virt_addr + qp_num / mw_max * rx_size;
+	rx_size = (unsigned int)mw->xlat_size / num_qps_mw;
+	qp->rx_buff = mw->virt_addr + rx_size * qp_num / mw_count;
 	rx_size -= sizeof(struct ntb_rx_info);
 
 	qp->remote_rx_info = qp->rx_buff + rx_size;
@@ -538,41 +571,55 @@ static void ntb_transport_setup_qp_mw(struct ntb_transport *nt,
 	qp->rx_pkts = 0;
 	qp->tx_pkts = 0;
 	qp->tx_index = 0;
+
+	return 0;
 }
 
-static void ntb_free_mw(struct ntb_transport *nt, int num_mw)
+static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
 {
-	struct ntb_transport_mw *mw = &nt->mw[num_mw];
-	struct pci_dev *pdev = ntb_query_pdev(nt->ndev);
+	struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
+	struct pci_dev *pdev = nt->ndev->pdev;
 
 	if (!mw->virt_addr)
 		return;
 
-	dma_free_coherent(&pdev->dev, mw->size, mw->virt_addr, mw->dma_addr);
+	ntb_mw_clear_trans(nt->ndev, num_mw);
+	dma_free_coherent(&pdev->dev, mw->buff_size,
+			  mw->virt_addr, mw->dma_addr);
+	mw->xlat_size = 0;
+	mw->buff_size = 0;
 	mw->virt_addr = NULL;
 }
 
-static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size)
+static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
+		      unsigned int size)
 {
-	struct ntb_transport_mw *mw = &nt->mw[num_mw];
-	struct pci_dev *pdev = ntb_query_pdev(nt->ndev);
+	struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
+	struct pci_dev *pdev = nt->ndev->pdev;
+	unsigned int xlat_size, buff_size;
+	int rc;
+
+	xlat_size = round_up(size, mw->xlat_align_size);
+	buff_size = round_up(size, mw->xlat_align);
 
 	/* No need to re-setup */
-	if (mw->size == ALIGN(size, 4096))
+	if (mw->xlat_size == xlat_size)
 		return 0;
 
-	if (mw->size != 0)
+	if (mw->buff_size)
 		ntb_free_mw(nt, num_mw);
 
-	/* Alloc memory for receiving data.  Must be 4k aligned */
-	mw->size = ALIGN(size, 4096);
+	/* Alloc memory for receiving data.  Must be aligned */
+	mw->xlat_size = xlat_size;
+	mw->buff_size = buff_size;
 
-	mw->virt_addr = dma_alloc_coherent(&pdev->dev, mw->size, &mw->dma_addr,
-					   GFP_KERNEL);
+	mw->virt_addr = dma_alloc_coherent(&pdev->dev, buff_size,
+			&mw->dma_addr, GFP_KERNEL);
 	if (!mw->virt_addr) {
-		mw->size = 0;
-		dev_err(&pdev->dev, "Unable to allocate MW buffer of size %d\n",
-		       (int) mw->size);
+		mw->xlat_size = 0;
+		mw->buff_size = 0;
+		dev_err(&pdev->dev, "Unable to alloc MW buff of size %d\n",
+			buff_size);
 		return -ENOMEM;
 	}
 
@@ -582,34 +629,39 @@ static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size)
 	 * is a requirement of the hardware. It is recommended to setup CMA
 	 * for BAR sizes equal or greater than 4MB.
 	 */
-	if (!IS_ALIGNED(mw->dma_addr, mw->size)) {
-		dev_err(&pdev->dev, "DMA memory %pad not aligned to BAR size\n",
+	if (!IS_ALIGNED(mw->dma_addr, mw->xlat_align)) {
+		dev_err(&pdev->dev, "DMA memory %pad is not aligned\n",
 			&mw->dma_addr);
 		ntb_free_mw(nt, num_mw);
 		return -ENOMEM;
 	}
 
 	/* Notify HW the memory location of the receive buffer */
-	ntb_set_mw_addr(nt->ndev, num_mw, mw->dma_addr);
+	rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
+	if (rc) {
+		dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
+		ntb_free_mw(nt, num_mw);
+		return -EIO;
+	}
 
 	return 0;
 }
 
 static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp)
 {
-	struct ntb_transport *nt = qp->transport;
-	struct pci_dev *pdev = ntb_query_pdev(nt->ndev);
+	struct ntb_transport_ctx *nt = qp->transport;
+	struct pci_dev *pdev = nt->ndev->pdev;
 
-	if (qp->qp_link == NTB_LINK_DOWN) {
+	if (qp->link_is_up) {
 		cancel_delayed_work_sync(&qp->link_work);
 		return;
 	}
 
-	if (qp->event_handler)
-		qp->event_handler(qp->cb_data, NTB_LINK_DOWN);
-
 	dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num);
-	qp->qp_link = NTB_LINK_DOWN;
+	qp->link_is_up = false;
+
+	if (qp->event_handler)
+		qp->event_handler(qp->cb_data, qp->link_is_up);
 }
 
 static void ntb_qp_link_cleanup_work(struct work_struct *work)
@@ -617,11 +669,11 @@ static void ntb_qp_link_cleanup_work(struct work_struct *work)
 	struct ntb_transport_qp *qp = container_of(work,
 						   struct ntb_transport_qp,
 						   link_cleanup);
-	struct ntb_transport *nt = qp->transport;
+	struct ntb_transport_ctx *nt = qp->transport;
 
 	ntb_qp_link_cleanup(qp);
 
-	if (nt->transport_link == NTB_LINK_UP)
+	if (nt->link_is_up)
 		schedule_delayed_work(&qp->link_work,
 				      msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
 }
@@ -631,180 +683,132 @@ static void ntb_qp_link_down(struct ntb_transport_qp *qp)
 	schedule_work(&qp->link_cleanup);
 }
 
-static void ntb_transport_link_cleanup(struct ntb_transport *nt)
+static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
 {
+	struct ntb_transport_qp *qp;
+	u64 qp_bitmap_alloc;
 	int i;
 
+	qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free;
+
 	/* Pass along the info to any clients */
-	for (i = 0; i < nt->max_qps; i++)
-		if (!test_bit(i, &nt->qp_bitmap))
-			ntb_qp_link_cleanup(&nt->qps[i]);
+	for (i = 0; i < nt->qp_count; i++)
+		if (qp_bitmap_alloc & BIT_ULL(i)) {
+			qp = &nt->qp_vec[i];
+			ntb_qp_link_cleanup(qp);
+			cancel_work_sync(&qp->link_cleanup);
+			cancel_delayed_work_sync(&qp->link_work);
+		}
 
-	if (nt->transport_link == NTB_LINK_DOWN)
+	if (!nt->link_is_up)
 		cancel_delayed_work_sync(&nt->link_work);
-	else
-		nt->transport_link = NTB_LINK_DOWN;
 
 	/* The scratchpad registers keep the values if the remote side
 	 * goes down, blast them now to give them a sane value the next
 	 * time they are accessed
 	 */
 	for (i = 0; i < MAX_SPAD; i++)
-		ntb_write_local_spad(nt->ndev, i, 0);
+		ntb_spad_write(nt->ndev, i, 0);
 }
 
 static void ntb_transport_link_cleanup_work(struct work_struct *work)
 {
-	struct ntb_transport *nt = container_of(work, struct ntb_transport,
-						link_cleanup);
+	struct ntb_transport_ctx *nt =
+		container_of(work, struct ntb_transport_ctx, link_cleanup);
 
 	ntb_transport_link_cleanup(nt);
 }
 
-static void ntb_transport_event_callback(void *data, enum ntb_hw_event event)
+static void ntb_transport_event_callback(void *data)
 {
-	struct ntb_transport *nt = data;
+	struct ntb_transport_ctx *nt = data;
 
-	switch (event) {
-	case NTB_EVENT_HW_LINK_UP:
+	if (ntb_link_is_up(nt->ndev, NULL, NULL) == 1)
 		schedule_delayed_work(&nt->link_work, 0);
-		break;
-	case NTB_EVENT_HW_LINK_DOWN:
+	else
 		schedule_work(&nt->link_cleanup);
-		break;
-	default:
-		BUG();
-	}
 }
 
 static void ntb_transport_link_work(struct work_struct *work)
 {
-	struct ntb_transport *nt = container_of(work, struct ntb_transport,
-						link_work.work);
-	struct ntb_device *ndev = nt->ndev;
-	struct pci_dev *pdev = ntb_query_pdev(ndev);
+	struct ntb_transport_ctx *nt =
+		container_of(work, struct ntb_transport_ctx, link_work.work);
+	struct ntb_dev *ndev = nt->ndev;
+	struct pci_dev *pdev = ndev->pdev;
+	resource_size_t size;
 	u32 val;
-	int rc, i;
+	int rc, i, spad;
 
 	/* send the local info, in the opposite order of the way we read it */
-	for (i = 0; i < ntb_max_mw(ndev); i++) {
-		rc = ntb_write_remote_spad(ndev, MW0_SZ_HIGH + (i * 2),
-					   ntb_get_mw_size(ndev, i) >> 32);
-		if (rc) {
-			dev_err(&pdev->dev, "Error writing %u to remote spad %d\n",
-				(u32)(ntb_get_mw_size(ndev, i) >> 32),
-				MW0_SZ_HIGH + (i * 2));
-			goto out;
-		}
+	for (i = 0; i < nt->mw_count; i++) {
+		size = nt->mw_vec[i].phys_size;
 
-		rc = ntb_write_remote_spad(ndev, MW0_SZ_LOW + (i * 2),
-					   (u32) ntb_get_mw_size(ndev, i));
-		if (rc) {
-			dev_err(&pdev->dev, "Error writing %u to remote spad %d\n",
-				(u32) ntb_get_mw_size(ndev, i),
-				MW0_SZ_LOW + (i * 2));
-			goto out;
-		}
-	}
+		if (max_mw_size && size > max_mw_size)
+			size = max_mw_size;
 
-	rc = ntb_write_remote_spad(ndev, NUM_MWS, ntb_max_mw(ndev));
-	if (rc) {
-		dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
-			ntb_max_mw(ndev), NUM_MWS);
-		goto out;
-	}
+		spad = MW0_SZ_HIGH + (i * 2);
+		ntb_peer_spad_write(ndev, spad, (u32)(size >> 32));
 
-	rc = ntb_write_remote_spad(ndev, NUM_QPS, nt->max_qps);
-	if (rc) {
-		dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
-			nt->max_qps, NUM_QPS);
-		goto out;
+		spad = MW0_SZ_LOW + (i * 2);
+		ntb_peer_spad_write(ndev, spad, (u32)size);
 	}
 
-	rc = ntb_write_remote_spad(ndev, VERSION, NTB_TRANSPORT_VERSION);
-	if (rc) {
-		dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
-			NTB_TRANSPORT_VERSION, VERSION);
-		goto out;
-	}
+	ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count);
 
-	/* Query the remote side for its info */
-	rc = ntb_read_remote_spad(ndev, VERSION, &val);
-	if (rc) {
-		dev_err(&pdev->dev, "Error reading remote spad %d\n", VERSION);
-		goto out;
-	}
+	ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count);
 
-	if (val != NTB_TRANSPORT_VERSION)
-		goto out;
-	dev_dbg(&pdev->dev, "Remote version = %d\n", val);
+	ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION);
 
-	rc = ntb_read_remote_spad(ndev, NUM_QPS, &val);
-	if (rc) {
-		dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_QPS);
+	/* Query the remote side for its info */
+	val = ntb_peer_spad_read(ndev, VERSION);
+	dev_dbg(&pdev->dev, "Remote version = %d\n", val);
+	if (val != NTB_TRANSPORT_VERSION)
 		goto out;
-	}
 
-	if (val != nt->max_qps)
-		goto out;
+	val = ntb_peer_spad_read(ndev, NUM_QPS);
 	dev_dbg(&pdev->dev, "Remote max number of qps = %d\n", val);
-
-	rc = ntb_read_remote_spad(ndev, NUM_MWS, &val);
-	if (rc) {
-		dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_MWS);
+	if (val != nt->qp_count)
 		goto out;
-	}
 
-	if (val != ntb_max_mw(ndev))
-		goto out;
+	val = ntb_peer_spad_read(ndev, NUM_MWS);
 	dev_dbg(&pdev->dev, "Remote number of mws = %d\n", val);
+	if (val != nt->mw_count)
+		goto out;
 
-	for (i = 0; i < ntb_max_mw(ndev); i++) {
+	for (i = 0; i < nt->mw_count; i++) {
 		u64 val64;
 
-		rc = ntb_read_remote_spad(ndev, MW0_SZ_HIGH + (i * 2), &val);
-		if (rc) {
-			dev_err(&pdev->dev, "Error reading remote spad %d\n",
-				MW0_SZ_HIGH + (i * 2));
-			goto out1;
-		}
-
-		val64 = (u64) val << 32;
-
-		rc = ntb_read_remote_spad(ndev, MW0_SZ_LOW + (i * 2), &val);
-		if (rc) {
-			dev_err(&pdev->dev, "Error reading remote spad %d\n",
-				MW0_SZ_LOW + (i * 2));
-			goto out1;
-		}
+		val = ntb_peer_spad_read(ndev, MW0_SZ_HIGH + (i * 2));
+		val64 = (u64)val << 32;
 
+		val = ntb_peer_spad_read(ndev, MW0_SZ_LOW + (i * 2));
 		val64 |= val;
 
-		dev_dbg(&pdev->dev, "Remote MW%d size = %llu\n", i, val64);
+		dev_dbg(&pdev->dev, "Remote MW%d size = %#llx\n", i, val64);
 
 		rc = ntb_set_mw(nt, i, val64);
 		if (rc)
 			goto out1;
 	}
 
-	nt->transport_link = NTB_LINK_UP;
+	nt->link_is_up = true;
 
-	for (i = 0; i < nt->max_qps; i++) {
-		struct ntb_transport_qp *qp = &nt->qps[i];
+	for (i = 0; i < nt->qp_count; i++) {
+		struct ntb_transport_qp *qp = &nt->qp_vec[i];
 
 		ntb_transport_setup_qp_mw(nt, i);
 
-		if (qp->client_ready == NTB_LINK_UP)
+		if (qp->client_ready)
 			schedule_delayed_work(&qp->link_work, 0);
 	}
 
 	return;
 
 out1:
-	for (i = 0; i < ntb_max_mw(ndev); i++)
+	for (i = 0; i < nt->mw_count; i++)
 		ntb_free_mw(nt, i);
 out:
-	if (ntb_hw_link_status(ndev))
+	if (ntb_link_is_up(ndev, NULL, NULL) == 1)
 		schedule_delayed_work(&nt->link_work,
 				      msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
 }
@@ -814,73 +818,73 @@ static void ntb_qp_link_work(struct work_struct *work)
 	struct ntb_transport_qp *qp = container_of(work,
 						   struct ntb_transport_qp,
 						   link_work.work);
-	struct pci_dev *pdev = ntb_query_pdev(qp->ndev);
-	struct ntb_transport *nt = qp->transport;
-	int rc, val;
+	struct pci_dev *pdev = qp->ndev->pdev;
+	struct ntb_transport_ctx *nt = qp->transport;
+	int val;
 
-	WARN_ON(nt->transport_link != NTB_LINK_UP);
+	WARN_ON(!nt->link_is_up);
 
-	rc = ntb_read_local_spad(nt->ndev, QP_LINKS, &val);
-	if (rc) {
-		dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS);
-		return;
-	}
+	val = ntb_spad_read(nt->ndev, QP_LINKS);
 
-	rc = ntb_write_remote_spad(nt->ndev, QP_LINKS, val | 1 << qp->qp_num);
-	if (rc)
-		dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
-			val | 1 << qp->qp_num, QP_LINKS);
+	ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num));
 
 	/* query remote spad for qp ready bits */
-	rc = ntb_read_remote_spad(nt->ndev, QP_LINKS, &val);
-	if (rc)
-		dev_err(&pdev->dev, "Error reading remote spad %d\n", QP_LINKS);
-
+	ntb_peer_spad_read(nt->ndev, QP_LINKS);
 	dev_dbg(&pdev->dev, "Remote QP link status = %x\n", val);
 
 	/* See if the remote side is up */
-	if (1 << qp->qp_num & val) {
-		qp->qp_link = NTB_LINK_UP;
-
+	if (val & BIT(qp->qp_num)) {
 		dev_info(&pdev->dev, "qp %d: Link Up\n", qp->qp_num);
+		qp->link_is_up = true;
+
 		if (qp->event_handler)
-			qp->event_handler(qp->cb_data, NTB_LINK_UP);
-	} else if (nt->transport_link == NTB_LINK_UP)
+			qp->event_handler(qp->cb_data, qp->link_is_up);
+	} else if (nt->link_is_up)
 		schedule_delayed_work(&qp->link_work,
 				      msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
 }
 
-static int ntb_transport_init_queue(struct ntb_transport *nt,
+static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
 				    unsigned int qp_num)
 {
 	struct ntb_transport_qp *qp;
+	struct ntb_transport_mw *mw;
+	phys_addr_t mw_base;
+	resource_size_t mw_size;
 	unsigned int num_qps_mw, tx_size;
-	u8 mw_num, mw_max;
+	unsigned int mw_num, mw_count, qp_count;
 	u64 qp_offset;
 
-	mw_max = ntb_max_mw(nt->ndev);
-	mw_num = QP_TO_MW(nt->ndev, qp_num);
+	mw_count = nt->mw_count;
+	qp_count = nt->qp_count;
 
-	qp = &nt->qps[qp_num];
+	mw_num = QP_TO_MW(nt, qp_num);
+	mw = &nt->mw_vec[mw_num];
+
+	qp = &nt->qp_vec[qp_num];
 	qp->qp_num = qp_num;
 	qp->transport = nt;
 	qp->ndev = nt->ndev;
-	qp->qp_link = NTB_LINK_DOWN;
-	qp->client_ready = NTB_LINK_DOWN;
+	qp->link_is_up = false;
+	qp->client_ready = false;
 	qp->event_handler = NULL;
 
-	if (nt->max_qps % mw_max && mw_num + 1 < nt->max_qps / mw_max)
-		num_qps_mw = nt->max_qps / mw_max + 1;
+	if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
+		num_qps_mw = qp_count / mw_count + 1;
 	else
-		num_qps_mw = nt->max_qps / mw_max;
+		num_qps_mw = qp_count / mw_count;
+
+	mw_base = nt->mw_vec[mw_num].phys_addr;
+	mw_size = nt->mw_vec[mw_num].phys_size;
+
+	tx_size = (unsigned int)mw_size / num_qps_mw;
+	qp_offset = tx_size * qp_num / mw_count;
 
-	tx_size = (unsigned int) ntb_get_mw_size(qp->ndev, mw_num) / num_qps_mw;
-	qp_offset = qp_num / mw_max * tx_size;
-	qp->tx_mw = ntb_get_mw_vbase(nt->ndev, mw_num) + qp_offset;
+	qp->tx_mw = nt->mw_vec[mw_num].vbase + qp_offset;
 	if (!qp->tx_mw)
 		return -EINVAL;
 
-	qp->tx_mw_phys = ntb_get_mw_base(qp->ndev, mw_num) + qp_offset;
+	qp->tx_mw_phys = mw_base + qp_offset;
 	if (!qp->tx_mw_phys)
 		return -EINVAL;
 
@@ -891,16 +895,19 @@ static int ntb_transport_init_queue(struct ntb_transport *nt,
 	qp->tx_max_frame = min(transport_mtu, tx_size / 2);
 	qp->tx_max_entry = tx_size / qp->tx_max_frame;
 
-	if (ntb_query_debugfs(nt->ndev)) {
+	if (nt_debugfs_dir) {
 		char debugfs_name[4];
 
 		snprintf(debugfs_name, 4, "qp%d", qp_num);
 		qp->debugfs_dir = debugfs_create_dir(debugfs_name,
-						 ntb_query_debugfs(nt->ndev));
+						 nt_debugfs_dir);
 
 		qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR,
 							qp->debugfs_dir, qp,
 							&ntb_qp_debugfs_stats);
+	} else {
+		qp->debugfs_dir = NULL;
+		qp->debugfs_stats = NULL;
 	}
 
 	INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work);
@@ -917,53 +924,88 @@ static int ntb_transport_init_queue(struct ntb_transport *nt,
 	return 0;
 }
 
-int ntb_transport_init(struct pci_dev *pdev)
+static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
 {
-	struct ntb_transport *nt;
+	struct ntb_transport_ctx *nt;
+	struct ntb_transport_mw *mw;
+	unsigned int mw_count, qp_count;
+	u64 qp_bitmap;
 	int rc, i;
 
-	nt = kzalloc(sizeof(struct ntb_transport), GFP_KERNEL);
+	if (ntb_db_is_unsafe(ndev))
+		dev_dbg(&ndev->dev,
+			"doorbell is unsafe, proceed anyway...\n");
+	if (ntb_spad_is_unsafe(ndev))
+		dev_dbg(&ndev->dev,
+			"scratchpad is unsafe, proceed anyway...\n");
+
+	nt = kzalloc(sizeof(*nt), GFP_KERNEL);
 	if (!nt)
 		return -ENOMEM;
 
-	nt->ndev = ntb_register_transport(pdev, nt);
-	if (!nt->ndev) {
-		rc = -EIO;
+	nt->ndev = ndev;
+
+	mw_count = ntb_mw_count(ndev);
+
+	nt->mw_count = mw_count;
+
+	nt->mw_vec = kcalloc(mw_count, sizeof(*nt->mw_vec), GFP_KERNEL);
+	if (!nt->mw_vec) {
+		rc = -ENOMEM;
 		goto err;
 	}
 
-	nt->mw = kcalloc(ntb_max_mw(nt->ndev), sizeof(struct ntb_transport_mw),
-			 GFP_KERNEL);
-	if (!nt->mw) {
-		rc = -ENOMEM;
-		goto err1;
+	for (i = 0; i < mw_count; i++) {
+		mw = &nt->mw_vec[i];
+
+		rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size,
+				      &mw->xlat_align, &mw->xlat_align_size);
+		if (rc)
+			goto err1;
+
+		mw->vbase = ioremap(mw->phys_addr, mw->phys_size);
+		if (!mw->vbase) {
+			rc = -ENOMEM;
+			goto err1;
+		}
+
+		mw->buff_size = 0;
+		mw->xlat_size = 0;
+		mw->virt_addr = NULL;
+		mw->dma_addr = 0;
 	}
 
-	if (max_num_clients)
-		nt->max_qps = min(ntb_max_cbs(nt->ndev), max_num_clients);
-	else
-		nt->max_qps = min(ntb_max_cbs(nt->ndev), ntb_max_mw(nt->ndev));
+	qp_bitmap = ntb_db_valid_mask(ndev);
+
+	qp_count = ilog2(qp_bitmap);
+	if (max_num_clients && max_num_clients < qp_count)
+		qp_count = max_num_clients;
+	else if (mw_count < qp_count)
+		qp_count = mw_count;
 
-	nt->qps = kcalloc(nt->max_qps, sizeof(struct ntb_transport_qp),
-			  GFP_KERNEL);
-	if (!nt->qps) {
+	qp_bitmap &= BIT_ULL(qp_count) - 1;
+
+	nt->qp_count = qp_count;
+	nt->qp_bitmap = qp_bitmap;
+	nt->qp_bitmap_free = qp_bitmap;
+
+	nt->qp_vec = kcalloc(qp_count, sizeof(*nt->qp_vec), GFP_KERNEL);
+	if (!nt->qp_vec) {
 		rc = -ENOMEM;
 		goto err2;
 	}
 
-	nt->qp_bitmap = ((u64) 1 << nt->max_qps) - 1;
-
-	for (i = 0; i < nt->max_qps; i++) {
+	for (i = 0; i < qp_count; i++) {
 		rc = ntb_transport_init_queue(nt, i);
 		if (rc)
 			goto err3;
 	}
 
 	INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
+	INIT_WORK(&nt->db_work, ntb_transport_doorbell_work);
 	INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work);
 
-	rc = ntb_register_event_callback(nt->ndev,
-					 ntb_transport_event_callback);
+	rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops);
 	if (rc)
 		goto err3;
 
@@ -972,51 +1014,62 @@ int ntb_transport_init(struct pci_dev *pdev)
 	if (rc)
 		goto err4;
 
-	if (ntb_hw_link_status(nt->ndev))
-		schedule_delayed_work(&nt->link_work, 0);
+	nt->link_is_up = false;
+	ntb_link_enable(ndev, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
+	ntb_link_event(ndev);
 
 	return 0;
 
 err4:
-	ntb_unregister_event_callback(nt->ndev);
+	ntb_clear_ctx(ndev);
 err3:
-	kfree(nt->qps);
+	kfree(nt->qp_vec);
 err2:
-	kfree(nt->mw);
+	kfree(nt->mw_vec);
 err1:
-	ntb_unregister_transport(nt->ndev);
+	while (i--) {
+		mw = &nt->mw_vec[i];
+		iounmap(mw->vbase);
+	}
 err:
 	kfree(nt);
 	return rc;
 }
 
-void ntb_transport_free(void *transport)
+static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev)
 {
-	struct ntb_transport *nt = transport;
-	struct ntb_device *ndev = nt->ndev;
+	struct ntb_transport_ctx *nt = ndev->ctx;
+	struct ntb_transport_qp *qp;
+	u64 qp_bitmap_alloc;
 	int i;
 
 	ntb_transport_link_cleanup(nt);
+	cancel_work_sync(&nt->db_work);
+	cancel_work_sync(&nt->link_cleanup);
+	cancel_delayed_work_sync(&nt->link_work);
+
+	qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free;
 
 	/* verify that all the qp's are freed */
-	for (i = 0; i < nt->max_qps; i++) {
-		if (!test_bit(i, &nt->qp_bitmap))
-			ntb_transport_free_queue(&nt->qps[i]);
-		debugfs_remove_recursive(nt->qps[i].debugfs_dir);
+	for (i = 0; i < nt->qp_count; i++) {
+		qp = &nt->qp_vec[i];
+		if (qp_bitmap_alloc & BIT_ULL(i))
+			ntb_transport_free_queue(qp);
+		debugfs_remove_recursive(qp->debugfs_dir);
 	}
 
-	ntb_bus_remove(nt);
-
-	cancel_delayed_work_sync(&nt->link_work);
+	ntb_link_disable(ndev);
+	ntb_clear_ctx(ndev);
 
-	ntb_unregister_event_callback(ndev);
+	ntb_bus_remove(nt);
 
-	for (i = 0; i < ntb_max_mw(ndev); i++)
+	for (i = nt->mw_count; i--; ) {
 		ntb_free_mw(nt, i);
+		iounmap(nt->mw_vec[i].vbase);
+	}
 
-	kfree(nt->qps);
-	kfree(nt->mw);
-	ntb_unregister_transport(ndev);
+	kfree(nt->qp_vec);
+	kfree(nt->mw_vec);
 	kfree(nt);
 }
 
@@ -1028,15 +1081,13 @@ static void ntb_rx_copy_callback(void *data)
 	unsigned int len = entry->len;
 	struct ntb_payload_header *hdr = entry->rx_hdr;
 
-	/* Ensure that the data is fully copied out before clearing the flag */
-	wmb();
 	hdr->flags = 0;
 
 	iowrite32(entry->index, &qp->rx_info->entry);
 
 	ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
 
-	if (qp->rx_handler && qp->client_ready == NTB_LINK_UP)
+	if (qp->rx_handler && qp->client_ready)
 		qp->rx_handler(qp, qp->cb_data, cb_data, len);
 }
 
@@ -1047,6 +1098,9 @@ static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
 
 	memcpy(buf, offset, len);
 
+	/* Ensure that the data is fully copied out before clearing the flag */
+	wmb();
+
 	ntb_rx_copy_callback(entry);
 }
 
@@ -1138,77 +1192,95 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
 	struct ntb_payload_header *hdr;
 	struct ntb_queue_entry *entry;
 	void *offset;
+	int rc;
 
 	offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index;
 	hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header);
 
-	entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
-	if (!entry) {
-		dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
-			"no buffer - HDR ver %u, len %d, flags %x\n",
-			hdr->ver, hdr->len, hdr->flags);
-		qp->rx_err_no_buf++;
-		return -ENOMEM;
-	}
+	dev_dbg(&qp->ndev->pdev->dev, "qp %d: RX ver %u len %d flags %x\n",
+		qp->qp_num, hdr->ver, hdr->len, hdr->flags);
 
 	if (!(hdr->flags & DESC_DONE_FLAG)) {
-		ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
-			     &qp->rx_pend_q);
+		dev_dbg(&qp->ndev->pdev->dev, "done flag not set\n");
 		qp->rx_ring_empty++;
 		return -EAGAIN;
 	}
 
-	if (hdr->ver != (u32) qp->rx_pkts) {
-		dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
-			"qp %d: version mismatch, expected %llu - got %u\n",
-			qp->qp_num, qp->rx_pkts, hdr->ver);
-		ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
-			     &qp->rx_pend_q);
+	if (hdr->flags & LINK_DOWN_FLAG) {
+		dev_dbg(&qp->ndev->pdev->dev, "link down flag set\n");
+		ntb_qp_link_down(qp);
+		hdr->flags = 0;
+		iowrite32(qp->rx_index, &qp->rx_info->entry);
+		return 0;
+	}
+
+	if (hdr->ver != (u32)qp->rx_pkts) {
+		dev_dbg(&qp->ndev->pdev->dev,
+			"version mismatch, expected %llu - got %u\n",
+			qp->rx_pkts, hdr->ver);
 		qp->rx_err_ver++;
 		return -EIO;
 	}
 
-	if (hdr->flags & LINK_DOWN_FLAG) {
-		ntb_qp_link_down(qp);
+	entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+	if (!entry) {
+		dev_dbg(&qp->ndev->pdev->dev, "no receive buffer\n");
+		qp->rx_err_no_buf++;
 
+		rc = -ENOMEM;
 		goto err;
 	}
 
-	dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
-		"rx offset %u, ver %u - %d payload received, buf size %d\n",
-		qp->rx_index, hdr->ver, hdr->len, entry->len);
-
-	qp->rx_bytes += hdr->len;
-	qp->rx_pkts++;
-
 	if (hdr->len > entry->len) {
-		qp->rx_err_oflow++;
-		dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
-			"RX overflow! Wanted %d got %d\n",
+		dev_dbg(&qp->ndev->pdev->dev,
+			"receive buffer overflow! Wanted %d got %d\n",
 			hdr->len, entry->len);
+		qp->rx_err_oflow++;
 
+		rc = -EIO;
 		goto err;
 	}
 
+	dev_dbg(&qp->ndev->pdev->dev,
+		"RX OK index %u ver %u size %d into buf size %d\n",
+		qp->rx_index, hdr->ver, hdr->len, entry->len);
+
+	qp->rx_bytes += hdr->len;
+	qp->rx_pkts++;
+
 	entry->index = qp->rx_index;
 	entry->rx_hdr = hdr;
 
 	ntb_async_rx(entry, offset, hdr->len);
 
-out:
 	qp->rx_index++;
 	qp->rx_index %= qp->rx_max_entry;
 
 	return 0;
 
 err:
-	ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q);
-	/* Ensure that the data is fully copied out before clearing the flag */
-	wmb();
+	/* FIXME: if this syncrhonous update of the rx_index gets ahead of
+	 * asyncrhonous ntb_rx_copy_callback of previous entry, there are three
+	 * scenarios:
+	 *
+	 * 1) The peer might miss this update, but observe the update
+	 * from the memcpy completion callback.  In this case, the buffer will
+	 * not be freed on the peer to be reused for a different packet.  The
+	 * successful rx of a later packet would clear the condition, but the
+	 * condition could persist if several rx fail in a row.
+	 *
+	 * 2) The peer may observe this update before the asyncrhonous copy of
+	 * prior packets is completed.  The peer may overwrite the buffers of
+	 * the prior packets before they are copied.
+	 *
+	 * 3) Both: the peer may observe the update, and then observe the index
+	 * decrement by the asynchronous completion callback.  Who knows what
+	 * badness that will cause.
+	 */
 	hdr->flags = 0;
 	iowrite32(qp->rx_index, &qp->rx_info->entry);
 
-	goto out;
+	return rc;
 }
 
 static int ntb_transport_rxc_db(void *data, int db_num)
@@ -1216,7 +1288,7 @@ static int ntb_transport_rxc_db(void *data, int db_num)
 	struct ntb_transport_qp *qp = data;
 	int rc, i;
 
-	dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n",
+	dev_dbg(&qp->ndev->pdev->dev, "%s: doorbell %d received\n",
 		__func__, db_num);
 
 	/* Limit the number of packets processed in a single interrupt to
@@ -1240,11 +1312,9 @@ static void ntb_tx_copy_callback(void *data)
 	struct ntb_transport_qp *qp = entry->qp;
 	struct ntb_payload_header __iomem *hdr = entry->tx_hdr;
 
-	/* Ensure that the data is fully copied out before setting the flags */
-	wmb();
 	iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags);
 
-	ntb_ring_doorbell(qp->ndev, qp->qp_num);
+	ntb_peer_db_set(qp->ndev, BIT_ULL(qp->qp_num));
 
 	/* The entry length can only be zero if the packet is intended to be a
 	 * "link down" or similar.  Since no payload is being sent in these
@@ -1265,6 +1335,9 @@ static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset)
 {
 	memcpy_toio(offset, entry->buf, entry->len);
 
+	/* Ensure that the data is fully copied out before setting the flags */
+	wmb();
+
 	ntb_tx_copy_callback(entry);
 }
 
@@ -1347,9 +1420,6 @@ err:
 static int ntb_process_tx(struct ntb_transport_qp *qp,
 			  struct ntb_queue_entry *entry)
 {
-	dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%lld - tx %u, entry len %d flags %x buff %p\n",
-		qp->tx_pkts, qp->tx_index, entry->len, entry->flags,
-		entry->buf);
 	if (qp->tx_index == qp->remote_rx_info->entry) {
 		qp->tx_ring_full++;
 		return -EAGAIN;
@@ -1376,14 +1446,14 @@ static int ntb_process_tx(struct ntb_transport_qp *qp,
 
 static void ntb_send_link_down(struct ntb_transport_qp *qp)
 {
-	struct pci_dev *pdev = ntb_query_pdev(qp->ndev);
+	struct pci_dev *pdev = qp->ndev->pdev;
 	struct ntb_queue_entry *entry;
 	int i, rc;
 
-	if (qp->qp_link == NTB_LINK_DOWN)
+	if (!qp->link_is_up)
 		return;
 
-	qp->qp_link = NTB_LINK_DOWN;
+	qp->link_is_up = false;
 	dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num);
 
 	for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) {
@@ -1422,18 +1492,21 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp)
  * RETURNS: pointer to newly created ntb_queue, NULL on error.
  */
 struct ntb_transport_qp *
-ntb_transport_create_queue(void *data, struct pci_dev *pdev,
+ntb_transport_create_queue(void *data, struct device *client_dev,
 			   const struct ntb_queue_handlers *handlers)
 {
+	struct ntb_dev *ndev;
+	struct pci_dev *pdev;
+	struct ntb_transport_ctx *nt;
 	struct ntb_queue_entry *entry;
 	struct ntb_transport_qp *qp;
-	struct ntb_transport *nt;
+	u64 qp_bit;
 	unsigned int free_queue;
-	int rc, i;
+	int i;
 
-	nt = ntb_find_transport(pdev);
-	if (!nt)
-		goto err;
+	ndev = dev_ntb(client_dev->parent);
+	pdev = ndev->pdev;
+	nt = ndev->ctx;
 
 	free_queue = ffs(nt->qp_bitmap);
 	if (!free_queue)
@@ -1442,9 +1515,11 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev,
 	/* decrement free_queue to make it zero based */
 	free_queue--;
 
-	clear_bit(free_queue, &nt->qp_bitmap);
+	qp = &nt->qp_vec[free_queue];
+	qp_bit = BIT_ULL(qp->qp_num);
+
+	nt->qp_bitmap_free &= ~qp_bit;
 
-	qp = &nt->qps[free_queue];
 	qp->cb_data = data;
 	qp->rx_handler = handlers->rx_handler;
 	qp->tx_handler = handlers->tx_handler;
@@ -1458,7 +1533,7 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev,
 	}
 
 	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
-		entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC);
+		entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 		if (!entry)
 			goto err1;
 
@@ -1468,7 +1543,7 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev,
 	}
 
 	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
-		entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC);
+		entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 		if (!entry)
 			goto err2;
 
@@ -1477,10 +1552,8 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev,
 			     &qp->tx_free_q);
 	}
 
-	rc = ntb_register_db_callback(qp->ndev, free_queue, qp,
-				      ntb_transport_rxc_db);
-	if (rc)
-		goto err2;
+	ntb_db_clear(qp->ndev, qp_bit);
+	ntb_db_clear_mask(qp->ndev, qp_bit);
 
 	dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num);
 
@@ -1494,7 +1567,7 @@ err1:
 		kfree(entry);
 	if (qp->dma_chan)
 		dmaengine_put();
-	set_bit(free_queue, &nt->qp_bitmap);
+	nt->qp_bitmap_free |= qp_bit;
 err:
 	return NULL;
 }
@@ -1508,13 +1581,15 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue);
  */
 void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 {
+	struct ntb_transport_ctx *nt = qp->transport;
 	struct pci_dev *pdev;
 	struct ntb_queue_entry *entry;
+	u64 qp_bit;
 
 	if (!qp)
 		return;
 
-	pdev = ntb_query_pdev(qp->ndev);
+	pdev = qp->ndev->pdev;
 
 	if (qp->dma_chan) {
 		struct dma_chan *chan = qp->dma_chan;
@@ -1531,10 +1606,17 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 		dmaengine_put();
 	}
 
-	ntb_unregister_db_callback(qp->ndev, qp->qp_num);
+	qp_bit = BIT_ULL(qp->qp_num);
+
+	ntb_db_set_mask(qp->ndev, qp_bit);
 
 	cancel_delayed_work_sync(&qp->link_work);
 
+	qp->cb_data = NULL;
+	qp->rx_handler = NULL;
+	qp->tx_handler = NULL;
+	qp->event_handler = NULL;
+
 	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
 		kfree(entry);
 
@@ -1546,7 +1628,7 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
 		kfree(entry);
 
-	set_bit(qp->qp_num, &qp->transport->qp_bitmap);
+	nt->qp_bitmap_free |= qp_bit;
 
 	dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num);
 }
@@ -1567,7 +1649,7 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len)
 	struct ntb_queue_entry *entry;
 	void *buf;
 
-	if (!qp || qp->client_ready == NTB_LINK_UP)
+	if (!qp || qp->client_ready)
 		return NULL;
 
 	entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
@@ -1636,7 +1718,7 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
 	struct ntb_queue_entry *entry;
 	int rc;
 
-	if (!qp || qp->qp_link != NTB_LINK_UP || !len)
+	if (!qp || !qp->link_is_up || !len)
 		return -EINVAL;
 
 	entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
@@ -1670,9 +1752,9 @@ void ntb_transport_link_up(struct ntb_transport_qp *qp)
 	if (!qp)
 		return;
 
-	qp->client_ready = NTB_LINK_UP;
+	qp->client_ready = true;
 
-	if (qp->transport->transport_link == NTB_LINK_UP)
+	if (qp->transport->link_is_up)
 		schedule_delayed_work(&qp->link_work, 0);
 }
 EXPORT_SYMBOL_GPL(ntb_transport_link_up);
@@ -1688,27 +1770,20 @@ EXPORT_SYMBOL_GPL(ntb_transport_link_up);
 void ntb_transport_link_down(struct ntb_transport_qp *qp)
 {
 	struct pci_dev *pdev;
-	int rc, val;
+	int val;
 
 	if (!qp)
 		return;
 
-	pdev = ntb_query_pdev(qp->ndev);
-	qp->client_ready = NTB_LINK_DOWN;
+	pdev = qp->ndev->pdev;
+	qp->client_ready = false;
 
-	rc = ntb_read_local_spad(qp->ndev, QP_LINKS, &val);
-	if (rc) {
-		dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS);
-		return;
-	}
+	val = ntb_spad_read(qp->ndev, QP_LINKS);
 
-	rc = ntb_write_remote_spad(qp->ndev, QP_LINKS,
-				   val & ~(1 << qp->qp_num));
-	if (rc)
-		dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
-			val & ~(1 << qp->qp_num), QP_LINKS);
+	ntb_peer_spad_write(qp->ndev, QP_LINKS,
+			    val & ~BIT(qp->qp_num));
 
-	if (qp->qp_link == NTB_LINK_UP)
+	if (qp->link_is_up)
 		ntb_send_link_down(qp);
 	else
 		cancel_delayed_work_sync(&qp->link_work);
@@ -1728,7 +1803,7 @@ bool ntb_transport_link_query(struct ntb_transport_qp *qp)
 	if (!qp)
 		return false;
 
-	return qp->qp_link == NTB_LINK_UP;
+	return qp->link_is_up;
 }
 EXPORT_SYMBOL_GPL(ntb_transport_link_query);
 
@@ -1774,3 +1849,93 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
 	return max;
 }
 EXPORT_SYMBOL_GPL(ntb_transport_max_size);
+
+static void ntb_transport_doorbell_work(struct work_struct *work)
+{
+	struct ntb_transport_ctx *nt = container_of(work,
+			struct ntb_transport_ctx, db_work);
+	struct ntb_transport_qp *qp;
+	u64 db_mask, db_bits, db_again;
+	unsigned int qp_num;
+	int rc;
+
+	db_mask = nt->qp_bitmap & ~nt->qp_bitmap_free;
+	db_bits = db_mask & ntb_db_read(nt->ndev);
+
+	while (db_bits) {
+		ntb_db_clear(nt->ndev, db_bits);
+		db_again = 0;
+
+		while (db_bits) {
+			qp_num = __ffs(db_bits);
+			qp = &nt->qp_vec[qp_num];
+
+			rc = ntb_transport_rxc_db(qp, qp_num);
+			if (rc == qp->rx_max_entry)
+				db_again |= BIT_ULL(qp_num);
+
+			db_bits &= ~BIT_ULL(qp_num);
+		}
+
+		db_bits = db_mask & ntb_db_read(nt->ndev);
+		db_bits |= db_again;
+	}
+
+	ntb_db_clear_mask(nt->ndev, db_mask);
+}
+
+static void ntb_transport_doorbell_callback(void *data, int vector)
+{
+	struct ntb_transport_ctx *nt = data;
+
+	ntb_db_set_mask(nt->ndev, ntb_db_valid_mask(nt->ndev));
+
+	schedule_work(&nt->db_work);
+}
+
+static const struct ntb_ctx_ops ntb_transport_ops = {
+	.link_event = ntb_transport_event_callback,
+	.db_event = ntb_transport_doorbell_callback,
+};
+
+static struct ntb_client ntb_transport_client = {
+	.ops = {
+		.probe = ntb_transport_probe,
+		.remove = ntb_transport_free,
+	},
+	.name = NTB_TRANSPORT_NAME,
+};
+
+static int __init ntb_transport_init(void)
+{
+	int rc;
+
+	if (debugfs_initialized())
+		nt_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+	rc = bus_register(&ntb_transport_bus);
+	if (rc)
+		goto err_bus;
+
+	rc = ntb_register_client(&ntb_transport_client);
+	if (rc)
+		goto err_client;
+
+	return 0;
+
+err_client:
+	bus_unregister(&ntb_transport_bus);
+err_bus:
+	debugfs_remove_recursive(nt_debugfs_dir);
+	return rc;
+}
+module_init(ntb_transport_init);
+
+static void __exit ntb_transport_exit(void)
+{
+	debugfs_remove_recursive(nt_debugfs_dir);
+
+	ntb_unregister_client(&ntb_transport_client);
+	bus_unregister(&ntb_transport_bus);
+}
+module_exit(ntb_transport_exit);
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
new file mode 100644
index 0000000..e8f29be
--- /dev/null
+++ b/include/linux/ntb.h
@@ -0,0 +1,983 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Allen Hubbe <Allen.Hubbe@emc.com>
+ */
+
+#ifndef _NTB_H_
+#define _NTB_H_
+
+#include <linux/completion.h>
+#include <linux/device.h>
+
+struct ntb_client;
+struct ntb_dev;
+struct pci_dev;
+
+/**
+ * enum ntb_topo - NTB connection topology
+ * @NTB_TOPO_NONE:	Topology is unknown or invalid.
+ * @NTB_TOPO_PRI:	On primary side of local ntb.
+ * @NTB_TOPO_SEC:	On secondary side of remote ntb.
+ * @NTB_TOPO_B2B_USD:	On primary side of local ntb upstream of remote ntb.
+ * @NTB_TOPO_B2B_DSD:	On primary side of local ntb downstream of remote ntb.
+ */
+enum ntb_topo {
+	NTB_TOPO_NONE = -1,
+	NTB_TOPO_PRI,
+	NTB_TOPO_SEC,
+	NTB_TOPO_B2B_USD,
+	NTB_TOPO_B2B_DSD,
+};
+
+static inline int ntb_topo_is_b2b(enum ntb_topo topo)
+{
+	switch ((int)topo) {
+	case NTB_TOPO_B2B_USD:
+	case NTB_TOPO_B2B_DSD:
+		return 1;
+	}
+	return 0;
+}
+
+static inline char *ntb_topo_string(enum ntb_topo topo)
+{
+	switch (topo) {
+	case NTB_TOPO_NONE:	return "NTB_TOPO_NONE";
+	case NTB_TOPO_PRI:	return "NTB_TOPO_PRI";
+	case NTB_TOPO_SEC:	return "NTB_TOPO_SEC";
+	case NTB_TOPO_B2B_USD:	return "NTB_TOPO_B2B_USD";
+	case NTB_TOPO_B2B_DSD:	return "NTB_TOPO_B2B_DSD";
+	}
+	return "NTB_TOPO_INVALID";
+}
+
+/**
+ * enum ntb_speed - NTB link training speed
+ * @NTB_SPEED_AUTO:	Request the max supported speed.
+ * @NTB_SPEED_NONE:	Link is not trained to any speed.
+ * @NTB_SPEED_GEN1:	Link is trained to gen1 speed.
+ * @NTB_SPEED_GEN2:	Link is trained to gen2 speed.
+ * @NTB_SPEED_GEN3:	Link is trained to gen3 speed.
+ */
+enum ntb_speed {
+	NTB_SPEED_AUTO = -1,
+	NTB_SPEED_NONE = 0,
+	NTB_SPEED_GEN1 = 1,
+	NTB_SPEED_GEN2 = 2,
+	NTB_SPEED_GEN3 = 3,
+};
+
+/**
+ * enum ntb_width - NTB link training width
+ * @NTB_WIDTH_AUTO:	Request the max supported width.
+ * @NTB_WIDTH_NONE:	Link is not trained to any width.
+ * @NTB_WIDTH_1:	Link is trained to 1 lane width.
+ * @NTB_WIDTH_2:	Link is trained to 2 lane width.
+ * @NTB_WIDTH_4:	Link is trained to 4 lane width.
+ * @NTB_WIDTH_8:	Link is trained to 8 lane width.
+ * @NTB_WIDTH_12:	Link is trained to 12 lane width.
+ * @NTB_WIDTH_16:	Link is trained to 16 lane width.
+ * @NTB_WIDTH_32:	Link is trained to 32 lane width.
+ */
+enum ntb_width {
+	NTB_WIDTH_AUTO = -1,
+	NTB_WIDTH_NONE = 0,
+	NTB_WIDTH_1 = 1,
+	NTB_WIDTH_2 = 2,
+	NTB_WIDTH_4 = 4,
+	NTB_WIDTH_8 = 8,
+	NTB_WIDTH_12 = 12,
+	NTB_WIDTH_16 = 16,
+	NTB_WIDTH_32 = 32,
+};
+
+/**
+ * struct ntb_client_ops - ntb client operations
+ * @probe:		Notify client of a new device.
+ * @remove:		Notify client to remove a device.
+ */
+struct ntb_client_ops {
+	int (*probe)(struct ntb_client *client, struct ntb_dev *ntb);
+	void (*remove)(struct ntb_client *client, struct ntb_dev *ntb);
+};
+
+static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops)
+{
+	/* commented callbacks are not required: */
+	return
+		ops->probe			&&
+		ops->remove			&&
+		1;
+}
+
+/**
+ * struct ntb_ctx_ops - ntb driver context operations
+ * @link_event:		See ntb_link_event().
+ * @db_event:		See ntb_db_event().
+ */
+struct ntb_ctx_ops {
+	void (*link_event)(void *ctx);
+	void (*db_event)(void *ctx, int db_vector);
+};
+
+static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
+{
+	/* commented callbacks are not required: */
+	return
+		/* ops->link_event		&& */
+		/* ops->db_event		&& */
+		1;
+}
+
+/**
+ * struct ntb_ctx_ops - ntb device operations
+ * @mw_count:		See ntb_mw_count().
+ * @mw_get_range:	See ntb_mw_get_range().
+ * @mw_set_trans:	See ntb_mw_set_trans().
+ * @mw_clear_trans:	See ntb_mw_clear_trans().
+ * @link_is_up:		See ntb_link_is_up().
+ * @link_enable:	See ntb_link_enable().
+ * @link_disable:	See ntb_link_disable().
+ * @db_is_unsafe:	See ntb_db_is_unsafe().
+ * @db_valid_mask:	See ntb_db_valid_mask().
+ * @db_vector_count:	See ntb_db_vector_count().
+ * @db_vector_mask:	See ntb_db_vector_mask().
+ * @db_read:		See ntb_db_read().
+ * @db_set:		See ntb_db_set().
+ * @db_clear:		See ntb_db_clear().
+ * @db_read_mask:	See ntb_db_read_mask().
+ * @db_set_mask:	See ntb_db_set_mask().
+ * @db_clear_mask:	See ntb_db_clear_mask().
+ * @peer_db_addr:	See ntb_peer_db_addr().
+ * @peer_db_read:	See ntb_peer_db_read().
+ * @peer_db_set:	See ntb_peer_db_set().
+ * @peer_db_clear:	See ntb_peer_db_clear().
+ * @peer_db_read_mask:	See ntb_peer_db_read_mask().
+ * @peer_db_set_mask:	See ntb_peer_db_set_mask().
+ * @peer_db_clear_mask:	See ntb_peer_db_clear_mask().
+ * @spad_is_unsafe:	See ntb_spad_is_unsafe().
+ * @spad_count:		See ntb_spad_count().
+ * @spad_read:		See ntb_spad_read().
+ * @spad_write:		See ntb_spad_write().
+ * @peer_spad_addr:	See ntb_peer_spad_addr().
+ * @peer_spad_read:	See ntb_peer_spad_read().
+ * @peer_spad_write:	See ntb_peer_spad_write().
+ */
+struct ntb_dev_ops {
+	int (*mw_count)(struct ntb_dev *ntb);
+	int (*mw_get_range)(struct ntb_dev *ntb, int idx,
+			    phys_addr_t *base, resource_size_t *size,
+			resource_size_t *align, resource_size_t *align_size);
+	int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
+			    dma_addr_t addr, resource_size_t size);
+	int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
+
+	int (*link_is_up)(struct ntb_dev *ntb,
+			  enum ntb_speed *speed, enum ntb_width *width);
+	int (*link_enable)(struct ntb_dev *ntb,
+			   enum ntb_speed max_speed, enum ntb_width max_width);
+	int (*link_disable)(struct ntb_dev *ntb);
+
+	int (*db_is_unsafe)(struct ntb_dev *ntb);
+	u64 (*db_valid_mask)(struct ntb_dev *ntb);
+	int (*db_vector_count)(struct ntb_dev *ntb);
+	u64 (*db_vector_mask)(struct ntb_dev *ntb, int db_vector);
+
+	u64 (*db_read)(struct ntb_dev *ntb);
+	int (*db_set)(struct ntb_dev *ntb, u64 db_bits);
+	int (*db_clear)(struct ntb_dev *ntb, u64 db_bits);
+
+	u64 (*db_read_mask)(struct ntb_dev *ntb);
+	int (*db_set_mask)(struct ntb_dev *ntb, u64 db_bits);
+	int (*db_clear_mask)(struct ntb_dev *ntb, u64 db_bits);
+
+	int (*peer_db_addr)(struct ntb_dev *ntb,
+			    phys_addr_t *db_addr, resource_size_t *db_size);
+	u64 (*peer_db_read)(struct ntb_dev *ntb);
+	int (*peer_db_set)(struct ntb_dev *ntb, u64 db_bits);
+	int (*peer_db_clear)(struct ntb_dev *ntb, u64 db_bits);
+
+	u64 (*peer_db_read_mask)(struct ntb_dev *ntb);
+	int (*peer_db_set_mask)(struct ntb_dev *ntb, u64 db_bits);
+	int (*peer_db_clear_mask)(struct ntb_dev *ntb, u64 db_bits);
+
+	int (*spad_is_unsafe)(struct ntb_dev *ntb);
+	int (*spad_count)(struct ntb_dev *ntb);
+
+	u32 (*spad_read)(struct ntb_dev *ntb, int idx);
+	int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+
+	int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
+			      phys_addr_t *spad_addr);
+	u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
+	int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+};
+
+static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
+{
+	/* commented callbacks are not required: */
+	return
+		ops->mw_count				&&
+		ops->mw_get_range			&&
+		ops->mw_set_trans			&&
+		/* ops->mw_clear_trans			&& */
+		ops->link_is_up				&&
+		ops->link_enable			&&
+		ops->link_disable			&&
+		/* ops->db_is_unsafe			&& */
+		ops->db_valid_mask			&&
+
+		/* both set, or both unset */
+		(!ops->db_vector_count == !ops->db_vector_mask) &&
+
+		ops->db_read				&&
+		/* ops->db_set				&& */
+		ops->db_clear				&&
+		/* ops->db_read_mask			&& */
+		ops->db_set_mask			&&
+		ops->db_clear_mask			&&
+		ops->peer_db_addr			&&
+		/* ops->peer_db_read			&& */
+		ops->peer_db_set			&&
+		/* ops->peer_db_clear			&& */
+		/* ops->peer_db_read_mask		&& */
+		/* ops->peer_db_set_mask		&& */
+		/* ops->peer_db_clear_mask		&& */
+		/* ops->spad_is_unsafe			&& */
+		ops->spad_count				&&
+		ops->spad_read				&&
+		ops->spad_write				&&
+		ops->peer_spad_addr			&&
+		/* ops->peer_spad_read			&& */
+		ops->peer_spad_write			&&
+		1;
+}
+
+/**
+ * struct ntb_client - client interested in ntb devices
+ * @drv:		Linux driver object.
+ * @name:		Client driver name.
+ * @ops:		See &ntb_client_ops.
+ */
+struct ntb_client {
+	struct device_driver		drv;
+	const char			*name;
+	const struct ntb_client_ops	ops;
+};
+
+#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
+
+/**
+ * struct ntb_device - ntb device
+ * @dev:		Linux device object.
+ * @pdev:		Pci device entry of the ntb.
+ * @topo:		Detected topology of the ntb.
+ * @ops:		See &ntb_dev_ops.
+ * @ctx:		See &ntb_ctx_ops.
+ * @ctx_ops:		See &ntb_ctx_ops.
+ * @ctx_lock:		Synchronize operations on ctx.
+ */
+struct ntb_dev {
+	struct device			dev;
+	struct pci_dev			*pdev;
+	enum ntb_topo			topo;
+	const struct ntb_dev_ops	*ops;
+	void				*ctx;
+	const struct ntb_ctx_ops	*ctx_ops;
+
+	/* private: */
+
+	/* synchronize setting, clearing, and calling ctx_ops */
+	spinlock_t			ctx_lock;
+	/* block unregister until device is fully released */
+	struct completion		released;
+};
+
+#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
+
+/**
+ * ntb_register_client() - register a client for interest in ntb devices
+ * @client:	Client context.
+ *
+ * The client will be added to the list of clients interested in ntb devices.
+ * The client will be notified of any ntb devices that are not already
+ * associated with a client, or if ntb devices are registered later.
+ *
+ * Return: Zero if the client is registered, otherwise an error number.
+ */
+int ntb_register_client(struct ntb_client *client);
+
+/**
+ * ntb_unregister_client() - unregister a client for interest in ntb devices
+ * @client:	Client context.
+ *
+ * The client will be removed from the list of clients interested in ntb
+ * devices.  If any ntb devices are associated with the client, the client will
+ * be notified to remove those devices.
+ */
+void ntb_unregister_client(struct ntb_client *client);
+
+#define module_ntb_client(__ntb_client) \
+	module_driver(__ntb_client, ntb_register_client, \
+			ntb_unregister_client)
+
+/**
+ * ntb_register_device() - register a ntb device
+ * @ntb:	NTB device context.
+ *
+ * The device will be added to the list of ntb devices.  If any clients are
+ * interested in ntb devices, each client will be notified of the ntb device,
+ * until at most one client accepts the device.
+ *
+ * Return: Zero if the device is registered, otherwise an error number.
+ */
+int ntb_register_device(struct ntb_dev *ntb);
+
+/**
+ * ntb_register_device() - unregister a ntb device
+ * @ntb:	NTB device context.
+ *
+ * The device will be removed from the list of ntb devices.  If the ntb device
+ * is associated with a client, the client will be notified to remove the
+ * device.
+ */
+void ntb_unregister_device(struct ntb_dev *ntb);
+
+/**
+ * ntb_set_ctx() - associate a driver context with an ntb device
+ * @ntb:	NTB device context.
+ * @ctx:	Driver context.
+ * @ctx_ops:	Driver context operations.
+ *
+ * Associate a driver context and operations with a ntb device.  The context is
+ * provided by the client driver, and the driver may associate a different
+ * context with each ntb device.
+ *
+ * Return: Zero if the context is associated, otherwise an error number.
+ */
+int ntb_set_ctx(struct ntb_dev *ntb, void *ctx,
+		const struct ntb_ctx_ops *ctx_ops);
+
+/**
+ * ntb_clear_ctx() - disassociate any driver context from an ntb device
+ * @ntb:	NTB device context.
+ *
+ * Clear any association that may exist between a driver context and the ntb
+ * device.
+ */
+void ntb_clear_ctx(struct ntb_dev *ntb);
+
+/**
+ * ntb_link_event() - notify driver context of a change in link status
+ * @ntb:	NTB device context.
+ *
+ * Notify the driver context that the link status may have changed.  The driver
+ * should call ntb_link_is_up() to get the current status.
+ */
+void ntb_link_event(struct ntb_dev *ntb);
+
+/**
+ * ntb_db_event() - notify driver context of a doorbell event
+ * @ntb:	NTB device context.
+ * @vector:	Interrupt vector number.
+ *
+ * Notify the driver context of a doorbell event.  If hardware supports
+ * multiple interrupt vectors for doorbells, the vector number indicates which
+ * vector received the interrupt.  The vector number is relative to the first
+ * vector used for doorbells, starting at zero, and must be less than
+ ** ntb_db_vector_count().  The driver may call ntb_db_read() to check which
+ * doorbell bits need service, and ntb_db_vector_mask() to determine which of
+ * those bits are associated with the vector number.
+ */
+void ntb_db_event(struct ntb_dev *ntb, int vector);
+
+/**
+ * ntb_mw_count() - get the number of memory windows
+ * @ntb:	NTB device context.
+ *
+ * Hardware and topology may support a different number of memory windows.
+ *
+ * Return: the number of memory windows.
+ */
+static inline int ntb_mw_count(struct ntb_dev *ntb)
+{
+	return ntb->ops->mw_count(ntb);
+}
+
+/**
+ * ntb_mw_get_range() - get the range of a memory window
+ * @ntb:	NTB device context.
+ * @idx:	Memory window number.
+ * @base:	OUT - the base address for mapping the memory window
+ * @size:	OUT - the size for mapping the memory window
+ * @align:	OUT - the base alignment for translating the memory window
+ * @align_size:	OUT - the size alignment for translating the memory window
+ *
+ * Get the range of a memory window.  NULL may be given for any output
+ * parameter if the value is not needed.  The base and size may be used for
+ * mapping the memory window, to access the peer memory.  The alignment and
+ * size may be used for translating the memory window, for the peer to access
+ * memory on the local system.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
+				   phys_addr_t *base, resource_size_t *size,
+		resource_size_t *align, resource_size_t *align_size)
+{
+	return ntb->ops->mw_get_range(ntb, idx, base, size,
+			align, align_size);
+}
+
+/**
+ * ntb_mw_set_trans() - set the translation of a memory window
+ * @ntb:	NTB device context.
+ * @idx:	Memory window number.
+ * @addr:	The dma address local memory to expose to the peer.
+ * @size:	The size of the local memory to expose to the peer.
+ *
+ * Set the translation of a memory window.  The peer may access local memory
+ * through the window starting at the address, up to the size.  The address
+ * must be aligned to the alignment specified by ntb_mw_get_range().  The size
+ * must be aligned to the size alignment specified by ntb_mw_get_range().
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+				   dma_addr_t addr, resource_size_t size)
+{
+	return ntb->ops->mw_set_trans(ntb, idx, addr, size);
+}
+
+/**
+ * ntb_mw_clear_trans() - clear the translation of a memory window
+ * @ntb:	NTB device context.
+ * @idx:	Memory window number.
+ *
+ * Clear the translation of a memory window.  The peer may no longer access
+ * local memory through the window.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
+{
+	if (!ntb->ops->mw_clear_trans)
+		return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
+
+	return ntb->ops->mw_clear_trans(ntb, idx);
+}
+
+/**
+ * ntb_link_is_up() - get the current ntb link state
+ * @ntb:	NTB device context.
+ * @speed:	OUT - The link speed expressed as PCIe generation number.
+ * @width:	OUT - The link width expressed as the number of PCIe lanes.
+ *
+ * Set the translation of a memory window.  The peer may access local memory
+ * through the window starting at the address, up to the size.  The address
+ * must be aligned to the alignment specified by ntb_mw_get_range().  The size
+ * must be aligned to the size alignment specified by ntb_mw_get_range().
+ *
+ * Return: One if the link is up, zero if the link is down, otherwise a
+ *		negative value indicating the error number.
+ */
+static inline int ntb_link_is_up(struct ntb_dev *ntb,
+				 enum ntb_speed *speed, enum ntb_width *width)
+{
+	return ntb->ops->link_is_up(ntb, speed, width);
+}
+
+/**
+ * ntb_link_enable() - enable the link on the secondary side of the ntb
+ * @ntb:	NTB device context.
+ * @max_speed:	The maximum link speed expressed as PCIe generation number.
+ * @max_width:	The maximum link width expressed as the number of PCIe lanes.
+ *
+ * Enable the link on the secondary side of the ntb.  This can only be done
+ * from the primary side of the ntb in primary or b2b topology.  The ntb device
+ * should train the link to its maximum speed and width, or the requested speed
+ * and width, whichever is smaller, if supported.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_link_enable(struct ntb_dev *ntb,
+				  enum ntb_speed max_speed,
+				  enum ntb_width max_width)
+{
+	return ntb->ops->link_enable(ntb, max_speed, max_width);
+}
+
+/**
+ * ntb_link_disable() - disable the link on the secondary side of the ntb
+ * @ntb:	NTB device context.
+ *
+ * Disable the link on the secondary side of the ntb.  This can only be
+ * done from the primary side of the ntb in primary or b2b topology.  The ntb
+ * device should disable the link.  Returning from this call must indicate that
+ * a barrier has passed, though with no more writes may pass in either
+ * direction across the link, except if this call returns an error number.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_link_disable(struct ntb_dev *ntb)
+{
+	return ntb->ops->link_disable(ntb);
+}
+
+/**
+ * ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
+ * @ntb:	NTB device context.
+ *
+ * It is possible for some ntb hardware to be affected by errata.  Hardware
+ * drivers can advise clients to avoid using doorbells.  Clients may ignore
+ * this advice, though caution is recommended.
+ *
+ * Return: Zero if it is safe to use doorbells, or One if it is not safe.
+ */
+static inline int ntb_db_is_unsafe(struct ntb_dev *ntb)
+{
+	if (!ntb->ops->db_is_unsafe)
+		return 0;
+
+	return ntb->ops->db_is_unsafe(ntb);
+}
+
+/**
+ * ntb_db_valid_mask() - get a mask of doorbell bits supported by the ntb
+ * @ntb:	NTB device context.
+ *
+ * Hardware may support different number or arrangement of doorbell bits.
+ *
+ * Return: A mask of doorbell bits supported by the ntb.
+ */
+static inline u64 ntb_db_valid_mask(struct ntb_dev *ntb)
+{
+	return ntb->ops->db_valid_mask(ntb);
+}
+
+/**
+ * ntb_db_vector_count() - get the number of doorbell interrupt vectors
+ * @ntb:	NTB device context.
+ *
+ * Hardware may support different number of interrupt vectors.
+ *
+ * Return: The number of doorbell interrupt vectors.
+ */
+static inline int ntb_db_vector_count(struct ntb_dev *ntb)
+{
+	if (!ntb->ops->db_vector_count)
+		return 1;
+
+	return ntb->ops->db_vector_count(ntb);
+}
+
+/**
+ * ntb_db_vector_mask() - get a mask of doorbell bits serviced by a vector
+ * @ntb:	NTB device context.
+ * @vector:	Doorbell vector number.
+ *
+ * Each interrupt vector may have a different number or arrangement of bits.
+ *
+ * Return: A mask of doorbell bits serviced by a vector.
+ */
+static inline u64 ntb_db_vector_mask(struct ntb_dev *ntb, int vector)
+{
+	if (!ntb->ops->db_vector_mask)
+		return ntb_db_valid_mask(ntb);
+
+	return ntb->ops->db_vector_mask(ntb, vector);
+}
+
+/**
+ * ntb_db_read() - read the local doorbell register
+ * @ntb:	NTB device context.
+ *
+ * Read the local doorbell register, and return the bits that are set.
+ *
+ * Return: The bits currently set in the local doorbell register.
+ */
+static inline u64 ntb_db_read(struct ntb_dev *ntb)
+{
+	return ntb->ops->db_read(ntb);
+}
+
+/**
+ * ntb_db_set() - set bits in the local doorbell register
+ * @ntb:	NTB device context.
+ * @db_bits:	Doorbell bits to set.
+ *
+ * Set bits in the local doorbell register, which may generate a local doorbell
+ * interrupt.  Bits that were already set must remain set.
+ *
+ * This is unusual, and hardware may not support it.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_db_set(struct ntb_dev *ntb, u64 db_bits)
+{
+	if (!ntb->ops->db_set)
+		return -EINVAL;
+
+	return ntb->ops->db_set(ntb, db_bits);
+}
+
+/**
+ * ntb_db_clear() - clear bits in the local doorbell register
+ * @ntb:	NTB device context.
+ * @db_bits:	Doorbell bits to clear.
+ *
+ * Clear bits in the local doorbell register, arming the bits for the next
+ * doorbell.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+	return ntb->ops->db_clear(ntb, db_bits);
+}
+
+/**
+ * ntb_db_read_mask() - read the local doorbell mask
+ * @ntb:	NTB device context.
+ *
+ * Read the local doorbell mask register, and return the bits that are set.
+ *
+ * This is unusual, though hardware is likely to support it.
+ *
+ * Return: The bits currently set in the local doorbell mask register.
+ */
+static inline u64 ntb_db_read_mask(struct ntb_dev *ntb)
+{
+	if (!ntb->ops->db_read_mask)
+		return 0;
+
+	return ntb->ops->db_read_mask(ntb);
+}
+
+/**
+ * ntb_db_set_mask() - set bits in the local doorbell mask
+ * @ntb:	NTB device context.
+ * @db_bits:	Doorbell mask bits to set.
+ *
+ * Set bits in the local doorbell mask register, preventing doorbell interrupts
+ * from being generated for those doorbell bits.  Bits that were already set
+ * must remain set.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	return ntb->ops->db_set_mask(ntb, db_bits);
+}
+
+/**
+ * ntb_db_clear_mask() - clear bits in the local doorbell mask
+ * @ntb:	NTB device context.
+ * @db_bits:	Doorbell bits to clear.
+ *
+ * Clear bits in the local doorbell mask register, allowing doorbell interrupts
+ * from being generated for those doorbell bits.  If a doorbell bit is already
+ * set at the time the mask is cleared, and the corresponding mask bit is
+ * changed from set to clear, then the ntb driver must ensure that
+ * ntb_db_event() is called.  If the hardware does not generate the interrupt
+ * on clearing the mask bit, then the driver must call ntb_db_event() anyway.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	return ntb->ops->db_clear_mask(ntb, db_bits);
+}
+
+/**
+ * ntb_peer_db_addr() - address and size of the peer doorbell register
+ * @ntb:	NTB device context.
+ * @db_addr:	OUT - The address of the peer doorbell register.
+ * @db_size:	OUT - The number of bytes to write the peer doorbell register.
+ *
+ * Return the address of the peer doorbell register.  This may be used, for
+ * example, by drivers that offload memory copy operations to a dma engine.
+ * The drivers may wish to ring the peer doorbell at the completion of memory
+ * copy operations.  For efficiency, and to simplify ordering of operations
+ * between the dma memory copies and the ringing doorbell, the driver may
+ * append one additional dma memory copy with the doorbell register as the
+ * destination, after the memory copy operations.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_db_addr(struct ntb_dev *ntb,
+				   phys_addr_t *db_addr,
+				   resource_size_t *db_size)
+{
+	return ntb->ops->peer_db_addr(ntb, db_addr, db_size);
+}
+
+/**
+ * ntb_peer_db_read() - read the peer doorbell register
+ * @ntb:	NTB device context.
+ *
+ * Read the peer doorbell register, and return the bits that are set.
+ *
+ * This is unusual, and hardware may not support it.
+ *
+ * Return: The bits currently set in the peer doorbell register.
+ */
+static inline u64 ntb_peer_db_read(struct ntb_dev *ntb)
+{
+	if (!ntb->ops->peer_db_read)
+		return 0;
+
+	return ntb->ops->peer_db_read(ntb);
+}
+
+/**
+ * ntb_peer_db_set() - set bits in the peer doorbell register
+ * @ntb:	NTB device context.
+ * @db_bits:	Doorbell bits to set.
+ *
+ * Set bits in the peer doorbell register, which may generate a peer doorbell
+ * interrupt.  Bits that were already set must remain set.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
+{
+	return ntb->ops->peer_db_set(ntb, db_bits);
+}
+
+/**
+ * ntb_peer_db_clear() - clear bits in the local doorbell register
+ * @ntb:	NTB device context.
+ * @db_bits:	Doorbell bits to clear.
+ *
+ * Clear bits in the peer doorbell register, arming the bits for the next
+ * doorbell.
+ *
+ * This is unusual, and hardware may not support it.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+	if (!ntb->ops->db_clear)
+		return -EINVAL;
+
+	return ntb->ops->peer_db_clear(ntb, db_bits);
+}
+
+/**
+ * ntb_peer_db_read_mask() - read the peer doorbell mask
+ * @ntb:	NTB device context.
+ *
+ * Read the peer doorbell mask register, and return the bits that are set.
+ *
+ * This is unusual, and hardware may not support it.
+ *
+ * Return: The bits currently set in the peer doorbell mask register.
+ */
+static inline u64 ntb_peer_db_read_mask(struct ntb_dev *ntb)
+{
+	if (!ntb->ops->db_read_mask)
+		return 0;
+
+	return ntb->ops->peer_db_read_mask(ntb);
+}
+
+/**
+ * ntb_peer_db_set_mask() - set bits in the peer doorbell mask
+ * @ntb:	NTB device context.
+ * @db_bits:	Doorbell mask bits to set.
+ *
+ * Set bits in the peer doorbell mask register, preventing doorbell interrupts
+ * from being generated for those doorbell bits.  Bits that were already set
+ * must remain set.
+ *
+ * This is unusual, and hardware may not support it.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	if (!ntb->ops->db_set_mask)
+		return -EINVAL;
+
+	return ntb->ops->peer_db_set_mask(ntb, db_bits);
+}
+
+/**
+ * ntb_peer_db_clear_mask() - clear bits in the peer doorbell mask
+ * @ntb:	NTB device context.
+ * @db_bits:	Doorbell bits to clear.
+ *
+ * Clear bits in the peer doorbell mask register, allowing doorbell interrupts
+ * from being generated for those doorbell bits.  If the hardware does not
+ * generate the interrupt on clearing the mask bit, then the driver should not
+ * implement this function!
+ *
+ * This is unusual, and hardware may not support it.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	if (!ntb->ops->db_clear_mask)
+		return -EINVAL;
+
+	return ntb->ops->peer_db_clear_mask(ntb, db_bits);
+}
+
+/**
+ * ntb_spad_is_unsafe() - check if it is safe to use the hardware scratchpads
+ * @ntb:	NTB device context.
+ *
+ * It is possible for some ntb hardware to be affected by errata.  Hardware
+ * drivers can advise clients to avoid using scratchpads.  Clients may ignore
+ * this advice, though caution is recommended.
+ *
+ * Return: Zero if it is safe to use scratchpads, or One if it is not safe.
+ */
+static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
+{
+	if (!ntb->ops->spad_is_unsafe)
+		return 0;
+
+	return ntb->ops->spad_is_unsafe(ntb);
+}
+
+/**
+ * ntb_mw_count() - get the number of scratchpads
+ * @ntb:	NTB device context.
+ *
+ * Hardware and topology may support a different number of scratchpads.
+ *
+ * Return: the number of scratchpads.
+ */
+static inline int ntb_spad_count(struct ntb_dev *ntb)
+{
+	return ntb->ops->spad_count(ntb);
+}
+
+/**
+ * ntb_spad_read() - read the local scratchpad register
+ * @ntb:	NTB device context.
+ * @idx:	Scratchpad index.
+ *
+ * Read the local scratchpad register, and return the value.
+ *
+ * Return: The value of the local scratchpad register.
+ */
+static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
+{
+	return ntb->ops->spad_read(ntb, idx);
+}
+
+/**
+ * ntb_spad_write() - write the local scratchpad register
+ * @ntb:	NTB device context.
+ * @idx:	Scratchpad index.
+ * @val:	Scratchpad value.
+ *
+ * Write the value to the local scratchpad register.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+{
+	return ntb->ops->spad_write(ntb, idx, val);
+}
+
+/**
+ * ntb_peer_spad_addr() - address of the peer scratchpad register
+ * @ntb:	NTB device context.
+ * @idx:	Scratchpad index.
+ * @spad_addr:	OUT - The address of the peer scratchpad register.
+ *
+ * Return the address of the peer doorbell register.  This may be used, for
+ * example, by drivers that offload memory copy operations to a dma engine.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+				     phys_addr_t *spad_addr)
+{
+	return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
+}
+
+/**
+ * ntb_peer_spad_read() - read the peer scratchpad register
+ * @ntb:	NTB device context.
+ * @idx:	Scratchpad index.
+ *
+ * Read the peer scratchpad register, and return the value.
+ *
+ * Return: The value of the local scratchpad register.
+ */
+static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+{
+	return ntb->ops->peer_spad_read(ntb, idx);
+}
+
+/**
+ * ntb_peer_spad_write() - write the peer scratchpad register
+ * @ntb:	NTB device context.
+ * @idx:	Scratchpad index.
+ * @val:	Scratchpad value.
+ *
+ * Write the value to the peer scratchpad register.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+{
+	return ntb->ops->peer_spad_write(ntb, idx, val);
+}
+
+#endif
diff --git a/include/linux/ntb_transport.h b/include/linux/ntb_transport.h
index 9ac1a62..2862861 100644
--- a/include/linux/ntb_transport.h
+++ b/include/linux/ntb_transport.h
@@ -5,6 +5,7 @@
  *   GPL LICENSE SUMMARY
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
  *   BSD LICENSE
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -40,7 +42,7 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Intel PCIe NTB Linux driver
+ * PCIe NTB Transport Linux driver
  *
  * Contact Information:
  * Jon Mason <jon.mason@intel.com>
@@ -48,21 +50,16 @@
 
 struct ntb_transport_qp;
 
-struct ntb_client {
+struct ntb_transport_client {
 	struct device_driver driver;
-	int (*probe)(struct pci_dev *pdev);
-	void (*remove)(struct pci_dev *pdev);
+	int (*probe)(struct device *client_dev);
+	void (*remove)(struct device *client_dev);
 };
 
-enum {
-	NTB_LINK_DOWN = 0,
-	NTB_LINK_UP,
-};
-
-int ntb_register_client(struct ntb_client *drvr);
-void ntb_unregister_client(struct ntb_client *drvr);
-int ntb_register_client_dev(char *device_name);
-void ntb_unregister_client_dev(char *device_name);
+int ntb_transport_register_client(struct ntb_transport_client *drvr);
+void ntb_transport_unregister_client(struct ntb_transport_client *drvr);
+int ntb_transport_register_client_dev(char *device_name);
+void ntb_transport_unregister_client_dev(char *device_name);
 
 struct ntb_queue_handlers {
 	void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
@@ -75,7 +72,7 @@ struct ntb_queue_handlers {
 unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp);
 unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp);
 struct ntb_transport_qp *
-ntb_transport_create_queue(void *data, struct pci_dev *pdev,
+ntb_transport_create_queue(void *data, struct device *client_dev,
 			   const struct ntb_queue_handlers *handlers);
 void ntb_transport_free_queue(struct ntb_transport_qp *qp);
 int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
  2015-05-20 15:41 ` [PATCH 01/16] Move files in preparation for NTB Abstraction Allen Hubbe
  2015-05-20 15:41 ` [PATCH 02/16] NTB Abstraction Layer Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 21:21   ` Bjorn Helgaas
  2015-05-20 15:41 ` [PATCH 04/16] Check the DID for certain workaround error flags to be set Allen Hubbe
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang

From: Dave Jiang <dave.jiang@intel.com>

Link training for RP should be enabled in the driver probe. We should
not have to wait for transport loaded for this to hapen. Otherwise the
device will not show up on the transparent bridge side.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/ntb/hw/intel/ntb_hw_intel.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 05c4b77..d162f22 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -1333,6 +1333,9 @@ static int snb_poll_link(struct intel_ntb_dev *ndev)
 
 static int snb_link_is_up(struct intel_ntb_dev *ndev)
 {
+	if (ndev->ntb.topo == NTB_TOPO_SEC)
+		return 1;
+
 	return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
 }
 
@@ -1642,6 +1645,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
 static int snb_init_ntb(struct intel_ntb_dev *ndev)
 {
 	int rc;
+	u32 ntb_ctl;
 
 	if (ndev->bar4_split)
 		ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
@@ -1658,6 +1662,12 @@ static int snb_init_ntb(struct intel_ntb_dev *ndev)
 			dev_err(ndev_dev(ndev), "NTB Primary config disabled\n");
 			return -EINVAL;
 		}
+
+		/* enable link to allow secondary side device to appear */
+		ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+		ntb_ctl &= ~NTB_CTL_DISABLE;
+		iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
 		/* use half the spads for the peer */
 		ndev->spad_count >>= 1;
 		ndev->self_reg = &snb_pri_reg;
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 04/16] Check the DID for certain workaround error flags to be set.
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (2 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 21:11   ` Bjorn Helgaas
  2015-05-20 15:41 ` [PATCH 05/16] Intel NTB params for snb b2b addresses Allen Hubbe
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang

From: Dave Jiang <dave.jiang@intel.com>

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/ntb/hw/intel/ntb_hw_intel.c | 196 +++++++++++++++++++-----------------
 drivers/ntb/hw/intel/ntb_hw_intel.h |  24 ++++-
 drivers/ntb/ntb_transport.c         |  16 +--
 3 files changed, 133 insertions(+), 103 deletions(-)

diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index d162f22..89fea50 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -503,7 +503,6 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
 	size_t buf_size;
 	ssize_t ret, off;
 	union { u64 v64; u32 v32; u16 v16; } u;
-	unsigned long reg;
 
 	ndev = filp->private_data;
 	mmio = ndev->self_mmio;
@@ -538,10 +537,10 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
 
 	if (!ndev->reg->link_is_up(ndev)) {
 		off += scnprintf(buf + off, buf_size - off,
-				 "Link Satus -\t\tDown\n");
+				 "Link Status -\t\tDown\n");
 	} else {
 		off += scnprintf(buf + off, buf_size - off,
-				 "Link Satus -\t\tUp\n");
+				 "Link Status -\t\tUp\n");
 		off += scnprintf(buf + off, buf_size - off,
 				 "Link Speed -\t\tPCI-E Gen %u\n",
 				 NTB_LNK_STA_SPEED(ndev->lnk_sta));
@@ -568,36 +567,30 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
 	off += scnprintf(buf + off, buf_size - off,
 			 "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
 
-	reg = ndev->self_reg->db_mask;
-	u.v64 = ndev_db_read(ndev, mmio + reg);
+	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask);
 	off += scnprintf(buf + off, buf_size - off,
 			 "Doorbell Mask -\t\t%#llx\n", u.v64);
 
-	reg = ndev->self_reg->db_bell;
-	u.v64 = ndev_db_read(ndev, mmio + reg);
+	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell);
 	off += scnprintf(buf + off, buf_size - off,
 			 "Doorbell Bell -\t\t%#llx\n", u.v64);
 
 	off += scnprintf(buf + off, buf_size - off,
 			 "\nNTB Incoming XLAT:\n");
 
-	reg = bar2_off(ndev->xlat_reg->bar2_xlat, 2);
-	u.v64 = ioread64(mmio + reg);
+	u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2));
 	off += scnprintf(buf + off, buf_size - off,
 			 "XLAT23 -\t\t%#018llx\n", u.v64);
 
-	reg = bar2_off(ndev->xlat_reg->bar2_xlat, 4);
-	u.v64 = ioread64(mmio + reg);
+	u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4));
 	off += scnprintf(buf + off, buf_size - off,
 			 "XLAT45 -\t\t%#018llx\n", u.v64);
 
-	reg = bar2_off(ndev->xlat_reg->bar2_limit, 2);
-	u.v64 = ioread64(mmio + reg);
+	u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2));
 	off += scnprintf(buf + off, buf_size - off,
 			 "LMT23 -\t\t\t%#018llx\n", u.v64);
 
-	reg = bar2_off(ndev->xlat_reg->bar2_limit, 4);
-	u.v64 = ioread64(mmio + reg);
+	u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4));
 	off += scnprintf(buf + off, buf_size - off,
 			 "LMT45 -\t\t\t%#018llx\n", u.v64);
 
@@ -606,41 +599,34 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
 			off += scnprintf(buf + off, buf_size - off,
 					 "\nNTB Outgoing B2B XLAT:\n");
 
-			reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 2);
-			u.v64 = ioread64(mmio + reg);
+			u.v64 = ioread64(mmio + SNB_PBAR23XLAT_OFFSET);
 			off += scnprintf(buf + off, buf_size - off,
 					 "B2B XLAT23 -\t\t%#018llx\n", u.v64);
 
-			reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 4);
-			u.v64 = ioread64(mmio + reg);
+			u.v64 = ioread64(mmio + SNB_PBAR45XLAT_OFFSET);
 			off += scnprintf(buf + off, buf_size - off,
 					 "B2B XLAT45 -\t\t%#018llx\n", u.v64);
 
-			reg = bar2_off(SNB_PBAR2LMT_OFFSET, 2);
-			u.v64 = ioread64(mmio + reg);
+			u.v64 = ioread64(mmio + SNB_PBAR23LMT_OFFSET);
 			off += scnprintf(buf + off, buf_size - off,
 					 "B2B LMT23 -\t\t%#018llx\n", u.v64);
 
-			reg = bar2_off(SNB_PBAR2LMT_OFFSET, 4);
-			u.v64 = ioread64(mmio + reg);
+			u.v64 = ioread64(mmio + SNB_PBAR45LMT_OFFSET);
 			off += scnprintf(buf + off, buf_size - off,
 					 "B2B LMT45 -\t\t%#018llx\n", u.v64);
 
 			off += scnprintf(buf + off, buf_size - off,
 					 "\nNTB Secondary BAR:\n");
 
-			reg = bar0_off(SNB_SBAR0BASE_OFFSET, 0);
-			u.v64 = ioread64(mmio + reg);
+			u.v64 = ioread64(mmio + SNB_SBAR0BASE_OFFSET);
 			off += scnprintf(buf + off, buf_size - off,
 					 "SBAR01 -\t\t%#018llx\n", u.v64);
 
-			reg = bar0_off(SNB_SBAR0BASE_OFFSET, 2);
-			u.v64 = ioread64(mmio + reg);
+			u.v64 = ioread64(mmio + SNB_SBAR23BASE_OFFSET);
 			off += scnprintf(buf + off, buf_size - off,
 					 "SBAR23 -\t\t%#018llx\n", u.v64);
 
-			reg = bar0_off(SNB_SBAR0BASE_OFFSET, 4);
-			u.v64 = ioread64(mmio + reg);
+			u.v64 = ioread64(mmio + SNB_SBAR45BASE_OFFSET);
 			off += scnprintf(buf + off, buf_size - off,
 					 "SBAR45 -\t\t%#018llx\n", u.v64);
 		}
@@ -648,31 +634,30 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
 		off += scnprintf(buf + off, buf_size - off,
 				 "\nSNB NTB Statistics:\n");
 
-		reg = SNB_USMEMMISS_OFFSET;
-		u.v16 = ioread16(mmio + reg);
+		u.v16 = ioread16(mmio + SNB_USMEMMISS_OFFSET);
 		off += scnprintf(buf + off, buf_size - off,
 				 "Upstream Memory Miss -\t%u\n", u.v16);
 
 		off += scnprintf(buf + off, buf_size - off,
 				 "\nSNB NTB Hardware Errors:\n");
 
-		reg = SNB_DEVSTS_OFFSET;
-		if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
+		if (!pci_read_config_word(ndev->ntb.pdev,
+					  SNB_DEVSTS_OFFSET, &u.v16))
 			off += scnprintf(buf + off, buf_size - off,
 					 "DEVSTS -\t\t%#06x\n", u.v16);
 
-		reg = SNB_LINK_STATUS_OFFSET;
-		if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
+		if (!pci_read_config_word(ndev->ntb.pdev,
+					  SNB_LINK_STATUS_OFFSET, &u.v16))
 			off += scnprintf(buf + off, buf_size - off,
 					 "LNKSTS -\t\t%#06x\n", u.v16);
 
-		reg = SNB_UNCERRSTS_OFFSET;
-		if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
+		if (!pci_read_config_dword(ndev->ntb.pdev,
+					   SNB_UNCERRSTS_OFFSET, &u.v32))
 			off += scnprintf(buf + off, buf_size - off,
 					 "UNCERRSTS -\t\t%#06x\n", u.v32);
 
-		reg = SNB_CORERRSTS_OFFSET;
-		if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
+		if (!pci_read_config_dword(ndev->ntb.pdev,
+					   SNB_CORERRSTS_OFFSET, &u.v32))
 			off += scnprintf(buf + off, buf_size - off,
 					 "CORERRSTS -\t\t%#06x\n", u.v32);
 	}
@@ -1388,7 +1373,6 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
 {
 	struct pci_dev *pdev;
 	void __iomem *mmio;
-	unsigned long off;
 	resource_size_t bar_size;
 	phys_addr_t bar_addr;
 	int b2b_bar;
@@ -1484,9 +1468,6 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
 		dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz);
 	}
 
-	/* setup incoming bar base addresses */
-	off = SNB_SBAR0BASE_OFFSET;
-
 	/* SBAR01 hit by first part of the b2b bar */
 	if (b2b_bar == 0) {
 		bar_addr = addr->bar0_addr;
@@ -1504,7 +1485,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
 	}
 
 	dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr);
-	iowrite64(bar_addr, mmio + bar0_off(off, 0));
+	iowrite64(bar_addr, mmio + SNB_SBAR0BASE_OFFSET);
 
 	/* Other SBAR are normally hit by the PBAR xlat, except for b2b bar.
 	 * The b2b bar is either disabled above, or configured half-size, and
@@ -1512,102 +1493,96 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
 	 */
 
 	bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
-	iowrite64(bar_addr, mmio + bar0_off(off, 2));
-	bar_addr = ioread64(mmio + bar0_off(off, 2));
+	iowrite64(bar_addr, mmio + SNB_SBAR23BASE_OFFSET);
+	bar_addr = ioread64(mmio + SNB_SBAR23BASE_OFFSET);
 	dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr);
 
 	if (!ndev->bar4_split) {
 		bar_addr = addr->bar4_addr64 +
 			(b2b_bar == 4 ? ndev->b2b_off : 0);
-		iowrite64(bar_addr, mmio + bar0_off(off, 4));
-		bar_addr = ioread64(mmio + bar0_off(off, 4));
+		iowrite64(bar_addr, mmio + SNB_SBAR45BASE_OFFSET);
+		bar_addr = ioread64(mmio + SNB_SBAR45BASE_OFFSET);
 		dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr);
 	} else {
 		bar_addr = addr->bar4_addr32 +
 			(b2b_bar == 4 ? ndev->b2b_off : 0);
-		iowrite32(bar_addr, mmio + bar0_off(off, 4));
-		bar_addr = ioread32(mmio + bar0_off(off, 4));
+		iowrite32(bar_addr, mmio + SNB_SBAR4BASE_OFFSET);
+		bar_addr = ioread32(mmio + SNB_SBAR4BASE_OFFSET);
 		dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr);
 
 		bar_addr = addr->bar5_addr32 +
 			(b2b_bar == 5 ? ndev->b2b_off : 0);
-		iowrite32(bar_addr, mmio + bar0_off(off, 5));
-		bar_addr = ioread32(mmio + bar0_off(off, 5));
+		iowrite32(bar_addr, mmio + SNB_SBAR5BASE_OFFSET);
+		bar_addr = ioread32(mmio + SNB_SBAR5BASE_OFFSET);
 		dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr);
 	}
 
 	/* setup incoming bar limits == base addrs (zero length windows) */
-	off = SNB_SBAR2LMT_OFFSET;
 
 	bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
-	iowrite64(bar_addr, mmio + bar2_off(off, 2));
-	bar_addr = ioread64(mmio + bar2_off(off, 2));
+	iowrite64(bar_addr, mmio + SNB_SBAR23LMT_OFFSET);
+	bar_addr = ioread64(mmio + SNB_SBAR23LMT_OFFSET);
 	dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr);
 
 	if (!ndev->bar4_split) {
 		bar_addr = addr->bar4_addr64 +
 			(b2b_bar == 4 ? ndev->b2b_off : 0);
-		iowrite64(bar_addr, mmio + bar2_off(off, 4));
-		bar_addr = ioread64(mmio + bar2_off(off, 4));
+		iowrite64(bar_addr, mmio + SNB_SBAR45LMT_OFFSET);
+		bar_addr = ioread64(mmio + SNB_SBAR45LMT_OFFSET);
 		dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr);
 	} else {
 		bar_addr = addr->bar4_addr32 +
 			(b2b_bar == 4 ? ndev->b2b_off : 0);
-		iowrite32(bar_addr, mmio + bar2_off(off, 4));
-		bar_addr = ioread32(mmio + bar2_off(off, 4));
+		iowrite32(bar_addr, mmio + SNB_SBAR4LMT_OFFSET);
+		bar_addr = ioread32(mmio + SNB_SBAR4LMT_OFFSET);
 		dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr);
 
 		bar_addr = addr->bar5_addr32 +
 			(b2b_bar == 5 ? ndev->b2b_off : 0);
-		iowrite32(bar_addr, mmio + bar2_off(off, 5));
-		bar_addr = ioread32(mmio + bar2_off(off, 5));
+		iowrite32(bar_addr, mmio + SNB_SBAR5LMT_OFFSET);
+		bar_addr = ioread32(mmio + SNB_SBAR5LMT_OFFSET);
 		dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr);
 	}
 
 	/* zero incoming translation addrs */
-	off = SNB_SBAR2XLAT_OFFSET;
-
-	iowrite64(0, mmio + bar2_off(off, 2));
+	iowrite64(0, mmio + SNB_SBAR23XLAT_OFFSET);
 
 	if (!ndev->bar4_split) {
-		iowrite64(0, mmio + bar2_off(off, 4));
+		iowrite64(0, mmio + SNB_SBAR45XLAT_OFFSET);
 	} else {
-		iowrite32(0, mmio + bar2_off(off, 4));
-		iowrite32(0, mmio + bar2_off(off, 5));
+		iowrite32(0, mmio + SNB_SBAR4XLAT_OFFSET);
+		iowrite32(0, mmio + SNB_SBAR5XLAT_OFFSET);
 	}
 
 	/* zero outgoing translation limits (whole bar size windows) */
-	off = SNB_PBAR2LMT_OFFSET;
-	iowrite64(0, mmio + bar2_off(off, 2));
+	iowrite64(0, mmio + SNB_PBAR23LMT_OFFSET);
 	if (!ndev->bar4_split) {
-		iowrite64(0, mmio + bar2_off(off, 4));
+		iowrite64(0, mmio + SNB_PBAR45LMT_OFFSET);
 	} else {
-		iowrite32(0, mmio + bar2_off(off, 4));
-		iowrite32(0, mmio + bar2_off(off, 5));
+		iowrite32(0, mmio + SNB_PBAR4LMT_OFFSET);
+		iowrite32(0, mmio + SNB_PBAR5LMT_OFFSET);
 	}
 
 	/* set outgoing translation offsets */
-	off = SNB_PBAR2XLAT_OFFSET;
-
 	bar_addr = peer_addr->bar2_addr64;
-	iowrite64(bar_addr, mmio + bar2_off(off, 2));
-	bar_addr = ioread64(mmio + bar2_off(off, 2));
+	iowrite64(bar_addr, mmio + SNB_PBAR23XLAT_OFFSET);
+	bar_addr = ioread64(mmio + SNB_PBAR23XLAT_OFFSET);
 	dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr);
 
 	if (!ndev->bar4_split) {
 		bar_addr = peer_addr->bar4_addr64;
-		iowrite64(bar_addr, mmio + bar2_off(off, 4));
-		bar_addr = ioread64(mmio + bar2_off(off, 4));
+		iowrite64(bar_addr, mmio + SNB_PBAR45XLAT_OFFSET);
+		bar_addr = ioread64(mmio + SNB_PBAR45XLAT_OFFSET);
 		dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr);
 	} else {
 		bar_addr = peer_addr->bar2_addr64;
-		iowrite32(bar_addr, mmio + bar2_off(off, 4));
-		bar_addr = ioread32(mmio + bar2_off(off, 4));
+		iowrite32(bar_addr, mmio + SNB_PBAR4XLAT_OFFSET);
+		bar_addr = ioread32(mmio + SNB_PBAR4XLAT_OFFSET);
 		dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr);
 
 		bar_addr = peer_addr->bar2_addr64;
-		iowrite32(bar_addr, mmio + bar2_off(off, 5));
-		bar_addr = ioread32(mmio + bar2_off(off, 5));
+		iowrite32(bar_addr, mmio + SNB_PBAR5XLAT_OFFSET);
+		bar_addr = ioread32(mmio + SNB_PBAR5XLAT_OFFSET);
 		dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr);
 	}
 
@@ -1747,29 +1722,68 @@ static int snb_init_dev(struct intel_ntb_dev *ndev)
 	u8 ppd;
 	int rc, mem;
 
+	pdev = ndev_pdev(ndev);
+
+	switch (pdev->device) {
 	/* 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
 	 * window to access the interrupt and scratch pad registers on the
 	 * remote system.
 	 */
-	ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
+	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+		ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
+		break;
+	}
 
+	switch (pdev->device) {
 	/* There is a hardware errata related to accessing any register in
 	 * SB01BASE in the presence of bidirectional traffic crossing the NTB.
 	 */
-	ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+		ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
+		break;
+	}
 
+	switch (pdev->device) {
 	/* HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
 	 * mirrored to the remote system.  Shrink the number of bits by one,
 	 * since bit 14 is the last bit.
 	 */
-	ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
+	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+		ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
+		break;
+	}
 
 	ndev->reg = &snb_reg;
 
-	pdev = ndev_pdev(ndev);
-
 	rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd);
 	if (rc)
 		return -EIO;
@@ -2062,14 +2076,14 @@ static const struct intel_ntb_xlat_reg snb_pri_xlat = {
 	 * window by setting the limit equal to base, nor can it limit the size
 	 * of the memory window by setting the limit to base + size.
 	 */
-	.bar2_limit		= SNB_PBAR2LMT_OFFSET,
-	.bar2_xlat		= SNB_PBAR2XLAT_OFFSET,
+	.bar2_limit		= SNB_PBAR23LMT_OFFSET,
+	.bar2_xlat		= SNB_PBAR23XLAT_OFFSET,
 };
 
 static const struct intel_ntb_xlat_reg snb_sec_xlat = {
 	.bar0_base		= SNB_SBAR0BASE_OFFSET,
-	.bar2_limit		= SNB_SBAR2LMT_OFFSET,
-	.bar2_xlat		= SNB_SBAR2XLAT_OFFSET,
+	.bar2_limit		= SNB_SBAR23LMT_OFFSET,
+	.bar2_xlat		= SNB_SBAR23XLAT_OFFSET,
 };
 
 static const struct intel_b2b_addr snb_b2b_usd_addr = {
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
index 0224b1a..fec689d 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.h
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
@@ -70,11 +70,27 @@
 
 /* SNB hardware (and JSF, IVT, HSX) */
 
-#define SNB_PBAR2LMT_OFFSET		0x0000
-#define SNB_PBAR2XLAT_OFFSET		0x0010
-#define SNB_SBAR2LMT_OFFSET		0x0020
-#define SNB_SBAR2XLAT_OFFSET		0x0030
+#define SNB_PBAR23LMT_OFFSET		0x0000
+#define SNB_PBAR45LMT_OFFSET		0x0008
+#define SNB_PBAR4LMT_OFFSET		0x0008
+#define SNB_PBAR5LMT_OFFSET		0x000c
+#define SNB_PBAR23XLAT_OFFSET		0x0010
+#define SNB_PBAR45XLAT_OFFSET		0x0018
+#define SNB_PBAR4XLAT_OFFSET		0x0018
+#define SNB_PBAR5XLAT_OFFSET		0x001c
+#define SNB_SBAR23LMT_OFFSET		0x0020
+#define SNB_SBAR45LMT_OFFSET		0x0028
+#define SNB_SBAR4LMT_OFFSET		0x0028
+#define SNB_SBAR5LMT_OFFSET		0x002c
+#define SNB_SBAR23XLAT_OFFSET		0x0030
+#define SNB_SBAR45XLAT_OFFSET		0x0038
+#define SNB_SBAR4XLAT_OFFSET		0x0038
+#define SNB_SBAR5XLAT_OFFSET		0x003c
 #define SNB_SBAR0BASE_OFFSET		0x0040
+#define SNB_SBAR23BASE_OFFSET		0x0048
+#define SNB_SBAR45BASE_OFFSET		0x0050
+#define SNB_SBAR4BASE_OFFSET		0x0050
+#define SNB_SBAR5BASE_OFFSET		0x0054
 #define SNB_SBDF_OFFSET			0x005c
 #define SNB_NTBCNTL_OFFSET		0x0058
 #define SNB_PDOORBELL_OFFSET		0x0060
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index f1ed1b7..bb2eb85 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -204,8 +204,8 @@ struct ntb_transport_ctx {
 
 	bool link_is_up;
 	struct delayed_work link_work;
-	struct work_struct db_work;
 	struct work_struct link_cleanup;
+	struct tasklet_struct db_work;
 };
 
 enum {
@@ -241,7 +241,7 @@ enum {
 #define NTB_QP_DEF_NUM_ENTRIES	100
 #define NTB_LINK_DOWN_TIMEOUT	10
 
-static void ntb_transport_doorbell_work(struct work_struct *ws);
+static void ntb_transport_doorbell_work(unsigned long data);
 static const struct ntb_ctx_ops ntb_transport_ops;
 static struct ntb_client ntb_transport_client;
 
@@ -1002,8 +1002,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
 	}
 
 	INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
-	INIT_WORK(&nt->db_work, ntb_transport_doorbell_work);
 	INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work);
+	tasklet_init(&nt->db_work, ntb_transport_doorbell_work,
+		     (unsigned long)nt);
 
 	rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops);
 	if (rc)
@@ -1044,7 +1045,7 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev)
 	int i;
 
 	ntb_transport_link_cleanup(nt);
-	cancel_work_sync(&nt->db_work);
+	tasklet_disable(&nt->db_work);
 	cancel_work_sync(&nt->link_cleanup);
 	cancel_delayed_work_sync(&nt->link_work);
 
@@ -1850,10 +1851,9 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
 }
 EXPORT_SYMBOL_GPL(ntb_transport_max_size);
 
-static void ntb_transport_doorbell_work(struct work_struct *work)
+static void ntb_transport_doorbell_work(unsigned long data)
 {
-	struct ntb_transport_ctx *nt = container_of(work,
-			struct ntb_transport_ctx, db_work);
+	struct ntb_transport_ctx *nt = (void *)data;
 	struct ntb_transport_qp *qp;
 	u64 db_mask, db_bits, db_again;
 	unsigned int qp_num;
@@ -1890,7 +1890,7 @@ static void ntb_transport_doorbell_callback(void *data, int vector)
 
 	ntb_db_set_mask(nt->ndev, ntb_db_valid_mask(nt->ndev));
 
-	schedule_work(&nt->db_work);
+	tasklet_schedule(&nt->db_work);
 }
 
 static const struct ntb_ctx_ops ntb_transport_ops = {
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 05/16] Intel NTB params for snb b2b addresses
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (3 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 04/16] Check the DID for certain workaround error flags to be set Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 06/16] NTB Pingpong Client Allen Hubbe
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

Add module parameters for the addresses to be used in b2b topology.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 Documentation/ntb.txt               | 10 +++++
 drivers/ntb/hw/intel/ntb_hw_intel.c | 77 ++++++++++++++++++++++++++++---------
 2 files changed, 68 insertions(+), 19 deletions(-)

diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt
index 725ba1e..00a3f92 100644
--- a/Documentation/ntb.txt
+++ b/Documentation/ntb.txt
@@ -56,3 +56,13 @@ Module Parameters:
 * b2b\_mw\_share - If the peer ntb is to be accessed via a memory window, and if
 	the memory window is large enough, still allow the client to use the
 	second half of the memory window for address translation to the peer.
+* snb\_b2b\_usd\_bar2\_addr64 - If using B2B topology on Xeon hardware, use this
+	64 bit address on the bus between the NTB devices for the window at
+	BAR2, on the upstream side of the link.
+* snb\_b2b\_usd\_bar4\_addr64 - See *snb\_b2b\_bar2\_addr64*.
+* snb\_b2b\_usd\_bar4\_addr32 - See *snb\_b2b\_bar2\_addr64*.
+* snb\_b2b\_usd\_bar5\_addr32 - See *snb\_b2b\_bar2\_addr64*.
+* snb\_b2b\_dsd\_bar2\_addr64 - See *snb\_b2b\_bar2\_addr64*.
+* snb\_b2b\_dsd\_bar4\_addr64 - See *snb\_b2b\_bar2\_addr64*.
+* snb\_b2b\_dsd\_bar4\_addr32 - See *snb\_b2b\_bar2\_addr64*.
+* snb\_b2b\_dsd\_bar5\_addr32 - See *snb\_b2b\_bar2\_addr64*.
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 89fea50..7e19d46 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -72,20 +72,6 @@ MODULE_AUTHOR("Intel Corporation");
 #define bar0_off(base, bar) ((base) + ((bar) << 2))
 #define bar2_off(base, bar) bar0_off(base, (bar) - 2)
 
-static int b2b_mw_idx = -1;
-module_param(b2b_mw_idx, int, 0644);
-MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb.  A "
-		 "value of zero or positive starts from first mw idx, and a "
-		 "negative value starts from last mw idx.  Both sides MUST "
-		 "set the same value here!");
-
-static unsigned int b2b_mw_share;
-module_param(b2b_mw_share, uint, 0644);
-MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the "
-		 "ntb so that the peer ntb only occupies the first half of "
-		 "the mw, so the second half can still be used as a mw.  Both "
-		 "sides MUST set the same value here!");
-
 static const struct intel_ntb_reg bwd_reg;
 static const struct intel_ntb_alt_reg bwd_pri_reg;
 static const struct intel_ntb_alt_reg bwd_sec_reg;
@@ -98,14 +84,67 @@ static const struct intel_ntb_alt_reg snb_sec_reg;
 static const struct intel_ntb_alt_reg snb_b2b_reg;
 static const struct intel_ntb_xlat_reg snb_pri_xlat;
 static const struct intel_ntb_xlat_reg snb_sec_xlat;
-static const struct intel_b2b_addr snb_b2b_usd_addr;
-static const struct intel_b2b_addr snb_b2b_dsd_addr;
-
+static struct intel_b2b_addr snb_b2b_usd_addr;
+static struct intel_b2b_addr snb_b2b_dsd_addr;
 static const struct ntb_dev_ops intel_ntb_ops;
 
 static const struct file_operations intel_ntb_debugfs_info;
 static struct dentry *debugfs_dir;
 
+static int b2b_mw_idx = -1;
+module_param(b2b_mw_idx, int, 0644);
+MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb.  A "
+		 "value of zero or positive starts from first mw idx, and a "
+		 "negative value starts from last mw idx.  Both sides MUST "
+		 "set the same value here!");
+
+static unsigned int b2b_mw_share;
+module_param(b2b_mw_share, uint, 0644);
+MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the "
+		 "ntb so that the peer ntb only occupies the first half of "
+		 "the mw, so the second half can still be used as a mw.  Both "
+		 "sides MUST set the same value here!");
+
+module_param_named(snb_b2b_usd_bar2_addr64,
+		   snb_b2b_usd_addr.bar2_addr64, ullong, 0644);
+MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64,
+		 "SNB B2B USD BAR 2 64-bit address");
+
+module_param_named(snb_b2b_usd_bar4_addr64,
+		   snb_b2b_usd_addr.bar4_addr64, ullong, 0644);
+MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64,
+		 "SNB B2B USD BAR 4 64-bit address");
+
+module_param_named(snb_b2b_usd_bar4_addr32,
+		   snb_b2b_usd_addr.bar4_addr32, ullong, 0644);
+MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64,
+		 "SNB B2B USD split-BAR 4 32-bit address");
+
+module_param_named(snb_b2b_usd_bar5_addr32,
+		   snb_b2b_usd_addr.bar5_addr32, ullong, 0644);
+MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64,
+		 "SNB B2B USD split-BAR 5 32-bit address");
+
+module_param_named(snb_b2b_dsd_bar2_addr64,
+		   snb_b2b_dsd_addr.bar2_addr64, ullong, 0644);
+MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64,
+		 "SNB B2B DSD BAR 2 64-bit address");
+
+module_param_named(snb_b2b_dsd_bar4_addr64,
+		   snb_b2b_dsd_addr.bar4_addr64, ullong, 0644);
+MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64,
+		 "SNB B2B DSD BAR 4 64-bit address");
+
+module_param_named(snb_b2b_dsd_bar4_addr32,
+		   snb_b2b_dsd_addr.bar4_addr32, ullong, 0644);
+MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64,
+		 "SNB B2B DSD split-BAR 4 32-bit address");
+
+module_param_named(snb_b2b_dsd_bar5_addr32,
+		   snb_b2b_dsd_addr.bar5_addr32, ullong, 0644);
+MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64,
+		 "SNB B2B DSD split-BAR 5 32-bit address");
+
 #ifndef ioread64
 #ifdef readq
 #define ioread64 readq
@@ -2086,14 +2125,14 @@ static const struct intel_ntb_xlat_reg snb_sec_xlat = {
 	.bar2_xlat		= SNB_SBAR23XLAT_OFFSET,
 };
 
-static const struct intel_b2b_addr snb_b2b_usd_addr = {
+static struct intel_b2b_addr snb_b2b_usd_addr = {
 	.bar2_addr64		= SNB_B2B_BAR2_USD_ADDR64,
 	.bar4_addr64		= SNB_B2B_BAR4_USD_ADDR64,
 	.bar4_addr32		= SNB_B2B_BAR4_USD_ADDR32,
 	.bar5_addr32		= SNB_B2B_BAR5_USD_ADDR32,
 };
 
-static const struct intel_b2b_addr snb_b2b_dsd_addr = {
+static struct intel_b2b_addr snb_b2b_dsd_addr = {
 	.bar2_addr64		= SNB_B2B_BAR2_DSD_ADDR64,
 	.bar4_addr64		= SNB_B2B_BAR4_DSD_ADDR64,
 	.bar4_addr32		= SNB_B2B_BAR4_DSD_ADDR32,
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 06/16] NTB Pingpong Client
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (4 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 05/16] Intel NTB params for snb b2b addresses Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-21  8:54   ` Paul Bolle
  2015-05-20 15:41 ` [PATCH 07/16] NTB Tool Client Allen Hubbe
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

This is a simple pingpong driver that exercises the scratchpads and
doorbells of the ntb hardware.  This driver may be used to test that
your ntb hardware and drivers are functioning at a basic level.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 Documentation/ntb.txt           |  27 +++++
 MAINTAINERS                     |   1 +
 drivers/ntb/Kconfig             |   2 +
 drivers/ntb/Makefile            |   2 +-
 drivers/ntb/test/Kconfig        |   9 ++
 drivers/ntb/test/Makefile       |   1 +
 drivers/ntb/test/ntb_pingpong.c | 251 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 292 insertions(+), 1 deletion(-)
 create mode 100644 drivers/ntb/test/Kconfig
 create mode 100644 drivers/ntb/test/Makefile
 create mode 100644 drivers/ntb/test/ntb_pingpong.c

diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt
index 00a3f92..e5d1591 100644
--- a/Documentation/ntb.txt
+++ b/Documentation/ntb.txt
@@ -37,6 +37,33 @@ Transport queue pair.  Network data is copied between socket buffers and the
 Transport queue pair buffer.  The Transport client may be used for other things
 besides Netdev, however no other applications have yet been written.
 
+### NTB Ping Pong Test Client (ntb\_pingpong)
+
+The Ping Pong test client serves as a demonstration to exercise the doorbell
+and scratchpad registers of NTB hardware, and as an example simple NTB client.
+Ping Pong enables the link when started, waits for the NTB link to come up, and
+then proceeds to read and write the doorbell scratchpad registers of the NTB.
+The peers interrupt each other using a bit mask of doorbell bits, which is
+shifted by one in each round, to test the behavior of multiple doorbell bits
+and interrupt vectors.  The Ping Pong driver also reads the first local
+scratchpad, and writes the value plus one to the first peer scratchpad, each
+round before writing the peer doorbell register.
+
+Module Parameters:
+
+* unsafe - Some hardware has known issues with scratchpad and doorbell
+	registers.  By default, Ping Pong will not attempt to exercise such
+	hardware.  You may override this behavior at your own risk by setting
+	unsafe=1.
+* delay\_ms - Specify the delay between receiving a doorbell
+	interrupt event and setting the peer doorbell register for the next
+	round.
+* init\_db - Specify the doorbell bits to start new series of rounds.  A new
+	series begins once all the doorbell bits have been shifted out of
+	range.
+* dyndbg - It is suggested to specify dyndbg=+p when loading this module, and
+	then to observe debugging output on the console.
+
 ## NTB Hardware Drivers
 
 NTB hardware drivers should register devices with the NTB core driver.  After
diff --git a/MAINTAINERS b/MAINTAINERS
index 2560e18..cbc9d3d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6952,6 +6952,7 @@ T:	git git://github.com/jonmason/ntb.git
 F:	drivers/ntb/
 F:	drivers/net/ntb_netdev.c
 F:	drivers/ntb/ntb.c
+F:	drivers/ntb/ntb_pingpong.c
 F:	drivers/ntb/ntb_transport.c
 F:	include/linux/ntb.h
 F:	include/linux/ntb_transport.h
diff --git a/drivers/ntb/Kconfig b/drivers/ntb/Kconfig
index 988b03d..c137eb7 100644
--- a/drivers/ntb/Kconfig
+++ b/drivers/ntb/Kconfig
@@ -14,6 +14,8 @@ if NTB
 
 source "drivers/ntb/hw/Kconfig"
 
+source "drivers/ntb/test/Kconfig"
+
 config NTB_TRANSPORT
        tristate "NTB Transport Client"
        depends on NTB
diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile
index 671c4e6..c2d2982 100644
--- a/drivers/ntb/Makefile
+++ b/drivers/ntb/Makefile
@@ -1,3 +1,3 @@
-obj-y += hw/
+obj-y += hw/ test/
 obj-$(CONFIG_NTB) += ntb.o
 obj-$(CONFIG_NTB_TRANSPORT) += ntb_transport.o
diff --git a/drivers/ntb/test/Kconfig b/drivers/ntb/test/Kconfig
new file mode 100644
index 0000000..9b81c4c
--- /dev/null
+++ b/drivers/ntb/test/Kconfig
@@ -0,0 +1,9 @@
+config NTB_PINGPONG
+       tristate "NTB Simple Ping Pong Client"
+       depends on NTB
+       help
+        This is a simple ping pong driver that exercises the scratchpads and
+        doorbells of the ntb hardware.  This driver may be used to test that
+        your ntb hardware and drivers are functioning at a basic level.
+
+        If unsure, say N.
diff --git a/drivers/ntb/test/Makefile b/drivers/ntb/test/Makefile
new file mode 100644
index 0000000..b323093
--- /dev/null
+++ b/drivers/ntb/test/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_NTB_PINGPONG) += ntb_pingpong.o
diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
new file mode 100644
index 0000000..a18f895
--- /dev/null
+++ b/drivers/ntb/test/ntb_pingpong.c
@@ -0,0 +1,251 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * PCIe NTB Pingpong Linux driver
+ *
+ * Contact Information:
+ * Allen Hubbe <Allen.Hubbe@emc.com>
+ */
+
+/* Note: load this module with option 'dyndbg=+p' */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <linux/ntb.h>
+
+#define DRIVER_NAME			"ntb_pingpong"
+#define DRIVER_DESCRIPTION		"PCIe NTB Simple Pingpong Client"
+
+#define DRIVER_LICENSE			"Dual BSD/GPL"
+#define DRIVER_VERSION			"1.0"
+#define DRIVER_RELDATE			"24 March 2015"
+#define DRIVER_AUTHOR			"Allen Hubbe <Allen.Hubbe@emc.com>"
+
+MODULE_LICENSE(DRIVER_LICENSE);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+
+static unsigned int unsafe;
+module_param(unsafe, uint, 0644);
+MODULE_PARM_DESC(unsafe, "Run even though ntb operations may be unsafe");
+
+static unsigned int delay_ms = 1000;
+module_param(delay_ms, uint, 0644);
+MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer");
+
+static unsigned long db_init = 0x7;
+module_param(db_init, ulong, 0644);
+MODULE_PARM_DESC(delay_ms, "Initial doorbell bits to ring on the peer");
+
+struct pp_ctx {
+	struct ntb_dev			*ntb;
+	u64				db_bits;
+	/* synchronize access to db_bits by ping and pong */
+	spinlock_t			db_lock;
+	struct timer_list		db_timer;
+	unsigned long			db_delay;
+};
+
+static void pp_ping(unsigned long ctx)
+{
+	struct pp_ctx *pp = (void *)ctx;
+	unsigned long irqflags;
+	u64 db_bits, db_mask;
+	u32 spad_rd, spad_wr;
+
+	spin_lock_irqsave(&pp->db_lock, irqflags);
+	{
+		db_mask = ntb_db_valid_mask(pp->ntb);
+		db_bits = ntb_db_read(pp->ntb);
+
+		if (db_bits) {
+			dev_dbg(&pp->ntb->dev,
+				"Masked pongs %#llx\n",
+				db_bits);
+			ntb_db_clear(pp->ntb, db_bits);
+		}
+
+		db_bits = ((pp->db_bits | db_bits) << 1) & db_mask;
+
+		if (!db_bits)
+			db_bits = db_init;
+
+		spad_rd = ntb_spad_read(pp->ntb, 0);
+		spad_wr = spad_rd + 1;
+
+		dev_dbg(&pp->ntb->dev,
+			"Ping bits %#llx read %#x write %#x\n",
+			db_bits, spad_rd, spad_wr);
+
+		ntb_peer_spad_write(pp->ntb, 0, spad_wr);
+		ntb_peer_db_set(pp->ntb, db_bits);
+		ntb_db_clear_mask(pp->ntb, db_mask);
+
+		pp->db_bits = 0;
+	}
+	spin_unlock_irqrestore(&pp->db_lock, irqflags);
+}
+
+static void pp_link_event(void *ctx)
+{
+	struct pp_ctx *pp = ctx;
+
+	if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) {
+		dev_dbg(&pp->ntb->dev, "link is up\n");
+		pp_ping((unsigned long)pp);
+	} else {
+		dev_dbg(&pp->ntb->dev, "link is down\n");
+		del_timer(&pp->db_timer);
+	}
+}
+
+static void pp_db_event(void *ctx, int vec)
+{
+	struct pp_ctx *pp = ctx;
+	u64 db_bits, db_mask;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&pp->db_lock, irqflags);
+	{
+		db_mask = ntb_db_vector_mask(pp->ntb, vec);
+		db_bits = db_mask & ntb_db_read(pp->ntb);
+		ntb_db_set_mask(pp->ntb, db_mask);
+		ntb_db_clear(pp->ntb, db_bits);
+
+		pp->db_bits |= db_bits;
+
+		mod_timer(&pp->db_timer, jiffies + pp->db_delay);
+
+		dev_dbg(&pp->ntb->dev,
+			"Pong vec %d bits %#llx\n",
+			vec, db_bits);
+	}
+	spin_unlock_irqrestore(&pp->db_lock, irqflags);
+}
+
+static const struct ntb_ctx_ops pp_ops = {
+	.link_event = pp_link_event,
+	.db_event = pp_db_event,
+};
+
+static int pp_probe(struct ntb_client *client,
+		    struct ntb_dev *ntb)
+{
+	struct pp_ctx *pp;
+	int rc;
+
+	if (ntb_db_is_unsafe(ntb)) {
+		dev_dbg(&ntb->dev, "doorbell is unsafe\n");
+		if (!unsafe) {
+			rc = -EINVAL;
+			goto err_pp;
+		}
+	}
+
+	if (ntb_spad_is_unsafe(ntb)) {
+		dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
+		if (!unsafe) {
+			rc = -EINVAL;
+			goto err_pp;
+		}
+	}
+
+	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		rc = -ENOMEM;
+		goto err_pp;
+	}
+
+	pp->ntb = ntb;
+	pp->db_bits = 0;
+	spin_lock_init(&pp->db_lock);
+	setup_timer(&pp->db_timer, pp_ping, (unsigned long)pp);
+	pp->db_delay = msecs_to_jiffies(delay_ms);
+
+	rc = ntb_set_ctx(ntb, pp, &pp_ops);
+	if (rc)
+		goto err_ctx;
+
+	ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
+	ntb_link_event(ntb);
+
+	return 0;
+
+err_ctx:
+	kfree(pp);
+err_pp:
+	return rc;
+}
+
+static void pp_remove(struct ntb_client *client,
+		      struct ntb_dev *ntb)
+{
+	struct pp_ctx *pp = ntb->ctx;
+
+	ntb_clear_ctx(ntb);
+	del_timer_sync(&pp->db_timer);
+	ntb_link_disable(ntb);
+
+	kfree(pp);
+}
+
+static struct ntb_client pp_client = {
+	.ops = {
+		.probe = pp_probe,
+		.remove = pp_remove,
+	},
+	.name = DRIVER_NAME,
+};
+module_ntb_client(pp_client);
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 07/16] NTB Tool Client
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (5 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 06/16] NTB Pingpong Client Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-21  9:02   ` Paul Bolle
  2015-05-20 15:41 ` [PATCH 08/16] ntb_transport: rate limit ntb_qp_link_work Allen Hubbe
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

This is a simple debugging driver that enables the doorbell and
scratchpad registers to be read and written from the debugfs.  This
tool enables more complicated debugging to be scripted from user space.
This driver may be used to test that your ntb hardware and drivers are
functioning at a basic level.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 Documentation/ntb.txt       |  32 +++
 MAINTAINERS                 |   1 +
 drivers/ntb/test/Kconfig    |  12 +
 drivers/ntb/test/Makefile   |   1 +
 drivers/ntb/test/ntb_tool.c | 557 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 603 insertions(+)
 create mode 100644 drivers/ntb/test/ntb_tool.c

diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt
index e5d1591..b48249a 100644
--- a/Documentation/ntb.txt
+++ b/Documentation/ntb.txt
@@ -64,6 +64,38 @@ Module Parameters:
 * dyndbg - It is suggested to specify dyndbg=+p when loading this module, and
 	then to observe debugging output on the console.
 
+### NTB Tool Test Client (ntb\_tool)
+
+The Tool test client serves for debugging, primarily, ntb hardware and drivers.
+The Tool provides access through debugfs for reading, setting, and clearing the
+NTB doorbell, and reading and writing scratchpads.
+
+The Tool does not currently have any module parameters.
+
+Debugfs Files:
+
+* *debugfs*/ntb\_tool/*hw*/ - A directory in debugfs will be created for each
+	NTB device probed by the tool.  This directory is shortened to *hw*
+	below.
+* *hw*/db - This file is used to read, set, and clear the local doorbell.  Not
+	all operations may be supported by all hardware.  To read the doorbell,
+	read the file.  To set the doorbell, write `s` followed by the bits to
+	set (eg: `echo 's 0x0101' > db`).  To clear the doorbell, write `c`
+	followed by the bits to clear.
+* *hw*/mask - This file is used to read, set, and clear the local doorbell mask.
+	See *db* for details.
+* *hw*/peer\_db - This file is used to read, set, and clear the peer doorbell.
+	See *db* for details.
+* *hw*/peer\_mask - This file is used to read, set, and clear the peer doorbell
+	mask.  See *db* for details.
+* *hw*/spad - This file is used to read and write local scratchpads.  To read
+	the values of all scratchpads, read the file.  To write values, write a
+	series of pairs of scratchpad number and value
+	(eg: `echo '4 0x123 7 0xabc' > spad`
+	# to set scratchpads `4` and `7` to `0x123` and `0xabc`, respectively).
+* *hw*/peer\_spad - This file is used to read and write peer scratchpads.  See
+	*spad* for details.
+
 ## NTB Hardware Drivers
 
 NTB hardware drivers should register devices with the NTB core driver.  After
diff --git a/MAINTAINERS b/MAINTAINERS
index cbc9d3d..dccfe82 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6953,6 +6953,7 @@ F:	drivers/ntb/
 F:	drivers/net/ntb_netdev.c
 F:	drivers/ntb/ntb.c
 F:	drivers/ntb/ntb_pingpong.c
+F:	drivers/ntb/ntb_tool.c
 F:	drivers/ntb/ntb_transport.c
 F:	include/linux/ntb.h
 F:	include/linux/ntb_transport.h
diff --git a/drivers/ntb/test/Kconfig b/drivers/ntb/test/Kconfig
index 9b81c4c..413829c 100644
--- a/drivers/ntb/test/Kconfig
+++ b/drivers/ntb/test/Kconfig
@@ -7,3 +7,15 @@ config NTB_PINGPONG
         your ntb hardware and drivers are functioning at a basic level.
 
         If unsure, say N.
+
+config NTB_TOOL
+       tristate "NTB Debugging Tool Client"
+       depends on NTB
+       help
+	This is a simple debugging driver that enables the doorbell and
+	scratchpad registers to be read and written from the debugfs.  This
+	enables more complicated debugging to be scripted from user space.
+	This driver may be used to test that your ntb hardware and drivers are
+	functioning at a basic level.
+
+        If unsure, say N.
diff --git a/drivers/ntb/test/Makefile b/drivers/ntb/test/Makefile
index b323093..0ea32a3 100644
--- a/drivers/ntb/test/Makefile
+++ b/drivers/ntb/test/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_NTB_PINGPONG) += ntb_pingpong.o
+obj-$(CONFIG_NTB_TOOL) += ntb_tool.o
diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
new file mode 100644
index 0000000..49628ef
--- /dev/null
+++ b/drivers/ntb/test/ntb_tool.c
@@ -0,0 +1,557 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * PCIe NTB Debugging Tool Linux driver
+ *
+ * Contact Information:
+ * Allen Hubbe <Allen.Hubbe@emc.com>
+ */
+
+/*
+ * How to use this tool, by example.
+ *
+ * Assuming $DBG_DIR is something like:
+ * '/sys/kernel/debug/ntb_tool/0000:00:03.0'
+ *
+ * Eg: check if clearing the doorbell mask generates an interrupt.
+ *
+ * # Set the doorbell mask
+ * root@self# echo 's 1' > $DBG_DIR/mask
+ *
+ * # Ring the doorbell from the peer
+ * root@peer# echo 's 1' > $DBG_DIR/peer_db
+ *
+ * # Clear the doorbell mask
+ * root@self# echo 'c 1' > $DBG_DIR/mask
+ *
+ * Observe debugging output in dmesg or your console.  You should see a
+ * doorbell event triggered by clearing the mask.  If not, this may indicate an
+ * issue with the hardware that needs to be worked around in the driver.
+ *
+ * Eg: read and write scratchpad registers
+ *
+ * root@peer# echo '0 0x01010101 1 0x7f7f7f7f' > $DBG_DIR/peer_spad
+ *
+ * root@self# cat $DBG_DIR/spad
+ *
+ * Observe that spad 0 and 1 have the values set by the peer.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <linux/ntb.h>
+
+#define DRIVER_NAME			"ntb_tool"
+#define DRIVER_DESCRIPTION		"PCIe NTB Debugging Tool"
+
+#define DRIVER_LICENSE			"Dual BSD/GPL"
+#define DRIVER_VERSION			"1.0"
+#define DRIVER_RELDATE			"22 April 2015"
+#define DRIVER_AUTHOR			"Allen Hubbe <Allen.Hubbe@emc.com>"
+
+MODULE_LICENSE(DRIVER_LICENSE);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+
+static struct dentry *tool_dbgfs;
+
+struct tool_ctx {
+	struct ntb_dev *ntb;
+	struct dentry *dbgfs;
+};
+
+#define SPAD_FNAME_SIZE 0x10
+#define INT_PTR(x) ((void *)(unsigned long)x)
+#define PTR_INT(x) ((int)(unsigned long)x)
+
+#define TOOL_FOPS_RDWR(__name, __read, __write) \
+	const struct file_operations __name = {	\
+		.owner = THIS_MODULE,		\
+		.open = simple_open,		\
+		.read = __read,			\
+		.write = __write,		\
+	}
+
+static void tool_link_event(void *ctx)
+{
+	struct tool_ctx *tc = ctx;
+	enum ntb_speed speed;
+	enum ntb_width width;
+	int up;
+
+	up = ntb_link_is_up(tc->ntb, &speed, &width);
+
+	dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
+		up ? "up" : "down", speed, width);
+}
+
+static void tool_db_event(void *ctx, int vec)
+{
+	struct tool_ctx *tc = ctx;
+	u64 db_bits, db_mask;
+
+	db_mask = ntb_db_vector_mask(tc->ntb, vec);
+	db_bits = ntb_db_read(tc->ntb);
+
+	dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
+		vec, db_mask, db_bits);
+}
+
+static const struct ntb_ctx_ops tool_ops = {
+	.link_event = tool_link_event,
+	.db_event = tool_db_event,
+};
+
+static ssize_t tool_dbfn_read(struct tool_ctx *tc, char __user *ubuf,
+			      size_t size, loff_t *offp,
+			      u64 (*db_read_fn)(struct ntb_dev *))
+{
+	size_t buf_size;
+	char *buf;
+	ssize_t pos, rc;
+
+	if (!db_read_fn)
+		return -EINVAL;
+
+	buf_size = min(size, 0x20ul);
+
+	buf = kmalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pos = scnprintf(buf, buf_size, "%#llx\n",
+			db_read_fn(tc->ntb));
+
+	rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
+
+	kfree(buf);
+
+	return rc;
+}
+
+static ssize_t tool_dbfn_write(struct tool_ctx *tc,
+			       const char __user *ubuf,
+			       size_t size, loff_t *offp,
+			       int (*db_set_fn)(struct ntb_dev *, u64),
+			       int (*db_clear_fn)(struct ntb_dev *, u64))
+{
+	u64 db_bits;
+	char *buf, cmd;
+	ssize_t rc;
+	int n;
+
+	buf = kmalloc(size + 1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	rc = simple_write_to_buffer(buf, size, offp, ubuf, size);
+	if (rc < 0) {
+		kfree(buf);
+		return rc;
+	}
+
+	buf[size] = 0;
+
+	n = sscanf(buf, "%c %lli", &cmd, &db_bits);
+
+	kfree(buf);
+
+	if (n != 2) {
+		rc = -EINVAL;
+	} else if (cmd == 's') {
+		if (!db_set_fn)
+			rc = -EINVAL;
+		else
+			rc = db_set_fn(tc->ntb, db_bits);
+	} else if (cmd == 'c') {
+		if (!db_clear_fn)
+			rc = -EINVAL;
+		else
+			rc = db_clear_fn(tc->ntb, db_bits);
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc ? : size;
+}
+
+static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
+				size_t size, loff_t *offp,
+				u32 (*spad_read_fn)(struct ntb_dev *, int))
+{
+	size_t buf_size;
+	char *buf;
+	ssize_t pos, rc;
+	int i, spad_count;
+
+	if (!spad_read_fn)
+		return -EINVAL;
+
+	buf_size = min(size, 0x100ul);
+
+	buf = kmalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pos = 0;
+
+	spad_count = ntb_spad_count(tc->ntb);
+	for (i = 0; i < spad_count; ++i) {
+		pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n",
+				 i, spad_read_fn(tc->ntb, i));
+	}
+
+	rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
+
+	kfree(buf);
+
+	return rc;
+}
+
+static ssize_t tool_spadfn_write(struct tool_ctx *tc,
+				 const char __user *ubuf,
+				 size_t size, loff_t *offp,
+				 int (*spad_write_fn)(struct ntb_dev *,
+						      int, u32))
+{
+	int spad_idx;
+	u32 spad_val;
+	char *buf;
+	int pos, n;
+	ssize_t rc;
+
+	if (!spad_write_fn) {
+		dev_dbg(&tc->ntb->dev, "no spad write fn\n");
+		return -EINVAL;
+	}
+
+	buf = kmalloc(size + 1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	rc = simple_write_to_buffer(buf, size, offp, ubuf, size);
+	if (rc < 0) {
+		kfree(buf);
+		return rc;
+	}
+
+	buf[size] = 0;
+
+	n = sscanf(buf, "%d %i%n", &spad_idx, &spad_val, &pos);
+	while (n == 2) {
+		rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
+		if (rc)
+			break;
+
+		n = sscanf(buf + pos, "%d %i%n", &spad_idx, &spad_val, &pos);
+	}
+
+	if (n < 0)
+		rc = n;
+
+	kfree(buf);
+
+	return rc ? : size;
+}
+
+static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
+			    size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_dbfn_read(tc, ubuf, size, offp,
+			      tc->ntb->ops->db_read);
+}
+
+static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
+			     size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_dbfn_write(tc, ubuf, size, offp,
+			       tc->ntb->ops->db_set,
+			       tc->ntb->ops->db_clear);
+}
+
+static TOOL_FOPS_RDWR(tool_db_fops,
+		      tool_db_read,
+		      tool_db_write);
+
+static ssize_t tool_mask_read(struct file *filep, char __user *ubuf,
+			      size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_dbfn_read(tc, ubuf, size, offp,
+			      tc->ntb->ops->db_read_mask);
+}
+
+static ssize_t tool_mask_write(struct file *filep, const char __user *ubuf,
+			       size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_dbfn_write(tc, ubuf, size, offp,
+			       tc->ntb->ops->db_set_mask,
+			       tc->ntb->ops->db_clear_mask);
+}
+
+static TOOL_FOPS_RDWR(tool_mask_fops,
+		      tool_mask_read,
+		      tool_mask_write);
+
+static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
+				 size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_dbfn_read(tc, ubuf, size, offp,
+			      tc->ntb->ops->peer_db_read);
+}
+
+static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
+				  size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_dbfn_write(tc, ubuf, size, offp,
+			       tc->ntb->ops->peer_db_set,
+			       tc->ntb->ops->peer_db_clear);
+}
+
+static TOOL_FOPS_RDWR(tool_peer_db_fops,
+		      tool_peer_db_read,
+		      tool_peer_db_write);
+
+static ssize_t tool_peer_mask_read(struct file *filep, char __user *ubuf,
+				   size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_dbfn_read(tc, ubuf, size, offp,
+			      tc->ntb->ops->peer_db_read_mask);
+}
+
+static ssize_t tool_peer_mask_write(struct file *filep, const char __user *ubuf,
+				    size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_dbfn_write(tc, ubuf, size, offp,
+			       tc->ntb->ops->peer_db_set_mask,
+			       tc->ntb->ops->peer_db_clear_mask);
+}
+
+static TOOL_FOPS_RDWR(tool_peer_mask_fops,
+		      tool_peer_mask_read,
+		      tool_peer_mask_write);
+
+static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
+			      size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_spadfn_read(tc, ubuf, size, offp,
+				tc->ntb->ops->spad_read);
+}
+
+static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
+			       size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_spadfn_write(tc, ubuf, size, offp,
+				 tc->ntb->ops->spad_write);
+}
+
+static TOOL_FOPS_RDWR(tool_spad_fops,
+		      tool_spad_read,
+		      tool_spad_write);
+
+static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
+				   size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_spadfn_read(tc, ubuf, size, offp,
+				tc->ntb->ops->peer_spad_read);
+}
+
+static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
+				    size_t size, loff_t *offp)
+{
+	struct tool_ctx *tc = filep->private_data;
+
+	return tool_spadfn_write(tc, ubuf, size, offp,
+				 tc->ntb->ops->peer_spad_write);
+}
+
+static TOOL_FOPS_RDWR(tool_peer_spad_fops,
+		      tool_peer_spad_read,
+		      tool_peer_spad_write);
+
+static void tool_setup_dbgfs(struct tool_ctx *tc)
+{
+	/* This modules is useless without dbgfs... */
+	if (!tool_dbgfs) {
+		tc->dbgfs = NULL;
+		return;
+	}
+
+	tc->dbgfs = debugfs_create_dir(dev_name(&tc->ntb->dev),
+				       tool_dbgfs);
+	if (!tc->dbgfs)
+		return;
+
+	debugfs_create_file("db", S_IRUSR | S_IWUSR, tc->dbgfs,
+			    tc, &tool_db_fops);
+
+	debugfs_create_file("mask", S_IRUSR | S_IWUSR, tc->dbgfs,
+			    tc, &tool_mask_fops);
+
+	debugfs_create_file("peer_db", S_IRUSR | S_IWUSR, tc->dbgfs,
+			    tc, &tool_peer_db_fops);
+
+	debugfs_create_file("peer_mask", S_IRUSR | S_IWUSR, tc->dbgfs,
+			    tc, &tool_peer_mask_fops);
+
+	debugfs_create_file("spad", S_IRUSR | S_IWUSR, tc->dbgfs,
+			    tc, &tool_spad_fops);
+
+	debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs,
+			    tc, &tool_peer_spad_fops);
+}
+
+static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
+{
+	struct tool_ctx *tc;
+	int rc;
+
+	if (ntb_db_is_unsafe(ntb))
+		dev_dbg(&ntb->dev, "doorbell is unsafe\n");
+
+	if (ntb_spad_is_unsafe(ntb))
+		dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
+
+	tc = kmalloc(sizeof(*tc), GFP_KERNEL);
+	if (!tc) {
+		rc = -ENOMEM;
+		goto err_tc;
+	}
+
+	tc->ntb = ntb;
+
+	tool_setup_dbgfs(tc);
+
+	rc = ntb_set_ctx(ntb, tc, &tool_ops);
+	if (rc)
+		goto err_ctx;
+
+	ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
+	ntb_link_event(ntb);
+
+	return 0;
+
+err_ctx:
+	debugfs_remove_recursive(tc->dbgfs);
+	kfree(tc);
+err_tc:
+	return rc;
+}
+
+static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
+{
+	struct tool_ctx *tc = ntb->ctx;
+
+	ntb_clear_ctx(ntb);
+	ntb_link_disable(ntb);
+
+	debugfs_remove_recursive(tc->dbgfs);
+	kfree(tc);
+}
+
+static struct ntb_client tool_client = {
+	.ops = {
+		.probe = tool_probe,
+		.remove = tool_remove,
+	},
+	.name = DRIVER_NAME,
+};
+
+static int __init tool_init(void)
+{
+	int rc;
+
+	if (debugfs_initialized())
+		tool_dbgfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+	rc = ntb_register_client(&tool_client);
+	if (rc)
+		goto err_client;
+
+	return 0;
+
+err_client:
+	debugfs_remove_recursive(tool_dbgfs);
+	return rc;
+}
+module_init(tool_init);
+
+static void __exit tool_exit(void)
+{
+	ntb_unregister_client(&tool_client);
+	debugfs_remove_recursive(tool_dbgfs);
+}
+module_exit(tool_exit);
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 08/16] ntb_transport: rate limit ntb_qp_link_work
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (6 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 07/16] NTB Tool Client Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 09/16] ntb_transport: differentiate link down messages Allen Hubbe
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

When the ntb transport is connecting and waiting for the peer, the debug
console receives lots of debug level messages about the remote qp link
status being down.  Rate limit those messages.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/ntb/ntb_transport.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index bb2eb85..833f5b6 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -830,7 +830,7 @@ static void ntb_qp_link_work(struct work_struct *work)
 
 	/* query remote spad for qp ready bits */
 	ntb_peer_spad_read(nt->ndev, QP_LINKS);
-	dev_dbg(&pdev->dev, "Remote QP link status = %x\n", val);
+	dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val);
 
 	/* See if the remote side is up */
 	if (val & BIT(qp->qp_num)) {
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 09/16] ntb_transport: differentiate link down messages
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (7 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 08/16] ntb_transport: rate limit ntb_qp_link_work Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 10/16] ntb_transport: don't advance rx on link down Allen Hubbe
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

The same message "qp%d: Link Down\n" was printed at two locations in
ntb_transport.  Change the messages so they are distinct.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/ntb/ntb_transport.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 833f5b6..8a6db1a 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -657,7 +657,7 @@ static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp)
 		return;
 	}
 
-	dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num);
+	dev_info(&pdev->dev, "qp %d: Link Cleanup\n", qp->qp_num);
 	qp->link_is_up = false;
 
 	if (qp->event_handler)
@@ -1455,7 +1455,7 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp)
 		return;
 
 	qp->link_is_up = false;
-	dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num);
+	dev_info(&pdev->dev, "qp %d: Send Link Down\n", qp->qp_num);
 
 	for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) {
 		entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 10/16] ntb_transport: don't advance rx on link down
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (8 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 09/16] ntb_transport: differentiate link down messages Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 11/16] ntb_transport: reset qp link stats on down Allen Hubbe
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

On link down, don't advance RX index to the next entry.  The next entry
should never be valid after receiving the link down flag.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/ntb/ntb_transport.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 8a6db1a..9b4e240 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -1211,8 +1211,7 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
 		dev_dbg(&qp->ndev->pdev->dev, "link down flag set\n");
 		ntb_qp_link_down(qp);
 		hdr->flags = 0;
-		iowrite32(qp->rx_index, &qp->rx_info->entry);
-		return 0;
+		return -EAGAIN;
 	}
 
 	if (hdr->ver != (u32)qp->rx_pkts) {
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 11/16] ntb_transport: reset qp link stats on down
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (9 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 10/16] ntb_transport: don't advance rx on link down Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 12/16] ntb_transport: numa aware memory and dma chan Allen Hubbe
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

Reset the link stats when the link goes down.  In particular, the tx and
rx index and count must be reset, or else the tx side will be sending
packets to the rx side, where the rx side is not expecting them.  Reset
all the stats, to be consistent.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/ntb/ntb_transport.c | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 9b4e240..c76d8b9 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -647,18 +647,37 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
 	return 0;
 }
 
+static void ntb_qp_link_down_reset(struct ntb_transport_qp *qp)
+{
+	qp->link_is_up = false;
+
+	qp->tx_index = 0;
+	qp->rx_index = 0;
+	qp->rx_bytes = 0;
+	qp->rx_pkts = 0;
+	qp->rx_ring_empty = 0;
+	qp->rx_err_no_buf = 0;
+	qp->rx_err_oflow = 0;
+	qp->rx_err_ver = 0;
+	qp->rx_memcpy = 0;
+	qp->rx_async = 0;
+	qp->tx_bytes = 0;
+	qp->tx_pkts = 0;
+	qp->tx_ring_full = 0;
+	qp->tx_err_no_buf = 0;
+	qp->tx_memcpy = 0;
+	qp->tx_async = 0;
+}
+
 static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp)
 {
 	struct ntb_transport_ctx *nt = qp->transport;
 	struct pci_dev *pdev = nt->ndev->pdev;
 
-	if (qp->link_is_up) {
-		cancel_delayed_work_sync(&qp->link_work);
-		return;
-	}
-
 	dev_info(&pdev->dev, "qp %d: Link Cleanup\n", qp->qp_num);
-	qp->link_is_up = false;
+
+	cancel_delayed_work_sync(&qp->link_work);
+	ntb_qp_link_down_reset(qp);
 
 	if (qp->event_handler)
 		qp->event_handler(qp->cb_data, qp->link_is_up);
@@ -865,9 +884,9 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
 	qp->qp_num = qp_num;
 	qp->transport = nt;
 	qp->ndev = nt->ndev;
-	qp->link_is_up = false;
 	qp->client_ready = false;
 	qp->event_handler = NULL;
+	ntb_qp_link_down_reset(qp);
 
 	if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
 		num_qps_mw = qp_count / mw_count + 1;
@@ -1453,7 +1472,6 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp)
 	if (!qp->link_is_up)
 		return;
 
-	qp->link_is_up = false;
 	dev_info(&pdev->dev, "qp %d: Send Link Down\n", qp->qp_num);
 
 	for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) {
@@ -1475,6 +1493,8 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp)
 	if (rc)
 		dev_err(&pdev->dev, "ntb: QP%d unable to send linkdown msg\n",
 			qp->qp_num);
+
+	ntb_qp_link_down_reset(qp);
 }
 
 /**
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 12/16] ntb_transport: numa aware memory and dma chan
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (10 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 11/16] ntb_transport: reset qp link stats on down Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 13/16] ntb_hw_intel: numa aware memory allocation Allen Hubbe
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

Allocate memory and request the dma channel for the same numa node as
the ntb device.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/ntb/ntb_transport.c | 46 +++++++++++++++++++++++++++++++--------------
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index c76d8b9..91809fa 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -346,6 +346,7 @@ int ntb_transport_register_client_dev(char *device_name)
 {
 	struct ntb_transport_client_dev *client_dev;
 	struct ntb_transport_ctx *nt;
+	int node;
 	int rc, i = 0;
 
 	if (list_empty(&ntb_transport_list))
@@ -354,8 +355,10 @@ int ntb_transport_register_client_dev(char *device_name)
 	list_for_each_entry(nt, &ntb_transport_list, entry) {
 		struct device *dev;
 
-		client_dev = kzalloc(sizeof(*client_dev),
-				     GFP_KERNEL);
+		node = dev_to_node(&nt->ndev->dev);
+
+		client_dev = kzalloc_node(sizeof(*client_dev),
+				     GFP_KERNEL, node);
 		if (!client_dev) {
 			rc = -ENOMEM;
 			goto err;
@@ -949,6 +952,7 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
 	struct ntb_transport_mw *mw;
 	unsigned int mw_count, qp_count;
 	u64 qp_bitmap;
+	int node;
 	int rc, i;
 
 	if (ntb_db_is_unsafe(ndev))
@@ -958,7 +962,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
 		dev_dbg(&ndev->dev,
 			"scratchpad is unsafe, proceed anyway...\n");
 
-	nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+	node = dev_to_node(&ndev->dev);
+
+	nt = kzalloc_node(sizeof(*nt), GFP_KERNEL, node);
 	if (!nt)
 		return -ENOMEM;
 
@@ -968,7 +974,8 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
 
 	nt->mw_count = mw_count;
 
-	nt->mw_vec = kcalloc(mw_count, sizeof(*nt->mw_vec), GFP_KERNEL);
+	nt->mw_vec = kzalloc_node(mw_count * sizeof(*nt->mw_vec),
+				  GFP_KERNEL, node);
 	if (!nt->mw_vec) {
 		rc = -ENOMEM;
 		goto err;
@@ -1008,7 +1015,8 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
 	nt->qp_bitmap = qp_bitmap;
 	nt->qp_bitmap_free = qp_bitmap;
 
-	nt->qp_vec = kcalloc(qp_count, sizeof(*nt->qp_vec), GFP_KERNEL);
+	nt->qp_vec = kzalloc_node(qp_count * sizeof(*nt->qp_vec),
+				  GFP_KERNEL, node);
 	if (!nt->qp_vec) {
 		rc = -ENOMEM;
 		goto err2;
@@ -1497,6 +1505,11 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp)
 	ntb_qp_link_down_reset(qp);
 }
 
+static bool ntb_dma_filter_fn(struct dma_chan *chan, void *node)
+{
+	return dev_to_node(&chan->dev->device) == (int)(unsigned long)node;
+}
+
 /**
  * ntb_transport_create_queue - Create a new NTB transport layer queue
  * @rx_handler: receive callback function
@@ -1522,12 +1535,16 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
 	struct ntb_transport_qp *qp;
 	u64 qp_bit;
 	unsigned int free_queue;
+	dma_cap_mask_t dma_mask;
+	int node;
 	int i;
 
 	ndev = dev_ntb(client_dev->parent);
 	pdev = ndev->pdev;
 	nt = ndev->ctx;
 
+	node = dev_to_node(&ndev->dev);
+
 	free_queue = ffs(nt->qp_bitmap);
 	if (!free_queue)
 		goto err;
@@ -1545,15 +1562,16 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
 	qp->tx_handler = handlers->tx_handler;
 	qp->event_handler = handlers->event_handler;
 
-	dmaengine_get();
-	qp->dma_chan = dma_find_channel(DMA_MEMCPY);
-	if (!qp->dma_chan) {
-		dmaengine_put();
+	dma_cap_zero(dma_mask);
+	dma_cap_set(DMA_MEMCPY, dma_mask);
+
+	qp->dma_chan = dma_request_channel(dma_mask, ntb_dma_filter_fn,
+					   (void *)(unsigned long)node);
+	if (!qp->dma_chan)
 		dev_info(&pdev->dev, "Unable to allocate DMA channel, using CPU instead\n");
-	}
 
 	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
-		entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+		entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node);
 		if (!entry)
 			goto err1;
 
@@ -1563,7 +1581,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
 	}
 
 	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
-		entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+		entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node);
 		if (!entry)
 			goto err2;
 
@@ -1586,7 +1604,7 @@ err1:
 	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
 		kfree(entry);
 	if (qp->dma_chan)
-		dmaengine_put();
+		dma_release_channel(qp->dma_chan);
 	nt->qp_bitmap_free |= qp_bit;
 err:
 	return NULL;
@@ -1623,7 +1641,7 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 		 */
 		dma_sync_wait(chan, qp->last_cookie);
 		dmaengine_terminate_all(chan);
-		dmaengine_put();
+		dma_release_channel(chan);
 	}
 
 	qp_bit = BIT_ULL(qp->qp_num);
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 13/16] ntb_hw_intel: numa aware memory allocation
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (11 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 12/16] ntb_transport: numa aware memory and dma chan Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 14/16] ntb: performance improvement by write combining Allen Hubbe
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

Allocate memory for the numa node of the ntb device.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/ntb/hw/intel/ntb_hw_intel.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
index 7e19d46..aa0bffb 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
@@ -413,10 +413,12 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev,
 			 int msix_shift, int total_shift)
 {
 	struct pci_dev *pdev;
-	int rc, i, msix_count;
+	int rc, i, msix_count, node;
 
 	pdev = ndev_pdev(ndev);
 
+	node = dev_to_node(&pdev->dev);
+
 	/* Mask all doorbell interrupts */
 	ndev->db_mask = ndev->db_valid_mask;
 	ndev->reg->db_iowrite(ndev->db_mask,
@@ -425,11 +427,13 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev,
 
 	/* Try to set up msix irq */
 
-	ndev->vec = kcalloc(msix_max, sizeof(*ndev->vec), GFP_KERNEL);
+	ndev->vec = kzalloc_node(msix_max * sizeof(*ndev->vec),
+				 GFP_KERNEL, node);
 	if (!ndev->vec)
 		goto err_msix_vec_alloc;
 
-	ndev->msix = kcalloc(msix_max, sizeof(*ndev->msix), GFP_KERNEL);
+	ndev->msix = kzalloc_node(msix_max * sizeof(*ndev->msix),
+				  GFP_KERNEL, node);
 	if (!ndev->msix)
 		goto err_msix_alloc;
 
@@ -1963,10 +1967,12 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev,
 			       const struct pci_device_id *id)
 {
 	struct intel_ntb_dev *ndev;
-	int rc;
+	int rc, node;
+
+	node = dev_to_node(&pdev->dev);
 
 	if (pdev_is_bwd(pdev)) {
-		ndev = kmalloc(sizeof(*ndev), GFP_KERNEL);
+		ndev = kmalloc_node(sizeof(*ndev), GFP_KERNEL, node);
 		if (!ndev) {
 			rc = -ENOMEM;
 			goto err_ndev;
@@ -1983,7 +1989,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev,
 			goto err_init_dev;
 
 	} else if (pdev_is_snb(pdev)) {
-		ndev = kmalloc(sizeof(*ndev), GFP_KERNEL);
+		ndev = kmalloc_node(sizeof(*ndev), GFP_KERNEL, node);
 		if (!ndev) {
 			rc = -ENOMEM;
 			goto err_ndev;
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 14/16] ntb: performance improvement by write combining
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (12 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 13/16] ntb_hw_intel: numa aware memory allocation Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 15/16] ntb: default to cpu memcpy for performance Allen Hubbe
  2015-05-20 15:41 ` [PATCH 16/16] ntb_transport: fix small code format issues Allen Hubbe
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang

From: Dave Jiang <dave.jiang@intel.com>

Changing the memory window BAR mappings to write combining significantly
boosts the performance.  We will also use memcpy that utilizies
non-temporal store which showed performance improement when doing
non-cached memcpys.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/ntb/ntb_transport.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 91809fa..cc0b7ff 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -58,6 +58,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/uaccess.h>
 #include "linux/ntb.h"
 #include "linux/ntb_transport.h"
 
@@ -989,7 +990,7 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
 		if (rc)
 			goto err1;
 
-		mw->vbase = ioremap(mw->phys_addr, mw->phys_size);
+		mw->vbase = ioremap_wc(mw->phys_addr, mw->phys_size);
 		if (!mw->vbase) {
 			rc = -ENOMEM;
 			goto err1;
@@ -1360,7 +1361,11 @@ static void ntb_tx_copy_callback(void *data)
 
 static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset)
 {
-	memcpy_toio(offset, entry->buf, entry->len);
+	/*
+	 * Using non-temporal mov to improve performance on non-cached
+	 * writes. Even though we aren't actually copying from user space.
+	 */
+	__copy_from_user_inatomic_nocache(offset, entry->buf, entry->len);
 
 	/* Ensure that the data is fully copied out before setting the flags */
 	wmb();
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 15/16] ntb: default to cpu memcpy for performance
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (13 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 14/16] ntb: performance improvement by write combining Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  2015-05-20 15:41 ` [PATCH 16/16] ntb_transport: fix small code format issues Allen Hubbe
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

From: Dave Jiang <dave.jiang@intel.com>

Disable DMA usage by default, since the CPU provides much better
performance with write combining.  Provide a module parameter to enable
DMA usage when offloading the memcpy is preferred.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/ntb/ntb_transport.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index cc0b7ff..237f76f 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -88,6 +88,10 @@ static unsigned int copy_bytes = 1024;
 module_param(copy_bytes, uint, 0644);
 MODULE_PARM_DESC(copy_bytes, "Threshold under which NTB will use the CPU to copy instead of DMA");
 
+static bool use_dma;
+module_param(use_dma, bool, 0644);
+MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy");
+
 static struct dentry *nt_debugfs_dir;
 
 struct ntb_queue_entry {
@@ -1570,10 +1574,15 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
 	dma_cap_zero(dma_mask);
 	dma_cap_set(DMA_MEMCPY, dma_mask);
 
-	qp->dma_chan = dma_request_channel(dma_mask, ntb_dma_filter_fn,
-					   (void *)(unsigned long)node);
-	if (!qp->dma_chan)
-		dev_info(&pdev->dev, "Unable to allocate DMA channel, using CPU instead\n");
+	if (use_dma) {
+		qp->dma_chan = dma_request_channel(dma_mask, ntb_dma_filter_fn,
+						   (void *)(unsigned long)node);
+		if (!qp->dma_chan)
+			dev_info(&pdev->dev, "Unable to allocate DMA channel\n");
+	} else {
+		qp->dma_chan = NULL;
+	}
+	dev_dbg(&pdev->dev, "Using %s memcpy\n", qp->dma_chan ? "DMA" : "CPU");
 
 	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
 		entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node);
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 16/16] ntb_transport: fix small code format issues
  2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
                   ` (14 preceding siblings ...)
  2015-05-20 15:41 ` [PATCH 15/16] ntb: default to cpu memcpy for performance Allen Hubbe
@ 2015-05-20 15:41 ` Allen Hubbe
  15 siblings, 0 replies; 40+ messages in thread
From: Allen Hubbe @ 2015-05-20 15:41 UTC (permalink / raw)
  To: linux-ntb; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang, Allen Hubbe

Fix code format issues detected by checkpatch.pl.  Fix one spelling
error, and some unnecessary whitespace after cast operators.  I did not
add the comments for spinlocks, which checkpatch still reports as
missing.

Signed-off-by: Allen Hubbe <Allen.Hubbe@emc.com>
---
 drivers/ntb/ntb_transport.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 237f76f..15d237c 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -97,7 +97,7 @@ static struct dentry *nt_debugfs_dir;
 struct ntb_queue_entry {
 	/* ntb_queue list reference */
 	struct list_head entry;
-	/* pointers to data to be transfered */
+	/* pointers to data to be transferred */
 	void *cb_data;
 	void *buf;
 	unsigned int len;
@@ -1158,8 +1158,8 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset,
 		goto err_wait;
 
 	device = chan->device;
-	pay_off = (size_t) offset & ~PAGE_MASK;
-	buff_off = (size_t) buf & ~PAGE_MASK;
+	pay_off = (size_t)offset & ~PAGE_MASK;
+	buff_off = (size_t)buf & ~PAGE_MASK;
 
 	if (!is_dma_copy_aligned(device, pay_off, buff_off, len))
 		goto err_wait;
@@ -1397,7 +1397,7 @@ static void ntb_async_tx(struct ntb_transport_qp *qp,
 	entry->tx_hdr = hdr;
 
 	iowrite32(entry->len, &hdr->len);
-	iowrite32((u32) qp->tx_pkts, &hdr->ver);
+	iowrite32((u32)qp->tx_pkts, &hdr->ver);
 
 	if (!chan)
 		goto err;
@@ -1407,8 +1407,8 @@ static void ntb_async_tx(struct ntb_transport_qp *qp,
 
 	device = chan->device;
 	dest = qp->tx_mw_phys + qp->tx_max_frame * qp->tx_index;
-	buff_off = (size_t) buf & ~PAGE_MASK;
-	dest_off = (size_t) dest & ~PAGE_MASK;
+	buff_off = (size_t)buf & ~PAGE_MASK;
+	dest_off = (size_t)dest & ~PAGE_MASK;
 
 	if (!is_dma_copy_aligned(device, buff_off, dest_off, len))
 		goto err;
-- 
2.4.0.rc0.43.gcf8a8c6


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/16] Check the DID for certain workaround error flags to be set.
  2015-05-20 15:41 ` [PATCH 04/16] Check the DID for certain workaround error flags to be set Allen Hubbe
@ 2015-05-20 21:11   ` Bjorn Helgaas
  2015-05-20 21:15       ` Jiang, Dave
  0 siblings, 1 reply; 40+ messages in thread
From: Bjorn Helgaas @ 2015-05-20 21:11 UTC (permalink / raw)
  To: Allen Hubbe; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com> wrote:
> From: Dave Jiang <dave.jiang@intel.com>
>
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>

Needs a topic in the subject line and a changelog.

It also seems to do a lot more than just checking device ID (I assume
that's what "DID" means), so this should probably be split into
several patches that each do one thing.  I see at least:

  - cosmetic code restructuring
  - work_struct/tasklet_struct changes
  - new #defines and bar2_off() changes

> ---
>  drivers/ntb/hw/intel/ntb_hw_intel.c | 196 +++++++++++++++++++-----------------
>  drivers/ntb/hw/intel/ntb_hw_intel.h |  24 ++++-
>  drivers/ntb/ntb_transport.c         |  16 +--
>  3 files changed, 133 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index d162f22..89fea50 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -503,7 +503,6 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
>         size_t buf_size;
>         ssize_t ret, off;
>         union { u64 v64; u32 v32; u16 v16; } u;
> -       unsigned long reg;
>
>         ndev = filp->private_data;
>         mmio = ndev->self_mmio;
> @@ -538,10 +537,10 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
>
>         if (!ndev->reg->link_is_up(ndev)) {
>                 off += scnprintf(buf + off, buf_size - off,
> -                                "Link Satus -\t\tDown\n");
> +                                "Link Status -\t\tDown\n");
>         } else {
>                 off += scnprintf(buf + off, buf_size - off,
> -                                "Link Satus -\t\tUp\n");
> +                                "Link Status -\t\tUp\n");
>                 off += scnprintf(buf + off, buf_size - off,
>                                  "Link Speed -\t\tPCI-E Gen %u\n",
>                                  NTB_LNK_STA_SPEED(ndev->lnk_sta));
> @@ -568,36 +567,30 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
>         off += scnprintf(buf + off, buf_size - off,
>                          "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
>
> -       reg = ndev->self_reg->db_mask;
> -       u.v64 = ndev_db_read(ndev, mmio + reg);
> +       u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask);
>         off += scnprintf(buf + off, buf_size - off,
>                          "Doorbell Mask -\t\t%#llx\n", u.v64);
>
> -       reg = ndev->self_reg->db_bell;
> -       u.v64 = ndev_db_read(ndev, mmio + reg);
> +       u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell);
>         off += scnprintf(buf + off, buf_size - off,
>                          "Doorbell Bell -\t\t%#llx\n", u.v64);
>
>         off += scnprintf(buf + off, buf_size - off,
>                          "\nNTB Incoming XLAT:\n");
>
> -       reg = bar2_off(ndev->xlat_reg->bar2_xlat, 2);
> -       u.v64 = ioread64(mmio + reg);
> +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2));
>         off += scnprintf(buf + off, buf_size - off,
>                          "XLAT23 -\t\t%#018llx\n", u.v64);
>
> -       reg = bar2_off(ndev->xlat_reg->bar2_xlat, 4);
> -       u.v64 = ioread64(mmio + reg);
> +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4));
>         off += scnprintf(buf + off, buf_size - off,
>                          "XLAT45 -\t\t%#018llx\n", u.v64);
>
> -       reg = bar2_off(ndev->xlat_reg->bar2_limit, 2);
> -       u.v64 = ioread64(mmio + reg);
> +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2));
>         off += scnprintf(buf + off, buf_size - off,
>                          "LMT23 -\t\t\t%#018llx\n", u.v64);
>
> -       reg = bar2_off(ndev->xlat_reg->bar2_limit, 4);
> -       u.v64 = ioread64(mmio + reg);
> +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4));
>         off += scnprintf(buf + off, buf_size - off,
>                          "LMT45 -\t\t\t%#018llx\n", u.v64);
>
> @@ -606,41 +599,34 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "\nNTB Outgoing B2B XLAT:\n");
>
> -                       reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 2);
> -                       u.v64 = ioread64(mmio + reg);
> +                       u.v64 = ioread64(mmio + SNB_PBAR23XLAT_OFFSET);
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "B2B XLAT23 -\t\t%#018llx\n", u.v64);
>
> -                       reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 4);
> -                       u.v64 = ioread64(mmio + reg);
> +                       u.v64 = ioread64(mmio + SNB_PBAR45XLAT_OFFSET);
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "B2B XLAT45 -\t\t%#018llx\n", u.v64);
>
> -                       reg = bar2_off(SNB_PBAR2LMT_OFFSET, 2);
> -                       u.v64 = ioread64(mmio + reg);
> +                       u.v64 = ioread64(mmio + SNB_PBAR23LMT_OFFSET);
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "B2B LMT23 -\t\t%#018llx\n", u.v64);
>
> -                       reg = bar2_off(SNB_PBAR2LMT_OFFSET, 4);
> -                       u.v64 = ioread64(mmio + reg);
> +                       u.v64 = ioread64(mmio + SNB_PBAR45LMT_OFFSET);
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "B2B LMT45 -\t\t%#018llx\n", u.v64);
>
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "\nNTB Secondary BAR:\n");
>
> -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 0);
> -                       u.v64 = ioread64(mmio + reg);
> +                       u.v64 = ioread64(mmio + SNB_SBAR0BASE_OFFSET);
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "SBAR01 -\t\t%#018llx\n", u.v64);
>
> -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 2);
> -                       u.v64 = ioread64(mmio + reg);
> +                       u.v64 = ioread64(mmio + SNB_SBAR23BASE_OFFSET);
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "SBAR23 -\t\t%#018llx\n", u.v64);
>
> -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 4);
> -                       u.v64 = ioread64(mmio + reg);
> +                       u.v64 = ioread64(mmio + SNB_SBAR45BASE_OFFSET);
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "SBAR45 -\t\t%#018llx\n", u.v64);
>                 }
> @@ -648,31 +634,30 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
>                 off += scnprintf(buf + off, buf_size - off,
>                                  "\nSNB NTB Statistics:\n");
>
> -               reg = SNB_USMEMMISS_OFFSET;
> -               u.v16 = ioread16(mmio + reg);
> +               u.v16 = ioread16(mmio + SNB_USMEMMISS_OFFSET);
>                 off += scnprintf(buf + off, buf_size - off,
>                                  "Upstream Memory Miss -\t%u\n", u.v16);
>
>                 off += scnprintf(buf + off, buf_size - off,
>                                  "\nSNB NTB Hardware Errors:\n");
>
> -               reg = SNB_DEVSTS_OFFSET;
> -               if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
> +               if (!pci_read_config_word(ndev->ntb.pdev,
> +                                         SNB_DEVSTS_OFFSET, &u.v16))
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "DEVSTS -\t\t%#06x\n", u.v16);
>
> -               reg = SNB_LINK_STATUS_OFFSET;
> -               if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
> +               if (!pci_read_config_word(ndev->ntb.pdev,
> +                                         SNB_LINK_STATUS_OFFSET, &u.v16))
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "LNKSTS -\t\t%#06x\n", u.v16);
>
> -               reg = SNB_UNCERRSTS_OFFSET;
> -               if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
> +               if (!pci_read_config_dword(ndev->ntb.pdev,
> +                                          SNB_UNCERRSTS_OFFSET, &u.v32))
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "UNCERRSTS -\t\t%#06x\n", u.v32);
>
> -               reg = SNB_CORERRSTS_OFFSET;
> -               if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
> +               if (!pci_read_config_dword(ndev->ntb.pdev,
> +                                          SNB_CORERRSTS_OFFSET, &u.v32))
>                         off += scnprintf(buf + off, buf_size - off,
>                                          "CORERRSTS -\t\t%#06x\n", u.v32);
>         }
> @@ -1388,7 +1373,6 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
>  {
>         struct pci_dev *pdev;
>         void __iomem *mmio;
> -       unsigned long off;
>         resource_size_t bar_size;
>         phys_addr_t bar_addr;
>         int b2b_bar;
> @@ -1484,9 +1468,6 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
>                 dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz);
>         }
>
> -       /* setup incoming bar base addresses */
> -       off = SNB_SBAR0BASE_OFFSET;
> -
>         /* SBAR01 hit by first part of the b2b bar */
>         if (b2b_bar == 0) {
>                 bar_addr = addr->bar0_addr;
> @@ -1504,7 +1485,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
>         }
>
>         dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr);
> -       iowrite64(bar_addr, mmio + bar0_off(off, 0));
> +       iowrite64(bar_addr, mmio + SNB_SBAR0BASE_OFFSET);
>
>         /* Other SBAR are normally hit by the PBAR xlat, except for b2b bar.
>          * The b2b bar is either disabled above, or configured half-size, and
> @@ -1512,102 +1493,96 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
>          */
>
>         bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
> -       iowrite64(bar_addr, mmio + bar0_off(off, 2));
> -       bar_addr = ioread64(mmio + bar0_off(off, 2));
> +       iowrite64(bar_addr, mmio + SNB_SBAR23BASE_OFFSET);
> +       bar_addr = ioread64(mmio + SNB_SBAR23BASE_OFFSET);
>         dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr);
>
>         if (!ndev->bar4_split) {
>                 bar_addr = addr->bar4_addr64 +
>                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> -               iowrite64(bar_addr, mmio + bar0_off(off, 4));
> -               bar_addr = ioread64(mmio + bar0_off(off, 4));
> +               iowrite64(bar_addr, mmio + SNB_SBAR45BASE_OFFSET);
> +               bar_addr = ioread64(mmio + SNB_SBAR45BASE_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr);
>         } else {
>                 bar_addr = addr->bar4_addr32 +
>                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> -               iowrite32(bar_addr, mmio + bar0_off(off, 4));
> -               bar_addr = ioread32(mmio + bar0_off(off, 4));
> +               iowrite32(bar_addr, mmio + SNB_SBAR4BASE_OFFSET);
> +               bar_addr = ioread32(mmio + SNB_SBAR4BASE_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr);
>
>                 bar_addr = addr->bar5_addr32 +
>                         (b2b_bar == 5 ? ndev->b2b_off : 0);
> -               iowrite32(bar_addr, mmio + bar0_off(off, 5));
> -               bar_addr = ioread32(mmio + bar0_off(off, 5));
> +               iowrite32(bar_addr, mmio + SNB_SBAR5BASE_OFFSET);
> +               bar_addr = ioread32(mmio + SNB_SBAR5BASE_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr);
>         }
>
>         /* setup incoming bar limits == base addrs (zero length windows) */
> -       off = SNB_SBAR2LMT_OFFSET;
>
>         bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
> -       iowrite64(bar_addr, mmio + bar2_off(off, 2));
> -       bar_addr = ioread64(mmio + bar2_off(off, 2));
> +       iowrite64(bar_addr, mmio + SNB_SBAR23LMT_OFFSET);
> +       bar_addr = ioread64(mmio + SNB_SBAR23LMT_OFFSET);
>         dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr);
>
>         if (!ndev->bar4_split) {
>                 bar_addr = addr->bar4_addr64 +
>                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> -               iowrite64(bar_addr, mmio + bar2_off(off, 4));
> -               bar_addr = ioread64(mmio + bar2_off(off, 4));
> +               iowrite64(bar_addr, mmio + SNB_SBAR45LMT_OFFSET);
> +               bar_addr = ioread64(mmio + SNB_SBAR45LMT_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr);
>         } else {
>                 bar_addr = addr->bar4_addr32 +
>                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> -               iowrite32(bar_addr, mmio + bar2_off(off, 4));
> -               bar_addr = ioread32(mmio + bar2_off(off, 4));
> +               iowrite32(bar_addr, mmio + SNB_SBAR4LMT_OFFSET);
> +               bar_addr = ioread32(mmio + SNB_SBAR4LMT_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr);
>
>                 bar_addr = addr->bar5_addr32 +
>                         (b2b_bar == 5 ? ndev->b2b_off : 0);
> -               iowrite32(bar_addr, mmio + bar2_off(off, 5));
> -               bar_addr = ioread32(mmio + bar2_off(off, 5));
> +               iowrite32(bar_addr, mmio + SNB_SBAR5LMT_OFFSET);
> +               bar_addr = ioread32(mmio + SNB_SBAR5LMT_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr);
>         }
>
>         /* zero incoming translation addrs */
> -       off = SNB_SBAR2XLAT_OFFSET;
> -
> -       iowrite64(0, mmio + bar2_off(off, 2));
> +       iowrite64(0, mmio + SNB_SBAR23XLAT_OFFSET);
>
>         if (!ndev->bar4_split) {
> -               iowrite64(0, mmio + bar2_off(off, 4));
> +               iowrite64(0, mmio + SNB_SBAR45XLAT_OFFSET);
>         } else {
> -               iowrite32(0, mmio + bar2_off(off, 4));
> -               iowrite32(0, mmio + bar2_off(off, 5));
> +               iowrite32(0, mmio + SNB_SBAR4XLAT_OFFSET);
> +               iowrite32(0, mmio + SNB_SBAR5XLAT_OFFSET);
>         }
>
>         /* zero outgoing translation limits (whole bar size windows) */
> -       off = SNB_PBAR2LMT_OFFSET;
> -       iowrite64(0, mmio + bar2_off(off, 2));
> +       iowrite64(0, mmio + SNB_PBAR23LMT_OFFSET);
>         if (!ndev->bar4_split) {
> -               iowrite64(0, mmio + bar2_off(off, 4));
> +               iowrite64(0, mmio + SNB_PBAR45LMT_OFFSET);
>         } else {
> -               iowrite32(0, mmio + bar2_off(off, 4));
> -               iowrite32(0, mmio + bar2_off(off, 5));
> +               iowrite32(0, mmio + SNB_PBAR4LMT_OFFSET);
> +               iowrite32(0, mmio + SNB_PBAR5LMT_OFFSET);
>         }
>
>         /* set outgoing translation offsets */
> -       off = SNB_PBAR2XLAT_OFFSET;
> -
>         bar_addr = peer_addr->bar2_addr64;
> -       iowrite64(bar_addr, mmio + bar2_off(off, 2));
> -       bar_addr = ioread64(mmio + bar2_off(off, 2));
> +       iowrite64(bar_addr, mmio + SNB_PBAR23XLAT_OFFSET);
> +       bar_addr = ioread64(mmio + SNB_PBAR23XLAT_OFFSET);
>         dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr);
>
>         if (!ndev->bar4_split) {
>                 bar_addr = peer_addr->bar4_addr64;
> -               iowrite64(bar_addr, mmio + bar2_off(off, 4));
> -               bar_addr = ioread64(mmio + bar2_off(off, 4));
> +               iowrite64(bar_addr, mmio + SNB_PBAR45XLAT_OFFSET);
> +               bar_addr = ioread64(mmio + SNB_PBAR45XLAT_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr);
>         } else {
>                 bar_addr = peer_addr->bar2_addr64;
> -               iowrite32(bar_addr, mmio + bar2_off(off, 4));
> -               bar_addr = ioread32(mmio + bar2_off(off, 4));
> +               iowrite32(bar_addr, mmio + SNB_PBAR4XLAT_OFFSET);
> +               bar_addr = ioread32(mmio + SNB_PBAR4XLAT_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr);
>
>                 bar_addr = peer_addr->bar2_addr64;
> -               iowrite32(bar_addr, mmio + bar2_off(off, 5));
> -               bar_addr = ioread32(mmio + bar2_off(off, 5));
> +               iowrite32(bar_addr, mmio + SNB_PBAR5XLAT_OFFSET);
> +               bar_addr = ioread32(mmio + SNB_PBAR5XLAT_OFFSET);
>                 dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr);
>         }
>
> @@ -1747,29 +1722,68 @@ static int snb_init_dev(struct intel_ntb_dev *ndev)
>         u8 ppd;
>         int rc, mem;
>
> +       pdev = ndev_pdev(ndev);
> +
> +       switch (pdev->device) {
>         /* 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
>          * window to access the interrupt and scratch pad registers on the
>          * remote system.
>          */
> -       ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> +               ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> +               break;
> +       }
>
> +       switch (pdev->device) {
>         /* There is a hardware errata related to accessing any register in
>          * SB01BASE in the presence of bidirectional traffic crossing the NTB.
>          */
> -       ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> +               ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> +               break;
> +       }
>
> +       switch (pdev->device) {
>         /* HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
>          * mirrored to the remote system.  Shrink the number of bits by one,
>          * since bit 14 is the last bit.
>          */
> -       ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> +               ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> +               break;
> +       }
>
>         ndev->reg = &snb_reg;
>
> -       pdev = ndev_pdev(ndev);
> -
>         rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd);
>         if (rc)
>                 return -EIO;
> @@ -2062,14 +2076,14 @@ static const struct intel_ntb_xlat_reg snb_pri_xlat = {
>          * window by setting the limit equal to base, nor can it limit the size
>          * of the memory window by setting the limit to base + size.
>          */
> -       .bar2_limit             = SNB_PBAR2LMT_OFFSET,
> -       .bar2_xlat              = SNB_PBAR2XLAT_OFFSET,
> +       .bar2_limit             = SNB_PBAR23LMT_OFFSET,
> +       .bar2_xlat              = SNB_PBAR23XLAT_OFFSET,
>  };
>
>  static const struct intel_ntb_xlat_reg snb_sec_xlat = {
>         .bar0_base              = SNB_SBAR0BASE_OFFSET,
> -       .bar2_limit             = SNB_SBAR2LMT_OFFSET,
> -       .bar2_xlat              = SNB_SBAR2XLAT_OFFSET,
> +       .bar2_limit             = SNB_SBAR23LMT_OFFSET,
> +       .bar2_xlat              = SNB_SBAR23XLAT_OFFSET,
>  };
>
>  static const struct intel_b2b_addr snb_b2b_usd_addr = {
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
> index 0224b1a..fec689d 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.h
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
> @@ -70,11 +70,27 @@
>
>  /* SNB hardware (and JSF, IVT, HSX) */
>
> -#define SNB_PBAR2LMT_OFFSET            0x0000
> -#define SNB_PBAR2XLAT_OFFSET           0x0010
> -#define SNB_SBAR2LMT_OFFSET            0x0020
> -#define SNB_SBAR2XLAT_OFFSET           0x0030
> +#define SNB_PBAR23LMT_OFFSET           0x0000
> +#define SNB_PBAR45LMT_OFFSET           0x0008
> +#define SNB_PBAR4LMT_OFFSET            0x0008
> +#define SNB_PBAR5LMT_OFFSET            0x000c
> +#define SNB_PBAR23XLAT_OFFSET          0x0010
> +#define SNB_PBAR45XLAT_OFFSET          0x0018
> +#define SNB_PBAR4XLAT_OFFSET           0x0018
> +#define SNB_PBAR5XLAT_OFFSET           0x001c
> +#define SNB_SBAR23LMT_OFFSET           0x0020
> +#define SNB_SBAR45LMT_OFFSET           0x0028
> +#define SNB_SBAR4LMT_OFFSET            0x0028
> +#define SNB_SBAR5LMT_OFFSET            0x002c
> +#define SNB_SBAR23XLAT_OFFSET          0x0030
> +#define SNB_SBAR45XLAT_OFFSET          0x0038
> +#define SNB_SBAR4XLAT_OFFSET           0x0038
> +#define SNB_SBAR5XLAT_OFFSET           0x003c
>  #define SNB_SBAR0BASE_OFFSET           0x0040
> +#define SNB_SBAR23BASE_OFFSET          0x0048
> +#define SNB_SBAR45BASE_OFFSET          0x0050
> +#define SNB_SBAR4BASE_OFFSET           0x0050
> +#define SNB_SBAR5BASE_OFFSET           0x0054
>  #define SNB_SBDF_OFFSET                        0x005c
>  #define SNB_NTBCNTL_OFFSET             0x0058
>  #define SNB_PDOORBELL_OFFSET           0x0060
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index f1ed1b7..bb2eb85 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -204,8 +204,8 @@ struct ntb_transport_ctx {
>
>         bool link_is_up;
>         struct delayed_work link_work;
> -       struct work_struct db_work;
>         struct work_struct link_cleanup;
> +       struct tasklet_struct db_work;
>  };
>
>  enum {
> @@ -241,7 +241,7 @@ enum {
>  #define NTB_QP_DEF_NUM_ENTRIES 100
>  #define NTB_LINK_DOWN_TIMEOUT  10
>
> -static void ntb_transport_doorbell_work(struct work_struct *ws);
> +static void ntb_transport_doorbell_work(unsigned long data);
>  static const struct ntb_ctx_ops ntb_transport_ops;
>  static struct ntb_client ntb_transport_client;
>
> @@ -1002,8 +1002,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
>         }
>
>         INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
> -       INIT_WORK(&nt->db_work, ntb_transport_doorbell_work);
>         INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work);
> +       tasklet_init(&nt->db_work, ntb_transport_doorbell_work,
> +                    (unsigned long)nt);
>
>         rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops);
>         if (rc)
> @@ -1044,7 +1045,7 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev)
>         int i;
>
>         ntb_transport_link_cleanup(nt);
> -       cancel_work_sync(&nt->db_work);
> +       tasklet_disable(&nt->db_work);
>         cancel_work_sync(&nt->link_cleanup);
>         cancel_delayed_work_sync(&nt->link_work);
>
> @@ -1850,10 +1851,9 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
>  }
>  EXPORT_SYMBOL_GPL(ntb_transport_max_size);
>
> -static void ntb_transport_doorbell_work(struct work_struct *work)
> +static void ntb_transport_doorbell_work(unsigned long data)
>  {
> -       struct ntb_transport_ctx *nt = container_of(work,
> -                       struct ntb_transport_ctx, db_work);
> +       struct ntb_transport_ctx *nt = (void *)data;
>         struct ntb_transport_qp *qp;
>         u64 db_mask, db_bits, db_again;
>         unsigned int qp_num;
> @@ -1890,7 +1890,7 @@ static void ntb_transport_doorbell_callback(void *data, int vector)
>
>         ntb_db_set_mask(nt->ndev, ntb_db_valid_mask(nt->ndev));
>
> -       schedule_work(&nt->db_work);
> +       tasklet_schedule(&nt->db_work);
>  }
>
>  static const struct ntb_ctx_ops ntb_transport_ops = {
> --
> 2.4.0.rc0.43.gcf8a8c6
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/16] Check the DID for certain workaround error flags to be set.
  2015-05-20 21:11   ` Bjorn Helgaas
  2015-05-20 21:15       ` Jiang, Dave
@ 2015-05-20 21:15       ` Jiang, Dave
  0 siblings, 0 replies; 40+ messages in thread
From: Jiang, Dave @ 2015-05-20 21:15 UTC (permalink / raw)
  To: bhelgaas; +Cc: Allen.Hubbe, linux-kernel, linux-pci, jdmason, linux-ntb

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 26814 bytes --]

On Wed, 2015-05-20 at 16:11 -0500, Bjorn Helgaas wrote:
> On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com> wrote:
> > From: Dave Jiang <dave.jiang@intel.com>
> >
> > Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> 
> Needs a topic in the subject line and a changelog.
> 
> It also seems to do a lot more than just checking device ID (I assume
> that's what "DID" means), so this should probably be split into
> several patches that each do one thing.  I see at least:
> 
>   - cosmetic code restructuring
>   - work_struct/tasklet_struct changes
>   - new #defines and bar2_off() changes

I think this patch got mangled with couple other patches. Allen?

> 
> > ---
> >  drivers/ntb/hw/intel/ntb_hw_intel.c | 196 +++++++++++++++++++-----------------
> >  drivers/ntb/hw/intel/ntb_hw_intel.h |  24 ++++-
> >  drivers/ntb/ntb_transport.c         |  16 +--
> >  3 files changed, 133 insertions(+), 103 deletions(-)
> >
> > diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> > index d162f22..89fea50 100644
> > --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> > +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> > @@ -503,7 +503,6 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >         size_t buf_size;
> >         ssize_t ret, off;
> >         union { u64 v64; u32 v32; u16 v16; } u;
> > -       unsigned long reg;
> >
> >         ndev = filp->private_data;
> >         mmio = ndev->self_mmio;
> > @@ -538,10 +537,10 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >
> >         if (!ndev->reg->link_is_up(ndev)) {
> >                 off += scnprintf(buf + off, buf_size - off,
> > -                                "Link Satus -\t\tDown\n");
> > +                                "Link Status -\t\tDown\n");
> >         } else {
> >                 off += scnprintf(buf + off, buf_size - off,
> > -                                "Link Satus -\t\tUp\n");
> > +                                "Link Status -\t\tUp\n");
> >                 off += scnprintf(buf + off, buf_size - off,
> >                                  "Link Speed -\t\tPCI-E Gen %u\n",
> >                                  NTB_LNK_STA_SPEED(ndev->lnk_sta));
> > @@ -568,36 +567,30 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
> >
> > -       reg = ndev->self_reg->db_mask;
> > -       u.v64 = ndev_db_read(ndev, mmio + reg);
> > +       u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask);
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "Doorbell Mask -\t\t%#llx\n", u.v64);
> >
> > -       reg = ndev->self_reg->db_bell;
> > -       u.v64 = ndev_db_read(ndev, mmio + reg);
> > +       u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell);
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "Doorbell Bell -\t\t%#llx\n", u.v64);
> >
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "\nNTB Incoming XLAT:\n");
> >
> > -       reg = bar2_off(ndev->xlat_reg->bar2_xlat, 2);
> > -       u.v64 = ioread64(mmio + reg);
> > +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2));
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "XLAT23 -\t\t%#018llx\n", u.v64);
> >
> > -       reg = bar2_off(ndev->xlat_reg->bar2_xlat, 4);
> > -       u.v64 = ioread64(mmio + reg);
> > +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4));
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "XLAT45 -\t\t%#018llx\n", u.v64);
> >
> > -       reg = bar2_off(ndev->xlat_reg->bar2_limit, 2);
> > -       u.v64 = ioread64(mmio + reg);
> > +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2));
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "LMT23 -\t\t\t%#018llx\n", u.v64);
> >
> > -       reg = bar2_off(ndev->xlat_reg->bar2_limit, 4);
> > -       u.v64 = ioread64(mmio + reg);
> > +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4));
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "LMT45 -\t\t\t%#018llx\n", u.v64);
> >
> > @@ -606,41 +599,34 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "\nNTB Outgoing B2B XLAT:\n");
> >
> > -                       reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 2);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_PBAR23XLAT_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "B2B XLAT23 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 4);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_PBAR45XLAT_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "B2B XLAT45 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar2_off(SNB_PBAR2LMT_OFFSET, 2);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_PBAR23LMT_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "B2B LMT23 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar2_off(SNB_PBAR2LMT_OFFSET, 4);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_PBAR45LMT_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "B2B LMT45 -\t\t%#018llx\n", u.v64);
> >
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "\nNTB Secondary BAR:\n");
> >
> > -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 0);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_SBAR0BASE_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "SBAR01 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 2);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_SBAR23BASE_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "SBAR23 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 4);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_SBAR45BASE_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "SBAR45 -\t\t%#018llx\n", u.v64);
> >                 }
> > @@ -648,31 +634,30 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >                 off += scnprintf(buf + off, buf_size - off,
> >                                  "\nSNB NTB Statistics:\n");
> >
> > -               reg = SNB_USMEMMISS_OFFSET;
> > -               u.v16 = ioread16(mmio + reg);
> > +               u.v16 = ioread16(mmio + SNB_USMEMMISS_OFFSET);
> >                 off += scnprintf(buf + off, buf_size - off,
> >                                  "Upstream Memory Miss -\t%u\n", u.v16);
> >
> >                 off += scnprintf(buf + off, buf_size - off,
> >                                  "\nSNB NTB Hardware Errors:\n");
> >
> > -               reg = SNB_DEVSTS_OFFSET;
> > -               if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
> > +               if (!pci_read_config_word(ndev->ntb.pdev,
> > +                                         SNB_DEVSTS_OFFSET, &u.v16))
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "DEVSTS -\t\t%#06x\n", u.v16);
> >
> > -               reg = SNB_LINK_STATUS_OFFSET;
> > -               if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
> > +               if (!pci_read_config_word(ndev->ntb.pdev,
> > +                                         SNB_LINK_STATUS_OFFSET, &u.v16))
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "LNKSTS -\t\t%#06x\n", u.v16);
> >
> > -               reg = SNB_UNCERRSTS_OFFSET;
> > -               if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
> > +               if (!pci_read_config_dword(ndev->ntb.pdev,
> > +                                          SNB_UNCERRSTS_OFFSET, &u.v32))
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "UNCERRSTS -\t\t%#06x\n", u.v32);
> >
> > -               reg = SNB_CORERRSTS_OFFSET;
> > -               if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
> > +               if (!pci_read_config_dword(ndev->ntb.pdev,
> > +                                          SNB_CORERRSTS_OFFSET, &u.v32))
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "CORERRSTS -\t\t%#06x\n", u.v32);
> >         }
> > @@ -1388,7 +1373,6 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
> >  {
> >         struct pci_dev *pdev;
> >         void __iomem *mmio;
> > -       unsigned long off;
> >         resource_size_t bar_size;
> >         phys_addr_t bar_addr;
> >         int b2b_bar;
> > @@ -1484,9 +1468,6 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
> >                 dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz);
> >         }
> >
> > -       /* setup incoming bar base addresses */
> > -       off = SNB_SBAR0BASE_OFFSET;
> > -
> >         /* SBAR01 hit by first part of the b2b bar */
> >         if (b2b_bar == 0) {
> >                 bar_addr = addr->bar0_addr;
> > @@ -1504,7 +1485,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
> >         }
> >
> >         dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr);
> > -       iowrite64(bar_addr, mmio + bar0_off(off, 0));
> > +       iowrite64(bar_addr, mmio + SNB_SBAR0BASE_OFFSET);
> >
> >         /* Other SBAR are normally hit by the PBAR xlat, except for b2b bar.
> >          * The b2b bar is either disabled above, or configured half-size, and
> > @@ -1512,102 +1493,96 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
> >          */
> >
> >         bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
> > -       iowrite64(bar_addr, mmio + bar0_off(off, 2));
> > -       bar_addr = ioread64(mmio + bar0_off(off, 2));
> > +       iowrite64(bar_addr, mmio + SNB_SBAR23BASE_OFFSET);
> > +       bar_addr = ioread64(mmio + SNB_SBAR23BASE_OFFSET);
> >         dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr);
> >
> >         if (!ndev->bar4_split) {
> >                 bar_addr = addr->bar4_addr64 +
> >                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> > -               iowrite64(bar_addr, mmio + bar0_off(off, 4));
> > -               bar_addr = ioread64(mmio + bar0_off(off, 4));
> > +               iowrite64(bar_addr, mmio + SNB_SBAR45BASE_OFFSET);
> > +               bar_addr = ioread64(mmio + SNB_SBAR45BASE_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr);
> >         } else {
> >                 bar_addr = addr->bar4_addr32 +
> >                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> > -               iowrite32(bar_addr, mmio + bar0_off(off, 4));
> > -               bar_addr = ioread32(mmio + bar0_off(off, 4));
> > +               iowrite32(bar_addr, mmio + SNB_SBAR4BASE_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_SBAR4BASE_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr);
> >
> >                 bar_addr = addr->bar5_addr32 +
> >                         (b2b_bar == 5 ? ndev->b2b_off : 0);
> > -               iowrite32(bar_addr, mmio + bar0_off(off, 5));
> > -               bar_addr = ioread32(mmio + bar0_off(off, 5));
> > +               iowrite32(bar_addr, mmio + SNB_SBAR5BASE_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_SBAR5BASE_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr);
> >         }
> >
> >         /* setup incoming bar limits == base addrs (zero length windows) */
> > -       off = SNB_SBAR2LMT_OFFSET;
> >
> >         bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
> > -       iowrite64(bar_addr, mmio + bar2_off(off, 2));
> > -       bar_addr = ioread64(mmio + bar2_off(off, 2));
> > +       iowrite64(bar_addr, mmio + SNB_SBAR23LMT_OFFSET);
> > +       bar_addr = ioread64(mmio + SNB_SBAR23LMT_OFFSET);
> >         dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr);
> >
> >         if (!ndev->bar4_split) {
> >                 bar_addr = addr->bar4_addr64 +
> >                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> > -               iowrite64(bar_addr, mmio + bar2_off(off, 4));
> > -               bar_addr = ioread64(mmio + bar2_off(off, 4));
> > +               iowrite64(bar_addr, mmio + SNB_SBAR45LMT_OFFSET);
> > +               bar_addr = ioread64(mmio + SNB_SBAR45LMT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr);
> >         } else {
> >                 bar_addr = addr->bar4_addr32 +
> >                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> > -               iowrite32(bar_addr, mmio + bar2_off(off, 4));
> > -               bar_addr = ioread32(mmio + bar2_off(off, 4));
> > +               iowrite32(bar_addr, mmio + SNB_SBAR4LMT_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_SBAR4LMT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr);
> >
> >                 bar_addr = addr->bar5_addr32 +
> >                         (b2b_bar == 5 ? ndev->b2b_off : 0);
> > -               iowrite32(bar_addr, mmio + bar2_off(off, 5));
> > -               bar_addr = ioread32(mmio + bar2_off(off, 5));
> > +               iowrite32(bar_addr, mmio + SNB_SBAR5LMT_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_SBAR5LMT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr);
> >         }
> >
> >         /* zero incoming translation addrs */
> > -       off = SNB_SBAR2XLAT_OFFSET;
> > -
> > -       iowrite64(0, mmio + bar2_off(off, 2));
> > +       iowrite64(0, mmio + SNB_SBAR23XLAT_OFFSET);
> >
> >         if (!ndev->bar4_split) {
> > -               iowrite64(0, mmio + bar2_off(off, 4));
> > +               iowrite64(0, mmio + SNB_SBAR45XLAT_OFFSET);
> >         } else {
> > -               iowrite32(0, mmio + bar2_off(off, 4));
> > -               iowrite32(0, mmio + bar2_off(off, 5));
> > +               iowrite32(0, mmio + SNB_SBAR4XLAT_OFFSET);
> > +               iowrite32(0, mmio + SNB_SBAR5XLAT_OFFSET);
> >         }
> >
> >         /* zero outgoing translation limits (whole bar size windows) */
> > -       off = SNB_PBAR2LMT_OFFSET;
> > -       iowrite64(0, mmio + bar2_off(off, 2));
> > +       iowrite64(0, mmio + SNB_PBAR23LMT_OFFSET);
> >         if (!ndev->bar4_split) {
> > -               iowrite64(0, mmio + bar2_off(off, 4));
> > +               iowrite64(0, mmio + SNB_PBAR45LMT_OFFSET);
> >         } else {
> > -               iowrite32(0, mmio + bar2_off(off, 4));
> > -               iowrite32(0, mmio + bar2_off(off, 5));
> > +               iowrite32(0, mmio + SNB_PBAR4LMT_OFFSET);
> > +               iowrite32(0, mmio + SNB_PBAR5LMT_OFFSET);
> >         }
> >
> >         /* set outgoing translation offsets */
> > -       off = SNB_PBAR2XLAT_OFFSET;
> > -
> >         bar_addr = peer_addr->bar2_addr64;
> > -       iowrite64(bar_addr, mmio + bar2_off(off, 2));
> > -       bar_addr = ioread64(mmio + bar2_off(off, 2));
> > +       iowrite64(bar_addr, mmio + SNB_PBAR23XLAT_OFFSET);
> > +       bar_addr = ioread64(mmio + SNB_PBAR23XLAT_OFFSET);
> >         dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr);
> >
> >         if (!ndev->bar4_split) {
> >                 bar_addr = peer_addr->bar4_addr64;
> > -               iowrite64(bar_addr, mmio + bar2_off(off, 4));
> > -               bar_addr = ioread64(mmio + bar2_off(off, 4));
> > +               iowrite64(bar_addr, mmio + SNB_PBAR45XLAT_OFFSET);
> > +               bar_addr = ioread64(mmio + SNB_PBAR45XLAT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr);
> >         } else {
> >                 bar_addr = peer_addr->bar2_addr64;
> > -               iowrite32(bar_addr, mmio + bar2_off(off, 4));
> > -               bar_addr = ioread32(mmio + bar2_off(off, 4));
> > +               iowrite32(bar_addr, mmio + SNB_PBAR4XLAT_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_PBAR4XLAT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr);
> >
> >                 bar_addr = peer_addr->bar2_addr64;
> > -               iowrite32(bar_addr, mmio + bar2_off(off, 5));
> > -               bar_addr = ioread32(mmio + bar2_off(off, 5));
> > +               iowrite32(bar_addr, mmio + SNB_PBAR5XLAT_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_PBAR5XLAT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr);
> >         }
> >
> > @@ -1747,29 +1722,68 @@ static int snb_init_dev(struct intel_ntb_dev *ndev)
> >         u8 ppd;
> >         int rc, mem;
> >
> > +       pdev = ndev_pdev(ndev);
> > +
> > +       switch (pdev->device) {
> >         /* 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
> >          * window to access the interrupt and scratch pad registers on the
> >          * remote system.
> >          */
> > -       ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > +               ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> > +               break;
> > +       }
> >
> > +       switch (pdev->device) {
> >         /* There is a hardware errata related to accessing any register in
> >          * SB01BASE in the presence of bidirectional traffic crossing the NTB.
> >          */
> > -       ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > +               ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> > +               break;
> > +       }
> >
> > +       switch (pdev->device) {
> >         /* HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
> >          * mirrored to the remote system.  Shrink the number of bits by one,
> >          * since bit 14 is the last bit.
> >          */
> > -       ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > +               ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> > +               break;
> > +       }
> >
> >         ndev->reg = &snb_reg;
> >
> > -       pdev = ndev_pdev(ndev);
> > -
> >         rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd);
> >         if (rc)
> >                 return -EIO;
> > @@ -2062,14 +2076,14 @@ static const struct intel_ntb_xlat_reg snb_pri_xlat = {
> >          * window by setting the limit equal to base, nor can it limit the size
> >          * of the memory window by setting the limit to base + size.
> >          */
> > -       .bar2_limit             = SNB_PBAR2LMT_OFFSET,
> > -       .bar2_xlat              = SNB_PBAR2XLAT_OFFSET,
> > +       .bar2_limit             = SNB_PBAR23LMT_OFFSET,
> > +       .bar2_xlat              = SNB_PBAR23XLAT_OFFSET,
> >  };
> >
> >  static const struct intel_ntb_xlat_reg snb_sec_xlat = {
> >         .bar0_base              = SNB_SBAR0BASE_OFFSET,
> > -       .bar2_limit             = SNB_SBAR2LMT_OFFSET,
> > -       .bar2_xlat              = SNB_SBAR2XLAT_OFFSET,
> > +       .bar2_limit             = SNB_SBAR23LMT_OFFSET,
> > +       .bar2_xlat              = SNB_SBAR23XLAT_OFFSET,
> >  };
> >
> >  static const struct intel_b2b_addr snb_b2b_usd_addr = {
> > diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
> > index 0224b1a..fec689d 100644
> > --- a/drivers/ntb/hw/intel/ntb_hw_intel.h
> > +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
> > @@ -70,11 +70,27 @@
> >
> >  /* SNB hardware (and JSF, IVT, HSX) */
> >
> > -#define SNB_PBAR2LMT_OFFSET            0x0000
> > -#define SNB_PBAR2XLAT_OFFSET           0x0010
> > -#define SNB_SBAR2LMT_OFFSET            0x0020
> > -#define SNB_SBAR2XLAT_OFFSET           0x0030
> > +#define SNB_PBAR23LMT_OFFSET           0x0000
> > +#define SNB_PBAR45LMT_OFFSET           0x0008
> > +#define SNB_PBAR4LMT_OFFSET            0x0008
> > +#define SNB_PBAR5LMT_OFFSET            0x000c
> > +#define SNB_PBAR23XLAT_OFFSET          0x0010
> > +#define SNB_PBAR45XLAT_OFFSET          0x0018
> > +#define SNB_PBAR4XLAT_OFFSET           0x0018
> > +#define SNB_PBAR5XLAT_OFFSET           0x001c
> > +#define SNB_SBAR23LMT_OFFSET           0x0020
> > +#define SNB_SBAR45LMT_OFFSET           0x0028
> > +#define SNB_SBAR4LMT_OFFSET            0x0028
> > +#define SNB_SBAR5LMT_OFFSET            0x002c
> > +#define SNB_SBAR23XLAT_OFFSET          0x0030
> > +#define SNB_SBAR45XLAT_OFFSET          0x0038
> > +#define SNB_SBAR4XLAT_OFFSET           0x0038
> > +#define SNB_SBAR5XLAT_OFFSET           0x003c
> >  #define SNB_SBAR0BASE_OFFSET           0x0040
> > +#define SNB_SBAR23BASE_OFFSET          0x0048
> > +#define SNB_SBAR45BASE_OFFSET          0x0050
> > +#define SNB_SBAR4BASE_OFFSET           0x0050
> > +#define SNB_SBAR5BASE_OFFSET           0x0054
> >  #define SNB_SBDF_OFFSET                        0x005c
> >  #define SNB_NTBCNTL_OFFSET             0x0058
> >  #define SNB_PDOORBELL_OFFSET           0x0060
> > diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> > index f1ed1b7..bb2eb85 100644
> > --- a/drivers/ntb/ntb_transport.c
> > +++ b/drivers/ntb/ntb_transport.c
> > @@ -204,8 +204,8 @@ struct ntb_transport_ctx {
> >
> >         bool link_is_up;
> >         struct delayed_work link_work;
> > -       struct work_struct db_work;
> >         struct work_struct link_cleanup;
> > +       struct tasklet_struct db_work;
> >  };
> >
> >  enum {
> > @@ -241,7 +241,7 @@ enum {
> >  #define NTB_QP_DEF_NUM_ENTRIES 100
> >  #define NTB_LINK_DOWN_TIMEOUT  10
> >
> > -static void ntb_transport_doorbell_work(struct work_struct *ws);
> > +static void ntb_transport_doorbell_work(unsigned long data);
> >  static const struct ntb_ctx_ops ntb_transport_ops;
> >  static struct ntb_client ntb_transport_client;
> >
> > @@ -1002,8 +1002,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
> >         }
> >
> >         INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
> > -       INIT_WORK(&nt->db_work, ntb_transport_doorbell_work);
> >         INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work);
> > +       tasklet_init(&nt->db_work, ntb_transport_doorbell_work,
> > +                    (unsigned long)nt);
> >
> >         rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops);
> >         if (rc)
> > @@ -1044,7 +1045,7 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev)
> >         int i;
> >
> >         ntb_transport_link_cleanup(nt);
> > -       cancel_work_sync(&nt->db_work);
> > +       tasklet_disable(&nt->db_work);
> >         cancel_work_sync(&nt->link_cleanup);
> >         cancel_delayed_work_sync(&nt->link_work);
> >
> > @@ -1850,10 +1851,9 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
> >  }
> >  EXPORT_SYMBOL_GPL(ntb_transport_max_size);
> >
> > -static void ntb_transport_doorbell_work(struct work_struct *work)
> > +static void ntb_transport_doorbell_work(unsigned long data)
> >  {
> > -       struct ntb_transport_ctx *nt = container_of(work,
> > -                       struct ntb_transport_ctx, db_work);
> > +       struct ntb_transport_ctx *nt = (void *)data;
> >         struct ntb_transport_qp *qp;
> >         u64 db_mask, db_bits, db_again;
> >         unsigned int qp_num;
> > @@ -1890,7 +1890,7 @@ static void ntb_transport_doorbell_callback(void *data, int vector)
> >
> >         ntb_db_set_mask(nt->ndev, ntb_db_valid_mask(nt->ndev));
> >
> > -       schedule_work(&nt->db_work);
> > +       tasklet_schedule(&nt->db_work);
> >  }
> >
> >  static const struct ntb_ctx_ops ntb_transport_ops = {
> > --
> > 2.4.0.rc0.43.gcf8a8c6
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/16] Check the DID for certain workaround error flags to be set.
@ 2015-05-20 21:15       ` Jiang, Dave
  0 siblings, 0 replies; 40+ messages in thread
From: Jiang, Dave @ 2015-05-20 21:15 UTC (permalink / raw)
  To: bhelgaas; +Cc: Allen.Hubbe, linux-kernel, linux-pci, jdmason, linux-ntb

T24gV2VkLCAyMDE1LTA1LTIwIGF0IDE2OjExIC0wNTAwLCBCam9ybiBIZWxnYWFzIHdyb3RlOg0K
PiBPbiBXZWQsIE1heSAyMCwgMjAxNSBhdCAxMDo0MSBBTSwgQWxsZW4gSHViYmUgPEFsbGVuLkh1
YmJlQGVtYy5jb20+IHdyb3RlOg0KPiA+IEZyb206IERhdmUgSmlhbmcgPGRhdmUuamlhbmdAaW50
ZWwuY29tPg0KPiA+DQo+ID4gU2lnbmVkLW9mZi1ieTogRGF2ZSBKaWFuZyA8ZGF2ZS5qaWFuZ0Bp
bnRlbC5jb20+DQo+IA0KPiBOZWVkcyBhIHRvcGljIGluIHRoZSBzdWJqZWN0IGxpbmUgYW5kIGEg
Y2hhbmdlbG9nLg0KPiANCj4gSXQgYWxzbyBzZWVtcyB0byBkbyBhIGxvdCBtb3JlIHRoYW4ganVz
dCBjaGVja2luZyBkZXZpY2UgSUQgKEkgYXNzdW1lDQo+IHRoYXQncyB3aGF0ICJESUQiIG1lYW5z
KSwgc28gdGhpcyBzaG91bGQgcHJvYmFibHkgYmUgc3BsaXQgaW50bw0KPiBzZXZlcmFsIHBhdGNo
ZXMgdGhhdCBlYWNoIGRvIG9uZSB0aGluZy4gIEkgc2VlIGF0IGxlYXN0Og0KPiANCj4gICAtIGNv
c21ldGljIGNvZGUgcmVzdHJ1Y3R1cmluZw0KPiAgIC0gd29ya19zdHJ1Y3QvdGFza2xldF9zdHJ1
Y3QgY2hhbmdlcw0KPiAgIC0gbmV3ICNkZWZpbmVzIGFuZCBiYXIyX29mZigpIGNoYW5nZXMNCg0K
SSB0aGluayB0aGlzIHBhdGNoIGdvdCBtYW5nbGVkIHdpdGggY291cGxlIG90aGVyIHBhdGNoZXMu
IEFsbGVuPw0KDQo+IA0KPiA+IC0tLQ0KPiA+ICBkcml2ZXJzL250Yi9ody9pbnRlbC9udGJfaHdf
aW50ZWwuYyB8IDE5NiArKysrKysrKysrKysrKysrKysrLS0tLS0tLS0tLS0tLS0tLS0NCj4gPiAg
ZHJpdmVycy9udGIvaHcvaW50ZWwvbnRiX2h3X2ludGVsLmggfCAgMjQgKysrKy0NCj4gPiAgZHJp
dmVycy9udGIvbnRiX3RyYW5zcG9ydC5jICAgICAgICAgfCAgMTYgKy0tDQo+ID4gIDMgZmlsZXMg
Y2hhbmdlZCwgMTMzIGluc2VydGlvbnMoKyksIDEwMyBkZWxldGlvbnMoLSkNCj4gPg0KPiA+IGRp
ZmYgLS1naXQgYS9kcml2ZXJzL250Yi9ody9pbnRlbC9udGJfaHdfaW50ZWwuYyBiL2RyaXZlcnMv
bnRiL2h3L2ludGVsL250Yl9od19pbnRlbC5jDQo+ID4gaW5kZXggZDE2MmYyMi4uODlmZWE1MCAx
MDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL250Yi9ody9pbnRlbC9udGJfaHdfaW50ZWwuYw0KPiA+
ICsrKyBiL2RyaXZlcnMvbnRiL2h3L2ludGVsL250Yl9od19pbnRlbC5jDQo+ID4gQEAgLTUwMyw3
ICs1MDMsNiBAQCBzdGF0aWMgc3NpemVfdCBuZGV2X2RlYnVnZnNfcmVhZChzdHJ1Y3QgZmlsZSAq
ZmlscCwgY2hhciBfX3VzZXIgKnVidWYsDQo+ID4gICAgICAgICBzaXplX3QgYnVmX3NpemU7DQo+
ID4gICAgICAgICBzc2l6ZV90IHJldCwgb2ZmOw0KPiA+ICAgICAgICAgdW5pb24geyB1NjQgdjY0
OyB1MzIgdjMyOyB1MTYgdjE2OyB9IHU7DQo+ID4gLSAgICAgICB1bnNpZ25lZCBsb25nIHJlZzsN
Cj4gPg0KPiA+ICAgICAgICAgbmRldiA9IGZpbHAtPnByaXZhdGVfZGF0YTsNCj4gPiAgICAgICAg
IG1taW8gPSBuZGV2LT5zZWxmX21taW87DQo+ID4gQEAgLTUzOCwxMCArNTM3LDEwIEBAIHN0YXRp
YyBzc2l6ZV90IG5kZXZfZGVidWdmc19yZWFkKHN0cnVjdCBmaWxlICpmaWxwLCBjaGFyIF9fdXNl
ciAqdWJ1ZiwNCj4gPg0KPiA+ICAgICAgICAgaWYgKCFuZGV2LT5yZWctPmxpbmtfaXNfdXAobmRl
dikpIHsNCj4gPiAgICAgICAgICAgICAgICAgb2ZmICs9IHNjbnByaW50ZihidWYgKyBvZmYsIGJ1
Zl9zaXplIC0gb2ZmLA0KPiA+IC0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMaW5r
IFNhdHVzIC1cdFx0RG93blxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIkxpbmsgU3RhdHVzIC1cdFx0RG93blxuIik7DQo+ID4gICAgICAgICB9IGVsc2Ugew0KPiA+
ICAgICAgICAgICAgICAgICBvZmYgKz0gc2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3NpemUgLSBv
ZmYsDQo+ID4gLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxpbmsgU2F0dXMgLVx0
XHRVcFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxpbmsgU3Rh
dHVzIC1cdFx0VXBcbiIpOw0KPiA+ICAgICAgICAgICAgICAgICBvZmYgKz0gc2NucHJpbnRmKGJ1
ZiArIG9mZiwgYnVmX3NpemUgLSBvZmYsDQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIkxpbmsgU3BlZWQgLVx0XHRQQ0ktRSBHZW4gJXVcbiIsDQo+ID4gICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgTlRCX0xOS19TVEFfU1BFRUQobmRldi0+bG5rX3N0YSkpOw0K
PiA+IEBAIC01NjgsMzYgKzU2NywzMCBAQCBzdGF0aWMgc3NpemVfdCBuZGV2X2RlYnVnZnNfcmVh
ZChzdHJ1Y3QgZmlsZSAqZmlscCwgY2hhciBfX3VzZXIgKnVidWYsDQo+ID4gICAgICAgICBvZmYg
Kz0gc2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3NpemUgLSBvZmYsDQo+ID4gICAgICAgICAgICAg
ICAgICAgICAgICAgICJEb29yYmVsbCBNYXNrIENhY2hlZCAtXHQlI2xseFxuIiwgbmRldi0+ZGJf
bWFzayk7DQo+ID4NCj4gPiAtICAgICAgIHJlZyA9IG5kZXYtPnNlbGZfcmVnLT5kYl9tYXNrOw0K
PiA+IC0gICAgICAgdS52NjQgPSBuZGV2X2RiX3JlYWQobmRldiwgbW1pbyArIHJlZyk7DQo+ID4g
KyAgICAgICB1LnY2NCA9IG5kZXZfZGJfcmVhZChuZGV2LCBtbWlvICsgbmRldi0+c2VsZl9yZWct
PmRiX21hc2spOw0KPiA+ICAgICAgICAgb2ZmICs9IHNjbnByaW50ZihidWYgKyBvZmYsIGJ1Zl9z
aXplIC0gb2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAiRG9vcmJlbGwgTWFzayAt
XHRcdCUjbGx4XG4iLCB1LnY2NCk7DQo+ID4NCj4gPiAtICAgICAgIHJlZyA9IG5kZXYtPnNlbGZf
cmVnLT5kYl9iZWxsOw0KPiA+IC0gICAgICAgdS52NjQgPSBuZGV2X2RiX3JlYWQobmRldiwgbW1p
byArIHJlZyk7DQo+ID4gKyAgICAgICB1LnY2NCA9IG5kZXZfZGJfcmVhZChuZGV2LCBtbWlvICsg
bmRldi0+c2VsZl9yZWctPmRiX2JlbGwpOw0KPiA+ICAgICAgICAgb2ZmICs9IHNjbnByaW50Zihi
dWYgKyBvZmYsIGJ1Zl9zaXplIC0gb2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAi
RG9vcmJlbGwgQmVsbCAtXHRcdCUjbGx4XG4iLCB1LnY2NCk7DQo+ID4NCj4gPiAgICAgICAgIG9m
ZiArPSBzY25wcmludGYoYnVmICsgb2ZmLCBidWZfc2l6ZSAtIG9mZiwNCj4gPiAgICAgICAgICAg
ICAgICAgICAgICAgICAgIlxuTlRCIEluY29taW5nIFhMQVQ6XG4iKTsNCj4gPg0KPiA+IC0gICAg
ICAgcmVnID0gYmFyMl9vZmYobmRldi0+eGxhdF9yZWctPmJhcjJfeGxhdCwgMik7DQo+ID4gLSAg
ICAgICB1LnY2NCA9IGlvcmVhZDY0KG1taW8gKyByZWcpOw0KPiA+ICsgICAgICAgdS52NjQgPSBp
b3JlYWQ2NChtbWlvICsgYmFyMl9vZmYobmRldi0+eGxhdF9yZWctPmJhcjJfeGxhdCwgMikpOw0K
PiA+ICAgICAgICAgb2ZmICs9IHNjbnByaW50ZihidWYgKyBvZmYsIGJ1Zl9zaXplIC0gb2ZmLA0K
PiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAiWExBVDIzIC1cdFx0JSMwMThsbHhcbiIsIHUu
djY0KTsNCj4gPg0KPiA+IC0gICAgICAgcmVnID0gYmFyMl9vZmYobmRldi0+eGxhdF9yZWctPmJh
cjJfeGxhdCwgNCk7DQo+ID4gLSAgICAgICB1LnY2NCA9IGlvcmVhZDY0KG1taW8gKyByZWcpOw0K
PiA+ICsgICAgICAgdS52NjQgPSBpb3JlYWQ2NChtbWlvICsgYmFyMl9vZmYobmRldi0+eGxhdF9y
ZWctPmJhcjJfeGxhdCwgNCkpOw0KPiA+ICAgICAgICAgb2ZmICs9IHNjbnByaW50ZihidWYgKyBv
ZmYsIGJ1Zl9zaXplIC0gb2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAiWExBVDQ1
IC1cdFx0JSMwMThsbHhcbiIsIHUudjY0KTsNCj4gPg0KPiA+IC0gICAgICAgcmVnID0gYmFyMl9v
ZmYobmRldi0+eGxhdF9yZWctPmJhcjJfbGltaXQsIDIpOw0KPiA+IC0gICAgICAgdS52NjQgPSBp
b3JlYWQ2NChtbWlvICsgcmVnKTsNCj4gPiArICAgICAgIHUudjY0ID0gaW9yZWFkNjQobW1pbyAr
IGJhcjJfb2ZmKG5kZXYtPnhsYXRfcmVnLT5iYXIyX2xpbWl0LCAyKSk7DQo+ID4gICAgICAgICBv
ZmYgKz0gc2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3NpemUgLSBvZmYsDQo+ID4gICAgICAgICAg
ICAgICAgICAgICAgICAgICJMTVQyMyAtXHRcdFx0JSMwMThsbHhcbiIsIHUudjY0KTsNCj4gPg0K
PiA+IC0gICAgICAgcmVnID0gYmFyMl9vZmYobmRldi0+eGxhdF9yZWctPmJhcjJfbGltaXQsIDQp
Ow0KPiA+IC0gICAgICAgdS52NjQgPSBpb3JlYWQ2NChtbWlvICsgcmVnKTsNCj4gPiArICAgICAg
IHUudjY0ID0gaW9yZWFkNjQobW1pbyArIGJhcjJfb2ZmKG5kZXYtPnhsYXRfcmVnLT5iYXIyX2xp
bWl0LCA0KSk7DQo+ID4gICAgICAgICBvZmYgKz0gc2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3Np
emUgLSBvZmYsDQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICJMTVQ0NSAtXHRcdFx0JSMw
MThsbHhcbiIsIHUudjY0KTsNCj4gPg0KPiA+IEBAIC02MDYsNDEgKzU5OSwzNCBAQCBzdGF0aWMg
c3NpemVfdCBuZGV2X2RlYnVnZnNfcmVhZChzdHJ1Y3QgZmlsZSAqZmlscCwgY2hhciBfX3VzZXIg
KnVidWYsDQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgb2ZmICs9IHNjbnByaW50ZihidWYg
KyBvZmYsIGJ1Zl9zaXplIC0gb2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIlxuTlRCIE91dGdvaW5nIEIyQiBYTEFUOlxuIik7DQo+ID4NCj4gPiAtICAg
ICAgICAgICAgICAgICAgICAgICByZWcgPSBiYXIyX29mZihTTkJfUEJBUjJYTEFUX09GRlNFVCwg
Mik7DQo+ID4gLSAgICAgICAgICAgICAgICAgICAgICAgdS52NjQgPSBpb3JlYWQ2NChtbWlvICsg
cmVnKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB1LnY2NCA9IGlvcmVhZDY0KG1taW8g
KyBTTkJfUEJBUjIzWExBVF9PRkZTRVQpOw0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgIG9m
ZiArPSBzY25wcmludGYoYnVmICsgb2ZmLCBidWZfc2l6ZSAtIG9mZiwNCj4gPiAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCMkIgWExBVDIzIC1cdFx0JSMwMThsbHhc
biIsIHUudjY0KTsNCj4gPg0KPiA+IC0gICAgICAgICAgICAgICAgICAgICAgIHJlZyA9IGJhcjJf
b2ZmKFNOQl9QQkFSMlhMQVRfT0ZGU0VULCA0KTsNCj4gPiAtICAgICAgICAgICAgICAgICAgICAg
ICB1LnY2NCA9IGlvcmVhZDY0KG1taW8gKyByZWcpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIHUudjY0ID0gaW9yZWFkNjQobW1pbyArIFNOQl9QQkFSNDVYTEFUX09GRlNFVCk7DQo+ID4g
ICAgICAgICAgICAgICAgICAgICAgICAgb2ZmICs9IHNjbnByaW50ZihidWYgKyBvZmYsIGJ1Zl9z
aXplIC0gb2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IkIyQiBYTEFUNDUgLVx0XHQlIzAxOGxseFxuIiwgdS52NjQpOw0KPiA+DQo+ID4gLSAgICAgICAg
ICAgICAgICAgICAgICAgcmVnID0gYmFyMl9vZmYoU05CX1BCQVIyTE1UX09GRlNFVCwgMik7DQo+
ID4gLSAgICAgICAgICAgICAgICAgICAgICAgdS52NjQgPSBpb3JlYWQ2NChtbWlvICsgcmVnKTsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICB1LnY2NCA9IGlvcmVhZDY0KG1taW8gKyBTTkJf
UEJBUjIzTE1UX09GRlNFVCk7DQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgb2ZmICs9IHNj
bnByaW50ZihidWYgKyBvZmYsIGJ1Zl9zaXplIC0gb2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIkIyQiBMTVQyMyAtXHRcdCUjMDE4bGx4XG4iLCB1LnY2
NCk7DQo+ID4NCj4gPiAtICAgICAgICAgICAgICAgICAgICAgICByZWcgPSBiYXIyX29mZihTTkJf
UEJBUjJMTVRfT0ZGU0VULCA0KTsNCj4gPiAtICAgICAgICAgICAgICAgICAgICAgICB1LnY2NCA9
IGlvcmVhZDY0KG1taW8gKyByZWcpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHUudjY0
ID0gaW9yZWFkNjQobW1pbyArIFNOQl9QQkFSNDVMTVRfT0ZGU0VUKTsNCj4gPiAgICAgICAgICAg
ICAgICAgICAgICAgICBvZmYgKz0gc2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3NpemUgLSBvZmYs
DQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQjJCIExNVDQ1
IC1cdFx0JSMwMThsbHhcbiIsIHUudjY0KTsNCj4gPg0KPiA+ICAgICAgICAgICAgICAgICAgICAg
ICAgIG9mZiArPSBzY25wcmludGYoYnVmICsgb2ZmLCBidWZfc2l6ZSAtIG9mZiwNCj4gPiAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbk5UQiBTZWNvbmRhcnkgQkFS
OlxuIik7DQo+ID4NCj4gPiAtICAgICAgICAgICAgICAgICAgICAgICByZWcgPSBiYXIwX29mZihT
TkJfU0JBUjBCQVNFX09GRlNFVCwgMCk7DQo+ID4gLSAgICAgICAgICAgICAgICAgICAgICAgdS52
NjQgPSBpb3JlYWQ2NChtbWlvICsgcmVnKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB1
LnY2NCA9IGlvcmVhZDY0KG1taW8gKyBTTkJfU0JBUjBCQVNFX09GRlNFVCk7DQo+ID4gICAgICAg
ICAgICAgICAgICAgICAgICAgb2ZmICs9IHNjbnByaW50ZihidWYgKyBvZmYsIGJ1Zl9zaXplIC0g
b2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNCQVIw
MSAtXHRcdCUjMDE4bGx4XG4iLCB1LnY2NCk7DQo+ID4NCj4gPiAtICAgICAgICAgICAgICAgICAg
ICAgICByZWcgPSBiYXIwX29mZihTTkJfU0JBUjBCQVNFX09GRlNFVCwgMik7DQo+ID4gLSAgICAg
ICAgICAgICAgICAgICAgICAgdS52NjQgPSBpb3JlYWQ2NChtbWlvICsgcmVnKTsNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICB1LnY2NCA9IGlvcmVhZDY0KG1taW8gKyBTTkJfU0JBUjIzQkFT
RV9PRkZTRVQpOw0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgIG9mZiArPSBzY25wcmludGYo
YnVmICsgb2ZmLCBidWZfc2l6ZSAtIG9mZiwNCj4gPiAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICJTQkFSMjMgLVx0XHQlIzAxOGxseFxuIiwgdS52NjQpOw0KPiA+DQo+
ID4gLSAgICAgICAgICAgICAgICAgICAgICAgcmVnID0gYmFyMF9vZmYoU05CX1NCQVIwQkFTRV9P
RkZTRVQsIDQpOw0KPiA+IC0gICAgICAgICAgICAgICAgICAgICAgIHUudjY0ID0gaW9yZWFkNjQo
bW1pbyArIHJlZyk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgdS52NjQgPSBpb3JlYWQ2
NChtbWlvICsgU05CX1NCQVI0NUJBU0VfT0ZGU0VUKTsNCj4gPiAgICAgICAgICAgICAgICAgICAg
ICAgICBvZmYgKz0gc2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3NpemUgLSBvZmYsDQo+ID4gICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0JBUjQ1IC1cdFx0JSMwMThs
bHhcbiIsIHUudjY0KTsNCj4gPiAgICAgICAgICAgICAgICAgfQ0KPiA+IEBAIC02NDgsMzEgKzYz
NCwzMCBAQCBzdGF0aWMgc3NpemVfdCBuZGV2X2RlYnVnZnNfcmVhZChzdHJ1Y3QgZmlsZSAqZmls
cCwgY2hhciBfX3VzZXIgKnVidWYsDQo+ID4gICAgICAgICAgICAgICAgIG9mZiArPSBzY25wcmlu
dGYoYnVmICsgb2ZmLCBidWZfc2l6ZSAtIG9mZiwNCj4gPiAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAiXG5TTkIgTlRCIFN0YXRpc3RpY3M6XG4iKTsNCj4gPg0KPiA+IC0gICAgICAg
ICAgICAgICByZWcgPSBTTkJfVVNNRU1NSVNTX09GRlNFVDsNCj4gPiAtICAgICAgICAgICAgICAg
dS52MTYgPSBpb3JlYWQxNihtbWlvICsgcmVnKTsNCj4gPiArICAgICAgICAgICAgICAgdS52MTYg
PSBpb3JlYWQxNihtbWlvICsgU05CX1VTTUVNTUlTU19PRkZTRVQpOw0KPiA+ICAgICAgICAgICAg
ICAgICBvZmYgKz0gc2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3NpemUgLSBvZmYsDQo+ID4gICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVwc3RyZWFtIE1lbW9yeSBNaXNzIC1cdCV1
XG4iLCB1LnYxNik7DQo+ID4NCj4gPiAgICAgICAgICAgICAgICAgb2ZmICs9IHNjbnByaW50Zihi
dWYgKyBvZmYsIGJ1Zl9zaXplIC0gb2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICJcblNOQiBOVEIgSGFyZHdhcmUgRXJyb3JzOlxuIik7DQo+ID4NCj4gPiAtICAgICAg
ICAgICAgICAgcmVnID0gU05CX0RFVlNUU19PRkZTRVQ7DQo+ID4gLSAgICAgICAgICAgICAgIGlm
ICghcGNpX3JlYWRfY29uZmlnX3dvcmQobmRldi0+bnRiLnBkZXYsIHJlZywgJnUudjE2KSkNCj4g
PiArICAgICAgICAgICAgICAgaWYgKCFwY2lfcmVhZF9jb25maWdfd29yZChuZGV2LT5udGIucGRl
diwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTTkJfREVW
U1RTX09GRlNFVCwgJnUudjE2KSkNCj4gPiAgICAgICAgICAgICAgICAgICAgICAgICBvZmYgKz0g
c2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3NpemUgLSBvZmYsDQo+ID4gICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAiREVWU1RTIC1cdFx0JSMwNnhcbiIsIHUudjE2KTsN
Cj4gPg0KPiA+IC0gICAgICAgICAgICAgICByZWcgPSBTTkJfTElOS19TVEFUVVNfT0ZGU0VUOw0K
PiA+IC0gICAgICAgICAgICAgICBpZiAoIXBjaV9yZWFkX2NvbmZpZ193b3JkKG5kZXYtPm50Yi5w
ZGV2LCByZWcsICZ1LnYxNikpDQo+ID4gKyAgICAgICAgICAgICAgIGlmICghcGNpX3JlYWRfY29u
ZmlnX3dvcmQobmRldi0+bnRiLnBkZXYsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgU05CX0xJTktfU1RBVFVTX09GRlNFVCwgJnUudjE2KSkNCj4gPiAgICAg
ICAgICAgICAgICAgICAgICAgICBvZmYgKz0gc2NucHJpbnRmKGJ1ZiArIG9mZiwgYnVmX3NpemUg
LSBvZmYsDQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTE5L
U1RTIC1cdFx0JSMwNnhcbiIsIHUudjE2KTsNCj4gPg0KPiA+IC0gICAgICAgICAgICAgICByZWcg
PSBTTkJfVU5DRVJSU1RTX09GRlNFVDsNCj4gPiAtICAgICAgICAgICAgICAgaWYgKCFwY2lfcmVh
ZF9jb25maWdfZHdvcmQobmRldi0+bnRiLnBkZXYsIHJlZywgJnUudjMyKSkNCj4gPiArICAgICAg
ICAgICAgICAgaWYgKCFwY2lfcmVhZF9jb25maWdfZHdvcmQobmRldi0+bnRiLnBkZXYsDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNOQl9VTkNFUlJTVFNf
T0ZGU0VULCAmdS52MzIpKQ0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgIG9mZiArPSBzY25w
cmludGYoYnVmICsgb2ZmLCBidWZfc2l6ZSAtIG9mZiwNCj4gPiAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICJVTkNFUlJTVFMgLVx0XHQlIzA2eFxuIiwgdS52MzIpOw0K
PiA+DQo+ID4gLSAgICAgICAgICAgICAgIHJlZyA9IFNOQl9DT1JFUlJTVFNfT0ZGU0VUOw0KPiA+
IC0gICAgICAgICAgICAgICBpZiAoIXBjaV9yZWFkX2NvbmZpZ19kd29yZChuZGV2LT5udGIucGRl
diwgcmVnLCAmdS52MzIpKQ0KPiA+ICsgICAgICAgICAgICAgICBpZiAoIXBjaV9yZWFkX2NvbmZp
Z19kd29yZChuZGV2LT5udGIucGRldiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgU05CX0NPUkVSUlNUU19PRkZTRVQsICZ1LnYzMikpDQo+ID4gICAgICAg
ICAgICAgICAgICAgICAgICAgb2ZmICs9IHNjbnByaW50ZihidWYgKyBvZmYsIGJ1Zl9zaXplIC0g
b2ZmLA0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPUkVS
UlNUUyAtXHRcdCUjMDZ4XG4iLCB1LnYzMik7DQo+ID4gICAgICAgICB9DQo+ID4gQEAgLTEzODgs
NyArMTM3Myw2IEBAIHN0YXRpYyBpbnQgc25iX3NldHVwX2IyYl9tdyhzdHJ1Y3QgaW50ZWxfbnRi
X2RldiAqbmRldiwNCj4gPiAgew0KPiA+ICAgICAgICAgc3RydWN0IHBjaV9kZXYgKnBkZXY7DQo+
ID4gICAgICAgICB2b2lkIF9faW9tZW0gKm1taW87DQo+ID4gLSAgICAgICB1bnNpZ25lZCBsb25n
IG9mZjsNCj4gPiAgICAgICAgIHJlc291cmNlX3NpemVfdCBiYXJfc2l6ZTsNCj4gPiAgICAgICAg
IHBoeXNfYWRkcl90IGJhcl9hZGRyOw0KPiA+ICAgICAgICAgaW50IGIyYl9iYXI7DQo+ID4gQEAg
LTE0ODQsOSArMTQ2OCw2IEBAIHN0YXRpYyBpbnQgc25iX3NldHVwX2IyYl9tdyhzdHJ1Y3QgaW50
ZWxfbnRiX2RldiAqbmRldiwNCj4gPiAgICAgICAgICAgICAgICAgZGV2X2RiZyhuZGV2X2Rldihu
ZGV2KSwgIlNCQVI1U1ogJSN4XG4iLCBiYXJfc3opOw0KPiA+ICAgICAgICAgfQ0KPiA+DQo+ID4g
LSAgICAgICAvKiBzZXR1cCBpbmNvbWluZyBiYXIgYmFzZSBhZGRyZXNzZXMgKi8NCj4gPiAtICAg
ICAgIG9mZiA9IFNOQl9TQkFSMEJBU0VfT0ZGU0VUOw0KPiA+IC0NCj4gPiAgICAgICAgIC8qIFNC
QVIwMSBoaXQgYnkgZmlyc3QgcGFydCBvZiB0aGUgYjJiIGJhciAqLw0KPiA+ICAgICAgICAgaWYg
KGIyYl9iYXIgPT0gMCkgew0KPiA+ICAgICAgICAgICAgICAgICBiYXJfYWRkciA9IGFkZHItPmJh
cjBfYWRkcjsNCj4gPiBAQCAtMTUwNCw3ICsxNDg1LDcgQEAgc3RhdGljIGludCBzbmJfc2V0dXBf
YjJiX213KHN0cnVjdCBpbnRlbF9udGJfZGV2ICpuZGV2LA0KPiA+ICAgICAgICAgfQ0KPiA+DQo+
ID4gICAgICAgICBkZXZfZGJnKG5kZXZfZGV2KG5kZXYpLCAiU0JBUjAxICUjMDE4bGx4XG4iLCBi
YXJfYWRkcik7DQo+ID4gLSAgICAgICBpb3dyaXRlNjQoYmFyX2FkZHIsIG1taW8gKyBiYXIwX29m
ZihvZmYsIDApKTsNCj4gPiArICAgICAgIGlvd3JpdGU2NChiYXJfYWRkciwgbW1pbyArIFNOQl9T
QkFSMEJBU0VfT0ZGU0VUKTsNCj4gPg0KPiA+ICAgICAgICAgLyogT3RoZXIgU0JBUiBhcmUgbm9y
bWFsbHkgaGl0IGJ5IHRoZSBQQkFSIHhsYXQsIGV4Y2VwdCBmb3IgYjJiIGJhci4NCj4gPiAgICAg
ICAgICAqIFRoZSBiMmIgYmFyIGlzIGVpdGhlciBkaXNhYmxlZCBhYm92ZSwgb3IgY29uZmlndXJl
ZCBoYWxmLXNpemUsIGFuZA0KPiA+IEBAIC0xNTEyLDEwMiArMTQ5Myw5NiBAQCBzdGF0aWMgaW50
IHNuYl9zZXR1cF9iMmJfbXcoc3RydWN0IGludGVsX250Yl9kZXYgKm5kZXYsDQo+ID4gICAgICAg
ICAgKi8NCj4gPg0KPiA+ICAgICAgICAgYmFyX2FkZHIgPSBhZGRyLT5iYXIyX2FkZHI2NCArIChi
MmJfYmFyID09IDIgPyBuZGV2LT5iMmJfb2ZmIDogMCk7DQo+ID4gLSAgICAgICBpb3dyaXRlNjQo
YmFyX2FkZHIsIG1taW8gKyBiYXIwX29mZihvZmYsIDIpKTsNCj4gPiAtICAgICAgIGJhcl9hZGRy
ID0gaW9yZWFkNjQobW1pbyArIGJhcjBfb2ZmKG9mZiwgMikpOw0KPiA+ICsgICAgICAgaW93cml0
ZTY0KGJhcl9hZGRyLCBtbWlvICsgU05CX1NCQVIyM0JBU0VfT0ZGU0VUKTsNCj4gPiArICAgICAg
IGJhcl9hZGRyID0gaW9yZWFkNjQobW1pbyArIFNOQl9TQkFSMjNCQVNFX09GRlNFVCk7DQo+ID4g
ICAgICAgICBkZXZfZGJnKG5kZXZfZGV2KG5kZXYpLCAiU0JBUjIzICUjMDE4bGx4XG4iLCBiYXJf
YWRkcik7DQo+ID4NCj4gPiAgICAgICAgIGlmICghbmRldi0+YmFyNF9zcGxpdCkgew0KPiA+ICAg
ICAgICAgICAgICAgICBiYXJfYWRkciA9IGFkZHItPmJhcjRfYWRkcjY0ICsNCj4gPiAgICAgICAg
ICAgICAgICAgICAgICAgICAoYjJiX2JhciA9PSA0ID8gbmRldi0+YjJiX29mZiA6IDApOw0KPiA+
IC0gICAgICAgICAgICAgICBpb3dyaXRlNjQoYmFyX2FkZHIsIG1taW8gKyBiYXIwX29mZihvZmYs
IDQpKTsNCj4gPiAtICAgICAgICAgICAgICAgYmFyX2FkZHIgPSBpb3JlYWQ2NChtbWlvICsgYmFy
MF9vZmYob2ZmLCA0KSk7DQo+ID4gKyAgICAgICAgICAgICAgIGlvd3JpdGU2NChiYXJfYWRkciwg
bW1pbyArIFNOQl9TQkFSNDVCQVNFX09GRlNFVCk7DQo+ID4gKyAgICAgICAgICAgICAgIGJhcl9h
ZGRyID0gaW9yZWFkNjQobW1pbyArIFNOQl9TQkFSNDVCQVNFX09GRlNFVCk7DQo+ID4gICAgICAg
ICAgICAgICAgIGRldl9kYmcobmRldl9kZXYobmRldiksICJTQkFSNDUgJSMwMThsbHhcbiIsIGJh
cl9hZGRyKTsNCj4gPiAgICAgICAgIH0gZWxzZSB7DQo+ID4gICAgICAgICAgICAgICAgIGJhcl9h
ZGRyID0gYWRkci0+YmFyNF9hZGRyMzIgKw0KPiA+ICAgICAgICAgICAgICAgICAgICAgICAgIChi
MmJfYmFyID09IDQgPyBuZGV2LT5iMmJfb2ZmIDogMCk7DQo+ID4gLSAgICAgICAgICAgICAgIGlv
d3JpdGUzMihiYXJfYWRkciwgbW1pbyArIGJhcjBfb2ZmKG9mZiwgNCkpOw0KPiA+IC0gICAgICAg
ICAgICAgICBiYXJfYWRkciA9IGlvcmVhZDMyKG1taW8gKyBiYXIwX29mZihvZmYsIDQpKTsNCj4g
PiArICAgICAgICAgICAgICAgaW93cml0ZTMyKGJhcl9hZGRyLCBtbWlvICsgU05CX1NCQVI0QkFT
RV9PRkZTRVQpOw0KPiA+ICsgICAgICAgICAgICAgICBiYXJfYWRkciA9IGlvcmVhZDMyKG1taW8g
KyBTTkJfU0JBUjRCQVNFX09GRlNFVCk7DQo+ID4gICAgICAgICAgICAgICAgIGRldl9kYmcobmRl
dl9kZXYobmRldiksICJTQkFSNCAlIzAxMGxseFxuIiwgYmFyX2FkZHIpOw0KPiA+DQo+ID4gICAg
ICAgICAgICAgICAgIGJhcl9hZGRyID0gYWRkci0+YmFyNV9hZGRyMzIgKw0KPiA+ICAgICAgICAg
ICAgICAgICAgICAgICAgIChiMmJfYmFyID09IDUgPyBuZGV2LT5iMmJfb2ZmIDogMCk7DQo+ID4g
LSAgICAgICAgICAgICAgIGlvd3JpdGUzMihiYXJfYWRkciwgbW1pbyArIGJhcjBfb2ZmKG9mZiwg
NSkpOw0KPiA+IC0gICAgICAgICAgICAgICBiYXJfYWRkciA9IGlvcmVhZDMyKG1taW8gKyBiYXIw
X29mZihvZmYsIDUpKTsNCj4gPiArICAgICAgICAgICAgICAgaW93cml0ZTMyKGJhcl9hZGRyLCBt
bWlvICsgU05CX1NCQVI1QkFTRV9PRkZTRVQpOw0KPiA+ICsgICAgICAgICAgICAgICBiYXJfYWRk
ciA9IGlvcmVhZDMyKG1taW8gKyBTTkJfU0JBUjVCQVNFX09GRlNFVCk7DQo+ID4gICAgICAgICAg
ICAgICAgIGRldl9kYmcobmRldl9kZXYobmRldiksICJTQkFSNSAlIzAxMGxseFxuIiwgYmFyX2Fk
ZHIpOw0KPiA+ICAgICAgICAgfQ0KPiA+DQo+ID4gICAgICAgICAvKiBzZXR1cCBpbmNvbWluZyBi
YXIgbGltaXRzID09IGJhc2UgYWRkcnMgKHplcm8gbGVuZ3RoIHdpbmRvd3MpICovDQo+ID4gLSAg
ICAgICBvZmYgPSBTTkJfU0JBUjJMTVRfT0ZGU0VUOw0KPiA+DQo+ID4gICAgICAgICBiYXJfYWRk
ciA9IGFkZHItPmJhcjJfYWRkcjY0ICsgKGIyYl9iYXIgPT0gMiA/IG5kZXYtPmIyYl9vZmYgOiAw
KTsNCj4gPiAtICAgICAgIGlvd3JpdGU2NChiYXJfYWRkciwgbW1pbyArIGJhcjJfb2ZmKG9mZiwg
MikpOw0KPiA+IC0gICAgICAgYmFyX2FkZHIgPSBpb3JlYWQ2NChtbWlvICsgYmFyMl9vZmYob2Zm
LCAyKSk7DQo+ID4gKyAgICAgICBpb3dyaXRlNjQoYmFyX2FkZHIsIG1taW8gKyBTTkJfU0JBUjIz
TE1UX09GRlNFVCk7DQo+ID4gKyAgICAgICBiYXJfYWRkciA9IGlvcmVhZDY0KG1taW8gKyBTTkJf
U0JBUjIzTE1UX09GRlNFVCk7DQo+ID4gICAgICAgICBkZXZfZGJnKG5kZXZfZGV2KG5kZXYpLCAi
U0JBUjIzTE1UICUjMDE4bGx4XG4iLCBiYXJfYWRkcik7DQo+ID4NCj4gPiAgICAgICAgIGlmICgh
bmRldi0+YmFyNF9zcGxpdCkgew0KPiA+ICAgICAgICAgICAgICAgICBiYXJfYWRkciA9IGFkZHIt
PmJhcjRfYWRkcjY0ICsNCj4gPiAgICAgICAgICAgICAgICAgICAgICAgICAoYjJiX2JhciA9PSA0
ID8gbmRldi0+YjJiX29mZiA6IDApOw0KPiA+IC0gICAgICAgICAgICAgICBpb3dyaXRlNjQoYmFy
X2FkZHIsIG1taW8gKyBiYXIyX29mZihvZmYsIDQpKTsNCj4gPiAtICAgICAgICAgICAgICAgYmFy
X2FkZHIgPSBpb3JlYWQ2NChtbWlvICsgYmFyMl9vZmYob2ZmLCA0KSk7DQo+ID4gKyAgICAgICAg
ICAgICAgIGlvd3JpdGU2NChiYXJfYWRkciwgbW1pbyArIFNOQl9TQkFSNDVMTVRfT0ZGU0VUKTsN
Cj4gPiArICAgICAgICAgICAgICAgYmFyX2FkZHIgPSBpb3JlYWQ2NChtbWlvICsgU05CX1NCQVI0
NUxNVF9PRkZTRVQpOw0KPiA+ICAgICAgICAgICAgICAgICBkZXZfZGJnKG5kZXZfZGV2KG5kZXYp
LCAiU0JBUjQ1TE1UICUjMDE4bGx4XG4iLCBiYXJfYWRkcik7DQo+ID4gICAgICAgICB9IGVsc2Ug
ew0KPiA+ICAgICAgICAgICAgICAgICBiYXJfYWRkciA9IGFkZHItPmJhcjRfYWRkcjMyICsNCj4g
PiAgICAgICAgICAgICAgICAgICAgICAgICAoYjJiX2JhciA9PSA0ID8gbmRldi0+YjJiX29mZiA6
IDApOw0KPiA+IC0gICAgICAgICAgICAgICBpb3dyaXRlMzIoYmFyX2FkZHIsIG1taW8gKyBiYXIy
X29mZihvZmYsIDQpKTsNCj4gPiAtICAgICAgICAgICAgICAgYmFyX2FkZHIgPSBpb3JlYWQzMiht
bWlvICsgYmFyMl9vZmYob2ZmLCA0KSk7DQo+ID4gKyAgICAgICAgICAgICAgIGlvd3JpdGUzMihi
YXJfYWRkciwgbW1pbyArIFNOQl9TQkFSNExNVF9PRkZTRVQpOw0KPiA+ICsgICAgICAgICAgICAg
ICBiYXJfYWRkciA9IGlvcmVhZDMyKG1taW8gKyBTTkJfU0JBUjRMTVRfT0ZGU0VUKTsNCj4gPiAg
ICAgICAgICAgICAgICAgZGV2X2RiZyhuZGV2X2RldihuZGV2KSwgIlNCQVI0TE1UICUjMDEwbGx4
XG4iLCBiYXJfYWRkcik7DQo+ID4NCj4gPiAgICAgICAgICAgICAgICAgYmFyX2FkZHIgPSBhZGRy
LT5iYXI1X2FkZHIzMiArDQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgKGIyYl9iYXIgPT0g
NSA/IG5kZXYtPmIyYl9vZmYgOiAwKTsNCj4gPiAtICAgICAgICAgICAgICAgaW93cml0ZTMyKGJh
cl9hZGRyLCBtbWlvICsgYmFyMl9vZmYob2ZmLCA1KSk7DQo+ID4gLSAgICAgICAgICAgICAgIGJh
cl9hZGRyID0gaW9yZWFkMzIobW1pbyArIGJhcjJfb2ZmKG9mZiwgNSkpOw0KPiA+ICsgICAgICAg
ICAgICAgICBpb3dyaXRlMzIoYmFyX2FkZHIsIG1taW8gKyBTTkJfU0JBUjVMTVRfT0ZGU0VUKTsN
Cj4gPiArICAgICAgICAgICAgICAgYmFyX2FkZHIgPSBpb3JlYWQzMihtbWlvICsgU05CX1NCQVI1
TE1UX09GRlNFVCk7DQo+ID4gICAgICAgICAgICAgICAgIGRldl9kYmcobmRldl9kZXYobmRldiks
ICJTQkFSNUxNVCAlIzA1bGx4XG4iLCBiYXJfYWRkcik7DQo+ID4gICAgICAgICB9DQo+ID4NCj4g
PiAgICAgICAgIC8qIHplcm8gaW5jb21pbmcgdHJhbnNsYXRpb24gYWRkcnMgKi8NCj4gPiAtICAg
ICAgIG9mZiA9IFNOQl9TQkFSMlhMQVRfT0ZGU0VUOw0KPiA+IC0NCj4gPiAtICAgICAgIGlvd3Jp
dGU2NCgwLCBtbWlvICsgYmFyMl9vZmYob2ZmLCAyKSk7DQo+ID4gKyAgICAgICBpb3dyaXRlNjQo
MCwgbW1pbyArIFNOQl9TQkFSMjNYTEFUX09GRlNFVCk7DQo+ID4NCj4gPiAgICAgICAgIGlmICgh
bmRldi0+YmFyNF9zcGxpdCkgew0KPiA+IC0gICAgICAgICAgICAgICBpb3dyaXRlNjQoMCwgbW1p
byArIGJhcjJfb2ZmKG9mZiwgNCkpOw0KPiA+ICsgICAgICAgICAgICAgICBpb3dyaXRlNjQoMCwg
bW1pbyArIFNOQl9TQkFSNDVYTEFUX09GRlNFVCk7DQo+ID4gICAgICAgICB9IGVsc2Ugew0KPiA+
IC0gICAgICAgICAgICAgICBpb3dyaXRlMzIoMCwgbW1pbyArIGJhcjJfb2ZmKG9mZiwgNCkpOw0K
PiA+IC0gICAgICAgICAgICAgICBpb3dyaXRlMzIoMCwgbW1pbyArIGJhcjJfb2ZmKG9mZiwgNSkp
Ow0KPiA+ICsgICAgICAgICAgICAgICBpb3dyaXRlMzIoMCwgbW1pbyArIFNOQl9TQkFSNFhMQVRf
T0ZGU0VUKTsNCj4gPiArICAgICAgICAgICAgICAgaW93cml0ZTMyKDAsIG1taW8gKyBTTkJfU0JB
UjVYTEFUX09GRlNFVCk7DQo+ID4gICAgICAgICB9DQo+ID4NCj4gPiAgICAgICAgIC8qIHplcm8g
b3V0Z29pbmcgdHJhbnNsYXRpb24gbGltaXRzICh3aG9sZSBiYXIgc2l6ZSB3aW5kb3dzKSAqLw0K
PiA+IC0gICAgICAgb2ZmID0gU05CX1BCQVIyTE1UX09GRlNFVDsNCj4gPiAtICAgICAgIGlvd3Jp
dGU2NCgwLCBtbWlvICsgYmFyMl9vZmYob2ZmLCAyKSk7DQo+ID4gKyAgICAgICBpb3dyaXRlNjQo
MCwgbW1pbyArIFNOQl9QQkFSMjNMTVRfT0ZGU0VUKTsNCj4gPiAgICAgICAgIGlmICghbmRldi0+
YmFyNF9zcGxpdCkgew0KPiA+IC0gICAgICAgICAgICAgICBpb3dyaXRlNjQoMCwgbW1pbyArIGJh
cjJfb2ZmKG9mZiwgNCkpOw0KPiA+ICsgICAgICAgICAgICAgICBpb3dyaXRlNjQoMCwgbW1pbyAr
IFNOQl9QQkFSNDVMTVRfT0ZGU0VUKTsNCj4gPiAgICAgICAgIH0gZWxzZSB7DQo+ID4gLSAgICAg
ICAgICAgICAgIGlvd3JpdGUzMigwLCBtbWlvICsgYmFyMl9vZmYob2ZmLCA0KSk7DQo+ID4gLSAg
ICAgICAgICAgICAgIGlvd3JpdGUzMigwLCBtbWlvICsgYmFyMl9vZmYob2ZmLCA1KSk7DQo+ID4g
KyAgICAgICAgICAgICAgIGlvd3JpdGUzMigwLCBtbWlvICsgU05CX1BCQVI0TE1UX09GRlNFVCk7
DQo+ID4gKyAgICAgICAgICAgICAgIGlvd3JpdGUzMigwLCBtbWlvICsgU05CX1BCQVI1TE1UX09G
RlNFVCk7DQo+ID4gICAgICAgICB9DQo+ID4NCj4gPiAgICAgICAgIC8qIHNldCBvdXRnb2luZyB0
cmFuc2xhdGlvbiBvZmZzZXRzICovDQo+ID4gLSAgICAgICBvZmYgPSBTTkJfUEJBUjJYTEFUX09G
RlNFVDsNCj4gPiAtDQo+ID4gICAgICAgICBiYXJfYWRkciA9IHBlZXJfYWRkci0+YmFyMl9hZGRy
NjQ7DQo+ID4gLSAgICAgICBpb3dyaXRlNjQoYmFyX2FkZHIsIG1taW8gKyBiYXIyX29mZihvZmYs
IDIpKTsNCj4gPiAtICAgICAgIGJhcl9hZGRyID0gaW9yZWFkNjQobW1pbyArIGJhcjJfb2ZmKG9m
ZiwgMikpOw0KPiA+ICsgICAgICAgaW93cml0ZTY0KGJhcl9hZGRyLCBtbWlvICsgU05CX1BCQVIy
M1hMQVRfT0ZGU0VUKTsNCj4gPiArICAgICAgIGJhcl9hZGRyID0gaW9yZWFkNjQobW1pbyArIFNO
Ql9QQkFSMjNYTEFUX09GRlNFVCk7DQo+ID4gICAgICAgICBkZXZfZGJnKG5kZXZfZGV2KG5kZXYp
LCAiUEJBUjIzWExBVCAlIzAxOGxseFxuIiwgYmFyX2FkZHIpOw0KPiA+DQo+ID4gICAgICAgICBp
ZiAoIW5kZXYtPmJhcjRfc3BsaXQpIHsNCj4gPiAgICAgICAgICAgICAgICAgYmFyX2FkZHIgPSBw
ZWVyX2FkZHItPmJhcjRfYWRkcjY0Ow0KPiA+IC0gICAgICAgICAgICAgICBpb3dyaXRlNjQoYmFy
X2FkZHIsIG1taW8gKyBiYXIyX29mZihvZmYsIDQpKTsNCj4gPiAtICAgICAgICAgICAgICAgYmFy
X2FkZHIgPSBpb3JlYWQ2NChtbWlvICsgYmFyMl9vZmYob2ZmLCA0KSk7DQo+ID4gKyAgICAgICAg
ICAgICAgIGlvd3JpdGU2NChiYXJfYWRkciwgbW1pbyArIFNOQl9QQkFSNDVYTEFUX09GRlNFVCk7
DQo+ID4gKyAgICAgICAgICAgICAgIGJhcl9hZGRyID0gaW9yZWFkNjQobW1pbyArIFNOQl9QQkFS
NDVYTEFUX09GRlNFVCk7DQo+ID4gICAgICAgICAgICAgICAgIGRldl9kYmcobmRldl9kZXYobmRl
diksICJQQkFSNDVYTEFUICUjMDE4bGx4XG4iLCBiYXJfYWRkcik7DQo+ID4gICAgICAgICB9IGVs
c2Ugew0KPiA+ICAgICAgICAgICAgICAgICBiYXJfYWRkciA9IHBlZXJfYWRkci0+YmFyMl9hZGRy
NjQ7DQo+ID4gLSAgICAgICAgICAgICAgIGlvd3JpdGUzMihiYXJfYWRkciwgbW1pbyArIGJhcjJf
b2ZmKG9mZiwgNCkpOw0KPiA+IC0gICAgICAgICAgICAgICBiYXJfYWRkciA9IGlvcmVhZDMyKG1t
aW8gKyBiYXIyX29mZihvZmYsIDQpKTsNCj4gPiArICAgICAgICAgICAgICAgaW93cml0ZTMyKGJh
cl9hZGRyLCBtbWlvICsgU05CX1BCQVI0WExBVF9PRkZTRVQpOw0KPiA+ICsgICAgICAgICAgICAg
ICBiYXJfYWRkciA9IGlvcmVhZDMyKG1taW8gKyBTTkJfUEJBUjRYTEFUX09GRlNFVCk7DQo+ID4g
ICAgICAgICAgICAgICAgIGRldl9kYmcobmRldl9kZXYobmRldiksICJQQkFSNFhMQVQgJSMwMTBs
bHhcbiIsIGJhcl9hZGRyKTsNCj4gPg0KPiA+ICAgICAgICAgICAgICAgICBiYXJfYWRkciA9IHBl
ZXJfYWRkci0+YmFyMl9hZGRyNjQ7DQo+ID4gLSAgICAgICAgICAgICAgIGlvd3JpdGUzMihiYXJf
YWRkciwgbW1pbyArIGJhcjJfb2ZmKG9mZiwgNSkpOw0KPiA+IC0gICAgICAgICAgICAgICBiYXJf
YWRkciA9IGlvcmVhZDMyKG1taW8gKyBiYXIyX29mZihvZmYsIDUpKTsNCj4gPiArICAgICAgICAg
ICAgICAgaW93cml0ZTMyKGJhcl9hZGRyLCBtbWlvICsgU05CX1BCQVI1WExBVF9PRkZTRVQpOw0K
PiA+ICsgICAgICAgICAgICAgICBiYXJfYWRkciA9IGlvcmVhZDMyKG1taW8gKyBTTkJfUEJBUjVY
TEFUX09GRlNFVCk7DQo+ID4gICAgICAgICAgICAgICAgIGRldl9kYmcobmRldl9kZXYobmRldiks
ICJQQkFSNVhMQVQgJSMwMTBsbHhcbiIsIGJhcl9hZGRyKTsNCj4gPiAgICAgICAgIH0NCj4gPg0K
PiA+IEBAIC0xNzQ3LDI5ICsxNzIyLDY4IEBAIHN0YXRpYyBpbnQgc25iX2luaXRfZGV2KHN0cnVj
dCBpbnRlbF9udGJfZGV2ICpuZGV2KQ0KPiA+ICAgICAgICAgdTggcHBkOw0KPiA+ICAgICAgICAg
aW50IHJjLCBtZW07DQo+ID4NCj4gPiArICAgICAgIHBkZXYgPSBuZGV2X3BkZXYobmRldik7DQo+
ID4gKw0KPiA+ICsgICAgICAgc3dpdGNoIChwZGV2LT5kZXZpY2UpIHsNCj4gPiAgICAgICAgIC8q
IFRoZXJlIGlzIGEgWGVvbiBoYXJkd2FyZSBlcnJhdGEgcmVsYXRlZCB0byB3cml0ZXMgdG8gU0RP
T1JCRUxMIG9yDQo+ID4gICAgICAgICAgKiBCMkJET09SQkVMTCBpbiBjb25qdW5jdGlvbiB3aXRo
IGluYm91bmQgYWNjZXNzIHRvIE5UQiBNTUlPIFNwYWNlLA0KPiA+ICAgICAgICAgICogd2hpY2gg
bWF5IGhhbmcgdGhlIHN5c3RlbS4gIFRvIHdvcmthcm91bmQgdGhpcyB1c2UgdGhlIHNlY29uZCBt
ZW1vcnkNCj4gPiAgICAgICAgICAqIHdpbmRvdyB0byBhY2Nlc3MgdGhlIGludGVycnVwdCBhbmQg
c2NyYXRjaCBwYWQgcmVnaXN0ZXJzIG9uIHRoZQ0KPiA+ICAgICAgICAgICogcmVtb3RlIHN5c3Rl
bS4NCj4gPiAgICAgICAgICAqLw0KPiA+IC0gICAgICAgbmRldi0+aHdlcnJfZmxhZ3MgfD0gTlRC
X0hXRVJSX1NET09SQkVMTF9MT0NLVVA7DQo+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURf
SU5URUxfTlRCX1NTX0pTRjoNCj4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9O
VEJfUFNfSlNGOg0KPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9CMkJf
SlNGOg0KPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9TU19TTkI6DQo+
ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX1BTX1NOQjoNCj4gPiArICAg
ICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJfQjJCX1NOQjoNCj4gPiArICAgICAgIGNh
c2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJfU1NfSVZUOg0KPiA+ICsgICAgICAgY2FzZSBQQ0lf
REVWSUNFX0lEX0lOVEVMX05UQl9QU19JVlQ6DQo+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0Vf
SURfSU5URUxfTlRCX0IyQl9JVlQ6DQo+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5U
RUxfTlRCX1NTX0hTWDoNCj4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJf
UFNfSFNYOg0KPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9CMkJfSFNY
Og0KPiA+ICsgICAgICAgICAgICAgICBuZGV2LT5od2Vycl9mbGFncyB8PSBOVEJfSFdFUlJfU0RP
T1JCRUxMX0xPQ0tVUDsNCj4gPiArICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICB9
DQo+ID4NCj4gPiArICAgICAgIHN3aXRjaCAocGRldi0+ZGV2aWNlKSB7DQo+ID4gICAgICAgICAv
KiBUaGVyZSBpcyBhIGhhcmR3YXJlIGVycmF0YSByZWxhdGVkIHRvIGFjY2Vzc2luZyBhbnkgcmVn
aXN0ZXIgaW4NCj4gPiAgICAgICAgICAqIFNCMDFCQVNFIGluIHRoZSBwcmVzZW5jZSBvZiBiaWRp
cmVjdGlvbmFsIHRyYWZmaWMgY3Jvc3NpbmcgdGhlIE5UQi4NCj4gPiAgICAgICAgICAqLw0KPiA+
IC0gICAgICAgbmRldi0+aHdlcnJfZmxhZ3MgfD0gTlRCX0hXRVJSX1NCMDFCQVNFX0xPQ0tVUDsN
Cj4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJfU1NfSVZUOg0KPiA+ICsg
ICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9QU19JVlQ6DQo+ID4gKyAgICAgICBj
YXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX0IyQl9JVlQ6DQo+ID4gKyAgICAgICBjYXNlIFBD
SV9ERVZJQ0VfSURfSU5URUxfTlRCX1NTX0hTWDoNCj4gPiArICAgICAgIGNhc2UgUENJX0RFVklD
RV9JRF9JTlRFTF9OVEJfUFNfSFNYOg0KPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lO
VEVMX05UQl9CMkJfSFNYOg0KPiA+ICsgICAgICAgICAgICAgICBuZGV2LT5od2Vycl9mbGFncyB8
PSBOVEJfSFdFUlJfU0IwMUJBU0VfTE9DS1VQOw0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsN
Cj4gPiArICAgICAgIH0NCj4gPg0KPiA+ICsgICAgICAgc3dpdGNoIChwZGV2LT5kZXZpY2UpIHsN
Cj4gPiAgICAgICAgIC8qIEhXIEVycmF0YSBvbiBiaXQgMTQgb2YgYjJiZG9vcmJlbGwgcmVnaXN0
ZXIuICBXcml0ZXMgd2lsbCBub3QgYmUNCj4gPiAgICAgICAgICAqIG1pcnJvcmVkIHRvIHRoZSBy
ZW1vdGUgc3lzdGVtLiAgU2hyaW5rIHRoZSBudW1iZXIgb2YgYml0cyBieSBvbmUsDQo+ID4gICAg
ICAgICAgKiBzaW5jZSBiaXQgMTQgaXMgdGhlIGxhc3QgYml0Lg0KPiA+ICAgICAgICAgICovDQo+
ID4gLSAgICAgICBuZGV2LT5od2Vycl9mbGFncyB8PSBOVEJfSFdFUlJfQjJCRE9PUkJFTExfQklU
MTQ7DQo+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX1NTX0pTRjoNCj4g
PiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJfUFNfSlNGOg0KPiA+ICsgICAg
ICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9CMkJfSlNGOg0KPiA+ICsgICAgICAgY2Fz
ZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9TU19TTkI6DQo+ID4gKyAgICAgICBjYXNlIFBDSV9E
RVZJQ0VfSURfSU5URUxfTlRCX1BTX1NOQjoNCj4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9J
RF9JTlRFTF9OVEJfQjJCX1NOQjoNCj4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRF
TF9OVEJfU1NfSVZUOg0KPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9Q
U19JVlQ6DQo+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX0IyQl9JVlQ6
DQo+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX1NTX0hTWDoNCj4gPiAr
ICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJfUFNfSFNYOg0KPiA+ICsgICAgICAg
Y2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9CMkJfSFNYOg0KPiA+ICsgICAgICAgICAgICAg
ICBuZGV2LT5od2Vycl9mbGFncyB8PSBOVEJfSFdFUlJfQjJCRE9PUkJFTExfQklUMTQ7DQo+ID4g
KyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgfQ0KPiA+DQo+ID4gICAgICAgICBu
ZGV2LT5yZWcgPSAmc25iX3JlZzsNCj4gPg0KPiA+IC0gICAgICAgcGRldiA9IG5kZXZfcGRldihu
ZGV2KTsNCj4gPiAtDQo+ID4gICAgICAgICByYyA9IHBjaV9yZWFkX2NvbmZpZ19ieXRlKHBkZXYs
IFNOQl9QUERfT0ZGU0VULCAmcHBkKTsNCj4gPiAgICAgICAgIGlmIChyYykNCj4gPiAgICAgICAg
ICAgICAgICAgcmV0dXJuIC1FSU87DQo+ID4gQEAgLTIwNjIsMTQgKzIwNzYsMTQgQEAgc3RhdGlj
IGNvbnN0IHN0cnVjdCBpbnRlbF9udGJfeGxhdF9yZWcgc25iX3ByaV94bGF0ID0gew0KPiA+ICAg
ICAgICAgICogd2luZG93IGJ5IHNldHRpbmcgdGhlIGxpbWl0IGVxdWFsIHRvIGJhc2UsIG5vciBj
YW4gaXQgbGltaXQgdGhlIHNpemUNCj4gPiAgICAgICAgICAqIG9mIHRoZSBtZW1vcnkgd2luZG93
IGJ5IHNldHRpbmcgdGhlIGxpbWl0IHRvIGJhc2UgKyBzaXplLg0KPiA+ICAgICAgICAgICovDQo+
ID4gLSAgICAgICAuYmFyMl9saW1pdCAgICAgICAgICAgICA9IFNOQl9QQkFSMkxNVF9PRkZTRVQs
DQo+ID4gLSAgICAgICAuYmFyMl94bGF0ICAgICAgICAgICAgICA9IFNOQl9QQkFSMlhMQVRfT0ZG
U0VULA0KPiA+ICsgICAgICAgLmJhcjJfbGltaXQgICAgICAgICAgICAgPSBTTkJfUEJBUjIzTE1U
X09GRlNFVCwNCj4gPiArICAgICAgIC5iYXIyX3hsYXQgICAgICAgICAgICAgID0gU05CX1BCQVIy
M1hMQVRfT0ZGU0VULA0KPiA+ICB9Ow0KPiA+DQo+ID4gIHN0YXRpYyBjb25zdCBzdHJ1Y3QgaW50
ZWxfbnRiX3hsYXRfcmVnIHNuYl9zZWNfeGxhdCA9IHsNCj4gPiAgICAgICAgIC5iYXIwX2Jhc2Ug
ICAgICAgICAgICAgID0gU05CX1NCQVIwQkFTRV9PRkZTRVQsDQo+ID4gLSAgICAgICAuYmFyMl9s
aW1pdCAgICAgICAgICAgICA9IFNOQl9TQkFSMkxNVF9PRkZTRVQsDQo+ID4gLSAgICAgICAuYmFy
Ml94bGF0ICAgICAgICAgICAgICA9IFNOQl9TQkFSMlhMQVRfT0ZGU0VULA0KPiA+ICsgICAgICAg
LmJhcjJfbGltaXQgICAgICAgICAgICAgPSBTTkJfU0JBUjIzTE1UX09GRlNFVCwNCj4gPiArICAg
ICAgIC5iYXIyX3hsYXQgICAgICAgICAgICAgID0gU05CX1NCQVIyM1hMQVRfT0ZGU0VULA0KPiA+
ICB9Ow0KPiA+DQo+ID4gIHN0YXRpYyBjb25zdCBzdHJ1Y3QgaW50ZWxfYjJiX2FkZHIgc25iX2Iy
Yl91c2RfYWRkciA9IHsNCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9udGIvaHcvaW50ZWwvbnRi
X2h3X2ludGVsLmggYi9kcml2ZXJzL250Yi9ody9pbnRlbC9udGJfaHdfaW50ZWwuaA0KPiA+IGlu
ZGV4IDAyMjRiMWEuLmZlYzY4OWQgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9udGIvaHcvaW50
ZWwvbnRiX2h3X2ludGVsLmgNCj4gPiArKysgYi9kcml2ZXJzL250Yi9ody9pbnRlbC9udGJfaHdf
aW50ZWwuaA0KPiA+IEBAIC03MCwxMSArNzAsMjcgQEANCj4gPg0KPiA+ICAvKiBTTkIgaGFyZHdh
cmUgKGFuZCBKU0YsIElWVCwgSFNYKSAqLw0KPiA+DQo+ID4gLSNkZWZpbmUgU05CX1BCQVIyTE1U
X09GRlNFVCAgICAgICAgICAgIDB4MDAwMA0KPiA+IC0jZGVmaW5lIFNOQl9QQkFSMlhMQVRfT0ZG
U0VUICAgICAgICAgICAweDAwMTANCj4gPiAtI2RlZmluZSBTTkJfU0JBUjJMTVRfT0ZGU0VUICAg
ICAgICAgICAgMHgwMDIwDQo+ID4gLSNkZWZpbmUgU05CX1NCQVIyWExBVF9PRkZTRVQgICAgICAg
ICAgIDB4MDAzMA0KPiA+ICsjZGVmaW5lIFNOQl9QQkFSMjNMTVRfT0ZGU0VUICAgICAgICAgICAw
eDAwMDANCj4gPiArI2RlZmluZSBTTkJfUEJBUjQ1TE1UX09GRlNFVCAgICAgICAgICAgMHgwMDA4
DQo+ID4gKyNkZWZpbmUgU05CX1BCQVI0TE1UX09GRlNFVCAgICAgICAgICAgIDB4MDAwOA0KPiA+
ICsjZGVmaW5lIFNOQl9QQkFSNUxNVF9PRkZTRVQgICAgICAgICAgICAweDAwMGMNCj4gPiArI2Rl
ZmluZSBTTkJfUEJBUjIzWExBVF9PRkZTRVQgICAgICAgICAgMHgwMDEwDQo+ID4gKyNkZWZpbmUg
U05CX1BCQVI0NVhMQVRfT0ZGU0VUICAgICAgICAgIDB4MDAxOA0KPiA+ICsjZGVmaW5lIFNOQl9Q
QkFSNFhMQVRfT0ZGU0VUICAgICAgICAgICAweDAwMTgNCj4gPiArI2RlZmluZSBTTkJfUEJBUjVY
TEFUX09GRlNFVCAgICAgICAgICAgMHgwMDFjDQo+ID4gKyNkZWZpbmUgU05CX1NCQVIyM0xNVF9P
RkZTRVQgICAgICAgICAgIDB4MDAyMA0KPiA+ICsjZGVmaW5lIFNOQl9TQkFSNDVMTVRfT0ZGU0VU
ICAgICAgICAgICAweDAwMjgNCj4gPiArI2RlZmluZSBTTkJfU0JBUjRMTVRfT0ZGU0VUICAgICAg
ICAgICAgMHgwMDI4DQo+ID4gKyNkZWZpbmUgU05CX1NCQVI1TE1UX09GRlNFVCAgICAgICAgICAg
IDB4MDAyYw0KPiA+ICsjZGVmaW5lIFNOQl9TQkFSMjNYTEFUX09GRlNFVCAgICAgICAgICAweDAw
MzANCj4gPiArI2RlZmluZSBTTkJfU0JBUjQ1WExBVF9PRkZTRVQgICAgICAgICAgMHgwMDM4DQo+
ID4gKyNkZWZpbmUgU05CX1NCQVI0WExBVF9PRkZTRVQgICAgICAgICAgIDB4MDAzOA0KPiA+ICsj
ZGVmaW5lIFNOQl9TQkFSNVhMQVRfT0ZGU0VUICAgICAgICAgICAweDAwM2MNCj4gPiAgI2RlZmlu
ZSBTTkJfU0JBUjBCQVNFX09GRlNFVCAgICAgICAgICAgMHgwMDQwDQo+ID4gKyNkZWZpbmUgU05C
X1NCQVIyM0JBU0VfT0ZGU0VUICAgICAgICAgIDB4MDA0OA0KPiA+ICsjZGVmaW5lIFNOQl9TQkFS
NDVCQVNFX09GRlNFVCAgICAgICAgICAweDAwNTANCj4gPiArI2RlZmluZSBTTkJfU0JBUjRCQVNF
X09GRlNFVCAgICAgICAgICAgMHgwMDUwDQo+ID4gKyNkZWZpbmUgU05CX1NCQVI1QkFTRV9PRkZT
RVQgICAgICAgICAgIDB4MDA1NA0KPiA+ICAjZGVmaW5lIFNOQl9TQkRGX09GRlNFVCAgICAgICAg
ICAgICAgICAgICAgICAgIDB4MDA1Yw0KPiA+ICAjZGVmaW5lIFNOQl9OVEJDTlRMX09GRlNFVCAg
ICAgICAgICAgICAweDAwNTgNCj4gPiAgI2RlZmluZSBTTkJfUERPT1JCRUxMX09GRlNFVCAgICAg
ICAgICAgMHgwMDYwDQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbnRiL250Yl90cmFuc3BvcnQu
YyBiL2RyaXZlcnMvbnRiL250Yl90cmFuc3BvcnQuYw0KPiA+IGluZGV4IGYxZWQxYjcuLmJiMmVi
ODUgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9udGIvbnRiX3RyYW5zcG9ydC5jDQo+ID4gKysr
IGIvZHJpdmVycy9udGIvbnRiX3RyYW5zcG9ydC5jDQo+ID4gQEAgLTIwNCw4ICsyMDQsOCBAQCBz
dHJ1Y3QgbnRiX3RyYW5zcG9ydF9jdHggew0KPiA+DQo+ID4gICAgICAgICBib29sIGxpbmtfaXNf
dXA7DQo+ID4gICAgICAgICBzdHJ1Y3QgZGVsYXllZF93b3JrIGxpbmtfd29yazsNCj4gPiAtICAg
ICAgIHN0cnVjdCB3b3JrX3N0cnVjdCBkYl93b3JrOw0KPiA+ICAgICAgICAgc3RydWN0IHdvcmtf
c3RydWN0IGxpbmtfY2xlYW51cDsNCj4gPiArICAgICAgIHN0cnVjdCB0YXNrbGV0X3N0cnVjdCBk
Yl93b3JrOw0KPiA+ICB9Ow0KPiA+DQo+ID4gIGVudW0gew0KPiA+IEBAIC0yNDEsNyArMjQxLDcg
QEAgZW51bSB7DQo+ID4gICNkZWZpbmUgTlRCX1FQX0RFRl9OVU1fRU5UUklFUyAxMDANCj4gPiAg
I2RlZmluZSBOVEJfTElOS19ET1dOX1RJTUVPVVQgIDEwDQo+ID4NCj4gPiAtc3RhdGljIHZvaWQg
bnRiX3RyYW5zcG9ydF9kb29yYmVsbF93b3JrKHN0cnVjdCB3b3JrX3N0cnVjdCAqd3MpOw0KPiA+
ICtzdGF0aWMgdm9pZCBudGJfdHJhbnNwb3J0X2Rvb3JiZWxsX3dvcmsodW5zaWduZWQgbG9uZyBk
YXRhKTsNCj4gPiAgc3RhdGljIGNvbnN0IHN0cnVjdCBudGJfY3R4X29wcyBudGJfdHJhbnNwb3J0
X29wczsNCj4gPiAgc3RhdGljIHN0cnVjdCBudGJfY2xpZW50IG50Yl90cmFuc3BvcnRfY2xpZW50
Ow0KPiA+DQo+ID4gQEAgLTEwMDIsOCArMTAwMiw5IEBAIHN0YXRpYyBpbnQgbnRiX3RyYW5zcG9y
dF9wcm9iZShzdHJ1Y3QgbnRiX2NsaWVudCAqc2VsZiwgc3RydWN0IG50Yl9kZXYgKm5kZXYpDQo+
ID4gICAgICAgICB9DQo+ID4NCj4gPiAgICAgICAgIElOSVRfREVMQVlFRF9XT1JLKCZudC0+bGlu
a193b3JrLCBudGJfdHJhbnNwb3J0X2xpbmtfd29yayk7DQo+ID4gLSAgICAgICBJTklUX1dPUkso
Jm50LT5kYl93b3JrLCBudGJfdHJhbnNwb3J0X2Rvb3JiZWxsX3dvcmspOw0KPiA+ICAgICAgICAg
SU5JVF9XT1JLKCZudC0+bGlua19jbGVhbnVwLCBudGJfdHJhbnNwb3J0X2xpbmtfY2xlYW51cF93
b3JrKTsNCj4gPiArICAgICAgIHRhc2tsZXRfaW5pdCgmbnQtPmRiX3dvcmssIG50Yl90cmFuc3Bv
cnRfZG9vcmJlbGxfd29yaywNCj4gPiArICAgICAgICAgICAgICAgICAgICAodW5zaWduZWQgbG9u
ZyludCk7DQo+ID4NCj4gPiAgICAgICAgIHJjID0gbnRiX3NldF9jdHgobmRldiwgbnQsICZudGJf
dHJhbnNwb3J0X29wcyk7DQo+ID4gICAgICAgICBpZiAocmMpDQo+ID4gQEAgLTEwNDQsNyArMTA0
NSw3IEBAIHN0YXRpYyB2b2lkIG50Yl90cmFuc3BvcnRfZnJlZShzdHJ1Y3QgbnRiX2NsaWVudCAq
c2VsZiwgc3RydWN0IG50Yl9kZXYgKm5kZXYpDQo+ID4gICAgICAgICBpbnQgaTsNCj4gPg0KPiA+
ICAgICAgICAgbnRiX3RyYW5zcG9ydF9saW5rX2NsZWFudXAobnQpOw0KPiA+IC0gICAgICAgY2Fu
Y2VsX3dvcmtfc3luYygmbnQtPmRiX3dvcmspOw0KPiA+ICsgICAgICAgdGFza2xldF9kaXNhYmxl
KCZudC0+ZGJfd29yayk7DQo+ID4gICAgICAgICBjYW5jZWxfd29ya19zeW5jKCZudC0+bGlua19j
bGVhbnVwKTsNCj4gPiAgICAgICAgIGNhbmNlbF9kZWxheWVkX3dvcmtfc3luYygmbnQtPmxpbmtf
d29yayk7DQo+ID4NCj4gPiBAQCAtMTg1MCwxMCArMTg1MSw5IEBAIHVuc2lnbmVkIGludCBudGJf
dHJhbnNwb3J0X21heF9zaXplKHN0cnVjdCBudGJfdHJhbnNwb3J0X3FwICpxcCkNCj4gPiAgfQ0K
PiA+ICBFWFBPUlRfU1lNQk9MX0dQTChudGJfdHJhbnNwb3J0X21heF9zaXplKTsNCj4gPg0KPiA+
IC1zdGF0aWMgdm9pZCBudGJfdHJhbnNwb3J0X2Rvb3JiZWxsX3dvcmsoc3RydWN0IHdvcmtfc3Ry
dWN0ICp3b3JrKQ0KPiA+ICtzdGF0aWMgdm9pZCBudGJfdHJhbnNwb3J0X2Rvb3JiZWxsX3dvcmso
dW5zaWduZWQgbG9uZyBkYXRhKQ0KPiA+ICB7DQo+ID4gLSAgICAgICBzdHJ1Y3QgbnRiX3RyYW5z
cG9ydF9jdHggKm50ID0gY29udGFpbmVyX29mKHdvcmssDQo+ID4gLSAgICAgICAgICAgICAgICAg
ICAgICAgc3RydWN0IG50Yl90cmFuc3BvcnRfY3R4LCBkYl93b3JrKTsNCj4gPiArICAgICAgIHN0
cnVjdCBudGJfdHJhbnNwb3J0X2N0eCAqbnQgPSAodm9pZCAqKWRhdGE7DQo+ID4gICAgICAgICBz
dHJ1Y3QgbnRiX3RyYW5zcG9ydF9xcCAqcXA7DQo+ID4gICAgICAgICB1NjQgZGJfbWFzaywgZGJf
Yml0cywgZGJfYWdhaW47DQo+ID4gICAgICAgICB1bnNpZ25lZCBpbnQgcXBfbnVtOw0KPiA+IEBA
IC0xODkwLDcgKzE4OTAsNyBAQCBzdGF0aWMgdm9pZCBudGJfdHJhbnNwb3J0X2Rvb3JiZWxsX2Nh
bGxiYWNrKHZvaWQgKmRhdGEsIGludCB2ZWN0b3IpDQo+ID4NCj4gPiAgICAgICAgIG50Yl9kYl9z
ZXRfbWFzayhudC0+bmRldiwgbnRiX2RiX3ZhbGlkX21hc2sobnQtPm5kZXYpKTsNCj4gPg0KPiA+
IC0gICAgICAgc2NoZWR1bGVfd29yaygmbnQtPmRiX3dvcmspOw0KPiA+ICsgICAgICAgdGFza2xl
dF9zY2hlZHVsZSgmbnQtPmRiX3dvcmspOw0KPiA+ICB9DQo+ID4NCj4gPiAgc3RhdGljIGNvbnN0
IHN0cnVjdCBudGJfY3R4X29wcyBudGJfdHJhbnNwb3J0X29wcyA9IHsNCj4gPiAtLQ0KPiA+IDIu
NC4wLnJjMC40My5nY2Y4YThjNg0KPiA+DQo+ID4gLS0NCj4gPiBUbyB1bnN1YnNjcmliZSBmcm9t
IHRoaXMgbGlzdDogc2VuZCB0aGUgbGluZSAidW5zdWJzY3JpYmUgbGludXgtcGNpIiBpbg0KPiA+
IHRoZSBib2R5IG9mIGEgbWVzc2FnZSB0byBtYWpvcmRvbW9Admdlci5rZXJuZWwub3JnDQo+ID4g
TW9yZSBtYWpvcmRvbW8gaW5mbyBhdCAgaHR0cDovL3ZnZXIua2VybmVsLm9yZy9tYWpvcmRvbW8t
aW5mby5odG1sDQo=

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/16] Check the DID for certain workaround error flags to be set.
@ 2015-05-20 21:15       ` Jiang, Dave
  0 siblings, 0 replies; 40+ messages in thread
From: Jiang, Dave @ 2015-05-20 21:15 UTC (permalink / raw)
  To: bhelgaas; +Cc: Allen.Hubbe, linux-kernel, linux-pci, jdmason, linux-ntb

On Wed, 2015-05-20 at 16:11 -0500, Bjorn Helgaas wrote:
> On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com> wrote:
> > From: Dave Jiang <dave.jiang@intel.com>
> >
> > Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> 
> Needs a topic in the subject line and a changelog.
> 
> It also seems to do a lot more than just checking device ID (I assume
> that's what "DID" means), so this should probably be split into
> several patches that each do one thing.  I see at least:
> 
>   - cosmetic code restructuring
>   - work_struct/tasklet_struct changes
>   - new #defines and bar2_off() changes

I think this patch got mangled with couple other patches. Allen?

> 
> > ---
> >  drivers/ntb/hw/intel/ntb_hw_intel.c | 196 +++++++++++++++++++-----------------
> >  drivers/ntb/hw/intel/ntb_hw_intel.h |  24 ++++-
> >  drivers/ntb/ntb_transport.c         |  16 +--
> >  3 files changed, 133 insertions(+), 103 deletions(-)
> >
> > diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> > index d162f22..89fea50 100644
> > --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> > +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> > @@ -503,7 +503,6 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >         size_t buf_size;
> >         ssize_t ret, off;
> >         union { u64 v64; u32 v32; u16 v16; } u;
> > -       unsigned long reg;
> >
> >         ndev = filp->private_data;
> >         mmio = ndev->self_mmio;
> > @@ -538,10 +537,10 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >
> >         if (!ndev->reg->link_is_up(ndev)) {
> >                 off += scnprintf(buf + off, buf_size - off,
> > -                                "Link Satus -\t\tDown\n");
> > +                                "Link Status -\t\tDown\n");
> >         } else {
> >                 off += scnprintf(buf + off, buf_size - off,
> > -                                "Link Satus -\t\tUp\n");
> > +                                "Link Status -\t\tUp\n");
> >                 off += scnprintf(buf + off, buf_size - off,
> >                                  "Link Speed -\t\tPCI-E Gen %u\n",
> >                                  NTB_LNK_STA_SPEED(ndev->lnk_sta));
> > @@ -568,36 +567,30 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
> >
> > -       reg = ndev->self_reg->db_mask;
> > -       u.v64 = ndev_db_read(ndev, mmio + reg);
> > +       u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask);
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "Doorbell Mask -\t\t%#llx\n", u.v64);
> >
> > -       reg = ndev->self_reg->db_bell;
> > -       u.v64 = ndev_db_read(ndev, mmio + reg);
> > +       u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell);
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "Doorbell Bell -\t\t%#llx\n", u.v64);
> >
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "\nNTB Incoming XLAT:\n");
> >
> > -       reg = bar2_off(ndev->xlat_reg->bar2_xlat, 2);
> > -       u.v64 = ioread64(mmio + reg);
> > +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2));
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "XLAT23 -\t\t%#018llx\n", u.v64);
> >
> > -       reg = bar2_off(ndev->xlat_reg->bar2_xlat, 4);
> > -       u.v64 = ioread64(mmio + reg);
> > +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4));
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "XLAT45 -\t\t%#018llx\n", u.v64);
> >
> > -       reg = bar2_off(ndev->xlat_reg->bar2_limit, 2);
> > -       u.v64 = ioread64(mmio + reg);
> > +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2));
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "LMT23 -\t\t\t%#018llx\n", u.v64);
> >
> > -       reg = bar2_off(ndev->xlat_reg->bar2_limit, 4);
> > -       u.v64 = ioread64(mmio + reg);
> > +       u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4));
> >         off += scnprintf(buf + off, buf_size - off,
> >                          "LMT45 -\t\t\t%#018llx\n", u.v64);
> >
> > @@ -606,41 +599,34 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "\nNTB Outgoing B2B XLAT:\n");
> >
> > -                       reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 2);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_PBAR23XLAT_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "B2B XLAT23 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar2_off(SNB_PBAR2XLAT_OFFSET, 4);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_PBAR45XLAT_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "B2B XLAT45 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar2_off(SNB_PBAR2LMT_OFFSET, 2);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_PBAR23LMT_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "B2B LMT23 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar2_off(SNB_PBAR2LMT_OFFSET, 4);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_PBAR45LMT_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "B2B LMT45 -\t\t%#018llx\n", u.v64);
> >
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "\nNTB Secondary BAR:\n");
> >
> > -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 0);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_SBAR0BASE_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "SBAR01 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 2);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_SBAR23BASE_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "SBAR23 -\t\t%#018llx\n", u.v64);
> >
> > -                       reg = bar0_off(SNB_SBAR0BASE_OFFSET, 4);
> > -                       u.v64 = ioread64(mmio + reg);
> > +                       u.v64 = ioread64(mmio + SNB_SBAR45BASE_OFFSET);
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "SBAR45 -\t\t%#018llx\n", u.v64);
> >                 }
> > @@ -648,31 +634,30 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
> >                 off += scnprintf(buf + off, buf_size - off,
> >                                  "\nSNB NTB Statistics:\n");
> >
> > -               reg = SNB_USMEMMISS_OFFSET;
> > -               u.v16 = ioread16(mmio + reg);
> > +               u.v16 = ioread16(mmio + SNB_USMEMMISS_OFFSET);
> >                 off += scnprintf(buf + off, buf_size - off,
> >                                  "Upstream Memory Miss -\t%u\n", u.v16);
> >
> >                 off += scnprintf(buf + off, buf_size - off,
> >                                  "\nSNB NTB Hardware Errors:\n");
> >
> > -               reg = SNB_DEVSTS_OFFSET;
> > -               if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
> > +               if (!pci_read_config_word(ndev->ntb.pdev,
> > +                                         SNB_DEVSTS_OFFSET, &u.v16))
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "DEVSTS -\t\t%#06x\n", u.v16);
> >
> > -               reg = SNB_LINK_STATUS_OFFSET;
> > -               if (!pci_read_config_word(ndev->ntb.pdev, reg, &u.v16))
> > +               if (!pci_read_config_word(ndev->ntb.pdev,
> > +                                         SNB_LINK_STATUS_OFFSET, &u.v16))
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "LNKSTS -\t\t%#06x\n", u.v16);
> >
> > -               reg = SNB_UNCERRSTS_OFFSET;
> > -               if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
> > +               if (!pci_read_config_dword(ndev->ntb.pdev,
> > +                                          SNB_UNCERRSTS_OFFSET, &u.v32))
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "UNCERRSTS -\t\t%#06x\n", u.v32);
> >
> > -               reg = SNB_CORERRSTS_OFFSET;
> > -               if (!pci_read_config_dword(ndev->ntb.pdev, reg, &u.v32))
> > +               if (!pci_read_config_dword(ndev->ntb.pdev,
> > +                                          SNB_CORERRSTS_OFFSET, &u.v32))
> >                         off += scnprintf(buf + off, buf_size - off,
> >                                          "CORERRSTS -\t\t%#06x\n", u.v32);
> >         }
> > @@ -1388,7 +1373,6 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
> >  {
> >         struct pci_dev *pdev;
> >         void __iomem *mmio;
> > -       unsigned long off;
> >         resource_size_t bar_size;
> >         phys_addr_t bar_addr;
> >         int b2b_bar;
> > @@ -1484,9 +1468,6 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
> >                 dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz);
> >         }
> >
> > -       /* setup incoming bar base addresses */
> > -       off = SNB_SBAR0BASE_OFFSET;
> > -
> >         /* SBAR01 hit by first part of the b2b bar */
> >         if (b2b_bar == 0) {
> >                 bar_addr = addr->bar0_addr;
> > @@ -1504,7 +1485,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
> >         }
> >
> >         dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr);
> > -       iowrite64(bar_addr, mmio + bar0_off(off, 0));
> > +       iowrite64(bar_addr, mmio + SNB_SBAR0BASE_OFFSET);
> >
> >         /* Other SBAR are normally hit by the PBAR xlat, except for b2b bar.
> >          * The b2b bar is either disabled above, or configured half-size, and
> > @@ -1512,102 +1493,96 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
> >          */
> >
> >         bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
> > -       iowrite64(bar_addr, mmio + bar0_off(off, 2));
> > -       bar_addr = ioread64(mmio + bar0_off(off, 2));
> > +       iowrite64(bar_addr, mmio + SNB_SBAR23BASE_OFFSET);
> > +       bar_addr = ioread64(mmio + SNB_SBAR23BASE_OFFSET);
> >         dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr);
> >
> >         if (!ndev->bar4_split) {
> >                 bar_addr = addr->bar4_addr64 +
> >                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> > -               iowrite64(bar_addr, mmio + bar0_off(off, 4));
> > -               bar_addr = ioread64(mmio + bar0_off(off, 4));
> > +               iowrite64(bar_addr, mmio + SNB_SBAR45BASE_OFFSET);
> > +               bar_addr = ioread64(mmio + SNB_SBAR45BASE_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr);
> >         } else {
> >                 bar_addr = addr->bar4_addr32 +
> >                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> > -               iowrite32(bar_addr, mmio + bar0_off(off, 4));
> > -               bar_addr = ioread32(mmio + bar0_off(off, 4));
> > +               iowrite32(bar_addr, mmio + SNB_SBAR4BASE_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_SBAR4BASE_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr);
> >
> >                 bar_addr = addr->bar5_addr32 +
> >                         (b2b_bar == 5 ? ndev->b2b_off : 0);
> > -               iowrite32(bar_addr, mmio + bar0_off(off, 5));
> > -               bar_addr = ioread32(mmio + bar0_off(off, 5));
> > +               iowrite32(bar_addr, mmio + SNB_SBAR5BASE_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_SBAR5BASE_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr);
> >         }
> >
> >         /* setup incoming bar limits == base addrs (zero length windows) */
> > -       off = SNB_SBAR2LMT_OFFSET;
> >
> >         bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
> > -       iowrite64(bar_addr, mmio + bar2_off(off, 2));
> > -       bar_addr = ioread64(mmio + bar2_off(off, 2));
> > +       iowrite64(bar_addr, mmio + SNB_SBAR23LMT_OFFSET);
> > +       bar_addr = ioread64(mmio + SNB_SBAR23LMT_OFFSET);
> >         dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr);
> >
> >         if (!ndev->bar4_split) {
> >                 bar_addr = addr->bar4_addr64 +
> >                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> > -               iowrite64(bar_addr, mmio + bar2_off(off, 4));
> > -               bar_addr = ioread64(mmio + bar2_off(off, 4));
> > +               iowrite64(bar_addr, mmio + SNB_SBAR45LMT_OFFSET);
> > +               bar_addr = ioread64(mmio + SNB_SBAR45LMT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr);
> >         } else {
> >                 bar_addr = addr->bar4_addr32 +
> >                         (b2b_bar == 4 ? ndev->b2b_off : 0);
> > -               iowrite32(bar_addr, mmio + bar2_off(off, 4));
> > -               bar_addr = ioread32(mmio + bar2_off(off, 4));
> > +               iowrite32(bar_addr, mmio + SNB_SBAR4LMT_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_SBAR4LMT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr);
> >
> >                 bar_addr = addr->bar5_addr32 +
> >                         (b2b_bar == 5 ? ndev->b2b_off : 0);
> > -               iowrite32(bar_addr, mmio + bar2_off(off, 5));
> > -               bar_addr = ioread32(mmio + bar2_off(off, 5));
> > +               iowrite32(bar_addr, mmio + SNB_SBAR5LMT_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_SBAR5LMT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr);
> >         }
> >
> >         /* zero incoming translation addrs */
> > -       off = SNB_SBAR2XLAT_OFFSET;
> > -
> > -       iowrite64(0, mmio + bar2_off(off, 2));
> > +       iowrite64(0, mmio + SNB_SBAR23XLAT_OFFSET);
> >
> >         if (!ndev->bar4_split) {
> > -               iowrite64(0, mmio + bar2_off(off, 4));
> > +               iowrite64(0, mmio + SNB_SBAR45XLAT_OFFSET);
> >         } else {
> > -               iowrite32(0, mmio + bar2_off(off, 4));
> > -               iowrite32(0, mmio + bar2_off(off, 5));
> > +               iowrite32(0, mmio + SNB_SBAR4XLAT_OFFSET);
> > +               iowrite32(0, mmio + SNB_SBAR5XLAT_OFFSET);
> >         }
> >
> >         /* zero outgoing translation limits (whole bar size windows) */
> > -       off = SNB_PBAR2LMT_OFFSET;
> > -       iowrite64(0, mmio + bar2_off(off, 2));
> > +       iowrite64(0, mmio + SNB_PBAR23LMT_OFFSET);
> >         if (!ndev->bar4_split) {
> > -               iowrite64(0, mmio + bar2_off(off, 4));
> > +               iowrite64(0, mmio + SNB_PBAR45LMT_OFFSET);
> >         } else {
> > -               iowrite32(0, mmio + bar2_off(off, 4));
> > -               iowrite32(0, mmio + bar2_off(off, 5));
> > +               iowrite32(0, mmio + SNB_PBAR4LMT_OFFSET);
> > +               iowrite32(0, mmio + SNB_PBAR5LMT_OFFSET);
> >         }
> >
> >         /* set outgoing translation offsets */
> > -       off = SNB_PBAR2XLAT_OFFSET;
> > -
> >         bar_addr = peer_addr->bar2_addr64;
> > -       iowrite64(bar_addr, mmio + bar2_off(off, 2));
> > -       bar_addr = ioread64(mmio + bar2_off(off, 2));
> > +       iowrite64(bar_addr, mmio + SNB_PBAR23XLAT_OFFSET);
> > +       bar_addr = ioread64(mmio + SNB_PBAR23XLAT_OFFSET);
> >         dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr);
> >
> >         if (!ndev->bar4_split) {
> >                 bar_addr = peer_addr->bar4_addr64;
> > -               iowrite64(bar_addr, mmio + bar2_off(off, 4));
> > -               bar_addr = ioread64(mmio + bar2_off(off, 4));
> > +               iowrite64(bar_addr, mmio + SNB_PBAR45XLAT_OFFSET);
> > +               bar_addr = ioread64(mmio + SNB_PBAR45XLAT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr);
> >         } else {
> >                 bar_addr = peer_addr->bar2_addr64;
> > -               iowrite32(bar_addr, mmio + bar2_off(off, 4));
> > -               bar_addr = ioread32(mmio + bar2_off(off, 4));
> > +               iowrite32(bar_addr, mmio + SNB_PBAR4XLAT_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_PBAR4XLAT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr);
> >
> >                 bar_addr = peer_addr->bar2_addr64;
> > -               iowrite32(bar_addr, mmio + bar2_off(off, 5));
> > -               bar_addr = ioread32(mmio + bar2_off(off, 5));
> > +               iowrite32(bar_addr, mmio + SNB_PBAR5XLAT_OFFSET);
> > +               bar_addr = ioread32(mmio + SNB_PBAR5XLAT_OFFSET);
> >                 dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr);
> >         }
> >
> > @@ -1747,29 +1722,68 @@ static int snb_init_dev(struct intel_ntb_dev *ndev)
> >         u8 ppd;
> >         int rc, mem;
> >
> > +       pdev = ndev_pdev(ndev);
> > +
> > +       switch (pdev->device) {
> >         /* 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
> >          * window to access the interrupt and scratch pad registers on the
> >          * remote system.
> >          */
> > -       ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > +               ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> > +               break;
> > +       }
> >
> > +       switch (pdev->device) {
> >         /* There is a hardware errata related to accessing any register in
> >          * SB01BASE in the presence of bidirectional traffic crossing the NTB.
> >          */
> > -       ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > +               ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> > +               break;
> > +       }
> >
> > +       switch (pdev->device) {
> >         /* HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
> >          * mirrored to the remote system.  Shrink the number of bits by one,
> >          * since bit 14 is the last bit.
> >          */
> > -       ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > +               ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> > +               break;
> > +       }
> >
> >         ndev->reg = &snb_reg;
> >
> > -       pdev = ndev_pdev(ndev);
> > -
> >         rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd);
> >         if (rc)
> >                 return -EIO;
> > @@ -2062,14 +2076,14 @@ static const struct intel_ntb_xlat_reg snb_pri_xlat = {
> >          * window by setting the limit equal to base, nor can it limit the size
> >          * of the memory window by setting the limit to base + size.
> >          */
> > -       .bar2_limit             = SNB_PBAR2LMT_OFFSET,
> > -       .bar2_xlat              = SNB_PBAR2XLAT_OFFSET,
> > +       .bar2_limit             = SNB_PBAR23LMT_OFFSET,
> > +       .bar2_xlat              = SNB_PBAR23XLAT_OFFSET,
> >  };
> >
> >  static const struct intel_ntb_xlat_reg snb_sec_xlat = {
> >         .bar0_base              = SNB_SBAR0BASE_OFFSET,
> > -       .bar2_limit             = SNB_SBAR2LMT_OFFSET,
> > -       .bar2_xlat              = SNB_SBAR2XLAT_OFFSET,
> > +       .bar2_limit             = SNB_SBAR23LMT_OFFSET,
> > +       .bar2_xlat              = SNB_SBAR23XLAT_OFFSET,
> >  };
> >
> >  static const struct intel_b2b_addr snb_b2b_usd_addr = {
> > diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
> > index 0224b1a..fec689d 100644
> > --- a/drivers/ntb/hw/intel/ntb_hw_intel.h
> > +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
> > @@ -70,11 +70,27 @@
> >
> >  /* SNB hardware (and JSF, IVT, HSX) */
> >
> > -#define SNB_PBAR2LMT_OFFSET            0x0000
> > -#define SNB_PBAR2XLAT_OFFSET           0x0010
> > -#define SNB_SBAR2LMT_OFFSET            0x0020
> > -#define SNB_SBAR2XLAT_OFFSET           0x0030
> > +#define SNB_PBAR23LMT_OFFSET           0x0000
> > +#define SNB_PBAR45LMT_OFFSET           0x0008
> > +#define SNB_PBAR4LMT_OFFSET            0x0008
> > +#define SNB_PBAR5LMT_OFFSET            0x000c
> > +#define SNB_PBAR23XLAT_OFFSET          0x0010
> > +#define SNB_PBAR45XLAT_OFFSET          0x0018
> > +#define SNB_PBAR4XLAT_OFFSET           0x0018
> > +#define SNB_PBAR5XLAT_OFFSET           0x001c
> > +#define SNB_SBAR23LMT_OFFSET           0x0020
> > +#define SNB_SBAR45LMT_OFFSET           0x0028
> > +#define SNB_SBAR4LMT_OFFSET            0x0028
> > +#define SNB_SBAR5LMT_OFFSET            0x002c
> > +#define SNB_SBAR23XLAT_OFFSET          0x0030
> > +#define SNB_SBAR45XLAT_OFFSET          0x0038
> > +#define SNB_SBAR4XLAT_OFFSET           0x0038
> > +#define SNB_SBAR5XLAT_OFFSET           0x003c
> >  #define SNB_SBAR0BASE_OFFSET           0x0040
> > +#define SNB_SBAR23BASE_OFFSET          0x0048
> > +#define SNB_SBAR45BASE_OFFSET          0x0050
> > +#define SNB_SBAR4BASE_OFFSET           0x0050
> > +#define SNB_SBAR5BASE_OFFSET           0x0054
> >  #define SNB_SBDF_OFFSET                        0x005c
> >  #define SNB_NTBCNTL_OFFSET             0x0058
> >  #define SNB_PDOORBELL_OFFSET           0x0060
> > diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> > index f1ed1b7..bb2eb85 100644
> > --- a/drivers/ntb/ntb_transport.c
> > +++ b/drivers/ntb/ntb_transport.c
> > @@ -204,8 +204,8 @@ struct ntb_transport_ctx {
> >
> >         bool link_is_up;
> >         struct delayed_work link_work;
> > -       struct work_struct db_work;
> >         struct work_struct link_cleanup;
> > +       struct tasklet_struct db_work;
> >  };
> >
> >  enum {
> > @@ -241,7 +241,7 @@ enum {
> >  #define NTB_QP_DEF_NUM_ENTRIES 100
> >  #define NTB_LINK_DOWN_TIMEOUT  10
> >
> > -static void ntb_transport_doorbell_work(struct work_struct *ws);
> > +static void ntb_transport_doorbell_work(unsigned long data);
> >  static const struct ntb_ctx_ops ntb_transport_ops;
> >  static struct ntb_client ntb_transport_client;
> >
> > @@ -1002,8 +1002,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
> >         }
> >
> >         INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
> > -       INIT_WORK(&nt->db_work, ntb_transport_doorbell_work);
> >         INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work);
> > +       tasklet_init(&nt->db_work, ntb_transport_doorbell_work,
> > +                    (unsigned long)nt);
> >
> >         rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops);
> >         if (rc)
> > @@ -1044,7 +1045,7 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev)
> >         int i;
> >
> >         ntb_transport_link_cleanup(nt);
> > -       cancel_work_sync(&nt->db_work);
> > +       tasklet_disable(&nt->db_work);
> >         cancel_work_sync(&nt->link_cleanup);
> >         cancel_delayed_work_sync(&nt->link_work);
> >
> > @@ -1850,10 +1851,9 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
> >  }
> >  EXPORT_SYMBOL_GPL(ntb_transport_max_size);
> >
> > -static void ntb_transport_doorbell_work(struct work_struct *work)
> > +static void ntb_transport_doorbell_work(unsigned long data)
> >  {
> > -       struct ntb_transport_ctx *nt = container_of(work,
> > -                       struct ntb_transport_ctx, db_work);
> > +       struct ntb_transport_ctx *nt = (void *)data;
> >         struct ntb_transport_qp *qp;
> >         u64 db_mask, db_bits, db_again;
> >         unsigned int qp_num;
> > @@ -1890,7 +1890,7 @@ static void ntb_transport_doorbell_callback(void *data, int vector)
> >
> >         ntb_db_set_mask(nt->ndev, ntb_db_valid_mask(nt->ndev));
> >
> > -       schedule_work(&nt->db_work);
> > +       tasklet_schedule(&nt->db_work);
> >  }
> >
> >  static const struct ntb_ctx_ops ntb_transport_ops = {
> > --
> > 2.4.0.rc0.43.gcf8a8c6
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
  2015-05-20 15:41 ` [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe Allen Hubbe
@ 2015-05-20 21:21   ` Bjorn Helgaas
  2015-05-20 21:46       ` Hubbe, Allen
  0 siblings, 1 reply; 40+ messages in thread
From: Bjorn Helgaas @ 2015-05-20 21:21 UTC (permalink / raw)
  To: Allen Hubbe; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

Please run "git log --oneline drivers/ntb" and make your subject lines
consistent.  The convention I use in PCI (and what was used in NTB
until recently) is

  - Acronyms and initialisms are capitalized
  - Subject line is a subsystem prefix ("PCI:", "NTB:", etc.) followed
by a complete sentence starting with a capitalized verb, with no
period at the end

On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com> wrote:
> From: Dave Jiang <dave.jiang@intel.com>
>
> Link training for RP should be enabled in the driver probe. We should
> not have to wait for transport loaded for this to hapen. Otherwise the

s/hapen/happen/

> device will not show up on the transparent bridge side.
>
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  drivers/ntb/hw/intel/ntb_hw_intel.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
> index 05c4b77..d162f22 100644
> --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> @@ -1333,6 +1333,9 @@ static int snb_poll_link(struct intel_ntb_dev *ndev)
>
>  static int snb_link_is_up(struct intel_ntb_dev *ndev)
>  {
> +       if (ndev->ntb.topo == NTB_TOPO_SEC)
> +               return 1;
> +
>         return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
>  }
>
> @@ -1642,6 +1645,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev,
>  static int snb_init_ntb(struct intel_ntb_dev *ndev)
>  {
>         int rc;
> +       u32 ntb_ctl;
>
>         if (ndev->bar4_split)
>                 ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
> @@ -1658,6 +1662,12 @@ static int snb_init_ntb(struct intel_ntb_dev *ndev)
>                         dev_err(ndev_dev(ndev), "NTB Primary config disabled\n");
>                         return -EINVAL;
>                 }
> +
> +               /* enable link to allow secondary side device to appear */
> +               ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
> +               ntb_ctl &= ~NTB_CTL_DISABLE;
> +               iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
> +
>                 /* use half the spads for the peer */
>                 ndev->spad_count >>= 1;
>                 ndev->self_reg = &snb_pri_reg;
> --
> 2.4.0.rc0.43.gcf8a8c6
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 04/16] Check the DID for certain workaround error flags to be set.
  2015-05-20 21:15       ` Jiang, Dave
  (?)
@ 2015-05-20 21:26         ` Hubbe, Allen
  -1 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-20 21:26 UTC (permalink / raw)
  To: Jiang, Dave, bhelgaas; +Cc: linux-kernel, linux-pci, jdmason, linux-ntb

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4539 bytes --]

From: linux-ntb@googlegroups.com [mailto:linux-ntb@googlegroups.com] On Behalf Of Jiang, Dave
> On Wed, 2015-05-20 at 16:11 -0500, Bjorn Helgaas wrote:
> > On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com>
> wrote:
> > > From: Dave Jiang <dave.jiang@intel.com>
> > >
> > > Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> >
> > Needs a topic in the subject line and a changelog.
> >
> > It also seems to do a lot more than just checking device ID (I assume
> > that's what "DID" means), so this should probably be split into
> > several patches that each do one thing.  I see at least:
> >
> >   - cosmetic code restructuring
> >   - work_struct/tasklet_struct changes
> >   - new #defines and bar2_off() changes
> 
> I think this patch got mangled with couple other patches. Allen?

Yes, there will be a v2 to fix the mangling.  The code restructuring is meant for a different patch.

This is all that is meant to change in this patch:

> > > @@ -1747,29 +1722,68 @@ static int snb_init_dev(struct intel_ntb_dev
> *ndev)
> > >         u8 ppd;
> > >         int rc, mem;
> > >
> > > +       pdev = ndev_pdev(ndev);
> > > +
> > > +       switch (pdev->device) {
> > >         /* 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
> > >          * window to access the interrupt and scratch pad registers
> on the
> > >          * remote system.
> > >          */
> > > -       ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > > +               ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> > > +               break;
> > > +       }
> > >
> > > +       switch (pdev->device) {
> > >         /* There is a hardware errata related to accessing any
> register in
> > >          * SB01BASE in the presence of bidirectional traffic
> crossing the NTB.
> > >          */
> > > -       ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > > +               ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> > > +               break;
> > > +       }
> > >
> > > +       switch (pdev->device) {
> > >         /* HW Errata on bit 14 of b2bdoorbell register.  Writes will
> not be
> > >          * mirrored to the remote system.  Shrink the number of bits
> by one,
> > >          * since bit 14 is the last bit.
> > >          */
> > > -       ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > > +               ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> > > +               break;
> > > +       }
> > >
> > >         ndev->reg = &snb_reg;
> > >
> > > -       pdev = ndev_pdev(ndev);
> > > -
> > >         rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd);
> > >         if (rc)
> > >                 return -EIO;
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 04/16] Check the DID for certain workaround error flags to be set.
@ 2015-05-20 21:26         ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-20 21:26 UTC (permalink / raw)
  To: Jiang, Dave, bhelgaas; +Cc: linux-kernel, linux-pci, jdmason, linux-ntb

RnJvbTogbGludXgtbnRiQGdvb2dsZWdyb3Vwcy5jb20gW21haWx0bzpsaW51eC1udGJAZ29vZ2xl
Z3JvdXBzLmNvbV0gT24gQmVoYWxmIE9mIEppYW5nLCBEYXZlDQo+IE9uIFdlZCwgMjAxNS0wNS0y
MCBhdCAxNjoxMSAtMDUwMCwgQmpvcm4gSGVsZ2FhcyB3cm90ZToNCj4gPiBPbiBXZWQsIE1heSAy
MCwgMjAxNSBhdCAxMDo0MSBBTSwgQWxsZW4gSHViYmUgPEFsbGVuLkh1YmJlQGVtYy5jb20+DQo+
IHdyb3RlOg0KPiA+ID4gRnJvbTogRGF2ZSBKaWFuZyA8ZGF2ZS5qaWFuZ0BpbnRlbC5jb20+DQo+
ID4gPg0KPiA+ID4gU2lnbmVkLW9mZi1ieTogRGF2ZSBKaWFuZyA8ZGF2ZS5qaWFuZ0BpbnRlbC5j
b20+DQo+ID4NCj4gPiBOZWVkcyBhIHRvcGljIGluIHRoZSBzdWJqZWN0IGxpbmUgYW5kIGEgY2hh
bmdlbG9nLg0KPiA+DQo+ID4gSXQgYWxzbyBzZWVtcyB0byBkbyBhIGxvdCBtb3JlIHRoYW4ganVz
dCBjaGVja2luZyBkZXZpY2UgSUQgKEkgYXNzdW1lDQo+ID4gdGhhdCdzIHdoYXQgIkRJRCIgbWVh
bnMpLCBzbyB0aGlzIHNob3VsZCBwcm9iYWJseSBiZSBzcGxpdCBpbnRvDQo+ID4gc2V2ZXJhbCBw
YXRjaGVzIHRoYXQgZWFjaCBkbyBvbmUgdGhpbmcuICBJIHNlZSBhdCBsZWFzdDoNCj4gPg0KPiA+
ICAgLSBjb3NtZXRpYyBjb2RlIHJlc3RydWN0dXJpbmcNCj4gPiAgIC0gd29ya19zdHJ1Y3QvdGFz
a2xldF9zdHJ1Y3QgY2hhbmdlcw0KPiA+ICAgLSBuZXcgI2RlZmluZXMgYW5kIGJhcjJfb2ZmKCkg
Y2hhbmdlcw0KPiANCj4gSSB0aGluayB0aGlzIHBhdGNoIGdvdCBtYW5nbGVkIHdpdGggY291cGxl
IG90aGVyIHBhdGNoZXMuIEFsbGVuPw0KDQpZZXMsIHRoZXJlIHdpbGwgYmUgYSB2MiB0byBmaXgg
dGhlIG1hbmdsaW5nLiAgVGhlIGNvZGUgcmVzdHJ1Y3R1cmluZyBpcyBtZWFudCBmb3IgYSBkaWZm
ZXJlbnQgcGF0Y2guDQoNClRoaXMgaXMgYWxsIHRoYXQgaXMgbWVhbnQgdG8gY2hhbmdlIGluIHRo
aXMgcGF0Y2g6DQoNCj4gPiA+IEBAIC0xNzQ3LDI5ICsxNzIyLDY4IEBAIHN0YXRpYyBpbnQgc25i
X2luaXRfZGV2KHN0cnVjdCBpbnRlbF9udGJfZGV2DQo+ICpuZGV2KQ0KPiA+ID4gICAgICAgICB1
OCBwcGQ7DQo+ID4gPiAgICAgICAgIGludCByYywgbWVtOw0KPiA+ID4NCj4gPiA+ICsgICAgICAg
cGRldiA9IG5kZXZfcGRldihuZGV2KTsNCj4gPiA+ICsNCj4gPiA+ICsgICAgICAgc3dpdGNoIChw
ZGV2LT5kZXZpY2UpIHsNCj4gPiA+ICAgICAgICAgLyogVGhlcmUgaXMgYSBYZW9uIGhhcmR3YXJl
IGVycmF0YSByZWxhdGVkIHRvIHdyaXRlcyB0bw0KPiBTRE9PUkJFTEwgb3INCj4gPiA+ICAgICAg
ICAgICogQjJCRE9PUkJFTEwgaW4gY29uanVuY3Rpb24gd2l0aCBpbmJvdW5kIGFjY2VzcyB0byBO
VEINCj4gTU1JTyBTcGFjZSwNCj4gPiA+ICAgICAgICAgICogd2hpY2ggbWF5IGhhbmcgdGhlIHN5
c3RlbS4gIFRvIHdvcmthcm91bmQgdGhpcyB1c2UgdGhlDQo+IHNlY29uZCBtZW1vcnkNCj4gPiA+
ICAgICAgICAgICogd2luZG93IHRvIGFjY2VzcyB0aGUgaW50ZXJydXB0IGFuZCBzY3JhdGNoIHBh
ZCByZWdpc3RlcnMNCj4gb24gdGhlDQo+ID4gPiAgICAgICAgICAqIHJlbW90ZSBzeXN0ZW0uDQo+
ID4gPiAgICAgICAgICAqLw0KPiA+ID4gLSAgICAgICBuZGV2LT5od2Vycl9mbGFncyB8PSBOVEJf
SFdFUlJfU0RPT1JCRUxMX0xPQ0tVUDsNCj4gPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lE
X0lOVEVMX05UQl9TU19KU0Y6DQo+ID4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRF
TF9OVEJfUFNfSlNGOg0KPiA+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRC
X0IyQl9KU0Y6DQo+ID4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJfU1Nf
U05COg0KPiA+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX1BTX1NOQjoN
Cj4gPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9CMkJfU05COg0KPiA+
ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX1NTX0lWVDoNCj4gPiA+ICsg
ICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9QU19JVlQ6DQo+ID4gPiArICAgICAg
IGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJfQjJCX0lWVDoNCj4gPiA+ICsgICAgICAgY2Fz
ZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9TU19IU1g6DQo+ID4gPiArICAgICAgIGNhc2UgUENJ
X0RFVklDRV9JRF9JTlRFTF9OVEJfUFNfSFNYOg0KPiA+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJ
Q0VfSURfSU5URUxfTlRCX0IyQl9IU1g6DQo+ID4gPiArICAgICAgICAgICAgICAgbmRldi0+aHdl
cnJfZmxhZ3MgfD0gTlRCX0hXRVJSX1NET09SQkVMTF9MT0NLVVA7DQo+ID4gPiArICAgICAgICAg
ICAgICAgYnJlYWs7DQo+ID4gPiArICAgICAgIH0NCj4gPiA+DQo+ID4gPiArICAgICAgIHN3aXRj
aCAocGRldi0+ZGV2aWNlKSB7DQo+ID4gPiAgICAgICAgIC8qIFRoZXJlIGlzIGEgaGFyZHdhcmUg
ZXJyYXRhIHJlbGF0ZWQgdG8gYWNjZXNzaW5nIGFueQ0KPiByZWdpc3RlciBpbg0KPiA+ID4gICAg
ICAgICAgKiBTQjAxQkFTRSBpbiB0aGUgcHJlc2VuY2Ugb2YgYmlkaXJlY3Rpb25hbCB0cmFmZmlj
DQo+IGNyb3NzaW5nIHRoZSBOVEIuDQo+ID4gPiAgICAgICAgICAqLw0KPiA+ID4gLSAgICAgICBu
ZGV2LT5od2Vycl9mbGFncyB8PSBOVEJfSFdFUlJfU0IwMUJBU0VfTE9DS1VQOw0KPiA+ID4gKyAg
ICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX1NTX0lWVDoNCj4gPiA+ICsgICAgICAg
Y2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9QU19JVlQ6DQo+ID4gPiArICAgICAgIGNhc2Ug
UENJX0RFVklDRV9JRF9JTlRFTF9OVEJfQjJCX0lWVDoNCj4gPiA+ICsgICAgICAgY2FzZSBQQ0lf
REVWSUNFX0lEX0lOVEVMX05UQl9TU19IU1g6DQo+ID4gPiArICAgICAgIGNhc2UgUENJX0RFVklD
RV9JRF9JTlRFTF9OVEJfUFNfSFNYOg0KPiA+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURf
SU5URUxfTlRCX0IyQl9IU1g6DQo+ID4gPiArICAgICAgICAgICAgICAgbmRldi0+aHdlcnJfZmxh
Z3MgfD0gTlRCX0hXRVJSX1NCMDFCQVNFX0xPQ0tVUDsNCj4gPiA+ICsgICAgICAgICAgICAgICBi
cmVhazsNCj4gPiA+ICsgICAgICAgfQ0KPiA+ID4NCj4gPiA+ICsgICAgICAgc3dpdGNoIChwZGV2
LT5kZXZpY2UpIHsNCj4gPiA+ICAgICAgICAgLyogSFcgRXJyYXRhIG9uIGJpdCAxNCBvZiBiMmJk
b29yYmVsbCByZWdpc3Rlci4gIFdyaXRlcyB3aWxsDQo+IG5vdCBiZQ0KPiA+ID4gICAgICAgICAg
KiBtaXJyb3JlZCB0byB0aGUgcmVtb3RlIHN5c3RlbS4gIFNocmluayB0aGUgbnVtYmVyIG9mIGJp
dHMNCj4gYnkgb25lLA0KPiA+ID4gICAgICAgICAgKiBzaW5jZSBiaXQgMTQgaXMgdGhlIGxhc3Qg
Yml0Lg0KPiA+ID4gICAgICAgICAgKi8NCj4gPiA+IC0gICAgICAgbmRldi0+aHdlcnJfZmxhZ3Mg
fD0gTlRCX0hXRVJSX0IyQkRPT1JCRUxMX0JJVDE0Ow0KPiA+ID4gKyAgICAgICBjYXNlIFBDSV9E
RVZJQ0VfSURfSU5URUxfTlRCX1NTX0pTRjoNCj4gPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNF
X0lEX0lOVEVMX05UQl9QU19KU0Y6DQo+ID4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9J
TlRFTF9OVEJfQjJCX0pTRjoNCj4gPiA+ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVM
X05UQl9TU19TTkI6DQo+ID4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJf
UFNfU05COg0KPiA+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX0IyQl9T
TkI6DQo+ID4gPiArICAgICAgIGNhc2UgUENJX0RFVklDRV9JRF9JTlRFTF9OVEJfU1NfSVZUOg0K
PiA+ID4gKyAgICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX1BTX0lWVDoNCj4gPiA+
ICsgICAgICAgY2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9CMkJfSVZUOg0KPiA+ID4gKyAg
ICAgICBjYXNlIFBDSV9ERVZJQ0VfSURfSU5URUxfTlRCX1NTX0hTWDoNCj4gPiA+ICsgICAgICAg
Y2FzZSBQQ0lfREVWSUNFX0lEX0lOVEVMX05UQl9QU19IU1g6DQo+ID4gPiArICAgICAgIGNhc2Ug
UENJX0RFVklDRV9JRF9JTlRFTF9OVEJfQjJCX0hTWDoNCj4gPiA+ICsgICAgICAgICAgICAgICBu
ZGV2LT5od2Vycl9mbGFncyB8PSBOVEJfSFdFUlJfQjJCRE9PUkJFTExfQklUMTQ7DQo+ID4gPiAr
ICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gPiArICAgICAgIH0NCj4gPiA+DQo+ID4gPiAgICAg
ICAgIG5kZXYtPnJlZyA9ICZzbmJfcmVnOw0KPiA+ID4NCj4gPiA+IC0gICAgICAgcGRldiA9IG5k
ZXZfcGRldihuZGV2KTsNCj4gPiA+IC0NCj4gPiA+ICAgICAgICAgcmMgPSBwY2lfcmVhZF9jb25m
aWdfYnl0ZShwZGV2LCBTTkJfUFBEX09GRlNFVCwgJnBwZCk7DQo+ID4gPiAgICAgICAgIGlmIChy
YykNCj4gPiA+ICAgICAgICAgICAgICAgICByZXR1cm4gLUVJTzsNCg==

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 04/16] Check the DID for certain workaround error flags to be set.
@ 2015-05-20 21:26         ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-20 21:26 UTC (permalink / raw)
  To: Jiang, Dave, bhelgaas; +Cc: linux-kernel, linux-pci, jdmason, linux-ntb

From: linux-ntb@googlegroups.com [mailto:linux-ntb@googlegroups.com] On Behalf Of Jiang, Dave
> On Wed, 2015-05-20 at 16:11 -0500, Bjorn Helgaas wrote:
> > On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com>
> wrote:
> > > From: Dave Jiang <dave.jiang@intel.com>
> > >
> > > Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> >
> > Needs a topic in the subject line and a changelog.
> >
> > It also seems to do a lot more than just checking device ID (I assume
> > that's what "DID" means), so this should probably be split into
> > several patches that each do one thing.  I see at least:
> >
> >   - cosmetic code restructuring
> >   - work_struct/tasklet_struct changes
> >   - new #defines and bar2_off() changes
> 
> I think this patch got mangled with couple other patches. Allen?

Yes, there will be a v2 to fix the mangling.  The code restructuring is meant for a different patch.

This is all that is meant to change in this patch:

> > > @@ -1747,29 +1722,68 @@ static int snb_init_dev(struct intel_ntb_dev
> *ndev)
> > >         u8 ppd;
> > >         int rc, mem;
> > >
> > > +       pdev = ndev_pdev(ndev);
> > > +
> > > +       switch (pdev->device) {
> > >         /* 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
> > >          * window to access the interrupt and scratch pad registers
> on the
> > >          * remote system.
> > >          */
> > > -       ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > > +               ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
> > > +               break;
> > > +       }
> > >
> > > +       switch (pdev->device) {
> > >         /* There is a hardware errata related to accessing any
> register in
> > >          * SB01BASE in the presence of bidirectional traffic
> crossing the NTB.
> > >          */
> > > -       ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > > +               ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
> > > +               break;
> > > +       }
> > >
> > > +       switch (pdev->device) {
> > >         /* HW Errata on bit 14 of b2bdoorbell register.  Writes will
> not be
> > >          * mirrored to the remote system.  Shrink the number of bits
> by one,
> > >          * since bit 14 is the last bit.
> > >          */
> > > -       ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> > > +       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> > > +               ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
> > > +               break;
> > > +       }
> > >
> > >         ndev->reg = &snb_reg;
> > >
> > > -       pdev = ndev_pdev(ndev);
> > > -
> > >         rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd);
> > >         if (rc)
> > >                 return -EIO;

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
  2015-05-20 21:21   ` Bjorn Helgaas
  2015-05-20 21:46       ` Hubbe, Allen
@ 2015-05-20 21:46       ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-20 21:46 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3597 bytes --]

From: Bjorn Helgaas [mailto:bhelgaas@google.com]
> Please run "git log --oneline drivers/ntb" and make your subject lines
> consistent.  The convention I use in PCI (and what was used in NTB
> until recently) is
> 
>   - Acronyms and initialisms are capitalized
>   - Subject line is a subsystem prefix ("PCI:", "NTB:", etc.) followed
> by a complete sentence starting with a capitalized verb, with no
> period at the end

These are the new subject lines that will be in the v2 of this set.

NTB: Fix small code format issues in transport
NTB: Default to CPU memcpy for performance
NTB: Improve performance with write combining
NTB: Use NUMA aware memory allocation
NTB: Use NUMA memory and DMA chan in transport
NTB: Reset transport QP link stats on down
NTB: Do not advance transport RX on link down
NTB: Differentiate transport link down messages
NTB: Rate limit ntb_qp_link_work
NTB: Add tool client
NTB: Add ping pong client
NTB: Intel NTB params for SNB B2B addresses
NTB: Check the DID for workaround error flags
NTB: Enable link training for RP mode in probe
NTB: Add NTB hardware abstraction layer
NTB: Move files in preparation for NTB abstraction

> 
> On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com>
> wrote:
> > From: Dave Jiang <dave.jiang@intel.com>
> >
> > Link training for RP should be enabled in the driver probe. We should
> > not have to wait for transport loaded for this to hapen. Otherwise the
> 
> s/hapen/happen/
> 
> > device will not show up on the transparent bridge side.
> >
> > Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> > ---
> >  drivers/ntb/hw/intel/ntb_hw_intel.c | 10 ++++++++++
> >  1 file changed, 10 insertions(+)
> >
> > diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c
> b/drivers/ntb/hw/intel/ntb_hw_intel.c
> > index 05c4b77..d162f22 100644
> > --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> > +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> > @@ -1333,6 +1333,9 @@ static int snb_poll_link(struct intel_ntb_dev
> *ndev)
> >
> >  static int snb_link_is_up(struct intel_ntb_dev *ndev)
> >  {
> > +       if (ndev->ntb.topo == NTB_TOPO_SEC)
> > +               return 1;
> > +
> >         return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
> >  }
> >
> > @@ -1642,6 +1645,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev
> *ndev,
> >  static int snb_init_ntb(struct intel_ntb_dev *ndev)
> >  {
> >         int rc;
> > +       u32 ntb_ctl;
> >
> >         if (ndev->bar4_split)
> >                 ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
> > @@ -1658,6 +1662,12 @@ static int snb_init_ntb(struct intel_ntb_dev
> *ndev)
> >                         dev_err(ndev_dev(ndev), "NTB Primary config
> disabled\n");
> >                         return -EINVAL;
> >                 }
> > +
> > +               /* enable link to allow secondary side device to
> appear */
> > +               ntb_ctl = ioread32(ndev->self_mmio + ndev->reg-
> >ntb_ctl);
> > +               ntb_ctl &= ~NTB_CTL_DISABLE;
> > +               iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg-
> >ntb_ctl);
> > +
> >                 /* use half the spads for the peer */
> >                 ndev->spad_count >>= 1;
> >                 ndev->self_reg = &snb_pri_reg;
> > --
> > 2.4.0.rc0.43.gcf8a8c6
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pci"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
@ 2015-05-20 21:46       ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-20 21:46 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

RnJvbTogQmpvcm4gSGVsZ2FhcyBbbWFpbHRvOmJoZWxnYWFzQGdvb2dsZS5jb21dDQo+IFBsZWFz
ZSBydW4gImdpdCBsb2cgLS1vbmVsaW5lIGRyaXZlcnMvbnRiIiBhbmQgbWFrZSB5b3VyIHN1Ympl
Y3QgbGluZXMNCj4gY29uc2lzdGVudC4gIFRoZSBjb252ZW50aW9uIEkgdXNlIGluIFBDSSAoYW5k
IHdoYXQgd2FzIHVzZWQgaW4gTlRCDQo+IHVudGlsIHJlY2VudGx5KSBpcw0KPiANCj4gICAtIEFj
cm9ueW1zIGFuZCBpbml0aWFsaXNtcyBhcmUgY2FwaXRhbGl6ZWQNCj4gICAtIFN1YmplY3QgbGlu
ZSBpcyBhIHN1YnN5c3RlbSBwcmVmaXggKCJQQ0k6IiwgIk5UQjoiLCBldGMuKSBmb2xsb3dlZA0K
PiBieSBhIGNvbXBsZXRlIHNlbnRlbmNlIHN0YXJ0aW5nIHdpdGggYSBjYXBpdGFsaXplZCB2ZXJi
LCB3aXRoIG5vDQo+IHBlcmlvZCBhdCB0aGUgZW5kDQoNClRoZXNlIGFyZSB0aGUgbmV3IHN1Ympl
Y3QgbGluZXMgdGhhdCB3aWxsIGJlIGluIHRoZSB2MiBvZiB0aGlzIHNldC4NCg0KTlRCOiBGaXgg
c21hbGwgY29kZSBmb3JtYXQgaXNzdWVzIGluIHRyYW5zcG9ydA0KTlRCOiBEZWZhdWx0IHRvIENQ
VSBtZW1jcHkgZm9yIHBlcmZvcm1hbmNlDQpOVEI6IEltcHJvdmUgcGVyZm9ybWFuY2Ugd2l0aCB3
cml0ZSBjb21iaW5pbmcNCk5UQjogVXNlIE5VTUEgYXdhcmUgbWVtb3J5IGFsbG9jYXRpb24NCk5U
QjogVXNlIE5VTUEgbWVtb3J5IGFuZCBETUEgY2hhbiBpbiB0cmFuc3BvcnQNCk5UQjogUmVzZXQg
dHJhbnNwb3J0IFFQIGxpbmsgc3RhdHMgb24gZG93bg0KTlRCOiBEbyBub3QgYWR2YW5jZSB0cmFu
c3BvcnQgUlggb24gbGluayBkb3duDQpOVEI6IERpZmZlcmVudGlhdGUgdHJhbnNwb3J0IGxpbmsg
ZG93biBtZXNzYWdlcw0KTlRCOiBSYXRlIGxpbWl0IG50Yl9xcF9saW5rX3dvcmsNCk5UQjogQWRk
IHRvb2wgY2xpZW50DQpOVEI6IEFkZCBwaW5nIHBvbmcgY2xpZW50DQpOVEI6IEludGVsIE5UQiBw
YXJhbXMgZm9yIFNOQiBCMkIgYWRkcmVzc2VzDQpOVEI6IENoZWNrIHRoZSBESUQgZm9yIHdvcmth
cm91bmQgZXJyb3IgZmxhZ3MNCk5UQjogRW5hYmxlIGxpbmsgdHJhaW5pbmcgZm9yIFJQIG1vZGUg
aW4gcHJvYmUNCk5UQjogQWRkIE5UQiBoYXJkd2FyZSBhYnN0cmFjdGlvbiBsYXllcg0KTlRCOiBN
b3ZlIGZpbGVzIGluIHByZXBhcmF0aW9uIGZvciBOVEIgYWJzdHJhY3Rpb24NCg0KPiANCj4gT24g
V2VkLCBNYXkgMjAsIDIwMTUgYXQgMTA6NDEgQU0sIEFsbGVuIEh1YmJlIDxBbGxlbi5IdWJiZUBl
bWMuY29tPg0KPiB3cm90ZToNCj4gPiBGcm9tOiBEYXZlIEppYW5nIDxkYXZlLmppYW5nQGludGVs
LmNvbT4NCj4gPg0KPiA+IExpbmsgdHJhaW5pbmcgZm9yIFJQIHNob3VsZCBiZSBlbmFibGVkIGlu
IHRoZSBkcml2ZXIgcHJvYmUuIFdlIHNob3VsZA0KPiA+IG5vdCBoYXZlIHRvIHdhaXQgZm9yIHRy
YW5zcG9ydCBsb2FkZWQgZm9yIHRoaXMgdG8gaGFwZW4uIE90aGVyd2lzZSB0aGUNCj4gDQo+IHMv
aGFwZW4vaGFwcGVuLw0KPiANCj4gPiBkZXZpY2Ugd2lsbCBub3Qgc2hvdyB1cCBvbiB0aGUgdHJh
bnNwYXJlbnQgYnJpZGdlIHNpZGUuDQo+ID4NCj4gPiBTaWduZWQtb2ZmLWJ5OiBEYXZlIEppYW5n
IDxkYXZlLmppYW5nQGludGVsLmNvbT4NCj4gPiAtLS0NCj4gPiAgZHJpdmVycy9udGIvaHcvaW50
ZWwvbnRiX2h3X2ludGVsLmMgfCAxMCArKysrKysrKysrDQo+ID4gIDEgZmlsZSBjaGFuZ2VkLCAx
MCBpbnNlcnRpb25zKCspDQo+ID4NCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9udGIvaHcvaW50
ZWwvbnRiX2h3X2ludGVsLmMNCj4gYi9kcml2ZXJzL250Yi9ody9pbnRlbC9udGJfaHdfaW50ZWwu
Yw0KPiA+IGluZGV4IDA1YzRiNzcuLmQxNjJmMjIgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9u
dGIvaHcvaW50ZWwvbnRiX2h3X2ludGVsLmMNCj4gPiArKysgYi9kcml2ZXJzL250Yi9ody9pbnRl
bC9udGJfaHdfaW50ZWwuYw0KPiA+IEBAIC0xMzMzLDYgKzEzMzMsOSBAQCBzdGF0aWMgaW50IHNu
Yl9wb2xsX2xpbmsoc3RydWN0IGludGVsX250Yl9kZXYNCj4gKm5kZXYpDQo+ID4NCj4gPiAgc3Rh
dGljIGludCBzbmJfbGlua19pc191cChzdHJ1Y3QgaW50ZWxfbnRiX2RldiAqbmRldikNCj4gPiAg
ew0KPiA+ICsgICAgICAgaWYgKG5kZXYtPm50Yi50b3BvID09IE5UQl9UT1BPX1NFQykNCj4gPiAr
ICAgICAgICAgICAgICAgcmV0dXJuIDE7DQo+ID4gKw0KPiA+ICAgICAgICAgcmV0dXJuIE5UQl9M
TktfU1RBX0FDVElWRShuZGV2LT5sbmtfc3RhKTsNCj4gPiAgfQ0KPiA+DQo+ID4gQEAgLTE2NDIs
NiArMTY0NSw3IEBAIHN0YXRpYyBpbnQgc25iX3NldHVwX2IyYl9tdyhzdHJ1Y3QgaW50ZWxfbnRi
X2Rldg0KPiAqbmRldiwNCj4gPiAgc3RhdGljIGludCBzbmJfaW5pdF9udGIoc3RydWN0IGludGVs
X250Yl9kZXYgKm5kZXYpDQo+ID4gIHsNCj4gPiAgICAgICAgIGludCByYzsNCj4gPiArICAgICAg
IHUzMiBudGJfY3RsOw0KPiA+DQo+ID4gICAgICAgICBpZiAobmRldi0+YmFyNF9zcGxpdCkNCj4g
PiAgICAgICAgICAgICAgICAgbmRldi0+bXdfY291bnQgPSBIU1hfU1BMSVRfQkFSX01XX0NPVU5U
Ow0KPiA+IEBAIC0xNjU4LDYgKzE2NjIsMTIgQEAgc3RhdGljIGludCBzbmJfaW5pdF9udGIoc3Ry
dWN0IGludGVsX250Yl9kZXYNCj4gKm5kZXYpDQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAg
ZGV2X2VycihuZGV2X2RldihuZGV2KSwgIk5UQiBQcmltYXJ5IGNvbmZpZw0KPiBkaXNhYmxlZFxu
Iik7DQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIC1FSU5WQUw7DQo+ID4gICAg
ICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIC8qIGVuYWJsZSBsaW5r
IHRvIGFsbG93IHNlY29uZGFyeSBzaWRlIGRldmljZSB0bw0KPiBhcHBlYXIgKi8NCj4gPiArICAg
ICAgICAgICAgICAgbnRiX2N0bCA9IGlvcmVhZDMyKG5kZXYtPnNlbGZfbW1pbyArIG5kZXYtPnJl
Zy0NCj4gPm50Yl9jdGwpOw0KPiA+ICsgICAgICAgICAgICAgICBudGJfY3RsICY9IH5OVEJfQ1RM
X0RJU0FCTEU7DQo+ID4gKyAgICAgICAgICAgICAgIGlvd3JpdGUzMihudGJfY3RsLCBuZGV2LT5z
ZWxmX21taW8gKyBuZGV2LT5yZWctDQo+ID5udGJfY3RsKTsNCj4gPiArDQo+ID4gICAgICAgICAg
ICAgICAgIC8qIHVzZSBoYWxmIHRoZSBzcGFkcyBmb3IgdGhlIHBlZXIgKi8NCj4gPiAgICAgICAg
ICAgICAgICAgbmRldi0+c3BhZF9jb3VudCA+Pj0gMTsNCj4gPiAgICAgICAgICAgICAgICAgbmRl
di0+c2VsZl9yZWcgPSAmc25iX3ByaV9yZWc7DQo+ID4gLS0NCj4gPiAyLjQuMC5yYzAuNDMuZ2Nm
OGE4YzYNCj4gPg0KPiA+IC0tDQo+ID4gVG8gdW5zdWJzY3JpYmUgZnJvbSB0aGlzIGxpc3Q6IHNl
bmQgdGhlIGxpbmUgInVuc3Vic2NyaWJlIGxpbnV4LXBjaSINCj4gaW4NCj4gPiB0aGUgYm9keSBv
ZiBhIG1lc3NhZ2UgdG8gbWFqb3Jkb21vQHZnZXIua2VybmVsLm9yZw0KPiA+IE1vcmUgbWFqb3Jk
b21vIGluZm8gYXQgIGh0dHA6Ly92Z2VyLmtlcm5lbC5vcmcvbWFqb3Jkb21vLWluZm8uaHRtbA0K

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
@ 2015-05-20 21:46       ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-20 21:46 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

From: Bjorn Helgaas [mailto:bhelgaas@google.com]
> Please run "git log --oneline drivers/ntb" and make your subject lines
> consistent.  The convention I use in PCI (and what was used in NTB
> until recently) is
> 
>   - Acronyms and initialisms are capitalized
>   - Subject line is a subsystem prefix ("PCI:", "NTB:", etc.) followed
> by a complete sentence starting with a capitalized verb, with no
> period at the end

These are the new subject lines that will be in the v2 of this set.

NTB: Fix small code format issues in transport
NTB: Default to CPU memcpy for performance
NTB: Improve performance with write combining
NTB: Use NUMA aware memory allocation
NTB: Use NUMA memory and DMA chan in transport
NTB: Reset transport QP link stats on down
NTB: Do not advance transport RX on link down
NTB: Differentiate transport link down messages
NTB: Rate limit ntb_qp_link_work
NTB: Add tool client
NTB: Add ping pong client
NTB: Intel NTB params for SNB B2B addresses
NTB: Check the DID for workaround error flags
NTB: Enable link training for RP mode in probe
NTB: Add NTB hardware abstraction layer
NTB: Move files in preparation for NTB abstraction

> 
> On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com>
> wrote:
> > From: Dave Jiang <dave.jiang@intel.com>
> >
> > Link training for RP should be enabled in the driver probe. We should
> > not have to wait for transport loaded for this to hapen. Otherwise the
> 
> s/hapen/happen/
> 
> > device will not show up on the transparent bridge side.
> >
> > Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> > ---
> >  drivers/ntb/hw/intel/ntb_hw_intel.c | 10 ++++++++++
> >  1 file changed, 10 insertions(+)
> >
> > diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c
> b/drivers/ntb/hw/intel/ntb_hw_intel.c
> > index 05c4b77..d162f22 100644
> > --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> > +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> > @@ -1333,6 +1333,9 @@ static int snb_poll_link(struct intel_ntb_dev
> *ndev)
> >
> >  static int snb_link_is_up(struct intel_ntb_dev *ndev)
> >  {
> > +       if (ndev->ntb.topo == NTB_TOPO_SEC)
> > +               return 1;
> > +
> >         return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
> >  }
> >
> > @@ -1642,6 +1645,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev
> *ndev,
> >  static int snb_init_ntb(struct intel_ntb_dev *ndev)
> >  {
> >         int rc;
> > +       u32 ntb_ctl;
> >
> >         if (ndev->bar4_split)
> >                 ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
> > @@ -1658,6 +1662,12 @@ static int snb_init_ntb(struct intel_ntb_dev
> *ndev)
> >                         dev_err(ndev_dev(ndev), "NTB Primary config
> disabled\n");
> >                         return -EINVAL;
> >                 }
> > +
> > +               /* enable link to allow secondary side device to
> appear */
> > +               ntb_ctl = ioread32(ndev->self_mmio + ndev->reg-
> >ntb_ctl);
> > +               ntb_ctl &= ~NTB_CTL_DISABLE;
> > +               iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg-
> >ntb_ctl);
> > +
> >                 /* use half the spads for the peer */
> >                 ndev->spad_count >>= 1;
> >                 ndev->self_reg = &snb_pri_reg;
> > --
> > 2.4.0.rc0.43.gcf8a8c6
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pci"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
  2015-05-20 21:46       ` Hubbe, Allen
  (?)
  (?)
@ 2015-05-20 22:20       ` Bjorn Helgaas
  2015-05-20 23:00           ` Hubbe, Allen
  -1 siblings, 1 reply; 40+ messages in thread
From: Bjorn Helgaas @ 2015-05-20 22:20 UTC (permalink / raw)
  To: Hubbe, Allen; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

On Wed, May 20, 2015 at 4:46 PM, Hubbe, Allen <Allen.Hubbe@emc.com> wrote:
> From: Bjorn Helgaas [mailto:bhelgaas@google.com]
>> Please run "git log --oneline drivers/ntb" and make your subject lines
>> consistent.  The convention I use in PCI (and what was used in NTB
>> until recently) is
>>
>>   - Acronyms and initialisms are capitalized
>>   - Subject line is a subsystem prefix ("PCI:", "NTB:", etc.) followed
>> by a complete sentence starting with a capitalized verb, with no
>> period at the end
>
> These are the new subject lines that will be in the v2 of this set.

That helps a lot, thanks.

> NTB: Fix small code format issues in transport
> NTB: Default to CPU memcpy for performance
> NTB: Improve performance with write combining
> NTB: Use NUMA aware memory allocation
> NTB: Use NUMA memory and DMA chan in transport
> NTB: Reset transport QP link stats on down
> NTB: Do not advance transport RX on link down
> NTB: Differentiate transport link down messages
> NTB: Rate limit ntb_qp_link_work
> NTB: Add tool client
> NTB: Add ping pong client

I think these are test cases, not part of the kernel itself.  It'd be
nice to know that from the summary.  I don't know what the precedent
is for that (if there is one).

> NTB: Intel NTB params for SNB B2B addresses

This sentence no verb :)  Not sure what you're doing with those params.

> NTB: Check the DID for workaround error flags

I think there's room to spell out "device ID".

> NTB: Enable link training for RP mode in probe

Is that Root Port?

> NTB: Add NTB hardware abstraction layer
> NTB: Move files in preparation for NTB abstraction

Of course, none of this has anything to do with the patches
themselves, which I don't intend to review because they're out of my
area :)

>>
>> On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com>
>> wrote:
>> > From: Dave Jiang <dave.jiang@intel.com>
>> >
>> > Link training for RP should be enabled in the driver probe. We should
>> > not have to wait for transport loaded for this to hapen. Otherwise the
>>
>> s/hapen/happen/
>>
>> > device will not show up on the transparent bridge side.
>> >
>> > Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>> > ---
>> >  drivers/ntb/hw/intel/ntb_hw_intel.c | 10 ++++++++++
>> >  1 file changed, 10 insertions(+)
>> >
>> > diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c
>> b/drivers/ntb/hw/intel/ntb_hw_intel.c
>> > index 05c4b77..d162f22 100644
>> > --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
>> > +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
>> > @@ -1333,6 +1333,9 @@ static int snb_poll_link(struct intel_ntb_dev
>> *ndev)
>> >
>> >  static int snb_link_is_up(struct intel_ntb_dev *ndev)
>> >  {
>> > +       if (ndev->ntb.topo == NTB_TOPO_SEC)
>> > +               return 1;
>> > +
>> >         return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
>> >  }
>> >
>> > @@ -1642,6 +1645,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev
>> *ndev,
>> >  static int snb_init_ntb(struct intel_ntb_dev *ndev)
>> >  {
>> >         int rc;
>> > +       u32 ntb_ctl;
>> >
>> >         if (ndev->bar4_split)
>> >                 ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
>> > @@ -1658,6 +1662,12 @@ static int snb_init_ntb(struct intel_ntb_dev
>> *ndev)
>> >                         dev_err(ndev_dev(ndev), "NTB Primary config
>> disabled\n");
>> >                         return -EINVAL;
>> >                 }
>> > +
>> > +               /* enable link to allow secondary side device to
>> appear */
>> > +               ntb_ctl = ioread32(ndev->self_mmio + ndev->reg-
>> >ntb_ctl);
>> > +               ntb_ctl &= ~NTB_CTL_DISABLE;
>> > +               iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg-
>> >ntb_ctl);
>> > +
>> >                 /* use half the spads for the peer */
>> >                 ndev->spad_count >>= 1;
>> >                 ndev->self_reg = &snb_pri_reg;
>> > --
>> > 2.4.0.rc0.43.gcf8a8c6
>> >
>> > --
>> > To unsubscribe from this list: send the line "unsubscribe linux-pci"
>> in
>> > the body of a message to majordomo@vger.kernel.org
>> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
  2015-05-20 22:20       ` Bjorn Helgaas
@ 2015-05-20 23:00           ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-20 23:00 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 5472 bytes --]

From: Bjorn Helgaas [mailto:bhelgaas@google.com]
> On Wed, May 20, 2015 at 4:46 PM, Hubbe, Allen <Allen.Hubbe@emc.com>
> wrote:
> > From: Bjorn Helgaas [mailto:bhelgaas@google.com]
> >> Please run "git log --oneline drivers/ntb" and make your subject
> lines
> >> consistent.  The convention I use in PCI (and what was used in NTB
> >> until recently) is
> >>
> >>   - Acronyms and initialisms are capitalized
> >>   - Subject line is a subsystem prefix ("PCI:", "NTB:", etc.)
> followed
> >> by a complete sentence starting with a capitalized verb, with no
> >> period at the end
> >
> > These are the new subject lines that will be in the v2 of this set.
> 
> That helps a lot, thanks.
> 
> > NTB: Fix small code format issues in transport
> > NTB: Default to CPU memcpy for performance
> > NTB: Improve performance with write combining
> > NTB: Use NUMA aware memory allocation
> > NTB: Use NUMA memory and DMA chan in transport
> > NTB: Reset transport QP link stats on down
> > NTB: Do not advance transport RX on link down
> > NTB: Differentiate transport link down messages
> > NTB: Rate limit ntb_qp_link_work
> > NTB: Add tool client
> > NTB: Add ping pong client
> 
> I think these are test cases, not part of the kernel itself.  It'd be
> nice to know that from the summary.  I don't know what the precedent
> is for that (if there is one).

Would you consider this as precedent:

4a776f0 dmatest: Simple DMA memcpy test client

> 
> > NTB: Intel NTB params for SNB B2B addresses
> 
> This sentence no verb :)  Not sure what you're doing with those params.

NTB: Add parameters for Intel SNB B2B addresses

> 
> > NTB: Check the DID for workaround error flags
> 
> I think there's room to spell out "device ID".

NTB: Check the device ID to set errata flags

Also, add this prose description to this commit:

Set errata flags for the specific device IDs to which they apply,
instead of the whole xeon hardware class.

> 
> > NTB: Enable link training for RP mode in probe
> 
> Is that Root Port?

yes

> 
> > NTB: Add NTB hardware abstraction layer
> > NTB: Move files in preparation for NTB abstraction
> 
> Of course, none of this has anything to do with the patches
> themselves, which I don't intend to review because they're out of my
> area :)
> 

I appreciate your comments :)

> >>
> >> On Wed, May 20, 2015 at 10:41 AM, Allen Hubbe <Allen.Hubbe@emc.com>
> >> wrote:
> >> > From: Dave Jiang <dave.jiang@intel.com>
> >> >
> >> > Link training for RP should be enabled in the driver probe. We
> should
> >> > not have to wait for transport loaded for this to hapen. Otherwise
> the
> >>
> >> s/hapen/happen/
> >>
> >> > device will not show up on the transparent bridge side.
> >> >
> >> > Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> >> > ---
> >> >  drivers/ntb/hw/intel/ntb_hw_intel.c | 10 ++++++++++
> >> >  1 file changed, 10 insertions(+)
> >> >
> >> > diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c
> >> b/drivers/ntb/hw/intel/ntb_hw_intel.c
> >> > index 05c4b77..d162f22 100644
> >> > --- a/drivers/ntb/hw/intel/ntb_hw_intel.c
> >> > +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c
> >> > @@ -1333,6 +1333,9 @@ static int snb_poll_link(struct intel_ntb_dev
> >> *ndev)
> >> >
> >> >  static int snb_link_is_up(struct intel_ntb_dev *ndev)
> >> >  {
> >> > +       if (ndev->ntb.topo == NTB_TOPO_SEC)
> >> > +               return 1;
> >> > +
> >> >         return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
> >> >  }
> >> >
> >> > @@ -1642,6 +1645,7 @@ static int snb_setup_b2b_mw(struct
> intel_ntb_dev
> >> *ndev,
> >> >  static int snb_init_ntb(struct intel_ntb_dev *ndev)
> >> >  {
> >> >         int rc;
> >> > +       u32 ntb_ctl;
> >> >
> >> >         if (ndev->bar4_split)
> >> >                 ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
> >> > @@ -1658,6 +1662,12 @@ static int snb_init_ntb(struct intel_ntb_dev
> >> *ndev)
> >> >                         dev_err(ndev_dev(ndev), "NTB Primary config
> >> disabled\n");
> >> >                         return -EINVAL;
> >> >                 }
> >> > +
> >> > +               /* enable link to allow secondary side device to
> >> appear */
> >> > +               ntb_ctl = ioread32(ndev->self_mmio + ndev->reg-
> >> >ntb_ctl);
> >> > +               ntb_ctl &= ~NTB_CTL_DISABLE;
> >> > +               iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg-
> >> >ntb_ctl);
> >> > +
> >> >                 /* use half the spads for the peer */
> >> >                 ndev->spad_count >>= 1;
> >> >                 ndev->self_reg = &snb_pri_reg;
> >> > --
> >> > 2.4.0.rc0.43.gcf8a8c6
> >> >
> >> > --
> >> > To unsubscribe from this list: send the line "unsubscribe linux-
> pci"
> >> in
> >> > the body of a message to majordomo@vger.kernel.org
> >> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> --
> You received this message because you are subscribed to the Google
> Groups "linux-ntb" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to linux-ntb+unsubscribe@googlegroups.com.
> To post to this group, send email to linux-ntb@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/linux-
> ntb/CAErSpo5WzQ86t5F2pfhHYipcUH3h2vv1DN1-
> Dpx_VPsOnbpu%3Dw%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
@ 2015-05-20 23:00           ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-20 23:00 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang

RnJvbTogQmpvcm4gSGVsZ2FhcyBbbWFpbHRvOmJoZWxnYWFzQGdvb2dsZS5jb21dDQo+IE9uIFdl
ZCwgTWF5IDIwLCAyMDE1IGF0IDQ6NDYgUE0sIEh1YmJlLCBBbGxlbiA8QWxsZW4uSHViYmVAZW1j
LmNvbT4NCj4gd3JvdGU6DQo+ID4gRnJvbTogQmpvcm4gSGVsZ2FhcyBbbWFpbHRvOmJoZWxnYWFz
QGdvb2dsZS5jb21dDQo+ID4+IFBsZWFzZSBydW4gImdpdCBsb2cgLS1vbmVsaW5lIGRyaXZlcnMv
bnRiIiBhbmQgbWFrZSB5b3VyIHN1YmplY3QNCj4gbGluZXMNCj4gPj4gY29uc2lzdGVudC4gIFRo
ZSBjb252ZW50aW9uIEkgdXNlIGluIFBDSSAoYW5kIHdoYXQgd2FzIHVzZWQgaW4gTlRCDQo+ID4+
IHVudGlsIHJlY2VudGx5KSBpcw0KPiA+Pg0KPiA+PiAgIC0gQWNyb255bXMgYW5kIGluaXRpYWxp
c21zIGFyZSBjYXBpdGFsaXplZA0KPiA+PiAgIC0gU3ViamVjdCBsaW5lIGlzIGEgc3Vic3lzdGVt
IHByZWZpeCAoIlBDSToiLCAiTlRCOiIsIGV0Yy4pDQo+IGZvbGxvd2VkDQo+ID4+IGJ5IGEgY29t
cGxldGUgc2VudGVuY2Ugc3RhcnRpbmcgd2l0aCBhIGNhcGl0YWxpemVkIHZlcmIsIHdpdGggbm8N
Cj4gPj4gcGVyaW9kIGF0IHRoZSBlbmQNCj4gPg0KPiA+IFRoZXNlIGFyZSB0aGUgbmV3IHN1Ympl
Y3QgbGluZXMgdGhhdCB3aWxsIGJlIGluIHRoZSB2MiBvZiB0aGlzIHNldC4NCj4gDQo+IFRoYXQg
aGVscHMgYSBsb3QsIHRoYW5rcy4NCj4gDQo+ID4gTlRCOiBGaXggc21hbGwgY29kZSBmb3JtYXQg
aXNzdWVzIGluIHRyYW5zcG9ydA0KPiA+IE5UQjogRGVmYXVsdCB0byBDUFUgbWVtY3B5IGZvciBw
ZXJmb3JtYW5jZQ0KPiA+IE5UQjogSW1wcm92ZSBwZXJmb3JtYW5jZSB3aXRoIHdyaXRlIGNvbWJp
bmluZw0KPiA+IE5UQjogVXNlIE5VTUEgYXdhcmUgbWVtb3J5IGFsbG9jYXRpb24NCj4gPiBOVEI6
IFVzZSBOVU1BIG1lbW9yeSBhbmQgRE1BIGNoYW4gaW4gdHJhbnNwb3J0DQo+ID4gTlRCOiBSZXNl
dCB0cmFuc3BvcnQgUVAgbGluayBzdGF0cyBvbiBkb3duDQo+ID4gTlRCOiBEbyBub3QgYWR2YW5j
ZSB0cmFuc3BvcnQgUlggb24gbGluayBkb3duDQo+ID4gTlRCOiBEaWZmZXJlbnRpYXRlIHRyYW5z
cG9ydCBsaW5rIGRvd24gbWVzc2FnZXMNCj4gPiBOVEI6IFJhdGUgbGltaXQgbnRiX3FwX2xpbmtf
d29yaw0KPiA+IE5UQjogQWRkIHRvb2wgY2xpZW50DQo+ID4gTlRCOiBBZGQgcGluZyBwb25nIGNs
aWVudA0KPiANCj4gSSB0aGluayB0aGVzZSBhcmUgdGVzdCBjYXNlcywgbm90IHBhcnQgb2YgdGhl
IGtlcm5lbCBpdHNlbGYuICBJdCdkIGJlDQo+IG5pY2UgdG8ga25vdyB0aGF0IGZyb20gdGhlIHN1
bW1hcnkuICBJIGRvbid0IGtub3cgd2hhdCB0aGUgcHJlY2VkZW50DQo+IGlzIGZvciB0aGF0IChp
ZiB0aGVyZSBpcyBvbmUpLg0KDQpXb3VsZCB5b3UgY29uc2lkZXIgdGhpcyBhcyBwcmVjZWRlbnQ6
DQoNCjRhNzc2ZjAgZG1hdGVzdDogU2ltcGxlIERNQSBtZW1jcHkgdGVzdCBjbGllbnQNCg0KPiAN
Cj4gPiBOVEI6IEludGVsIE5UQiBwYXJhbXMgZm9yIFNOQiBCMkIgYWRkcmVzc2VzDQo+IA0KPiBU
aGlzIHNlbnRlbmNlIG5vIHZlcmIgOikgIE5vdCBzdXJlIHdoYXQgeW91J3JlIGRvaW5nIHdpdGgg
dGhvc2UgcGFyYW1zLg0KDQpOVEI6IEFkZCBwYXJhbWV0ZXJzIGZvciBJbnRlbCBTTkIgQjJCIGFk
ZHJlc3Nlcw0KDQo+IA0KPiA+IE5UQjogQ2hlY2sgdGhlIERJRCBmb3Igd29ya2Fyb3VuZCBlcnJv
ciBmbGFncw0KPiANCj4gSSB0aGluayB0aGVyZSdzIHJvb20gdG8gc3BlbGwgb3V0ICJkZXZpY2Ug
SUQiLg0KDQpOVEI6IENoZWNrIHRoZSBkZXZpY2UgSUQgdG8gc2V0IGVycmF0YSBmbGFncw0KDQpB
bHNvLCBhZGQgdGhpcyBwcm9zZSBkZXNjcmlwdGlvbiB0byB0aGlzIGNvbW1pdDoNCg0KU2V0IGVy
cmF0YSBmbGFncyBmb3IgdGhlIHNwZWNpZmljIGRldmljZSBJRHMgdG8gd2hpY2ggdGhleSBhcHBs
eSwNCmluc3RlYWQgb2YgdGhlIHdob2xlIHhlb24gaGFyZHdhcmUgY2xhc3MuDQoNCj4gDQo+ID4g
TlRCOiBFbmFibGUgbGluayB0cmFpbmluZyBmb3IgUlAgbW9kZSBpbiBwcm9iZQ0KPiANCj4gSXMg
dGhhdCBSb290IFBvcnQ/DQoNCnllcw0KDQo+IA0KPiA+IE5UQjogQWRkIE5UQiBoYXJkd2FyZSBh
YnN0cmFjdGlvbiBsYXllcg0KPiA+IE5UQjogTW92ZSBmaWxlcyBpbiBwcmVwYXJhdGlvbiBmb3Ig
TlRCIGFic3RyYWN0aW9uDQo+IA0KPiBPZiBjb3Vyc2UsIG5vbmUgb2YgdGhpcyBoYXMgYW55dGhp
bmcgdG8gZG8gd2l0aCB0aGUgcGF0Y2hlcw0KPiB0aGVtc2VsdmVzLCB3aGljaCBJIGRvbid0IGlu
dGVuZCB0byByZXZpZXcgYmVjYXVzZSB0aGV5J3JlIG91dCBvZiBteQ0KPiBhcmVhIDopDQo+IA0K
DQpJIGFwcHJlY2lhdGUgeW91ciBjb21tZW50cyA6KQ0KDQo+ID4+DQo+ID4+IE9uIFdlZCwgTWF5
IDIwLCAyMDE1IGF0IDEwOjQxIEFNLCBBbGxlbiBIdWJiZSA8QWxsZW4uSHViYmVAZW1jLmNvbT4N
Cj4gPj4gd3JvdGU6DQo+ID4+ID4gRnJvbTogRGF2ZSBKaWFuZyA8ZGF2ZS5qaWFuZ0BpbnRlbC5j
b20+DQo+ID4+ID4NCj4gPj4gPiBMaW5rIHRyYWluaW5nIGZvciBSUCBzaG91bGQgYmUgZW5hYmxl
ZCBpbiB0aGUgZHJpdmVyIHByb2JlLiBXZQ0KPiBzaG91bGQNCj4gPj4gPiBub3QgaGF2ZSB0byB3
YWl0IGZvciB0cmFuc3BvcnQgbG9hZGVkIGZvciB0aGlzIHRvIGhhcGVuLiBPdGhlcndpc2UNCj4g
dGhlDQo+ID4+DQo+ID4+IHMvaGFwZW4vaGFwcGVuLw0KPiA+Pg0KPiA+PiA+IGRldmljZSB3aWxs
IG5vdCBzaG93IHVwIG9uIHRoZSB0cmFuc3BhcmVudCBicmlkZ2Ugc2lkZS4NCj4gPj4gPg0KPiA+
PiA+IFNpZ25lZC1vZmYtYnk6IERhdmUgSmlhbmcgPGRhdmUuamlhbmdAaW50ZWwuY29tPg0KPiA+
PiA+IC0tLQ0KPiA+PiA+ICBkcml2ZXJzL250Yi9ody9pbnRlbC9udGJfaHdfaW50ZWwuYyB8IDEw
ICsrKysrKysrKysNCj4gPj4gPiAgMSBmaWxlIGNoYW5nZWQsIDEwIGluc2VydGlvbnMoKykNCj4g
Pj4gPg0KPiA+PiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL250Yi9ody9pbnRlbC9udGJfaHdfaW50
ZWwuYw0KPiA+PiBiL2RyaXZlcnMvbnRiL2h3L2ludGVsL250Yl9od19pbnRlbC5jDQo+ID4+ID4g
aW5kZXggMDVjNGI3Ny4uZDE2MmYyMiAxMDA2NDQNCj4gPj4gPiAtLS0gYS9kcml2ZXJzL250Yi9o
dy9pbnRlbC9udGJfaHdfaW50ZWwuYw0KPiA+PiA+ICsrKyBiL2RyaXZlcnMvbnRiL2h3L2ludGVs
L250Yl9od19pbnRlbC5jDQo+ID4+ID4gQEAgLTEzMzMsNiArMTMzMyw5IEBAIHN0YXRpYyBpbnQg
c25iX3BvbGxfbGluayhzdHJ1Y3QgaW50ZWxfbnRiX2Rldg0KPiA+PiAqbmRldikNCj4gPj4gPg0K
PiA+PiA+ICBzdGF0aWMgaW50IHNuYl9saW5rX2lzX3VwKHN0cnVjdCBpbnRlbF9udGJfZGV2ICpu
ZGV2KQ0KPiA+PiA+ICB7DQo+ID4+ID4gKyAgICAgICBpZiAobmRldi0+bnRiLnRvcG8gPT0gTlRC
X1RPUE9fU0VDKQ0KPiA+PiA+ICsgICAgICAgICAgICAgICByZXR1cm4gMTsNCj4gPj4gPiArDQo+
ID4+ID4gICAgICAgICByZXR1cm4gTlRCX0xOS19TVEFfQUNUSVZFKG5kZXYtPmxua19zdGEpOw0K
PiA+PiA+ICB9DQo+ID4+ID4NCj4gPj4gPiBAQCAtMTY0Miw2ICsxNjQ1LDcgQEAgc3RhdGljIGlu
dCBzbmJfc2V0dXBfYjJiX213KHN0cnVjdA0KPiBpbnRlbF9udGJfZGV2DQo+ID4+ICpuZGV2LA0K
PiA+PiA+ICBzdGF0aWMgaW50IHNuYl9pbml0X250YihzdHJ1Y3QgaW50ZWxfbnRiX2RldiAqbmRl
dikNCj4gPj4gPiAgew0KPiA+PiA+ICAgICAgICAgaW50IHJjOw0KPiA+PiA+ICsgICAgICAgdTMy
IG50Yl9jdGw7DQo+ID4+ID4NCj4gPj4gPiAgICAgICAgIGlmIChuZGV2LT5iYXI0X3NwbGl0KQ0K
PiA+PiA+ICAgICAgICAgICAgICAgICBuZGV2LT5td19jb3VudCA9IEhTWF9TUExJVF9CQVJfTVdf
Q09VTlQ7DQo+ID4+ID4gQEAgLTE2NTgsNiArMTY2MiwxMiBAQCBzdGF0aWMgaW50IHNuYl9pbml0
X250YihzdHJ1Y3QgaW50ZWxfbnRiX2Rldg0KPiA+PiAqbmRldikNCj4gPj4gPiAgICAgICAgICAg
ICAgICAgICAgICAgICBkZXZfZXJyKG5kZXZfZGV2KG5kZXYpLCAiTlRCIFByaW1hcnkgY29uZmln
DQo+ID4+IGRpc2FibGVkXG4iKTsNCj4gPj4gPiAgICAgICAgICAgICAgICAgICAgICAgICByZXR1
cm4gLUVJTlZBTDsNCj4gPj4gPiAgICAgICAgICAgICAgICAgfQ0KPiA+PiA+ICsNCj4gPj4gPiAr
ICAgICAgICAgICAgICAgLyogZW5hYmxlIGxpbmsgdG8gYWxsb3cgc2Vjb25kYXJ5IHNpZGUgZGV2
aWNlIHRvDQo+ID4+IGFwcGVhciAqLw0KPiA+PiA+ICsgICAgICAgICAgICAgICBudGJfY3RsID0g
aW9yZWFkMzIobmRldi0+c2VsZl9tbWlvICsgbmRldi0+cmVnLQ0KPiA+PiA+bnRiX2N0bCk7DQo+
ID4+ID4gKyAgICAgICAgICAgICAgIG50Yl9jdGwgJj0gfk5UQl9DVExfRElTQUJMRTsNCj4gPj4g
PiArICAgICAgICAgICAgICAgaW93cml0ZTMyKG50Yl9jdGwsIG5kZXYtPnNlbGZfbW1pbyArIG5k
ZXYtPnJlZy0NCj4gPj4gPm50Yl9jdGwpOw0KPiA+PiA+ICsNCj4gPj4gPiAgICAgICAgICAgICAg
ICAgLyogdXNlIGhhbGYgdGhlIHNwYWRzIGZvciB0aGUgcGVlciAqLw0KPiA+PiA+ICAgICAgICAg
ICAgICAgICBuZGV2LT5zcGFkX2NvdW50ID4+PSAxOw0KPiA+PiA+ICAgICAgICAgICAgICAgICBu
ZGV2LT5zZWxmX3JlZyA9ICZzbmJfcHJpX3JlZzsNCj4gPj4gPiAtLQ0KPiA+PiA+IDIuNC4wLnJj
MC40My5nY2Y4YThjNg0KPiA+PiA+DQo+ID4+ID4gLS0NCj4gPj4gPiBUbyB1bnN1YnNjcmliZSBm
cm9tIHRoaXMgbGlzdDogc2VuZCB0aGUgbGluZSAidW5zdWJzY3JpYmUgbGludXgtDQo+IHBjaSIN
Cj4gPj4gaW4NCj4gPj4gPiB0aGUgYm9keSBvZiBhIG1lc3NhZ2UgdG8gbWFqb3Jkb21vQHZnZXIu
a2VybmVsLm9yZw0KPiA+PiA+IE1vcmUgbWFqb3Jkb21vIGluZm8gYXQgIGh0dHA6Ly92Z2VyLmtl
cm5lbC5vcmcvbWFqb3Jkb21vLWluZm8uaHRtbA0KPiANCj4gLS0NCj4gWW91IHJlY2VpdmVkIHRo
aXMgbWVzc2FnZSBiZWNhdXNlIHlvdSBhcmUgc3Vic2NyaWJlZCB0byB0aGUgR29vZ2xlDQo+IEdy
b3VwcyAibGludXgtbnRiIiBncm91cC4NCj4gVG8gdW5zdWJzY3JpYmUgZnJvbSB0aGlzIGdyb3Vw
IGFuZCBzdG9wIHJlY2VpdmluZyBlbWFpbHMgZnJvbSBpdCwgc2VuZA0KPiBhbiBlbWFpbCB0byBs
aW51eC1udGIrdW5zdWJzY3JpYmVAZ29vZ2xlZ3JvdXBzLmNvbS4NCj4gVG8gcG9zdCB0byB0aGlz
IGdyb3VwLCBzZW5kIGVtYWlsIHRvIGxpbnV4LW50YkBnb29nbGVncm91cHMuY29tLg0KPiBUbyB2
aWV3IHRoaXMgZGlzY3Vzc2lvbiBvbiB0aGUgd2ViIHZpc2l0DQo+IGh0dHBzOi8vZ3JvdXBzLmdv
b2dsZS5jb20vZC9tc2dpZC9saW51eC0NCj4gbnRiL0NBRXJTcG81V3pRODZ0NUYycGZoSFlpcGNV
SDNoMnZ2MUROMS0NCj4gRHB4X1ZQc09uYnB1JTNEdyU0MG1haWwuZ21haWwuY29tLg0KPiBGb3Ig
bW9yZSBvcHRpb25zLCB2aXNpdCBodHRwczovL2dyb3Vwcy5nb29nbGUuY29tL2Qvb3B0b3V0Lg0K

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 02/16] NTB Abstraction Layer
  2015-05-20 15:41 ` [PATCH 02/16] NTB Abstraction Layer Allen Hubbe
@ 2015-05-21  8:51   ` Paul Bolle
  2015-05-21 11:32       ` Hubbe, Allen
  0 siblings, 1 reply; 40+ messages in thread
From: Paul Bolle @ 2015-05-21  8:51 UTC (permalink / raw)
  To: Allen Hubbe; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

On Wed, 2015-05-20 at 11:41 -0400, Allen Hubbe wrote:
>  Documentation/ntb.txt               |   58 +
>  MAINTAINERS                         |   14 +-
>  drivers/net/ntb_netdev.c            |   58 +-
>  drivers/ntb/Kconfig                 |   20 +-
>  drivers/ntb/Makefile                |    4 +-
>  drivers/ntb/hw/Kconfig              |    1 +
>  drivers/ntb/hw/Makefile             |    1 +
>  drivers/ntb/hw/intel/Kconfig        |    8 +
>  drivers/ntb/hw/intel/Makefile       |    1 +
>  drivers/ntb/hw/intel/ntb_hw_intel.c | 3108 +++++++++++++++++++----------------
>  drivers/ntb/hw/intel/ntb_hw_intel.h |  591 +++----
>  drivers/ntb/ntb.c                   |  251 +++
>  drivers/ntb/ntb_transport.c         |  927 ++++++-----
>  include/linux/ntb.h                 |  983 +++++++++++
>  include/linux/ntb_transport.h       |   25 +-
>  15 files changed, 3873 insertions(+), 2177 deletions(-)
>  create mode 100644 Documentation/ntb.txt
>  create mode 100644 drivers/ntb/hw/Kconfig
>  create mode 100644 drivers/ntb/hw/Makefile
>  create mode 100644 drivers/ntb/hw/intel/Kconfig
>  create mode 100644 drivers/ntb/hw/intel/Makefile
>  create mode 100644 drivers/ntb/ntb.c
>  create mode 100644 include/linux/ntb.h

(My mailer tells me this message is over 200KB in size. Did you consider
offering bribes to get people to review this patch?)

I just spotted two nits.

> --- a/drivers/ntb/Kconfig
> +++ b/drivers/ntb/Kconfig
>  
> +if NTB
> +
> +source "drivers/ntb/hw/Kconfig"
> +
> +config NTB_TRANSPORT
> +       tristate "NTB Transport Client"
> +       depends on NTB

Superfluous dependency.

> +       help
> +        This is a transport driver that enables connected systems to exchange
> +        messages over the ntb hardware.  The transport exposes a queue pair api
> +        to client drivers.
> +
> +        If unsure, say N.
> +
> +endif # NTB

> --- /dev/null
> +++ b/drivers/ntb/hw/intel/Kconfig

> +config NTB_INTEL
> +       tristate "Intel Non-Transparent Bridge support"
> +       depends on NTB

Ditto.

> +       depends on X86
> +       help
> +        This driver supports Intel NTB on capable Xeon and Atom hardware.
> +
> +        If unsure, say N.

Thanks,


Paul Bolle


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 06/16] NTB Pingpong Client
  2015-05-20 15:41 ` [PATCH 06/16] NTB Pingpong Client Allen Hubbe
@ 2015-05-21  8:54   ` Paul Bolle
  0 siblings, 0 replies; 40+ messages in thread
From: Paul Bolle @ 2015-05-21  8:54 UTC (permalink / raw)
  To: Allen Hubbe; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

Similar nit as for 2/6.

On Wed, 2015-05-20 at 11:41 -0400, Allen Hubbe wrote:
> --- a/drivers/ntb/Kconfig
> +++ b/drivers/ntb/Kconfig
> @@ -14,6 +14,8 @@ if NTB
>  
>  source "drivers/ntb/hw/Kconfig"
>  
> +source "drivers/ntb/test/Kconfig"
> +
>  config NTB_TRANSPORT

> --- /dev/null
> +++ b/drivers/ntb/test/Kconfig

> +config NTB_PINGPONG
> +       tristate "NTB Simple Ping Pong Client"
> +       depends on NTB

Again, superfluous dependency.

> +       help
> +        This is a simple ping pong driver that exercises the scratchpads and
> +        doorbells of the ntb hardware.  This driver may be used to test that
> +        your ntb hardware and drivers are functioning at a basic level.
> +
> +        If unsure, say N.

Thanks,


Paul Bolle


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 07/16] NTB Tool Client
  2015-05-20 15:41 ` [PATCH 07/16] NTB Tool Client Allen Hubbe
@ 2015-05-21  9:02   ` Paul Bolle
  0 siblings, 0 replies; 40+ messages in thread
From: Paul Bolle @ 2015-05-21  9:02 UTC (permalink / raw)
  To: Allen Hubbe; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

On Wed, 2015-05-20 at 11:41 -0400, Allen Hubbe wrote:
> --- a/drivers/ntb/test/Kconfig
> +++ b/drivers/ntb/test/Kconfig
> +config NTB_TOOL
> +       tristate "NTB Debugging Tool Client"
> +       depends on NTB

Same nit as for 2/16 and 7/16.

> +       help

> +        If unsure, say N.

(Please start the indentation with a tab, and not with spaces.)

Thanks,


Paul Bolle


^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 02/16] NTB Abstraction Layer
  2015-05-21  8:51   ` Paul Bolle
  2015-05-21 11:32       ` Hubbe, Allen
@ 2015-05-21 11:32       ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-21 11:32 UTC (permalink / raw)
  To: Paul Bolle; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1829 bytes --]

From: Paul Bolle [mailto:pebolle@tiscali.nl]
> On Wed, 2015-05-20 at 11:41 -0400, Allen Hubbe wrote:


> 
> (My mailer tells me this message is over 200KB in size. Did you consider
> offering bribes to get people to review this patch?)

I would have liked to send smaller patches, too.

I attempted to split this one in three:
1) add the ntb core driver and header file
2) change ntb_hw_intel driver to use new api
3) change ntb_transport driver to use new api

The problem is, any change to the old ntb_hw_intel (was ntb.ko), or ntb_transport, alone will cause the other not to work.

> 
> I just spotted two nits.
> 
> > --- a/drivers/ntb/Kconfig
> > +++ b/drivers/ntb/Kconfig
> >
> > +if NTB
> > +
> > +source "drivers/ntb/hw/Kconfig"
> > +
> > +config NTB_TRANSPORT
> > +       tristate "NTB Transport Client"
> > +       depends on NTB
> 
> Superfluous dependency.

I will remove depends NTB from this, and other things within if NTB.

I will also change the leading spaces to tabs.

> 
> > +       help
> > +        This is a transport driver that enables connected systems to
> exchange
> > +        messages over the ntb hardware.  The transport exposes a
> queue pair api
> > +        to client drivers.
> > +
> > +        If unsure, say N.
> > +
> > +endif # NTB
> 
> > --- /dev/null
> > +++ b/drivers/ntb/hw/intel/Kconfig
> 
> > +config NTB_INTEL
> > +       tristate "Intel Non-Transparent Bridge support"
> > +       depends on NTB
> 
> Ditto.
> 
> > +       depends on X86
> > +       help
> > +        This driver supports Intel NTB on capable Xeon and Atom
> hardware.
> > +
> > +        If unsure, say N.
> 
> Thanks,
> 
> 
> Paul Bolle

Thanks,
Allen
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 02/16] NTB Abstraction Layer
@ 2015-05-21 11:32       ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-21 11:32 UTC (permalink / raw)
  To: Paul Bolle; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

RnJvbTogUGF1bCBCb2xsZSBbbWFpbHRvOnBlYm9sbGVAdGlzY2FsaS5ubF0NCj4gT24gV2VkLCAy
MDE1LTA1LTIwIGF0IDExOjQxIC0wNDAwLCBBbGxlbiBIdWJiZSB3cm90ZToNCg0KDQo+IA0KPiAo
TXkgbWFpbGVyIHRlbGxzIG1lIHRoaXMgbWVzc2FnZSBpcyBvdmVyIDIwMEtCIGluIHNpemUuIERp
ZCB5b3UgY29uc2lkZXINCj4gb2ZmZXJpbmcgYnJpYmVzIHRvIGdldCBwZW9wbGUgdG8gcmV2aWV3
IHRoaXMgcGF0Y2g/KQ0KDQpJIHdvdWxkIGhhdmUgbGlrZWQgdG8gc2VuZCBzbWFsbGVyIHBhdGNo
ZXMsIHRvby4NCg0KSSBhdHRlbXB0ZWQgdG8gc3BsaXQgdGhpcyBvbmUgaW4gdGhyZWU6DQoxKSBh
ZGQgdGhlIG50YiBjb3JlIGRyaXZlciBhbmQgaGVhZGVyIGZpbGUNCjIpIGNoYW5nZSBudGJfaHdf
aW50ZWwgZHJpdmVyIHRvIHVzZSBuZXcgYXBpDQozKSBjaGFuZ2UgbnRiX3RyYW5zcG9ydCBkcml2
ZXIgdG8gdXNlIG5ldyBhcGkNCg0KVGhlIHByb2JsZW0gaXMsIGFueSBjaGFuZ2UgdG8gdGhlIG9s
ZCBudGJfaHdfaW50ZWwgKHdhcyBudGIua28pLCBvciBudGJfdHJhbnNwb3J0LCBhbG9uZSB3aWxs
IGNhdXNlIHRoZSBvdGhlciBub3QgdG8gd29yay4NCg0KPiANCj4gSSBqdXN0IHNwb3R0ZWQgdHdv
IG5pdHMuDQo+IA0KPiA+IC0tLSBhL2RyaXZlcnMvbnRiL0tjb25maWcNCj4gPiArKysgYi9kcml2
ZXJzL250Yi9LY29uZmlnDQo+ID4NCj4gPiAraWYgTlRCDQo+ID4gKw0KPiA+ICtzb3VyY2UgImRy
aXZlcnMvbnRiL2h3L0tjb25maWciDQo+ID4gKw0KPiA+ICtjb25maWcgTlRCX1RSQU5TUE9SVA0K
PiA+ICsgICAgICAgdHJpc3RhdGUgIk5UQiBUcmFuc3BvcnQgQ2xpZW50Ig0KPiA+ICsgICAgICAg
ZGVwZW5kcyBvbiBOVEINCj4gDQo+IFN1cGVyZmx1b3VzIGRlcGVuZGVuY3kuDQoNCkkgd2lsbCBy
ZW1vdmUgZGVwZW5kcyBOVEIgZnJvbSB0aGlzLCBhbmQgb3RoZXIgdGhpbmdzIHdpdGhpbiBpZiBO
VEIuDQoNCkkgd2lsbCBhbHNvIGNoYW5nZSB0aGUgbGVhZGluZyBzcGFjZXMgdG8gdGFicy4NCg0K
PiANCj4gPiArICAgICAgIGhlbHANCj4gPiArICAgICAgICBUaGlzIGlzIGEgdHJhbnNwb3J0IGRy
aXZlciB0aGF0IGVuYWJsZXMgY29ubmVjdGVkIHN5c3RlbXMgdG8NCj4gZXhjaGFuZ2UNCj4gPiAr
ICAgICAgICBtZXNzYWdlcyBvdmVyIHRoZSBudGIgaGFyZHdhcmUuICBUaGUgdHJhbnNwb3J0IGV4
cG9zZXMgYQ0KPiBxdWV1ZSBwYWlyIGFwaQ0KPiA+ICsgICAgICAgIHRvIGNsaWVudCBkcml2ZXJz
Lg0KPiA+ICsNCj4gPiArICAgICAgICBJZiB1bnN1cmUsIHNheSBOLg0KPiA+ICsNCj4gPiArZW5k
aWYgIyBOVEINCj4gDQo+ID4gLS0tIC9kZXYvbnVsbA0KPiA+ICsrKyBiL2RyaXZlcnMvbnRiL2h3
L2ludGVsL0tjb25maWcNCj4gDQo+ID4gK2NvbmZpZyBOVEJfSU5URUwNCj4gPiArICAgICAgIHRy
aXN0YXRlICJJbnRlbCBOb24tVHJhbnNwYXJlbnQgQnJpZGdlIHN1cHBvcnQiDQo+ID4gKyAgICAg
ICBkZXBlbmRzIG9uIE5UQg0KPiANCj4gRGl0dG8uDQo+IA0KPiA+ICsgICAgICAgZGVwZW5kcyBv
biBYODYNCj4gPiArICAgICAgIGhlbHANCj4gPiArICAgICAgICBUaGlzIGRyaXZlciBzdXBwb3J0
cyBJbnRlbCBOVEIgb24gY2FwYWJsZSBYZW9uIGFuZCBBdG9tDQo+IGhhcmR3YXJlLg0KPiA+ICsN
Cj4gPiArICAgICAgICBJZiB1bnN1cmUsIHNheSBOLg0KPiANCj4gVGhhbmtzLA0KPiANCj4gDQo+
IFBhdWwgQm9sbGUNCg0KVGhhbmtzLA0KQWxsZW4NCg==

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 02/16] NTB Abstraction Layer
@ 2015-05-21 11:32       ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-21 11:32 UTC (permalink / raw)
  To: Paul Bolle; +Cc: linux-ntb, linux-kernel, linux-pci, Jon Mason, Dave Jiang

From: Paul Bolle [mailto:pebolle@tiscali.nl]
> On Wed, 2015-05-20 at 11:41 -0400, Allen Hubbe wrote:


> 
> (My mailer tells me this message is over 200KB in size. Did you consider
> offering bribes to get people to review this patch?)

I would have liked to send smaller patches, too.

I attempted to split this one in three:
1) add the ntb core driver and header file
2) change ntb_hw_intel driver to use new api
3) change ntb_transport driver to use new api

The problem is, any change to the old ntb_hw_intel (was ntb.ko), or ntb_transport, alone will cause the other not to work.

> 
> I just spotted two nits.
> 
> > --- a/drivers/ntb/Kconfig
> > +++ b/drivers/ntb/Kconfig
> >
> > +if NTB
> > +
> > +source "drivers/ntb/hw/Kconfig"
> > +
> > +config NTB_TRANSPORT
> > +       tristate "NTB Transport Client"
> > +       depends on NTB
> 
> Superfluous dependency.

I will remove depends NTB from this, and other things within if NTB.

I will also change the leading spaces to tabs.

> 
> > +       help
> > +        This is a transport driver that enables connected systems to
> exchange
> > +        messages over the ntb hardware.  The transport exposes a
> queue pair api
> > +        to client drivers.
> > +
> > +        If unsure, say N.
> > +
> > +endif # NTB
> 
> > --- /dev/null
> > +++ b/drivers/ntb/hw/intel/Kconfig
> 
> > +config NTB_INTEL
> > +       tristate "Intel Non-Transparent Bridge support"
> > +       depends on NTB
> 
> Ditto.
> 
> > +       depends on X86
> > +       help
> > +        This driver supports Intel NTB on capable Xeon and Atom
> hardware.
> > +
> > +        If unsure, say N.
> 
> Thanks,
> 
> 
> Paul Bolle

Thanks,
Allen

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
  2015-05-20 23:00           ` Hubbe, Allen
  (?)
@ 2015-05-21 12:06           ` Bjorn Helgaas
  2015-05-21 12:49               ` Hubbe, Allen
  -1 siblings, 1 reply; 40+ messages in thread
From: Bjorn Helgaas @ 2015-05-21 12:06 UTC (permalink / raw)
  To: Hubbe, Allen; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang

On Wed, May 20, 2015 at 6:00 PM, Hubbe, Allen <Allen.Hubbe@emc.com> wrote:
> From: Bjorn Helgaas [mailto:bhelgaas@google.com]
>> On Wed, May 20, 2015 at 4:46 PM, Hubbe, Allen <Allen.Hubbe@emc.com>
>> wrote:
>> > From: Bjorn Helgaas [mailto:bhelgaas@google.com]
>> >> Please run "git log --oneline drivers/ntb" and make your subject
>> lines
>> >> consistent.  The convention I use in PCI (and what was used in NTB
>> >> until recently) is
>> >>
>> >>   - Acronyms and initialisms are capitalized
>> >>   - Subject line is a subsystem prefix ("PCI:", "NTB:", etc.)
>> followed
>> >> by a complete sentence starting with a capitalized verb, with no
>> >> period at the end
>> >
>> > These are the new subject lines that will be in the v2 of this set.
>>
>> That helps a lot, thanks.
>>
>> > NTB: Fix small code format issues in transport
>> > NTB: Default to CPU memcpy for performance
>> > NTB: Improve performance with write combining
>> > NTB: Use NUMA aware memory allocation
>> > NTB: Use NUMA memory and DMA chan in transport
>> > NTB: Reset transport QP link stats on down
>> > NTB: Do not advance transport RX on link down
>> > NTB: Differentiate transport link down messages
>> > NTB: Rate limit ntb_qp_link_work
>> > NTB: Add tool client
>> > NTB: Add ping pong client
>>
>> I think these are test cases, not part of the kernel itself.  It'd be
>> nice to know that from the summary.  I don't know what the precedent
>> is for that (if there is one).
>
> Would you consider this as precedent:
>
> 4a776f0 dmatest: Simple DMA memcpy test client
>
>>
>> > NTB: Intel NTB params for SNB B2B addresses
>>
>> This sentence no verb :)  Not sure what you're doing with those params.
>
> NTB: Add parameters for Intel SNB B2B addresses
>
>>
>> > NTB: Check the DID for workaround error flags
>>
>> I think there's room to spell out "device ID".
>
> NTB: Check the device ID to set errata flags
>
> Also, add this prose description to this commit:
>
> Set errata flags for the specific device IDs to which they apply,
> instead of the whole xeon hardware class.
>
>>
>> > NTB: Enable link training for RP mode in probe
>>
>> Is that Root Port?
>
> yes
>
>>
>> > NTB: Add NTB hardware abstraction layer
>> > NTB: Move files in preparation for NTB abstraction

All looks good to me!

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
  2015-05-21 12:06           ` Bjorn Helgaas
@ 2015-05-21 12:49               ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-21 12:49 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2701 bytes --]

From: linux-pci-owner@vger.kernel.org [mailto:linux-pci-owner@vger.kernel.org] On Behalf Of Bjorn Helgaas
> On Wed, May 20, 2015 at 6:00 PM, Hubbe, Allen <Allen.Hubbe@emc.com>
> wrote:
> > From: Bjorn Helgaas [mailto:bhelgaas@google.com]
> >> On Wed, May 20, 2015 at 4:46 PM, Hubbe, Allen <Allen.Hubbe@emc.com>
> >> wrote:
> >> > From: Bjorn Helgaas [mailto:bhelgaas@google.com]
> >> >> Please run "git log --oneline drivers/ntb" and make your subject
> >> lines
> >> >> consistent.  The convention I use in PCI (and what was used in NTB
> >> >> until recently) is
> >> >>
> >> >>   - Acronyms and initialisms are capitalized
> >> >>   - Subject line is a subsystem prefix ("PCI:", "NTB:", etc.)
> >> followed
> >> >> by a complete sentence starting with a capitalized verb, with no
> >> >> period at the end
> >> >
> >> > These are the new subject lines that will be in the v2 of this set.
> >>
> >> That helps a lot, thanks.
> >>
> >> > NTB: Fix small code format issues in transport
> >> > NTB: Default to CPU memcpy for performance
> >> > NTB: Improve performance with write combining
> >> > NTB: Use NUMA aware memory allocation
> >> > NTB: Use NUMA memory and DMA chan in transport
> >> > NTB: Reset transport QP link stats on down
> >> > NTB: Do not advance transport RX on link down
> >> > NTB: Differentiate transport link down messages
> >> > NTB: Rate limit ntb_qp_link_work
> >> > NTB: Add tool client
> >> > NTB: Add ping pong client
> >>
> >> I think these are test cases, not part of the kernel itself.  It'd be
> >> nice to know that from the summary.  I don't know what the precedent
> >> is for that (if there is one).
> >
> > Would you consider this as precedent:
> >
> > 4a776f0 dmatest: Simple DMA memcpy test client
> >
> >>
> >> > NTB: Intel NTB params for SNB B2B addresses
> >>
> >> This sentence no verb :)  Not sure what you're doing with those
> params.
> >
> > NTB: Add parameters for Intel SNB B2B addresses
> >
> >>
> >> > NTB: Check the DID for workaround error flags
> >>
> >> I think there's room to spell out "device ID".
> >
> > NTB: Check the device ID to set errata flags
> >
> > Also, add this prose description to this commit:
> >
> > Set errata flags for the specific device IDs to which they apply,
> > instead of the whole xeon hardware class.
> >
> >>
> >> > NTB: Enable link training for RP mode in probe
> >>
> >> Is that Root Port?
> >
> > yes
> >
> >>
> >> > NTB: Add NTB hardware abstraction layer
> >> > NTB: Move files in preparation for NTB abstraction
> 
> All looks good to me!

Thanks!
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe
@ 2015-05-21 12:49               ` Hubbe, Allen
  0 siblings, 0 replies; 40+ messages in thread
From: Hubbe, Allen @ 2015-05-21 12:49 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-kernel, linux-pci, Jon Mason, Dave Jiang

RnJvbTogbGludXgtcGNpLW93bmVyQHZnZXIua2VybmVsLm9yZyBbbWFpbHRvOmxpbnV4LXBjaS1v
d25lckB2Z2VyLmtlcm5lbC5vcmddIE9uIEJlaGFsZiBPZiBCam9ybiBIZWxnYWFzDQo+IE9uIFdl
ZCwgTWF5IDIwLCAyMDE1IGF0IDY6MDAgUE0sIEh1YmJlLCBBbGxlbiA8QWxsZW4uSHViYmVAZW1j
LmNvbT4NCj4gd3JvdGU6DQo+ID4gRnJvbTogQmpvcm4gSGVsZ2FhcyBbbWFpbHRvOmJoZWxnYWFz
QGdvb2dsZS5jb21dDQo+ID4+IE9uIFdlZCwgTWF5IDIwLCAyMDE1IGF0IDQ6NDYgUE0sIEh1YmJl
LCBBbGxlbiA8QWxsZW4uSHViYmVAZW1jLmNvbT4NCj4gPj4gd3JvdGU6DQo+ID4+ID4gRnJvbTog
Qmpvcm4gSGVsZ2FhcyBbbWFpbHRvOmJoZWxnYWFzQGdvb2dsZS5jb21dDQo+ID4+ID4+IFBsZWFz
ZSBydW4gImdpdCBsb2cgLS1vbmVsaW5lIGRyaXZlcnMvbnRiIiBhbmQgbWFrZSB5b3VyIHN1Ympl
Y3QNCj4gPj4gbGluZXMNCj4gPj4gPj4gY29uc2lzdGVudC4gIFRoZSBjb252ZW50aW9uIEkgdXNl
IGluIFBDSSAoYW5kIHdoYXQgd2FzIHVzZWQgaW4gTlRCDQo+ID4+ID4+IHVudGlsIHJlY2VudGx5
KSBpcw0KPiA+PiA+Pg0KPiA+PiA+PiAgIC0gQWNyb255bXMgYW5kIGluaXRpYWxpc21zIGFyZSBj
YXBpdGFsaXplZA0KPiA+PiA+PiAgIC0gU3ViamVjdCBsaW5lIGlzIGEgc3Vic3lzdGVtIHByZWZp
eCAoIlBDSToiLCAiTlRCOiIsIGV0Yy4pDQo+ID4+IGZvbGxvd2VkDQo+ID4+ID4+IGJ5IGEgY29t
cGxldGUgc2VudGVuY2Ugc3RhcnRpbmcgd2l0aCBhIGNhcGl0YWxpemVkIHZlcmIsIHdpdGggbm8N
Cj4gPj4gPj4gcGVyaW9kIGF0IHRoZSBlbmQNCj4gPj4gPg0KPiA+PiA+IFRoZXNlIGFyZSB0aGUg
bmV3IHN1YmplY3QgbGluZXMgdGhhdCB3aWxsIGJlIGluIHRoZSB2MiBvZiB0aGlzIHNldC4NCj4g
Pj4NCj4gPj4gVGhhdCBoZWxwcyBhIGxvdCwgdGhhbmtzLg0KPiA+Pg0KPiA+PiA+IE5UQjogRml4
IHNtYWxsIGNvZGUgZm9ybWF0IGlzc3VlcyBpbiB0cmFuc3BvcnQNCj4gPj4gPiBOVEI6IERlZmF1
bHQgdG8gQ1BVIG1lbWNweSBmb3IgcGVyZm9ybWFuY2UNCj4gPj4gPiBOVEI6IEltcHJvdmUgcGVy
Zm9ybWFuY2Ugd2l0aCB3cml0ZSBjb21iaW5pbmcNCj4gPj4gPiBOVEI6IFVzZSBOVU1BIGF3YXJl
IG1lbW9yeSBhbGxvY2F0aW9uDQo+ID4+ID4gTlRCOiBVc2UgTlVNQSBtZW1vcnkgYW5kIERNQSBj
aGFuIGluIHRyYW5zcG9ydA0KPiA+PiA+IE5UQjogUmVzZXQgdHJhbnNwb3J0IFFQIGxpbmsgc3Rh
dHMgb24gZG93bg0KPiA+PiA+IE5UQjogRG8gbm90IGFkdmFuY2UgdHJhbnNwb3J0IFJYIG9uIGxp
bmsgZG93bg0KPiA+PiA+IE5UQjogRGlmZmVyZW50aWF0ZSB0cmFuc3BvcnQgbGluayBkb3duIG1l
c3NhZ2VzDQo+ID4+ID4gTlRCOiBSYXRlIGxpbWl0IG50Yl9xcF9saW5rX3dvcmsNCj4gPj4gPiBO
VEI6IEFkZCB0b29sIGNsaWVudA0KPiA+PiA+IE5UQjogQWRkIHBpbmcgcG9uZyBjbGllbnQNCj4g
Pj4NCj4gPj4gSSB0aGluayB0aGVzZSBhcmUgdGVzdCBjYXNlcywgbm90IHBhcnQgb2YgdGhlIGtl
cm5lbCBpdHNlbGYuICBJdCdkIGJlDQo+ID4+IG5pY2UgdG8ga25vdyB0aGF0IGZyb20gdGhlIHN1
bW1hcnkuICBJIGRvbid0IGtub3cgd2hhdCB0aGUgcHJlY2VkZW50DQo+ID4+IGlzIGZvciB0aGF0
IChpZiB0aGVyZSBpcyBvbmUpLg0KPiA+DQo+ID4gV291bGQgeW91IGNvbnNpZGVyIHRoaXMgYXMg
cHJlY2VkZW50Og0KPiA+DQo+ID4gNGE3NzZmMCBkbWF0ZXN0OiBTaW1wbGUgRE1BIG1lbWNweSB0
ZXN0IGNsaWVudA0KPiA+DQo+ID4+DQo+ID4+ID4gTlRCOiBJbnRlbCBOVEIgcGFyYW1zIGZvciBT
TkIgQjJCIGFkZHJlc3Nlcw0KPiA+Pg0KPiA+PiBUaGlzIHNlbnRlbmNlIG5vIHZlcmIgOikgIE5v
dCBzdXJlIHdoYXQgeW91J3JlIGRvaW5nIHdpdGggdGhvc2UNCj4gcGFyYW1zLg0KPiA+DQo+ID4g
TlRCOiBBZGQgcGFyYW1ldGVycyBmb3IgSW50ZWwgU05CIEIyQiBhZGRyZXNzZXMNCj4gPg0KPiA+
Pg0KPiA+PiA+IE5UQjogQ2hlY2sgdGhlIERJRCBmb3Igd29ya2Fyb3VuZCBlcnJvciBmbGFncw0K
PiA+Pg0KPiA+PiBJIHRoaW5rIHRoZXJlJ3Mgcm9vbSB0byBzcGVsbCBvdXQgImRldmljZSBJRCIu
DQo+ID4NCj4gPiBOVEI6IENoZWNrIHRoZSBkZXZpY2UgSUQgdG8gc2V0IGVycmF0YSBmbGFncw0K
PiA+DQo+ID4gQWxzbywgYWRkIHRoaXMgcHJvc2UgZGVzY3JpcHRpb24gdG8gdGhpcyBjb21taXQ6
DQo+ID4NCj4gPiBTZXQgZXJyYXRhIGZsYWdzIGZvciB0aGUgc3BlY2lmaWMgZGV2aWNlIElEcyB0
byB3aGljaCB0aGV5IGFwcGx5LA0KPiA+IGluc3RlYWQgb2YgdGhlIHdob2xlIHhlb24gaGFyZHdh
cmUgY2xhc3MuDQo+ID4NCj4gPj4NCj4gPj4gPiBOVEI6IEVuYWJsZSBsaW5rIHRyYWluaW5nIGZv
ciBSUCBtb2RlIGluIHByb2JlDQo+ID4+DQo+ID4+IElzIHRoYXQgUm9vdCBQb3J0Pw0KPiA+DQo+
ID4geWVzDQo+ID4NCj4gPj4NCj4gPj4gPiBOVEI6IEFkZCBOVEIgaGFyZHdhcmUgYWJzdHJhY3Rp
b24gbGF5ZXINCj4gPj4gPiBOVEI6IE1vdmUgZmlsZXMgaW4gcHJlcGFyYXRpb24gZm9yIE5UQiBh
YnN0cmFjdGlvbg0KPiANCj4gQWxsIGxvb2tzIGdvb2QgdG8gbWUhDQoNClRoYW5rcyENCg==

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2015-05-21 12:49 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-20 15:41 [PATCH 00/16] ntb: NTB Abstraction Layer Allen Hubbe
2015-05-20 15:41 ` [PATCH 01/16] Move files in preparation for NTB Abstraction Allen Hubbe
2015-05-20 15:41 ` [PATCH 02/16] NTB Abstraction Layer Allen Hubbe
2015-05-21  8:51   ` Paul Bolle
2015-05-21 11:32     ` Hubbe, Allen
2015-05-21 11:32       ` Hubbe, Allen
2015-05-21 11:32       ` Hubbe, Allen
2015-05-20 15:41 ` [PATCH 03/16] ntb: Enable link training for RP mode in the driver probe Allen Hubbe
2015-05-20 21:21   ` Bjorn Helgaas
2015-05-20 21:46     ` Hubbe, Allen
2015-05-20 21:46       ` Hubbe, Allen
2015-05-20 21:46       ` Hubbe, Allen
2015-05-20 22:20       ` Bjorn Helgaas
2015-05-20 23:00         ` Hubbe, Allen
2015-05-20 23:00           ` Hubbe, Allen
2015-05-21 12:06           ` Bjorn Helgaas
2015-05-21 12:49             ` Hubbe, Allen
2015-05-21 12:49               ` Hubbe, Allen
2015-05-20 15:41 ` [PATCH 04/16] Check the DID for certain workaround error flags to be set Allen Hubbe
2015-05-20 21:11   ` Bjorn Helgaas
2015-05-20 21:15     ` Jiang, Dave
2015-05-20 21:15       ` Jiang, Dave
2015-05-20 21:15       ` Jiang, Dave
2015-05-20 21:26       ` Hubbe, Allen
2015-05-20 21:26         ` Hubbe, Allen
2015-05-20 21:26         ` Hubbe, Allen
2015-05-20 15:41 ` [PATCH 05/16] Intel NTB params for snb b2b addresses Allen Hubbe
2015-05-20 15:41 ` [PATCH 06/16] NTB Pingpong Client Allen Hubbe
2015-05-21  8:54   ` Paul Bolle
2015-05-20 15:41 ` [PATCH 07/16] NTB Tool Client Allen Hubbe
2015-05-21  9:02   ` Paul Bolle
2015-05-20 15:41 ` [PATCH 08/16] ntb_transport: rate limit ntb_qp_link_work Allen Hubbe
2015-05-20 15:41 ` [PATCH 09/16] ntb_transport: differentiate link down messages Allen Hubbe
2015-05-20 15:41 ` [PATCH 10/16] ntb_transport: don't advance rx on link down Allen Hubbe
2015-05-20 15:41 ` [PATCH 11/16] ntb_transport: reset qp link stats on down Allen Hubbe
2015-05-20 15:41 ` [PATCH 12/16] ntb_transport: numa aware memory and dma chan Allen Hubbe
2015-05-20 15:41 ` [PATCH 13/16] ntb_hw_intel: numa aware memory allocation Allen Hubbe
2015-05-20 15:41 ` [PATCH 14/16] ntb: performance improvement by write combining Allen Hubbe
2015-05-20 15:41 ` [PATCH 15/16] ntb: default to cpu memcpy for performance Allen Hubbe
2015-05-20 15:41 ` [PATCH 16/16] ntb_transport: fix small code format issues Allen Hubbe

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.