svn commit: r289396 - in head/sys/dev/ntb: if_ntb ntb_hw

Conrad E. Meyer cem at FreeBSD.org
Thu Oct 15 23:45:44 UTC 2015


Author: cem
Date: Thu Oct 15 23:45:43 2015
New Revision: 289396
URL: https://svnweb.freebsd.org/changeset/base/289396

Log:
  NTB: Add variable number MW, DB CB support code
  
  This is a follow-up to r289208: "Xeon Errata Workaround."
  
  Add logic to support a variable number of memory windows and doorbell
  callbacks.  This was added to the Linux driver in the "Xeon Errata
  Workaround" commit, but I skipped it because it didn't look neccessary
  at the time.  It is needed for future Haswell split-BAR support, so
  bring it in now.
  
  A new tunable was added for if_ntb, 'hw.ntb.max_num_clients'.  By
  default, it is set to zero -- infer the number of clients from the
  number of memory windows available from the hardware.  Any other
  positive value can specify a different number of clients, limited by the
  number of doorbell callbacks available (4 under MSI-X, or 15 (Xeon) or
  34 (SoC) under legacy INTx).
  
  Obtained from:	Linux (Dual BSD/GPL driver)
  Sponsored by:	EMC / Isilon Storage Division

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

Modified: head/sys/dev/ntb/if_ntb/if_ntb.c
==============================================================================
--- head/sys/dev/ntb/if_ntb/if_ntb.c	Thu Oct 15 23:45:00 2015	(r289395)
+++ head/sys/dev/ntb/if_ntb/if_ntb.c	Thu Oct 15 23:45:43 2015	(r289396)
@@ -80,11 +80,11 @@ __FBSDID("$FreeBSD$");
 
 static unsigned int transport_mtu = 0x4000 + ETHER_HDR_LEN + ETHER_CRC_LEN;
 
-/*
- * This is an oversimplification to work around Xeon Errata.  The second client
- * may be usable for unidirectional traffic.
- */
-static unsigned int max_num_clients = 1;
+static unsigned int max_num_clients;
+SYSCTL_UINT(_hw_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.");
 
 STAILQ_HEAD(ntb_queue_list, ntb_queue_entry);
 
@@ -174,7 +174,7 @@ struct ntb_transport_mw {
 struct ntb_netdev {
 	struct ntb_softc	*ntb;
 	struct ifnet		*ifp;
-	struct ntb_transport_mw	mw[NTB_NUM_MW];
+	struct ntb_transport_mw	mw[NTB_MAX_NUM_MW];
 	struct ntb_transport_qp	*qps;
 	uint64_t		max_qps;
 	uint64_t		qp_bitmap;
@@ -220,7 +220,7 @@ enum {
 	IF_NTB_MAX_SPAD,
 };
 
-#define QP_TO_MW(qp)		((qp) % NTB_NUM_MW)
+#define QP_TO_MW(ntb, qp)	((qp) % ntb_get_max_mw(ntb))
 #define NTB_QP_DEF_NUM_ENTRIES	100
 #define NTB_LINK_DOWN_TIMEOUT	10
 
@@ -492,7 +492,11 @@ ntb_transport_init(struct ntb_softc *ntb
 	struct ntb_netdev *nt = &net_softc;
 	int rc, i;
 
-	nt->max_qps = max_num_clients;
+	if (max_num_clients == 0)
+		nt->max_qps = MIN(ntb_get_max_cbs(ntb), ntb_get_max_mw(ntb));
+	else
+		nt->max_qps = MIN(ntb_get_max_cbs(ntb), 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);
@@ -544,7 +548,7 @@ ntb_transport_free(void *transport)
 
 	ntb_unregister_event_callback(ntb);
 
-	for (i = 0; i < NTB_NUM_MW; i++)
+	for (i = 0; i < NTB_MAX_NUM_MW; i++)
 		ntb_free_mw(nt, i);
 
 	free(nt->qps, M_NTB_IF);
@@ -556,7 +560,10 @@ ntb_transport_init_queue(struct ntb_netd
 {
 	struct ntb_transport_qp *qp;
 	unsigned int num_qps_mw, tx_size;
-	uint8_t mw_num = QP_TO_MW(qp_num);
+	uint8_t mw_num, mw_max;
+
+	mw_max = ntb_get_max_mw(nt->ntb);
+	mw_num = QP_TO_MW(nt->ntb, qp_num);
 
 	qp = &nt->qps[qp_num];
 	qp->qp_num = qp_num;
@@ -566,15 +573,15 @@ ntb_transport_init_queue(struct ntb_netd
 	qp->client_ready = NTB_LINK_DOWN;
 	qp->event_handler = NULL;
 
-	if (nt->max_qps % NTB_NUM_MW && mw_num + 1 < nt->max_qps / NTB_NUM_MW)
-		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
+	if (nt->max_qps % mw_max && mw_num + 1 < nt->max_qps / mw_max)
+		num_qps_mw = nt->max_qps / mw_max + 1;
 	else
-		num_qps_mw = nt->max_qps / NTB_NUM_MW;
+		num_qps_mw = nt->max_qps / mw_max;
 
 	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));
+	    (qp_num / mw_max * tx_size));
 	tx_size -= sizeof(struct ntb_rx_info);
 
 	qp->tx_mw = qp->rx_info + 1;
@@ -1048,10 +1055,7 @@ ntb_transport_link_work(void *arg)
 	uint32_t val, i, num_mw;
 	int rc;
 
-	if (ntb_has_feature(ntb, NTB_REGS_THRU_MW))
-		num_mw = NTB_NUM_MW - 1;
-	else
-		num_mw = NTB_NUM_MW;
+	num_mw = ntb_get_max_mw(ntb);
 
 	/* send the local info, in the opposite order of the way we read it */
 	for (i = 0; i < num_mw; i++) {
@@ -1136,7 +1140,7 @@ ntb_transport_link_work(void *arg)
 	return;
 
 free_mws:
-	for (i = 0; i < NTB_NUM_MW; i++)
+	for (i = 0; i < NTB_MAX_NUM_MW; i++)
 		ntb_free_mw(nt, i);
 out:
 	if (ntb_query_link_status(ntb))
@@ -1207,17 +1211,20 @@ ntb_transport_setup_qp_mw(struct ntb_net
 	struct ntb_transport_qp *qp = &nt->qps[qp_num];
 	void *offset;
 	unsigned int rx_size, num_qps_mw;
-	uint8_t mw_num = QP_TO_MW(qp_num);
+	uint8_t mw_num, mw_max;
 	unsigned int i;
 
-	if (nt->max_qps % NTB_NUM_MW && mw_num + 1 < nt->max_qps / NTB_NUM_MW)
-		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
+	mw_max = ntb_get_max_mw(nt->ntb);
+	mw_num = QP_TO_MW(nt->ntb, qp_num);
+
+	if (nt->max_qps % mw_max && mw_num + 1 < nt->max_qps / mw_max)
+		num_qps_mw = nt->max_qps / mw_max + 1;
 	else
-		num_qps_mw = nt->max_qps / NTB_NUM_MW;
+		num_qps_mw = nt->max_qps / mw_max;
 
 	rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw;
 	qp->remote_rx_info = (void *)((uint8_t *)nt->mw[mw_num].virt_addr +
-			     (qp_num / NTB_NUM_MW * rx_size));
+			     (qp_num / mw_max * rx_size));
 	rx_size -= sizeof(struct ntb_rx_info);
 
 	qp->rx_buff = qp->remote_rx_info + 1;

Modified: head/sys/dev/ntb/ntb_hw/ntb_hw.c
==============================================================================
--- head/sys/dev/ntb/ntb_hw/ntb_hw.c	Thu Oct 15 23:45:00 2015	(r289395)
+++ head/sys/dev/ntb/ntb_hw/ntb_hw.c	Thu Oct 15 23:45:43 2015	(r289396)
@@ -127,9 +127,11 @@ struct ntb_softc {
 
 	void			*ntb_transport;
 	ntb_event_callback	event_cb;
-	struct ntb_db_cb 	*db_cb;
+	struct ntb_db_cb	*db_cb;
+	uint8_t			max_cbs;
 
 	struct {
+		uint8_t max_mw;
 		uint8_t max_spads;
 		uint8_t max_db_bits;
 		uint8_t msix_cnt;
@@ -321,6 +323,8 @@ ntb_attach(device_t device)
 	if (error)
 		goto out;
 
+	ntb->limits.max_mw = NTB_MAX_NUM_MW;
+
 	error = ntb_map_pci_bars(ntb);
 	if (error)
 		goto out;
@@ -533,6 +537,7 @@ ntb_setup_xeon_msix(struct ntb_softc *nt
 	 * slot, from which they will never be called back.
 	 */
 	ntb->db_cb[num_vectors - 1].reserved = true;
+	ntb->max_cbs--;
 	return (0);
 }
 
@@ -649,16 +654,32 @@ ntb_setup_interrupts(struct ntb_softc *n
 	} else
 		num_vectors = 1;
 
+	/*
+	 * If allocating MSI-X interrupts succeeds, limit callbacks to the
+	 * number of MSI-X slots available.
+	 */
 	ntb_create_callbacks(ntb, num_vectors);
 
 	if (ntb->type == NTB_XEON)
 		rc = ntb_setup_xeon_msix(ntb, num_vectors);
 	else
 		rc = ntb_setup_soc_msix(ntb, num_vectors);
-	if (rc != 0)
+	if (rc != 0) {
 		device_printf(ntb->device,
 		    "Error allocating MSI-X interrupts: %d\n", rc);
 
+		/*
+		 * If allocating MSI-X interrupts failed and we're forced to
+		 * use legacy INTx anyway, the only limit on individual
+		 * callbacks is the number of doorbell bits.
+		 *
+		 * CEM: This seems odd to me but matches the behavior of the
+		 * Linux driver ca. September 2013
+		 */
+		ntb_free_callbacks(ntb);
+		ntb_create_callbacks(ntb, ntb->limits.max_db_bits);
+	}
+
 	if (ntb->type == NTB_XEON && rc == ENOSPC)
 		rc = ntb_setup_legacy_interrupt(ntb);
 
@@ -842,6 +863,7 @@ ntb_create_callbacks(struct ntb_softc *n
 {
 	uint32_t i;
 
+	ntb->max_cbs = num_vectors;
 	ntb->db_cb = malloc(num_vectors * sizeof(*ntb->db_cb), M_NTB,
 	    M_ZERO | M_WAITOK);
 	for (i = 0; i < num_vectors; i++) {
@@ -857,10 +879,11 @@ ntb_free_callbacks(struct ntb_softc *ntb
 {
 	uint8_t i;
 
-	for (i = 0; i < ntb->limits.max_db_bits; i++)
+	for (i = 0; i < ntb->max_cbs; i++)
 		ntb_unregister_db_callback(ntb, i);
 
 	free(ntb->db_cb, M_NTB);
+	ntb->max_cbs = 0;
 }
 
 static struct ntb_hw_info *
@@ -989,14 +1012,16 @@ ntb_setup_xeon(struct ntb_softc *ntb)
 	 * This should already be the case based on the driver defaults, but
 	 * write the limit registers first just in case.
 	 */
-	if (HAS_FEATURE(NTB_REGS_THRU_MW))
+	if (HAS_FEATURE(NTB_REGS_THRU_MW)) {
+		/* Reserve the last MW for mapping remote spad */
+		ntb->limits.max_mw--;
 		/*
 		 * Set the Limit register to 4k, the minimum size, to prevent
 		 * an illegal access.
 		 */
 		ntb_reg_write(8, XEON_PBAR4LMT_OFFSET,
 		    ntb_get_mw_size(ntb, 1) + 0x1000);
-	else
+	} else
 		/*
 		 * Disable the limit register, just in case it is set to
 		 * something silly.
@@ -1432,8 +1457,7 @@ ntb_register_db_callback(struct ntb_soft
 {
 	struct ntb_db_cb *db_cb = &ntb->db_cb[idx];
 
-	if (idx >= ntb->allocated_interrupts || db_cb->callback ||
-	    db_cb->reserved) {
+	if (idx >= ntb->max_cbs || db_cb->callback != NULL || db_cb->reserved) {
 		device_printf(ntb->device, "Invalid Index.\n");
 		return (EINVAL);
 	}
@@ -1459,7 +1483,7 @@ void
 ntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx)
 {
 
-	if (idx >= ntb->allocated_interrupts || !ntb->db_cb[idx].callback)
+	if (idx >= ntb->max_cbs || ntb->db_cb[idx].callback == NULL)
 		return;
 
 	mask_ldb_interrupt(ntb, idx);
@@ -1518,12 +1542,12 @@ ntb_register_transport(struct ntb_softc 
 void
 ntb_unregister_transport(struct ntb_softc *ntb)
 {
-	int i;
+	uint8_t i;
 
 	if (ntb->ntb_transport == NULL)
 		return;
 
-	for (i = 0; i < ntb->allocated_interrupts; i++)
+	for (i = 0; i < ntb->max_cbs; i++)
 		ntb_unregister_db_callback(ntb, i);
 
 	ntb_unregister_event_callback(ntb);
@@ -1546,6 +1570,20 @@ ntb_get_max_spads(struct ntb_softc *ntb)
 	return (ntb->limits.max_spads);
 }
 
+uint8_t
+ntb_get_max_cbs(struct ntb_softc *ntb)
+{
+
+	return (ntb->max_cbs);
+}
+
+uint8_t
+ntb_get_max_mw(struct ntb_softc *ntb)
+{
+
+	return (ntb->limits.max_mw);
+}
+
 /**
  * ntb_write_local_spad() - write to the secondary scratchpad register
  * @ntb: pointer to ntb_softc instance
@@ -1658,7 +1696,7 @@ void *
 ntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw)
 {
 
-	if (mw >= NTB_NUM_MW)
+	if (mw >= ntb_get_max_mw(ntb))
 		return (NULL);
 
 	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].vbase);
@@ -1668,7 +1706,7 @@ vm_paddr_t
 ntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw)
 {
 
-	if (mw >= NTB_NUM_MW)
+	if (mw >= ntb_get_max_mw(ntb))
 		return (0);
 
 	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].pbase);
@@ -1687,7 +1725,7 @@ u_long
 ntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw)
 {
 
-	if (mw >= NTB_NUM_MW)
+	if (mw >= ntb_get_max_mw(ntb))
 		return (0);
 
 	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].size);
@@ -1707,7 +1745,7 @@ void
 ntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr)
 {
 
-	if (mw >= NTB_NUM_MW)
+	if (mw >= ntb_get_max_mw(ntb))
 		return;
 
 	switch (NTB_MW_TO_BAR(mw)) {

Modified: head/sys/dev/ntb/ntb_hw/ntb_hw.h
==============================================================================
--- head/sys/dev/ntb/ntb_hw/ntb_hw.h	Thu Oct 15 23:45:00 2015	(r289395)
+++ head/sys/dev/ntb/ntb_hw/ntb_hw.h	Thu Oct 15 23:45:43 2015	(r289396)
@@ -31,7 +31,7 @@
 
 struct ntb_softc;
 
-#define NTB_NUM_MW	2
+#define NTB_MAX_NUM_MW	2
 
 enum ntb_link_event {
 	NTB_LINK_DOWN = 0,
@@ -61,6 +61,8 @@ void *ntb_find_transport(struct ntb_soft
 struct ntb_softc *ntb_register_transport(struct ntb_softc *ntb,
     void *transport);
 void ntb_unregister_transport(struct ntb_softc *ntb);
+uint8_t ntb_get_max_cbs(struct ntb_softc *ntb);
+uint8_t ntb_get_max_mw(struct ntb_softc *ntb);
 uint8_t ntb_get_max_spads(struct ntb_softc *ntb);
 int ntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val);
 int ntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val);


More information about the svn-src-head mailing list