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
This commit is contained in:
parent
8076e3efdf
commit
a2d3d01d7a
@ -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_netdev *nt, unsigned int qp_num)
|
||||
{
|
||||
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_netdev *nt, unsigned int qp_num)
|
||||
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_netdev *nt, unsigned int qp_num)
|
||||
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;
|
||||
|
@ -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 *ntb, uint32_t num_vectors)
|
||||
* 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 *ntb)
|
||||
} 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 *ntb, uint32_t num_vectors)
|
||||
{
|
||||
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_softc *ntb, unsigned int idx, void *data,
|
||||
{
|
||||
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 *ntb, void *transport)
|
||||
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)) {
|
||||
|
@ -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_softc *ntb);
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user