]> xenbits.xensource.com Git - people/julieng/freebsd.git/commitdiff
NTB: Add variable number MW, DB CB support code
authorcem <cem@FreeBSD.org>
Thu, 15 Oct 2015 23:45:43 +0000 (23:45 +0000)
committercem <cem@FreeBSD.org>
Thu, 15 Oct 2015 23:45:43 +0000 (23:45 +0000)
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

sys/dev/ntb/if_ntb/if_ntb.c
sys/dev/ntb/ntb_hw/ntb_hw.c
sys/dev/ntb/ntb_hw/ntb_hw.h

index 169296564d74edf117e44e00509da715baf1896d..8b1fa7a5bd63e52528c02af9f3459d8cbf1cf6fa 100644 (file)
@@ -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;
index 58ff611ff7a09090afe96cff98d4e5eb102e453f..c91a1e2ad43e81a9b9128766ab1f4dc56b461778 100644 (file)
@@ -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)) {
index 7abd10c54dbf4a335b2804ea0047ccc0b37fc494..b6b85a02448e506409339b095e154cc9717ade16 100644 (file)
@@ -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);