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-all
mailing list