Date: Thu, 15 Oct 2015 23:45:43 +0000 (UTC) From: "Conrad E. Meyer" <cem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r289396 - in head/sys/dev/ntb: if_ntb ntb_hw Message-ID: <201510152345.t9FNjh08090235@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201510152345.t9FNjh08090235>