Date: Sun, 18 Oct 2015 20:20:57 +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: r289546 - in head/sys/dev/ntb: if_ntb ntb_hw Message-ID: <201510182020.t9IKKvjR093144@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: cem Date: Sun Oct 18 20:20:57 2015 New Revision: 289546 URL: https://svnweb.freebsd.org/changeset/base/289546 Log: if_ntb: MFV e26a5843: Move MW/DB management to if_ntb This is the last e26a5843 patch. The general thrust of the rewrite was to move more responsibility for Memory Window and Doorbell interrupt management from the ntb_hw driver to if_ntb. A number of APIs have been added, removed, or replaced. The old DB callback mechanism has been excised. Instead, callers (if_ntb) are responsible for configuring MWs and handling their interrupts more directly. This adds a tunable, hw.ntb.max_mw_size, allowing users to limit the size of memory windows used by if_ntb (identical to the Linux modparam of the same name). Despite attempts to keep mechanical name changes to separate commits, some have snuck in here. At least the driver should be much more similar to the latest Linux one now -- making porting fixes easier. Authored by: Allen Hubbe 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 head/sys/dev/ntb/ntb_hw/ntb_regs.h Modified: head/sys/dev/ntb/if_ntb/if_ntb.c ============================================================================== --- head/sys/dev/ntb/if_ntb/if_ntb.c Sun Oct 18 20:20:48 2015 (r289545) +++ head/sys/dev/ntb/if_ntb/if_ntb.c Sun Oct 18 20:20:57 2015 (r289546) @@ -81,12 +81,22 @@ BITSET_DEFINE(_qpset, QP_SETSIZE); #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 +enum ntb_link_event { + NTB_LINK_DOWN = 0, + NTB_LINK_UP, +}; + static unsigned int transport_mtu = 0x4000 + ETHER_HDR_LEN + ETHER_CRC_LEN; +static uint64_t max_mw_size; +SYSCTL_UQUAD(_hw_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 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. " @@ -99,11 +109,15 @@ 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; + unsigned len; + unsigned flags; + + struct ntb_transport_qp *qp; + struct ntb_payload_header *x_hdr; + unsigned index; }; struct ntb_rx_info { @@ -128,6 +142,7 @@ struct ntb_transport_qp { struct ntb_queue_list tx_free_q; struct mtx ntb_tx_free_q_lock; void *tx_mw; + bus_addr_t tx_mw_phys; uint64_t tx_index; uint64_t tx_max_entry; uint64_t tx_max_frame; @@ -139,6 +154,7 @@ struct ntb_transport_qp { struct mtx ntb_rx_pend_q_lock; struct mtx ntb_rx_free_q_lock; struct task rx_completion_task; + struct task rxc_db_work; void *rx_buff; uint64_t rx_index; uint64_t rx_max_entry; @@ -171,11 +187,18 @@ struct ntb_queue_handlers { void (*event_handler)(void *data, enum ntb_link_event status); }; - struct ntb_transport_mw { + vm_paddr_t phys_addr; + size_t phys_size; + size_t xlat_align; + size_t xlat_align_size; + /* Tx buff is off vbase / phys_addr */ + void *vbase; size_t xlat_size; + size_t buff_size; + /* Rx buff is off virt_addr / dma_addr */ void *virt_addr; - vm_paddr_t dma_addr; + bus_addr_t dma_addr; }; struct ntb_transport_ctx { @@ -184,15 +207,18 @@ struct ntb_transport_ctx { 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; enum ntb_link_event link_is_up; struct callout link_work; - struct ntb_transport_qp *qp; 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_transport_ctx net_softc; @@ -244,31 +270,32 @@ static void ntb_net_rx_handler(struct nt void *data, int len); static void ntb_net_event_handler(void *data, enum ntb_link_event status); static int ntb_transport_init(struct ntb_softc *ntb); -static void ntb_transport_free(void *transport); +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 int ntb_transport_rxc_db(void *arg, int dummy); +static void ntb_transport_rxc_db(void *arg, int pending); static void ntb_rx_pendq_full(void *arg); static int ntb_process_rxc(struct ntb_transport_qp *qp); static void ntb_rx_copy_task(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 void ntb_complete_rxc(void *arg, int pending); +static void ntb_transport_doorbell_callback(void *data, int vector); +static void ntb_transport_event_callback(void *data); static void ntb_transport_link_work(void *arg); static int ntb_set_mw(struct ntb_transport_ctx *, int num_mw, unsigned size); static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw); -static void ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, +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_transport_ctx *nt); @@ -283,6 +310,11 @@ static struct ntb_queue_entry *ntb_list_ static void create_random_local_eui48(u_char *eaddr); static unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp); +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"); /* Module setup and teardown */ @@ -320,6 +352,7 @@ 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) { @@ -327,11 +360,16 @@ ntb_setup_interface(void) return (ENXIO); } - ntb_transport_init(net_softc.ntb); + rc = ntb_transport_init(net_softc.ntb); + if (rc != 0) { + printf("ntb: Cannot init transport: %d\n", rc); + return (rc); + } 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); } @@ -498,83 +536,107 @@ static int ntb_transport_init(struct ntb_softc *ntb) { struct ntb_transport_ctx *nt = &net_softc; + struct ntb_transport_mw *mw; + uint64_t qp_bitmap; int rc; - uint8_t i; + unsigned i; nt->mw_count = ntb_mw_count(ntb); - if (max_num_clients == 0) - nt->qp_count = MIN(ntb_get_max_cbs(ntb), ntb_mw_count(ntb)); - else - nt->qp_count = MIN(ntb_get_max_cbs(ntb), max_num_clients); + 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); + if (rc != 0) + goto err; + + mw->buff_size = 0; + mw->xlat_size = 0; + mw->virt_addr = 0; + 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")); - 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->qp_vec = malloc(nt->qp_count * sizeof(*nt->qp_vec), M_NTB_IF, M_WAITOK | M_ZERO); - KASSERT(nt->qp_count <= QP_SETSIZE, ("invalid qp_count")); - 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); - 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_link_is_up(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); return (0); err: free(nt->qp_vec, M_NTB_IF); - ntb_unregister_transport(ntb); + nt->qp_vec = NULL; return (rc); } static void -ntb_transport_free(void *transport) +ntb_transport_free(struct ntb_transport_ctx *nt) { - struct ntb_transport_ctx *nt = transport; struct ntb_softc *ntb = nt->ntb; + struct _qpset qp_bitmap_alloc; uint8_t i; ntb_transport_link_cleanup(nt); callout_drain(&nt->link_work); - /* verify that all the qps are freed */ + 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, &nt->qp_bitmap)) + 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_MAX_NUM_MW; i++) + for (i = 0; i < nt->mw_count; i++) ntb_free_mw(nt, i); free(nt->qp_vec, M_NTB_IF); - ntb_unregister_transport(ntb); } static void 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, mw_count; + 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 = ntb_mw_count(nt->ntb); + mw_count = nt->mw_count; mw_num = QP_TO_MW(nt, qp_num); + mw = &nt->mw_vec[mw_num]; qp = &nt->qp_vec[qp_num]; qp->qp_num = qp_num; @@ -589,13 +651,22 @@ ntb_transport_init_queue(struct ntb_tran else num_qps_mw = nt->qp_count / mw_count; - tx_size = 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 / mw_count * tx_size)); + 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 = (char *)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 -= sizeof(struct ntb_rx_info); + qp->rx_info = (void *)((char *)qp->tx_mw + tx_size); - qp->tx_mw = qp->rx_info + 1; /* Due to house-keeping, there must be at least 2 buffs */ qp->tx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header), tx_size / 2); @@ -608,7 +679,8 @@ ntb_transport_init_queue(struct ntb_tran 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_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_pend_q); STAILQ_INIT(&qp->rx_free_q); @@ -625,7 +697,14 @@ 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))) free(entry, M_NTB_IF); @@ -636,7 +715,7 @@ ntb_transport_free_queue(struct ntb_tran 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); } /** @@ -654,37 +733,34 @@ 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_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_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->qp_vec[free_queue]; + clear_bit(1ull << 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; @@ -692,26 +768,13 @@ ntb_transport_create_queue(void *data, s } 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); } /** @@ -813,7 +876,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; @@ -824,20 +887,31 @@ 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; - CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset); - if (entry->buf != NULL) - m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset); - + /* 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; hdr->len = entry->len; /* TODO: replace with bus_space_write */ hdr->ver = qp->tx_pkts; /* TODO: replace with bus_space_write */ - wmb(); + + /* This piece is ntb_memcpy_tx() */ + CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset); + if (entry->buf != NULL) { + m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset); + + /* + * Ensure that the data is fully copied before setting the + * flags + */ + wmb(); + } + + /* The rest is ntb_tx_copy_callback() */ /* TODO: replace with bus_space_write */ hdr->flags = entry->flags | IF_NTB_DESC_DONE_FLAG; @@ -879,8 +953,8 @@ ntb_rx_pendq_full(void *arg) ntb_transport_rxc_db(arg, 0); } -static int -ntb_transport_rxc_db(void *arg, int dummy __unused) +static void +ntb_transport_rxc_db(void *arg, int pending __unused) { struct ntb_transport_qp *qp = arg; uint64_t i; @@ -890,9 +964,9 @@ ntb_transport_rxc_db(void *arg, int dumm * Limit the number of packets processed in a single interrupt to * provide fairness to others */ - mtx_lock(&qp->transport->rx_lock); CTR0(KTR_NTB, "RX: transport_rx"); - for (i = 0; i < MIN(qp->rx_max_entry, INT_MAX); i++) { + mtx_lock(&qp->transport->rx_lock); + for (i = 0; i < qp->rx_max_entry; i++) { rc = ntb_process_rxc(qp); if (rc != 0) { CTR0(KTR_NTB, "RX: process_rxc failed"); @@ -901,7 +975,20 @@ ntb_transport_rxc_db(void *arg, int dumm } mtx_unlock(&qp->transport->rx_lock); - return ((int)i); + if (i == qp->rx_max_entry) + taskqueue_enqueue(taskqueue_swi, &qp->rxc_db_work); + else if ((ntb_db_read(qp->ntb) & (1ull << qp->qp_num)) != 0) { + /* If db is set, clear it and read it back to commit clear. */ + ntb_db_clear(qp->ntb, 1ull << qp->qp_num); + (void)ntb_db_read(qp->ntb); + + /* + * An interrupt may have arrived between finishing + * ntb_process_rxc and clearing the doorbell bit: there might + * be some more work to do. + */ + taskqueue_enqueue(taskqueue_swi, &qp->rxc_db_work); + } } static int @@ -918,66 +1005,61 @@ ntb_process_rxc(struct ntb_transport_qp sizeof(struct ntb_payload_header)); CTR1(KTR_NTB, "RX: process_rxc rx_index = %u", qp->rx_index); - entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); - if (entry == NULL) { - qp->rx_err_no_buf++; - CTR0(KTR_NTB, "RX: No entries in rx_pend_q"); - return (ENOMEM); - } - callout_stop(&qp->rx_full); - CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry); - if ((hdr->flags & IF_NTB_DESC_DONE_FLAG) == 0) { - CTR1(KTR_NTB, - "RX: hdr not done. Returning entry %p to rx_pend_q", entry); - ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); + CTR0(KTR_NTB, "RX: hdr not done"); qp->rx_ring_empty++; return (EAGAIN); } - if (hdr->ver != (uint32_t) qp->rx_pkts) { - CTR3(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). " - "Returning entry %p to rx_pend_q", hdr->ver, qp->rx_pkts, - entry); - ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); + if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) { + CTR0(KTR_NTB, "RX: link down"); + ntb_qp_link_down(qp); + hdr->flags = 0; + return (EAGAIN); + } + + if (hdr->ver != (uint32_t)qp->rx_pkts) { + CTR2(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). " + "Returning entry %p to rx_pend_q", hdr->ver, qp->rx_pkts); qp->rx_err_ver++; return (EIO); } - if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) { - ntb_qp_link_down(qp); - CTR1(KTR_NTB, - "RX: link down. adding entry %p back to rx_pend_q", entry); - ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); - goto out; + entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); + if (entry == NULL) { + qp->rx_err_no_buf++; + CTR0(KTR_NTB, "RX: No entries in rx_pend_q"); + return (EAGAIN); } + callout_stop(&qp->rx_full); + CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry); - if (hdr->len <= entry->len) { - entry->len = hdr->len; - ntb_rx_copy_task(qp, entry, offset); - } else { - CTR1(KTR_NTB, - "RX: len too long. Returning entry %p to rx_pend_q", entry); - ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); + entry->x_hdr = hdr; + entry->index = qp->rx_index; + if (hdr->len > entry->len) { + CTR2(KTR_NTB, "RX: len too long. Wanted %ju got %ju", + (uintmax_t)hdr->len, (uintmax_t)entry->len); qp->rx_err_oflow++; - } - qp->rx_bytes += hdr->len; - qp->rx_pkts++; - CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts); + entry->len = -EIO; + entry->flags |= IF_NTB_DESC_DONE_FLAG; + ntb_list_add(&qp->ntb_rx_free_q_lock, entry, &qp->rx_free_q); + taskqueue_enqueue(taskqueue_swi, &qp->rx_completion_task); + } else { + qp->rx_bytes += hdr->len; + qp->rx_pkts++; -out: - /* Ensure that the data is globally visible before clearing the flag */ - wmb(); - hdr->flags = 0; - /* TODO: replace with bus_space_write */ - qp->rx_info->entry = qp->rx_index; + CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts); + + entry->len = hdr->len; + + ntb_rx_copy_task(qp, entry, offset); + } qp->rx_index++; qp->rx_index %= qp->rx_max_entry; - return (0); } @@ -995,6 +1077,12 @@ ntb_rx_copy_task(struct ntb_transport_qp entry->buf = (void *)m; + /* Ensure that the data is globally visible before clearing the flag */ + wmb(); + entry->x_hdr->flags = 0; + /* TODO: replace with bus_space_write */ + qp->rx_info->entry = qp->rx_index; + CTR2(KTR_NTB, "RX: copied entry %p to mbuf %p. Adding entry to rx_free_q", entry, m); @@ -1004,7 +1092,7 @@ ntb_rx_copy_task(struct ntb_transport_qp } static void -ntb_rx_completion_task(void *arg, int pending) +ntb_complete_rxc(void *arg, int pending) { struct ntb_transport_qp *qp = arg; struct mbuf *m; @@ -1033,25 +1121,52 @@ ntb_rx_completion_task(void *arg, int pe } } +static void +ntb_transport_doorbell_callback(void *data, int vector) +{ + struct ntb_transport_ctx *nt = data; + struct ntb_transport_qp *qp; + struct _qpset db_bits; + uint64_t vec_mask; + unsigned qp_num; + + BIT_COPY(QP_SETSIZE, &nt->qp_bitmap, &db_bits); + BIT_NAND(QP_SETSIZE, &db_bits, &nt->qp_bitmap_free); + + vec_mask = ntb_db_vector_mask(nt->ntb, vector); + while (vec_mask != 0) { + qp_num = ffsl(vec_mask); + /* i386 doesn't have ffsll(), fake it */ + if (qp_num == 0) { + qp_num = ffsl(vec_mask >> 32); + KASSERT(qp_num != 0, ("ffs")); + qp_num += 32; + } + qp_num--; + + if (test_bit(qp_num, &db_bits)) { + qp = &nt->qp_vec[qp_num]; + taskqueue_enqueue(taskqueue_swi, &qp->rxc_db_work); + } + + vec_mask &= ~(1ull << qp_num); + } +} + /* Link Event handler */ static void -ntb_transport_event_callback(void *data, enum ntb_hw_event event) +ntb_transport_event_callback(void *data) { struct ntb_transport_ctx *nt = data; - switch (event) { - case NTB_EVENT_HW_LINK_UP: + if (ntb_link_is_up(nt->ntb, NULL, NULL)) { if (bootverbose) device_printf(ntb_get_device(nt->ntb), "HW link up\n"); callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt); - break; - case NTB_EVENT_HW_LINK_DOWN: + } else { if (bootverbose) device_printf(ntb_get_device(nt->ntb), "HW link down\n"); ntb_transport_link_cleanup(nt); - break; - default: - panic("ntb: Unknown NTB event"); } } @@ -1062,72 +1177,48 @@ ntb_transport_link_work(void *arg) struct ntb_transport_ctx *nt = arg; struct ntb_softc *ntb = nt->ntb; struct ntb_transport_qp *qp; - uint64_t val64; - uint32_t val, i, num_mw; + uint64_t val64, size; + uint32_t val; + unsigned i; int rc; - num_mw = ntb_mw_count(ntb); - /* send the local info, in the opposite order of the way we read it */ - for (i = 0; i < num_mw; i++) { - rc = ntb_peer_spad_write(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2), - (uint64_t)ntb_get_mw_size(ntb, i) >> 32); - if (rc != 0) - goto out; + for (i = 0; i < nt->mw_count; i++) { + size = nt->mw_vec[i].phys_size; - rc = ntb_peer_spad_write(ntb, IF_NTB_MW0_SZ_LOW + (i * 2), - (uint32_t)ntb_get_mw_size(ntb, i)); - if (rc != 0) - goto out; + if (max_mw_size != 0 && size > max_mw_size) + size = max_mw_size; + + ntb_peer_spad_write(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2), + size >> 32); + ntb_peer_spad_write(ntb, IF_NTB_MW0_SZ_LOW + (i * 2), size); } - rc = ntb_peer_spad_write(ntb, IF_NTB_NUM_MWS, num_mw); - if (rc != 0) - goto out; + ntb_peer_spad_write(ntb, IF_NTB_NUM_MWS, nt->mw_count); - rc = ntb_peer_spad_write(ntb, IF_NTB_NUM_QPS, nt->qp_count); - if (rc != 0) - goto out; + ntb_peer_spad_write(ntb, IF_NTB_NUM_QPS, nt->qp_count); - rc = ntb_peer_spad_write(ntb, IF_NTB_VERSION, NTB_TRANSPORT_VERSION); - if (rc != 0) - goto out; + ntb_peer_spad_write(ntb, IF_NTB_VERSION, NTB_TRANSPORT_VERSION); /* Query the remote side for its info */ - rc = ntb_spad_read(ntb, IF_NTB_VERSION, &val); - if (rc != 0) - goto out; - + val = 0; + ntb_spad_read(ntb, IF_NTB_VERSION, &val); if (val != NTB_TRANSPORT_VERSION) goto out; - rc = ntb_spad_read(ntb, IF_NTB_NUM_QPS, &val); - if (rc != 0) - goto out; - + ntb_spad_read(ntb, IF_NTB_NUM_QPS, &val); if (val != nt->qp_count) goto out; - rc = ntb_spad_read(ntb, IF_NTB_NUM_MWS, &val); - if (rc != 0) - goto out; - - if (val != num_mw) + ntb_spad_read(ntb, IF_NTB_NUM_MWS, &val); + if (val != nt->mw_count) goto out; - for (i = 0; i < num_mw; i++) { - rc = ntb_spad_read(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2), - &val); - if (rc != 0) - goto free_mws; - + for (i = 0; i < nt->mw_count; i++) { + ntb_spad_read(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2), &val); val64 = (uint64_t)val << 32; - rc = ntb_spad_read(ntb, IF_NTB_MW0_SZ_LOW + (i * 2), - &val); - if (rc != 0) - goto free_mws; - + ntb_spad_read(ntb, IF_NTB_MW0_SZ_LOW + (i * 2), &val); val64 |= val; rc = ntb_set_mw(nt, i, val64); @@ -1151,33 +1242,40 @@ ntb_transport_link_work(void *arg) return; free_mws: - for (i = 0; i < NTB_MAX_NUM_MW; i++) + for (i = 0; i < nt->mw_count; i++) ntb_free_mw(nt, i); out: - if (ntb_link_is_up(ntb)) + if (ntb_link_is_up(ntb, NULL, NULL)) callout_reset(&nt->link_work, NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_transport_link_work, nt); } static int -ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, unsigned int size) +ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, unsigned size) { struct ntb_transport_mw *mw = &nt->mw_vec[num_mw]; + unsigned xlat_size, buff_size; + int rc; + + xlat_size = roundup(size, mw->xlat_align_size); + buff_size = roundup(size, mw->xlat_align); /* No need to re-setup */ - if (mw->xlat_size == size) + if (mw->xlat_size == xlat_size) return (0); - if (mw->xlat_size != 0) + if (mw->buff_size != 0) ntb_free_mw(nt, num_mw); - /* Alloc memory for receiving data. Must be 4k aligned */ - mw->xlat_size = size; + /* Alloc memory for receiving data. Must be aligned */ + mw->xlat_size = xlat_size; + mw->buff_size = buff_size; - mw->virt_addr = contigmalloc(mw->xlat_size, M_NTB_IF, M_ZERO, 0, - BUS_SPACE_MAXADDR, mw->xlat_size, 0); + mw->virt_addr = contigmalloc(mw->buff_size, M_NTB_IF, M_ZERO, 0, + BUS_SPACE_MAXADDR, mw->xlat_align, 0); if (mw->virt_addr == NULL) { mw->xlat_size = 0; + mw->buff_size = 0; printf("ntb: Unable to allocate MW buffer of size %zu\n", mw->xlat_size); return (ENOMEM); @@ -1190,7 +1288,7 @@ ntb_set_mw(struct ntb_transport_ctx *nt, * requested. XXX: This may not be needed -- brought in for parity * with the Linux driver. */ - if (mw->dma_addr % size != 0) { + if (mw->dma_addr % mw->xlat_align != 0) { device_printf(ntb_get_device(nt->ntb), "DMA memory 0x%jx not aligned to BAR size 0x%x\n", (uintmax_t)mw->dma_addr, size); @@ -1199,7 +1297,13 @@ ntb_set_mw(struct ntb_transport_ctx *nt, } /* Notify HW the memory location of the receive buffer */ - ntb_set_mw_addr(nt->ntb, num_mw, mw->dma_addr); + rc = ntb_mw_set_trans(nt->ntb, num_mw, mw->dma_addr, mw->xlat_size); + if (rc) { + device_printf(ntb_get_device(nt->ntb), + "Unable to set mw%d translation", num_mw); + ntb_free_mw(nt, num_mw); + return (rc); + } return (0); } @@ -1212,33 +1316,41 @@ ntb_free_mw(struct ntb_transport_ctx *nt if (mw->virt_addr == NULL) return; + ntb_mw_clear_trans(nt->ntb, num_mw); contigfree(mw->virt_addr, mw->xlat_size, M_NTB_IF); + mw->xlat_size = 0; + mw->buff_size = 0; mw->virt_addr = NULL; } -static void +static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, unsigned int qp_num) { struct ntb_transport_qp *qp = &nt->qp_vec[qp_num]; + struct ntb_transport_mw *mw; void *offset; - unsigned int rx_size, num_qps_mw; - uint8_t mw_num, mw_count; - unsigned int i; + uint64_t i; + size_t rx_size; + unsigned num_qps_mw, mw_num, mw_count; - mw_count = ntb_mw_count(nt->ntb); + mw_count = nt->mw_count; mw_num = QP_TO_MW(nt, qp_num); + mw = &nt->mw_vec[mw_num]; + + if (mw->virt_addr == NULL) + return (ENOMEM); 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->qp_count / mw_count; - rx_size = nt->mw_vec[mw_num].xlat_size / num_qps_mw; - qp->remote_rx_info = (void *)((uint8_t *)nt->mw_vec[mw_num].virt_addr + - (qp_num / mw_count * rx_size)); + rx_size = mw->xlat_size / num_qps_mw; + qp->rx_buff = (char *)mw->virt_addr + rx_size * qp_num / mw_count; rx_size -= sizeof(struct ntb_rx_info); - qp->rx_buff = qp->remote_rx_info + 1; + qp->remote_rx_info = (void*)((char *)qp->rx_buff + rx_size); + /* Due to house-keeping, there must be at least 2 buffs */ qp->rx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header), rx_size / 2); @@ -1247,7 +1359,7 @@ ntb_transport_setup_qp_mw(struct ntb_tra qp->remote_rx_info->entry = qp->rx_max_entry - 1; - /* setup the hdr offsets with 0's */ + /* Set up the hdr offsets with 0s */ for (i = 0; i < qp->rx_max_entry; i++) { offset = (void *)((uint8_t *)qp->rx_buff + qp->rx_max_frame * (i + 1) - @@ -1258,6 +1370,8 @@ ntb_transport_setup_qp_mw(struct ntb_tra qp->rx_pkts = 0; qp->tx_pkts = 0; qp->tx_index = 0; + + return (0); } static void @@ -1266,46 +1380,51 @@ ntb_qp_link_work(void *arg) struct ntb_transport_qp *qp = arg; struct ntb_softc *ntb = qp->ntb; struct ntb_transport_ctx *nt = qp->transport; - int rc, val; - + int val; - rc = ntb_peer_spad_read(ntb, IF_NTB_QP_LINKS, &val); - if (rc != 0) - return; + ntb_spad_read(ntb, IF_NTB_QP_LINKS, &val); - rc = ntb_peer_spad_write(ntb, IF_NTB_QP_LINKS, val | 1 << qp->qp_num); + ntb_peer_spad_write(ntb, IF_NTB_QP_LINKS, val | (1ull << qp->qp_num)); /* query remote spad for qp ready bits */ - rc = ntb_spad_read(ntb, IF_NTB_QP_LINKS, &val); + ntb_peer_spad_read(ntb, IF_NTB_QP_LINKS, &val); /* See if the remote side is up */ - if ((1 << qp->qp_num & val) != 0) { + if ((val & (1ull << qp->qp_num)) != 0) { + if (bootverbose) + device_printf(ntb_get_device(ntb), "qp link up\n"); qp->link_is_up = true; + if (qp->event_handler != NULL) qp->event_handler(qp->cb_data, NTB_LINK_UP); - if (bootverbose) - device_printf(ntb_get_device(ntb), "qp link up\n"); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201510182020.t9IKKvjR093144>