svn commit: r300373 - in stable/10/sys: conf dev/ntb/if_ntb dev/ntb/ntb_hw

Alexander Motin mav at FreeBSD.org
Sat May 21 15:15:13 UTC 2016


Author: mav
Date: Sat May 21 15:15:11 2016
New Revision: 300373
URL: https://svnweb.freebsd.org/changeset/base/300373

Log:
  MFC 103 ntb(4) patches by cem@ up to r295487.

Modified:
  stable/10/sys/conf/files.i386
  stable/10/sys/dev/ntb/if_ntb/if_ntb.c
  stable/10/sys/dev/ntb/ntb_hw/ntb_hw.c
  stable/10/sys/dev/ntb/ntb_hw/ntb_hw.h
  stable/10/sys/dev/ntb/ntb_hw/ntb_regs.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/conf/files.i386
==============================================================================
--- stable/10/sys/conf/files.i386	Sat May 21 14:51:49 2016	(r300372)
+++ stable/10/sys/conf/files.i386	Sat May 21 15:15:11 2016	(r300373)
@@ -274,6 +274,8 @@ dev/lindev/lindev.c		optional lindev
 dev/mse/mse.c			optional mse
 dev/mse/mse_isa.c		optional mse isa
 dev/nfe/if_nfe.c		optional nfe pci
+dev/ntb/if_ntb/if_ntb.c		optional if_ntb
+dev/ntb/ntb_hw/ntb_hw.c		optional if_ntb | ntb_hw
 dev/nvd/nvd.c			optional nvd nvme
 dev/nve/if_nve.c		optional nve pci
 dev/nvme/nvme.c			optional nvme

Modified: stable/10/sys/dev/ntb/if_ntb/if_ntb.c
==============================================================================
--- stable/10/sys/dev/ntb/if_ntb/if_ntb.c	Sat May 21 14:51:49 2016	(r300372)
+++ stable/10/sys/dev/ntb/if_ntb/if_ntb.c	Sat May 21 15:15:11 2016	(r300373)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (C) 2013 Intel Corporation
+ * Copyright (C) 2015 EMC Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,8 +31,10 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
+#include <sys/bitset.h>
 #include <sys/bus.h>
 #include <sys/ktr.h>
+#include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
@@ -39,19 +42,26 @@ __FBSDID("$FreeBSD$");
 #include <sys/queue.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
+#include <sys/sysctl.h>
 #include <sys/taskqueue.h>
+
 #include <net/if.h>
 #include <net/if_media.h>
 #include <net/if_types.h>
 #include <net/if_var.h>
 #include <net/bpf.h>
 #include <net/ethernet.h>
+
 #include <vm/vm.h>
 #include <vm/pmap.h>
+
 #include <machine/bus.h>
 #include <machine/cpufunc.h>
 #include <machine/pmap.h>
 
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
 #include "../ntb_hw/ntb_hw.h"
 
 /*
@@ -65,72 +75,113 @@ __FBSDID("$FreeBSD$");
  * be picked up and redistributed in Linux with a dual GPL/BSD license.
  */
 
-/* TODO: These functions should really be part of the kernel */
-#define test_bit(pos, bitmap_addr)  (*(bitmap_addr) & 1UL << (pos))
-#define set_bit(pos, bitmap_addr)   *(bitmap_addr) |= 1UL << (pos)
-#define clear_bit(pos, bitmap_addr) *(bitmap_addr) &= ~(1UL << (pos))
+#define QP_SETSIZE	64
+BITSET_DEFINE(_qpset, QP_SETSIZE);
+#define test_bit(pos, addr)	BIT_ISSET(QP_SETSIZE, (pos), (addr))
+#define set_bit(pos, addr)	BIT_SET(QP_SETSIZE, (pos), (addr))
+#define clear_bit(pos, addr)	BIT_CLR(QP_SETSIZE, (pos), (addr))
+#define ffs_bit(addr)		BIT_FFS(QP_SETSIZE, (addr))
 
 #define KTR_NTB KTR_SPARE3
 
-#define NTB_TRANSPORT_VERSION	3
+#define NTB_TRANSPORT_VERSION	4
 #define NTB_RX_MAX_PKTS		64
 #define	NTB_RXQ_SIZE		300
 
-static unsigned int transport_mtu = 0x4000 + ETHER_HDR_LEN + ETHER_CRC_LEN;
-static unsigned int max_num_clients = 1;
+enum ntb_link_event {
+	NTB_LINK_DOWN = 0,
+	NTB_LINK_UP,
+};
+
+static SYSCTL_NODE(_hw, OID_AUTO, if_ntb, CTLFLAG_RW, 0, "if_ntb");
+
+static unsigned g_if_ntb_debug_level;
+SYSCTL_UINT(_hw_if_ntb, OID_AUTO, debug_level, CTLFLAG_RWTUN,
+    &g_if_ntb_debug_level, 0, "if_ntb log level -- higher is more verbose");
+#define ntb_printf(lvl, ...) do {			\
+	if ((lvl) <= g_if_ntb_debug_level) {		\
+		if_printf(nt->ifp, __VA_ARGS__);	\
+	}						\
+} while (0)
+
+static unsigned transport_mtu = IP_MAXPACKET + ETHER_HDR_LEN + ETHER_CRC_LEN;
+
+static uint64_t max_mw_size;
+SYSCTL_UQUAD(_hw_if_ntb, OID_AUTO, max_mw_size, CTLFLAG_RDTUN, &max_mw_size, 0,
+    "If enabled (non-zero), limit the size of large memory windows. "
+    "Both sides of the NTB MUST set the same value here.");
+
+static unsigned max_num_clients;
+SYSCTL_UINT(_hw_if_ntb, OID_AUTO, max_num_clients, CTLFLAG_RDTUN,
+    &max_num_clients, 0, "Maximum number of NTB transport clients.  "
+    "0 (default) - use all available NTB memory windows; "
+    "positive integer N - Limit to N memory windows.");
+
+static unsigned enable_xeon_watchdog;
+SYSCTL_UINT(_hw_if_ntb, OID_AUTO, enable_xeon_watchdog, CTLFLAG_RDTUN,
+    &enable_xeon_watchdog, 0, "If non-zero, write a register every second to "
+    "keep a watchdog from tearing down the NTB link");
 
 STAILQ_HEAD(ntb_queue_list, ntb_queue_entry);
 
+typedef uint32_t ntb_q_idx_t;
+
 struct ntb_queue_entry {
 	/* ntb_queue list reference */
 	STAILQ_ENTRY(ntb_queue_entry) entry;
 
-	/* info on data to be transfered */
+	/* info on data to be transferred */
 	void		*cb_data;
 	void		*buf;
-	uint64_t	len;
-	uint64_t	flags;
+	uint32_t	len;
+	uint32_t	flags;
+
+	struct ntb_transport_qp		*qp;
+	struct ntb_payload_header	*x_hdr;
+	ntb_q_idx_t	index;
 };
 
 struct ntb_rx_info {
-	unsigned int entry;
+	ntb_q_idx_t	entry;
 };
 
 struct ntb_transport_qp {
-	struct ntb_netdev	*transport;
+	struct ntb_transport_ctx	*transport;
 	struct ntb_softc	*ntb;
 
 	void			*cb_data;
 
 	bool			client_ready;
-	bool			qp_link;
+	volatile bool		link_is_up;
 	uint8_t			qp_num;	/* Only 64 QPs are allowed.  0-63 */
 
 	struct ntb_rx_info	*rx_info;
 	struct ntb_rx_info	*remote_rx_info;
 
-	void (*tx_handler) (struct ntb_transport_qp *qp, void *qp_data,
+	void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data,
 	    void *data, int len);
 	struct ntb_queue_list	tx_free_q;
 	struct mtx		ntb_tx_free_q_lock;
-	void			*tx_mw;
-	uint64_t		tx_index;
-	uint64_t		tx_max_entry;
+	caddr_t			tx_mw;
+	bus_addr_t		tx_mw_phys;
+	ntb_q_idx_t		tx_index;
+	ntb_q_idx_t		tx_max_entry;
 	uint64_t		tx_max_frame;
 
-	void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
+	void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
 	    void *data, int len);
+	struct ntb_queue_list	rx_post_q;
 	struct ntb_queue_list	rx_pend_q;
-	struct ntb_queue_list	rx_free_q;
-	struct mtx		ntb_rx_pend_q_lock;
-	struct mtx		ntb_rx_free_q_lock;
+	/* ntb_rx_q_lock: synchronize access to rx_XXXX_q */
+	struct mtx		ntb_rx_q_lock;
 	struct task		rx_completion_task;
-	void			*rx_buff;
-	uint64_t		rx_index;
-	uint64_t		rx_max_entry;
+	struct task		rxc_db_work;
+	caddr_t			rx_buff;
+	ntb_q_idx_t		rx_index;
+	ntb_q_idx_t		rx_max_entry;
 	uint64_t		rx_max_frame;
 
-	void (*event_handler) (void *data, int status);
+	void (*event_handler)(void *data, enum ntb_link_event status);
 	struct callout		link_work;
 	struct callout		queue_full;
 	struct callout		rx_full;
@@ -147,40 +198,55 @@ struct ntb_transport_qp {
 	uint64_t		tx_bytes;
 	uint64_t		tx_pkts;
 	uint64_t		tx_ring_full;
+	uint64_t		tx_err_no_buf;
 };
 
 struct ntb_queue_handlers {
-	void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
+	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 (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data,
 	    void *data, int len);
-	void (*event_handler) (void *data, int status);
+	void (*event_handler)(void *data, enum ntb_link_event status);
 };
 
-
 struct ntb_transport_mw {
-	size_t		size;
-	void		*virt_addr;
-	vm_paddr_t	dma_addr;
+	vm_paddr_t	phys_addr;
+	size_t		phys_size;
+	size_t		xlat_align;
+	size_t		xlat_align_size;
+	bus_addr_t	addr_limit;
+	/* Tx buff is off vbase / phys_addr */
+	caddr_t		vbase;
+	size_t		xlat_size;
+	size_t		buff_size;
+	/* Rx buff is off virt_addr / dma_addr */
+	caddr_t		virt_addr;
+	bus_addr_t	dma_addr;
 };
 
-struct ntb_netdev {
+struct ntb_transport_ctx {
 	struct ntb_softc	*ntb;
 	struct ifnet		*ifp;
-	struct ntb_transport_mw	mw[NTB_NUM_MW];
-	struct ntb_transport_qp	*qps;
-	uint64_t		max_qps;
-	uint64_t		qp_bitmap;
-	bool			transport_link;
+	struct ntb_transport_mw	mw_vec[NTB_MAX_NUM_MW];
+	struct ntb_transport_qp	*qp_vec;
+	struct _qpset		qp_bitmap;
+	struct _qpset		qp_bitmap_free;
+	unsigned		mw_count;
+	unsigned		qp_count;
+	volatile bool		link_is_up;
 	struct callout		link_work;
-	struct ntb_transport_qp *qp;
+	struct callout		link_watchdog;
+	struct task		link_cleanup;
 	uint64_t		bufsize;
 	u_char			eaddr[ETHER_ADDR_LEN];
 	struct mtx		tx_lock;
 	struct mtx		rx_lock;
+
+	/* The hardcoded single queuepair in ntb_setup_interface() */
+	struct ntb_transport_qp *qp;
 };
 
-static struct ntb_netdev net_softc;
+static struct ntb_transport_ctx net_softc;
 
 enum {
 	IF_NTB_DESC_DONE_FLAG = 1 << 0,
@@ -188,21 +254,42 @@ enum {
 };
 
 struct ntb_payload_header {
-	uint64_t ver;
-	uint64_t len;
-	uint64_t flags;
+	ntb_q_idx_t ver;
+	uint32_t len;
+	uint32_t flags;
 };
 
 enum {
+	/*
+	 * The order of this enum is part of the if_ntb remote protocol.  Do
+	 * not reorder without bumping protocol version (and it's probably best
+	 * to keep the protocol in lock-step with the Linux NTB driver.
+	 */
 	IF_NTB_VERSION = 0,
-	IF_NTB_MW0_SZ,
-	IF_NTB_MW1_SZ,
-	IF_NTB_NUM_QPS,
 	IF_NTB_QP_LINKS,
+	IF_NTB_NUM_QPS,
+	IF_NTB_NUM_MWS,
+	/*
+	 * N.B.: transport_link_work assumes MW1 enums = MW0 + 2.
+	 */
+	IF_NTB_MW0_SZ_HIGH,
+	IF_NTB_MW0_SZ_LOW,
+	IF_NTB_MW1_SZ_HIGH,
+	IF_NTB_MW1_SZ_LOW,
 	IF_NTB_MAX_SPAD,
+
+	/*
+	 * Some NTB-using hardware have a watchdog to work around NTB hangs; if
+	 * a register or doorbell isn't written every few seconds, the link is
+	 * torn down.  Write an otherwise unused register every few seconds to
+	 * work around this watchdog.
+	 */
+	IF_NTB_WATCHDOG_SPAD = 15
 };
+CTASSERT(IF_NTB_WATCHDOG_SPAD < XEON_SPAD_COUNT &&
+    IF_NTB_WATCHDOG_SPAD < ATOM_SPAD_COUNT);
 
-#define QP_TO_MW(qp)		((qp) % NTB_NUM_MW)
+#define QP_TO_MW(nt, qp)	((qp) % nt->mw_count)
 #define NTB_QP_DEF_NUM_ENTRIES	100
 #define NTB_LINK_DOWN_TIMEOUT	10
 
@@ -216,37 +303,41 @@ static void ntb_net_tx_handler(struct nt
     void *data, int len);
 static void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
     void *data, int len);
-static void ntb_net_event_handler(void *data, int status);
-static int ntb_transport_init(struct ntb_softc *ntb);
-static void ntb_transport_free(void *transport);
-static void ntb_transport_init_queue(struct ntb_netdev *nt,
+static void ntb_net_event_handler(void *data, enum ntb_link_event status);
+static int ntb_transport_probe(struct ntb_softc *ntb);
+static void ntb_transport_free(struct ntb_transport_ctx *);
+static void ntb_transport_init_queue(struct ntb_transport_ctx *nt,
     unsigned int qp_num);
 static void ntb_transport_free_queue(struct ntb_transport_qp *qp);
-static struct ntb_transport_qp * ntb_transport_create_queue(void *data,
+static struct ntb_transport_qp *ntb_transport_create_queue(void *data,
     struct ntb_softc *pdev, const struct ntb_queue_handlers *handlers);
 static void ntb_transport_link_up(struct ntb_transport_qp *qp);
 static int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb,
     void *data, unsigned int len);
 static int ntb_process_tx(struct ntb_transport_qp *qp,
     struct ntb_queue_entry *entry);
-static void ntb_tx_copy_task(struct ntb_transport_qp *qp,
+static void ntb_memcpy_tx(struct ntb_transport_qp *qp,
     struct ntb_queue_entry *entry, void *offset);
 static void ntb_qp_full(void *arg);
-static void ntb_transport_rxc_db(void *data, int db_num);
-static void ntb_rx_pendq_full(void *arg);
-static void ntb_transport_rx(struct ntb_transport_qp *qp);
+static void ntb_transport_rxc_db(void *arg, int pending);
 static int ntb_process_rxc(struct ntb_transport_qp *qp);
-static void ntb_rx_copy_task(struct ntb_transport_qp *qp,
+static void ntb_memcpy_rx(struct ntb_transport_qp *qp,
     struct ntb_queue_entry *entry, void *offset);
-static void ntb_rx_completion_task(void *arg, int pending);
-static void ntb_transport_event_callback(void *data, enum ntb_hw_event event);
+static inline void ntb_rx_copy_callback(struct ntb_transport_qp *qp,
+    void *data);
+static void ntb_complete_rxc(void *arg, int pending);
+static void ntb_transport_doorbell_callback(void *data, uint32_t vector);
+static void ntb_transport_event_callback(void *data);
 static void ntb_transport_link_work(void *arg);
-static int ntb_set_mw(struct ntb_netdev *nt, int num_mw, unsigned int size);
-static void ntb_transport_setup_qp_mw(struct ntb_netdev *nt,
+static int ntb_set_mw(struct ntb_transport_ctx *, int num_mw, size_t size);
+static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw);
+static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
     unsigned int qp_num);
 static void ntb_qp_link_work(void *arg);
-static void ntb_transport_link_cleanup(struct ntb_netdev *nt);
+static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt);
+static void ntb_transport_link_cleanup_work(void *, int);
 static void ntb_qp_link_down(struct ntb_transport_qp *qp);
+static void ntb_qp_link_down_reset(struct ntb_transport_qp *qp);
 static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp);
 static void ntb_transport_link_down(struct ntb_transport_qp *qp);
 static void ntb_send_link_down(struct ntb_transport_qp *qp);
@@ -254,11 +345,27 @@ static void ntb_list_add(struct mtx *loc
     struct ntb_queue_list *list);
 static struct ntb_queue_entry *ntb_list_rm(struct mtx *lock,
     struct ntb_queue_list *list);
+static struct ntb_queue_entry *ntb_list_mv(struct mtx *lock,
+    struct ntb_queue_list *from, struct ntb_queue_list *to);
 static void create_random_local_eui48(u_char *eaddr);
 static unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp);
+static void xeon_link_watchdog_hb(void *);
+
+static const struct ntb_ctx_ops ntb_transport_ops = {
+	.link_event = ntb_transport_event_callback,
+	.db_event = ntb_transport_doorbell_callback,
+};
 
 MALLOC_DEFINE(M_NTB_IF, "if_ntb", "ntb network driver");
 
+static inline void
+iowrite32(uint32_t val, void *addr)
+{
+
+	bus_space_write_4(X86_BUS_SPACE_MEM, 0/* HACK */, (uintptr_t)addr,
+	    val);
+}
+
 /* Module setup and teardown */
 static int
 ntb_handle_module_events(struct module *m, int what, void *arg)
@@ -289,11 +396,12 @@ DECLARE_MODULE(if_ntb, if_ntb_mod, SI_SU
 MODULE_DEPEND(if_ntb, ntb_hw, 1, 1, 1);
 
 static int
-ntb_setup_interface()
+ntb_setup_interface(void)
 {
 	struct ifnet *ifp;
 	struct ntb_queue_handlers handlers = { ntb_net_rx_handler,
 	    ntb_net_tx_handler, ntb_net_event_handler };
+	int rc;
 
 	net_softc.ntb = devclass_get_softc(devclass_find("ntb_hw"), 0);
 	if (net_softc.ntb == NULL) {
@@ -301,17 +409,23 @@ ntb_setup_interface()
 		return (ENXIO);
 	}
 
-	ntb_transport_init(net_softc.ntb);
-
 	ifp = net_softc.ifp = if_alloc(IFT_ETHER);
 	if (ifp == NULL) {
-		printf("ntb: cannot allocate ifnet structure\n");
+		ntb_transport_free(&net_softc);
+		printf("ntb: Cannot allocate ifnet structure\n");
 		return (ENOMEM);
 	}
+	if_initname(ifp, "ntb", 0);
+
+	rc = ntb_transport_probe(net_softc.ntb);
+	if (rc != 0) {
+		printf("ntb: Cannot init transport: %d\n", rc);
+		if_free(net_softc.ifp);
+		return (rc);
+	}
 
 	net_softc.qp = ntb_transport_create_queue(ifp, net_softc.ntb,
 	    &handlers);
-	if_initname(ifp, "ntb", 0);
 	ifp->if_init = ntb_net_init;
 	ifp->if_softc = &net_softc;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
@@ -324,6 +438,8 @@ ntb_setup_interface()
 	ether_ifattach(ifp, net_softc.eaddr);
 	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_JUMBO_MTU;
 	ifp->if_capenable = ifp->if_capabilities;
+	ifp->if_mtu = ntb_transport_max_size(net_softc.qp) - ETHER_HDR_LEN -
+	    ETHER_CRC_LEN;
 
 	ntb_transport_link_up(net_softc.qp);
 	net_softc.bufsize = ntb_transport_max_size(net_softc.qp) +
@@ -332,20 +448,20 @@ ntb_setup_interface()
 }
 
 static int
-ntb_teardown_interface()
+ntb_teardown_interface(void)
 {
 
-	if (net_softc.qp != NULL)
+	if (net_softc.qp != NULL) {
 		ntb_transport_link_down(net_softc.qp);
 
+		ntb_transport_free_queue(net_softc.qp);
+		ntb_transport_free(&net_softc);
+	}
+
 	if (net_softc.ifp != NULL) {
 		ether_ifdetach(net_softc.ifp);
 		if_free(net_softc.ifp);
-	}
-
-	if (net_softc.qp != NULL) {
-		ntb_transport_free_queue(net_softc.qp);
-		ntb_transport_free(&net_softc);
+		net_softc.ifp = NULL;
 	}
 
 	return (0);
@@ -356,7 +472,7 @@ ntb_teardown_interface()
 static void
 ntb_net_init(void *arg)
 {
-	struct ntb_netdev *ntb_softc = arg;
+	struct ntb_transport_ctx *ntb_softc = arg;
 	struct ifnet *ifp = ntb_softc->ifp;
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -368,7 +484,7 @@ ntb_net_init(void *arg)
 static int
 ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
-	struct ntb_netdev *nt = ifp->if_softc;
+	struct ntb_transport_ctx *nt = ifp->if_softc;
 	struct ifreq *ifr = (struct ifreq *)data;
 	int error = 0;
 
@@ -397,7 +513,7 @@ static void
 ntb_start(struct ifnet *ifp)
 {
 	struct mbuf *m_head;
-	struct ntb_netdev *nt = ifp->if_softc;
+	struct ntb_transport_ctx *nt = ifp->if_softc;
 	int rc;
 
 	mtx_lock(&nt->tx_lock);
@@ -447,125 +563,199 @@ ntb_net_rx_handler(struct ntb_transport_
 }
 
 static void
-ntb_net_event_handler(void *data, int status)
+ntb_net_event_handler(void *data, enum ntb_link_event status)
 {
+	struct ifnet *ifp;
+
+	ifp = data;
+	(void)ifp;
+
+	/* XXX The Linux driver munges with the carrier status here. */
 
+	switch (status) {
+	case NTB_LINK_DOWN:
+		break;
+	case NTB_LINK_UP:
+		break;
+	default:
+		panic("Bogus ntb_link_event %u\n", status);
+	}
 }
 
 /* Transport Init and teardown */
 
+static void
+xeon_link_watchdog_hb(void *arg)
+{
+	struct ntb_transport_ctx *nt;
+
+	nt = arg;
+	ntb_spad_write(nt->ntb, IF_NTB_WATCHDOG_SPAD, 0);
+	callout_reset(&nt->link_watchdog, 1 * hz, xeon_link_watchdog_hb, nt);
+}
+
 static int
-ntb_transport_init(struct ntb_softc *ntb)
+ntb_transport_probe(struct ntb_softc *ntb)
 {
-	struct ntb_netdev *nt = &net_softc;
-	int rc, i;
+	struct ntb_transport_ctx *nt = &net_softc;
+	struct ntb_transport_mw *mw;
+	uint64_t qp_bitmap;
+	int rc;
+	unsigned i;
+
+	nt->mw_count = ntb_mw_count(ntb);
+	for (i = 0; i < nt->mw_count; i++) {
+		mw = &nt->mw_vec[i];
+
+		rc = ntb_mw_get_range(ntb, i, &mw->phys_addr, &mw->vbase,
+		    &mw->phys_size, &mw->xlat_align, &mw->xlat_align_size,
+		    &mw->addr_limit);
+		if (rc != 0)
+			goto err;
+
+		mw->buff_size = 0;
+		mw->xlat_size = 0;
+		mw->virt_addr = NULL;
+		mw->dma_addr = 0;
+	}
+
+	qp_bitmap = ntb_db_valid_mask(ntb);
+	nt->qp_count = flsll(qp_bitmap);
+	KASSERT(nt->qp_count != 0, ("bogus db bitmap"));
+	nt->qp_count -= 1;
+
+	if (max_num_clients != 0 && max_num_clients < nt->qp_count)
+		nt->qp_count = max_num_clients;
+	else if (nt->mw_count < nt->qp_count)
+		nt->qp_count = nt->mw_count;
+	KASSERT(nt->qp_count <= QP_SETSIZE, ("invalid qp_count"));
 
-	nt->max_qps = max_num_clients;
-	ntb_register_transport(ntb, nt);
 	mtx_init(&nt->tx_lock, "ntb transport tx", NULL, MTX_DEF);
 	mtx_init(&nt->rx_lock, "ntb transport rx", NULL, MTX_DEF);
 
-	nt->qps = malloc(nt->max_qps * sizeof(struct ntb_transport_qp),
-			  M_NTB_IF, M_WAITOK|M_ZERO);
-
-	nt->qp_bitmap = ((uint64_t) 1 << nt->max_qps) - 1;
+	nt->qp_vec = malloc(nt->qp_count * sizeof(*nt->qp_vec), M_NTB_IF,
+	    M_WAITOK | M_ZERO);
 
-	for (i = 0; i < nt->max_qps; i++)
+	for (i = 0; i < nt->qp_count; i++) {
+		set_bit(i, &nt->qp_bitmap);
+		set_bit(i, &nt->qp_bitmap_free);
 		ntb_transport_init_queue(nt, i);
+	}
 
 	callout_init(&nt->link_work, 0);
+	callout_init(&nt->link_watchdog, 0);
+	TASK_INIT(&nt->link_cleanup, 0, ntb_transport_link_cleanup_work, nt);
 
-	rc = ntb_register_event_callback(ntb,
-					 ntb_transport_event_callback);
+	rc = ntb_set_ctx(ntb, nt, &ntb_transport_ops);
 	if (rc != 0)
 		goto err;
 
-	if (ntb_query_link_status(ntb)) {
-		if (bootverbose)
-			device_printf(ntb_get_device(ntb), "link up\n");
-		callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
-	}
-
+	nt->link_is_up = false;
+	ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
+	ntb_link_event(ntb);
+
+	callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
+	if (enable_xeon_watchdog != 0)
+		callout_reset(&nt->link_watchdog, 0, xeon_link_watchdog_hb, nt);
 	return (0);
 
 err:
-	free(nt->qps, M_NTB_IF);
-	ntb_unregister_transport(ntb);
+	free(nt->qp_vec, M_NTB_IF);
+	nt->qp_vec = NULL;
 	return (rc);
 }
 
 static void
-ntb_transport_free(void *transport)
+ntb_transport_free(struct ntb_transport_ctx *nt)
 {
-	struct ntb_netdev *nt = transport;
 	struct ntb_softc *ntb = nt->ntb;
-	int i;
-
-	nt->transport_link = NTB_LINK_DOWN;
+	struct _qpset qp_bitmap_alloc;
+	uint8_t i;
 
+	ntb_transport_link_cleanup(nt);
+	taskqueue_drain(taskqueue_swi, &nt->link_cleanup);
 	callout_drain(&nt->link_work);
+	callout_drain(&nt->link_watchdog);
 
-	/* verify that all the qps are freed */
-	for (i = 0; i < nt->max_qps; i++)
-		if (!test_bit(i, &nt->qp_bitmap))
-			ntb_transport_free_queue(&nt->qps[i]);
+	BIT_COPY(QP_SETSIZE, &nt->qp_bitmap, &qp_bitmap_alloc);
+	BIT_NAND(QP_SETSIZE, &qp_bitmap_alloc, &nt->qp_bitmap_free);
 
+	/* Verify that all the QPs are freed */
+	for (i = 0; i < nt->qp_count; i++)
+		if (test_bit(i, &qp_bitmap_alloc))
+			ntb_transport_free_queue(&nt->qp_vec[i]);
 
-	ntb_unregister_event_callback(ntb);
+	ntb_link_disable(ntb);
+	ntb_clear_ctx(ntb);
 
-	for (i = 0; i < NTB_NUM_MW; i++)
-		if (nt->mw[i].virt_addr != NULL)
-			contigfree(nt->mw[i].virt_addr, nt->mw[i].size,
-					  M_NTB_IF);
+	for (i = 0; i < nt->mw_count; i++)
+		ntb_free_mw(nt, i);
 
-	free(nt->qps, M_NTB_IF);
-	ntb_unregister_transport(ntb);
+	free(nt->qp_vec, M_NTB_IF);
 }
 
 static void
-ntb_transport_init_queue(struct ntb_netdev *nt, unsigned int qp_num)
+ntb_transport_init_queue(struct ntb_transport_ctx *nt, unsigned int qp_num)
 {
+	struct ntb_transport_mw *mw;
 	struct ntb_transport_qp *qp;
-	unsigned int num_qps_mw, tx_size;
-	uint8_t mw_num = QP_TO_MW(qp_num);
+	vm_paddr_t mw_base;
+	uint64_t mw_size, qp_offset;
+	size_t tx_size;
+	unsigned num_qps_mw, mw_num, mw_count;
+
+	mw_count = nt->mw_count;
+	mw_num = QP_TO_MW(nt, qp_num);
+	mw = &nt->mw_vec[mw_num];
 
-	qp = &nt->qps[qp_num];
+	qp = &nt->qp_vec[qp_num];
 	qp->qp_num = qp_num;
 	qp->transport = nt;
 	qp->ntb = nt->ntb;
-	qp->qp_link = NTB_LINK_DOWN;
-	qp->client_ready = NTB_LINK_DOWN;
+	qp->client_ready = false;
 	qp->event_handler = NULL;
+	ntb_qp_link_down_reset(qp);
 
-	if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
-		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
+	if (nt->qp_count % mw_count && mw_num + 1 < nt->qp_count / mw_count)
+		num_qps_mw = nt->qp_count / mw_count + 1;
 	else
-		num_qps_mw = nt->max_qps / NTB_NUM_MW;
+		num_qps_mw = nt->qp_count / mw_count;
+
+	mw_base = mw->phys_addr;
+	mw_size = mw->phys_size;
+
+	tx_size = mw_size / num_qps_mw;
+	qp_offset = tx_size * (qp_num / mw_count);
+
+	qp->tx_mw = mw->vbase + qp_offset;
+	KASSERT(qp->tx_mw != NULL, ("uh oh?"));
+
+	/* XXX Assumes that a vm_paddr_t is equivalent to bus_addr_t */
+	qp->tx_mw_phys = mw_base + qp_offset;
+	KASSERT(qp->tx_mw_phys != 0, ("uh oh?"));
 
-	tx_size = (unsigned int) ntb_get_mw_size(qp->ntb, mw_num) / num_qps_mw;
-	qp->rx_info = (struct ntb_rx_info *)
-	    ((char *)ntb_get_mw_vbase(qp->ntb, mw_num) +
-	    (qp_num / NTB_NUM_MW * tx_size));
 	tx_size -= sizeof(struct ntb_rx_info);
+	qp->rx_info = (void *)(qp->tx_mw + tx_size);
 
-	qp->tx_mw = qp->rx_info + sizeof(struct ntb_rx_info);
-	qp->tx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header),
-	    tx_size);
+	/* Due to house-keeping, there must be at least 2 buffs */
+	qp->tx_max_frame = qmin(tx_size / 2,
+	    transport_mtu + sizeof(struct ntb_payload_header));
 	qp->tx_max_entry = tx_size / qp->tx_max_frame;
-	qp->tx_index = 0;
 
 	callout_init(&qp->link_work, 0);
 	callout_init(&qp->queue_full, CALLOUT_MPSAFE);
 	callout_init(&qp->rx_full, CALLOUT_MPSAFE);
 
-	mtx_init(&qp->ntb_rx_pend_q_lock, "ntb rx pend q", NULL, MTX_SPIN);
-	mtx_init(&qp->ntb_rx_free_q_lock, "ntb rx free q", NULL, MTX_SPIN);
+	mtx_init(&qp->ntb_rx_q_lock, "ntb rx q", NULL, MTX_SPIN);
 	mtx_init(&qp->ntb_tx_free_q_lock, "ntb tx free q", NULL, MTX_SPIN);
-	TASK_INIT(&qp->rx_completion_task, 0, ntb_rx_completion_task, qp);
+	TASK_INIT(&qp->rx_completion_task, 0, ntb_complete_rxc, qp);
+	TASK_INIT(&qp->rxc_db_work, 0, ntb_transport_rxc_db, qp);
 
+	STAILQ_INIT(&qp->rx_post_q);
 	STAILQ_INIT(&qp->rx_pend_q);
-	STAILQ_INIT(&qp->rx_free_q);
 	STAILQ_INIT(&qp->tx_free_q);
+
+	callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
 }
 
 static void
@@ -578,18 +768,25 @@ ntb_transport_free_queue(struct ntb_tran
 
 	callout_drain(&qp->link_work);
 
-	ntb_unregister_db_callback(qp->ntb, qp->qp_num);
+	ntb_db_set_mask(qp->ntb, 1ull << qp->qp_num);
+	taskqueue_drain(taskqueue_swi, &qp->rxc_db_work);
+	taskqueue_drain(taskqueue_swi, &qp->rx_completion_task);
+
+	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)))
+	while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q)))
 		free(entry, M_NTB_IF);
 
-	while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q)))
+	while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_post_q)))
 		free(entry, M_NTB_IF);
 
 	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
 		free(entry, M_NTB_IF);
 
-	set_bit(qp->qp_num, &qp->transport->qp_bitmap);
+	set_bit(qp->qp_num, &qp->transport->qp_bitmap_free);
 }
 
 /**
@@ -607,64 +804,48 @@ ntb_transport_free_queue(struct ntb_tran
  * RETURNS: pointer to newly created ntb_queue, NULL on error.
  */
 static struct ntb_transport_qp *
-ntb_transport_create_queue(void *data, struct ntb_softc *pdev,
+ntb_transport_create_queue(void *data, struct ntb_softc *ntb,
     const struct ntb_queue_handlers *handlers)
 {
 	struct ntb_queue_entry *entry;
 	struct ntb_transport_qp *qp;
-	struct ntb_netdev *nt;
+	struct ntb_transport_ctx *nt;
 	unsigned int free_queue;
-	int rc, i;
+	int i;
 
-	nt = ntb_find_transport(pdev);
-	if (nt == NULL)
-		goto err;
+	nt = ntb_get_ctx(ntb, NULL);
+	KASSERT(nt != NULL, ("bogus"));
 
-	free_queue = ffs(nt->qp_bitmap);
+	free_queue = ffs_bit(&nt->qp_bitmap);
 	if (free_queue == 0)
-		goto err;
+		return (NULL);
 
 	/* decrement free_queue to make it zero based */
 	free_queue--;
 
-	clear_bit(free_queue, &nt->qp_bitmap);
-
-	qp = &nt->qps[free_queue];
+	qp = &nt->qp_vec[free_queue];
+	clear_bit(qp->qp_num, &nt->qp_bitmap_free);
 	qp->cb_data = data;
 	qp->rx_handler = handlers->rx_handler;
 	qp->tx_handler = handlers->tx_handler;
 	qp->event_handler = handlers->event_handler;
 
 	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
-		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
-		    M_WAITOK|M_ZERO);
+		entry = malloc(sizeof(*entry), M_NTB_IF, M_WAITOK | M_ZERO);
 		entry->cb_data = nt->ifp;
 		entry->buf = NULL;
 		entry->len = transport_mtu;
-		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
+		ntb_list_add(&qp->ntb_rx_q_lock, entry, &qp->rx_pend_q);
 	}
 
 	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
-		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
-		    M_WAITOK|M_ZERO);
+		entry = malloc(sizeof(*entry), M_NTB_IF, M_WAITOK | M_ZERO);
 		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
 	}
 
-	rc = ntb_register_db_callback(qp->ntb, free_queue, qp,
-				      ntb_transport_rxc_db);
-	if (rc != 0)
-		goto err1;
-
+	ntb_db_clear(ntb, 1ull << qp->qp_num);
+	ntb_db_clear_mask(ntb, 1ull << qp->qp_num);
 	return (qp);
-
-err1:
-	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
-		free(entry, M_NTB_IF);
-	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
-		free(entry, M_NTB_IF);
-	set_bit(free_queue, &nt->qp_bitmap);
-err:
-	return (NULL);
 }
 
 /**
@@ -676,15 +857,17 @@ err:
 static void
 ntb_transport_link_up(struct ntb_transport_qp *qp)
 {
+	struct ntb_transport_ctx *nt;
 
 	if (qp == NULL)
 		return;
 
-	qp->client_ready = NTB_LINK_UP;
-	if (bootverbose)
-		device_printf(ntb_get_device(qp->ntb), "qp client ready\n");
+	qp->client_ready = true;
+
+	nt = qp->transport;
+	ntb_printf(2, "qp client ready\n");
 
-	if (qp->transport->transport_link == NTB_LINK_UP)
+	if (qp->transport->link_is_up)
 		callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
 }
 
@@ -700,7 +883,7 @@ ntb_transport_link_up(struct ntb_transpo
  * @len: length of the data buffer
  *
  * Enqueue a new transmit buffer onto the transport queue from which a NTB
- * payload will be transmitted.  This assumes that a lock is behing held to
+ * payload will be transmitted.  This assumes that a lock is being held to
  * serialize access to the qp.
  *
  * RETURNS: An appropriate ERRNO error value on error, or zero for success.
@@ -712,7 +895,7 @@ ntb_transport_tx_enqueue(struct ntb_tran
 	struct ntb_queue_entry *entry;
 	int rc;
 
-	if (qp == NULL || qp->qp_link != NTB_LINK_UP || len == 0) {
+	if (qp == NULL || !qp->link_is_up || len == 0) {
 		CTR0(KTR_NTB, "TX: link not up");
 		return (EINVAL);
 	}
@@ -720,7 +903,8 @@ ntb_transport_tx_enqueue(struct ntb_tran
 	entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
 	if (entry == NULL) {
 		CTR0(KTR_NTB, "TX: could not get entry from tx_free_q");
-		return (ENOMEM);
+		qp->tx_err_no_buf++;
+		return (EBUSY);
 	}
 	CTR1(KTR_NTB, "TX: got entry %p from tx_free_q", entry);
 
@@ -744,9 +928,9 @@ ntb_process_tx(struct ntb_transport_qp *
 {
 	void *offset;
 
-	offset = (char *)qp->tx_mw + qp->tx_max_frame * qp->tx_index;
+	offset = qp->tx_mw + qp->tx_max_frame * qp->tx_index;
 	CTR3(KTR_NTB,
-	    "TX: process_tx: tx_pkts=%u, tx_index=%u, remote entry=%u",
+	    "TX: process_tx: tx_pkts=%lu, tx_index=%u, remote entry=%u",
 	    qp->tx_pkts, qp->tx_index, qp->remote_rx_info->entry);
 	if (qp->tx_index == qp->remote_rx_info->entry) {
 		CTR0(KTR_NTB, "TX: ring full");
@@ -757,8 +941,11 @@ ntb_process_tx(struct ntb_transport_qp *
 	if (entry->len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) {
 		if (qp->tx_handler != NULL)
 			qp->tx_handler(qp, qp->cb_data, entry->buf,
-				       EIO);
+			    EIO);
+		else
+			m_freem(entry->buf);
 
+		entry->buf = NULL;
 		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
 		CTR1(KTR_NTB,
 		    "TX: frame too big. returning entry %p to tx_free_q",
@@ -766,7 +953,7 @@ ntb_process_tx(struct ntb_transport_qp *
 		return (0);
 	}
 	CTR2(KTR_NTB, "TX: copying entry %p to offset %p", entry, offset);
-	ntb_tx_copy_task(qp, entry, offset);
+	ntb_memcpy_tx(qp, entry, offset);
 
 	qp->tx_index++;
 	qp->tx_index %= qp->tx_max_entry;
@@ -777,26 +964,37 @@ ntb_process_tx(struct ntb_transport_qp *
 }
 
 static void
-ntb_tx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
+ntb_memcpy_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
     void *offset)
 {
 	struct ntb_payload_header *hdr;
 
+	/* This piece is from Linux' ntb_async_tx() */
+	hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame -
+	    sizeof(struct ntb_payload_header));
+	entry->x_hdr = hdr;
+	iowrite32(entry->len, &hdr->len);
+	iowrite32(qp->tx_pkts, &hdr->ver);
+
+	/* This piece is ntb_memcpy_tx() */
 	CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset);
-	if (entry->buf != NULL)
+	if (entry->buf != NULL) {
 		m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset);
 
-	hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame -
-	    sizeof(struct ntb_payload_header));
-	hdr->len = entry->len; /* TODO: replace with bus_space_write */
-	hdr->ver = qp->tx_pkts; /* TODO: replace with bus_space_write */
-	wmb();
-	/* TODO: replace with bus_space_write */
-	hdr->flags = entry->flags | IF_NTB_DESC_DONE_FLAG;
+		/*
+		 * Ensure that the data is fully copied before setting the
+		 * flags
+		 */
+		wmb();
+	}
 
-	ntb_ring_sdb(qp->ntb, qp->qp_num);
+	/* The rest is ntb_tx_copy_callback() */
+	iowrite32(entry->flags | IF_NTB_DESC_DONE_FLAG, &hdr->flags);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list