Author: cem
Date: Sun Oct 18 20:20:29 2015
New Revision: 289543
URL: https://svnweb.freebsd.org/changeset/base/289543

Log:
  NTB: Flesh out the rest of the xeon_setup_b2b_mw changes
  
  Move all Xeon secondary register setup to the setup_b2b_mw routine.  We
  use subroutines to make it a bit less wordy than the Linux version.
  
  Adds a new tunable, 'hw.ntb.b2b_mw_share'.  By default, it is off
  (zero).  If both sides enable it (any non-zero value), the NTB driver
  attempts to use only half of a memory window for remote register MMIO
  access.
  
  This is still part of the large Linux rewrite (e26a5843).
  
  Authored by:  Allen Hubbe
  Obtained from:        Linux (e26a5843) (Dual BSD/GPL driver)
  Sponsored by: EMC / Isilon Storage Division

Modified:
  head/sys/dev/ntb/ntb_hw/ntb_hw.c
  head/sys/dev/ntb/ntb_hw/ntb_regs.h

Modified: head/sys/dev/ntb/ntb_hw/ntb_hw.c
==============================================================================
--- head/sys/dev/ntb/ntb_hw/ntb_hw.c    Sun Oct 18 20:20:20 2015        
(r289542)
+++ head/sys/dev/ntb/ntb_hw/ntb_hw.c    Sun Oct 18 20:20:29 2015        
(r289543)
@@ -99,6 +99,13 @@ struct ntb_pci_bar_info {
        vm_paddr_t              pbase;
        void                    *vbase;
        u_long                  size;
+
+       /* Configuration register offsets */
+       uint32_t                psz_off;
+       uint32_t                ssz_off;
+       uint32_t                sbarbase_off;
+       uint32_t                sbarlmt_off;
+       uint32_t                pbarxlat_off;
 };
 
 struct ntb_int_info {
@@ -178,6 +185,7 @@ struct ntb_softc {
        /* Offset of peer bar0 in B2B BAR */
        uint64_t                        b2b_off;
        /* Memory window used to access peer bar0 */
+#define B2B_MW_DISABLED                        UINT8_MAX
        uint8_t                         b2b_mw_idx;
 
        uint8_t                         mw_count;
@@ -277,7 +285,12 @@ static int ntb_xeon_init_dev(struct ntb_
 static int ntb_soc_init_dev(struct ntb_softc *ntb);
 static void ntb_teardown_xeon(struct ntb_softc *ntb);
 static void configure_soc_secondary_side_bars(struct ntb_softc *ntb);
-static void configure_xeon_secondary_side_bars(struct ntb_softc *ntb);
+static void xeon_reset_sbar_size(struct ntb_softc *, enum ntb_bar idx,
+    enum ntb_bar regbar);
+static void xeon_set_sbar_base_and_limit(struct ntb_softc *,
+    uint64_t base_addr, enum ntb_bar idx, enum ntb_bar regbar);
+static void xeon_set_pbar_xlat(struct ntb_softc *, uint64_t base_addr,
+    enum ntb_bar idx);
 static int xeon_setup_b2b_mw(struct ntb_softc *,
     const struct ntb_b2b_addr *addr, const struct ntb_b2b_addr *peer_addr);
 static void soc_link_hb(void *arg);
@@ -418,7 +431,7 @@ ntb_attach(device_t device)
        ntb->device = device;
        ntb->type = p->type;
        ntb->features = p->features;
-       ntb->b2b_mw_idx = UINT8_MAX;
+       ntb->b2b_mw_idx = B2B_MW_DISABLED;
 
        /* Heartbeat timer for NTB_SOC since there is no link interrupt */
        callout_init(&ntb->heartbeat_timer, 1);
@@ -488,7 +501,8 @@ static inline enum ntb_bar
 ntb_mw_to_bar(struct ntb_softc *ntb, unsigned mw)
 {
 
-       KASSERT(mw < ntb->mw_count || (mw != UINT8_MAX && mw == 
ntb->b2b_mw_idx),
+       KASSERT(mw < ntb->mw_count ||
+           (mw != B2B_MW_DISABLED && mw == ntb->b2b_mw_idx),
            ("%s: mw:%u > count:%u", __func__, mw, (unsigned)ntb->mw_count));
 
        return (ntb->reg->mw_bar[mw]);
@@ -508,12 +522,24 @@ ntb_map_pci_bars(struct ntb_softc *ntb)
        rc = map_memory_window_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_1]);
        if (rc != 0)
                goto out;
+       ntb->bar_info[NTB_B2B_BAR_1].psz_off = XEON_PBAR23SZ_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_1].ssz_off = XEON_SBAR23SZ_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_1].sbarbase_off = XEON_SBAR2BASE_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_1].sbarlmt_off = XEON_SBAR2LMT_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_1].pbarxlat_off = XEON_PBAR2XLAT_OFFSET;
 
        ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4);
+       /* XXX Are shared MW B2Bs write-combining? */
        if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP) && !HAS_FEATURE(NTB_SPLIT_BAR))
                rc = map_mmr_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_2]);
        else
                rc = map_memory_window_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_2]);
+       ntb->bar_info[NTB_B2B_BAR_2].psz_off = XEON_PBAR4SZ_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_2].ssz_off = XEON_SBAR4SZ_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_2].sbarbase_off = XEON_SBAR4BASE_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_2].sbarlmt_off = XEON_SBAR4LMT_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_2].pbarxlat_off = XEON_PBAR4XLAT_OFFSET;
+
        if (!HAS_FEATURE(NTB_SPLIT_BAR))
                goto out;
 
@@ -522,6 +548,11 @@ ntb_map_pci_bars(struct ntb_softc *ntb)
                rc = map_mmr_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_3]);
        else
                rc = map_memory_window_bar(ntb, &ntb->bar_info[NTB_B2B_BAR_3]);
+       ntb->bar_info[NTB_B2B_BAR_3].psz_off = XEON_PBAR5SZ_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_3].ssz_off = XEON_SBAR5SZ_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_3].sbarbase_off = XEON_SBAR5BASE_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_3].sbarlmt_off = XEON_SBAR5LMT_OFFSET;
+       ntb->bar_info[NTB_B2B_BAR_3].pbarxlat_off = XEON_PBAR5XLAT_OFFSET;
 
 out:
        if (rc != 0)
@@ -1117,35 +1148,11 @@ ntb_xeon_init_dev(struct ntb_softc *ntb)
         * which may hang the system.  To workaround this use the second memory
         * window to access the interrupt and scratch pad registers on the
         * remote system.
-        *
-        * There is another HW errata on the limit registers -- they can only
-        * be written when the base register is (?)4GB aligned and < 32-bit.
-        * This should already be the case based on the driver defaults, but
-        * write the limit registers first just in case.
         */
-       if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) {
-               /* Reserve the last MW for mapping remote spad */
+       if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
+               /* Use the last MW for mapping remote spad */
                ntb->b2b_mw_idx = ntb->mw_count - 1;
-               ntb->mw_count--;
-               /*
-                * Set the Limit register to 4k, the minimum size, to prevent
-                * an illegal access.
-                */
-               if (HAS_FEATURE(NTB_SPLIT_BAR)) {
-                       ntb_reg_write(4, XEON_PBAR4LMT_OFFSET, 0);
-                       ntb_reg_write(4, XEON_PBAR5LMT_OFFSET,
-                           ntb_get_mw_size(ntb, ntb->b2b_mw_idx) + 0x1000);
-               } else
-                       ntb_reg_write(8, XEON_PBAR4LMT_OFFSET,
-                           ntb_get_mw_size(ntb, ntb->b2b_mw_idx) + 0x1000);
-       } else {
-               /*
-                * Disable the limit register, just in case it is set to
-                * something silly.  A 64-bit write will also clear PBAR5LMT in
-                * split-bar mode, and this is desired.
-                */
-               ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0);
-
+       else if (HAS_FEATURE(NTB_B2BDOORBELL_BIT14))
                /*
                 * HW Errata on bit 14 of b2bdoorbell register.  Writes will 
not be
                 * mirrored to the remote system.  Shrink the number of bits by 
one,
@@ -1154,9 +1161,7 @@ ntb_xeon_init_dev(struct ntb_softc *ntb)
                 * On REGS_THRU_MW errata mode, we don't use the b2bdoorbell 
register
                 * anyway.  Nor for non-B2B connection types.
                 */
-               if (HAS_FEATURE(NTB_B2BDOORBELL_BIT14))
-                       ntb->db_count = XEON_DB_COUNT - 1;
-       }
+               ntb->db_count = XEON_DB_COUNT - 1;
 
        ntb->db_valid_mask = (1ull << ntb->db_count) - 1;
 
@@ -1244,44 +1249,198 @@ configure_soc_secondary_side_bars(struct
        }
 }
 
+
+/*
+ * When working around Xeon SDOORBELL errata by remapping remote registers in a
+ * MW, limit the B2B MW to half a MW.  By sharing a MW, half the shared MW
+ * remains for use by a higher layer.
+ *
+ * Will only be used if working around SDOORBELL errata and the BIOS-configured
+ * MW size is sufficiently large.
+ */
+static unsigned int ntb_b2b_mw_share;
+SYSCTL_UINT(_hw_ntb, OID_AUTO, b2b_mw_share, CTLFLAG_RDTUN, &ntb_b2b_mw_share,
+    0, "If enabled (non-zero), prefer to share half of the B2B peer register "
+    "MW with higher level consumers.  Both sides of the NTB MUST set the same "
+    "value here.");
+
+static void
+xeon_reset_sbar_size(struct ntb_softc *ntb, enum ntb_bar idx,
+    enum ntb_bar regbar)
+{
+       struct ntb_pci_bar_info *bar;
+       uint8_t bar_sz;
+
+       if (!HAS_FEATURE(NTB_SPLIT_BAR) && idx >= NTB_B2B_BAR_3)
+               return;
+
+       bar = &ntb->bar_info[idx];
+       bar_sz = pci_read_config(ntb->device, bar->psz_off, 1);
+       if (idx == regbar) {
+               if (ntb->b2b_off != 0)
+                       bar_sz--;
+               else
+                       bar_sz = 0;
+       }
+       pci_write_config(ntb->device, bar->ssz_off, bar_sz, 1);
+       bar_sz = pci_read_config(ntb->device, bar->ssz_off, 1);
+       (void)bar_sz;
+}
+
+static void
+xeon_set_sbar_base_and_limit(struct ntb_softc *ntb, uint64_t base_addr,
+    enum ntb_bar idx, enum ntb_bar regbar)
+{
+       struct ntb_pci_bar_info *bar;
+       vm_paddr_t bar_addr;
+
+       bar = &ntb->bar_info[idx];
+       bar_addr = base_addr + ((idx == regbar) ? ntb->b2b_off : 0);
+
+       if (HAS_FEATURE(NTB_SPLIT_BAR) && idx >= NTB_B2B_BAR_2) {
+               ntb_reg_write(4, bar->sbarbase_off, bar_addr);
+               ntb_reg_write(4, bar->sbarlmt_off, bar_addr);
+               bar_addr = ntb_reg_read(4, bar->sbarbase_off);
+               (void)bar_addr;
+               bar_addr = ntb_reg_read(4, bar->sbarlmt_off);
+       } else {
+               ntb_reg_write(8, bar->sbarbase_off, bar_addr);
+               ntb_reg_write(8, bar->sbarlmt_off, bar_addr);
+               bar_addr = ntb_reg_read(8, bar->sbarbase_off);
+               (void)bar_addr;
+               bar_addr = ntb_reg_read(8, bar->sbarlmt_off);
+       }
+       (void)bar_addr;
+}
+
+static void
+xeon_set_pbar_xlat(struct ntb_softc *ntb, uint64_t base_addr, enum ntb_bar idx)
+{
+       struct ntb_pci_bar_info *bar;
+
+       bar = &ntb->bar_info[idx];
+       if (HAS_FEATURE(NTB_SPLIT_BAR) && idx >= NTB_B2B_BAR_2) {
+               ntb_reg_write(4, bar->pbarxlat_off, base_addr);
+               base_addr = ntb_reg_read(4, bar->pbarxlat_off);
+       } else {
+               ntb_reg_write(8, bar->pbarxlat_off, base_addr);
+               base_addr = ntb_reg_read(8, bar->pbarxlat_off);
+       }
+       (void)base_addr;
+}
+
 static int
 xeon_setup_b2b_mw(struct ntb_softc *ntb, const struct ntb_b2b_addr *addr,
     const struct ntb_b2b_addr *peer_addr)
 {
-
-       /* Local addresses */
-       ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, addr->bar2_addr64);
-       if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
-               ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, addr->bar0_addr);
-       else {
-               if (HAS_FEATURE(NTB_SPLIT_BAR)) {
-                       ntb_reg_write(4, XEON_PBAR4XLAT_OFFSET,
-                           addr->bar4_addr32);
-                       ntb_reg_write(4, XEON_PBAR5XLAT_OFFSET,
-                           addr->bar5_addr32);
-               } else
-                       ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
-                           addr->bar4_addr64);
-               /*
-                * B2B_XLAT_OFFSET is a 64-bit register but can only be
-                * written 32 bits at a time.
-                */
-               ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL,
-                   addr->bar0_addr & 0xffffffff);
-               ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, addr->bar0_addr >> 32);
+       struct ntb_pci_bar_info *b2b_bar;
+       vm_size_t bar_size;
+       uint64_t bar_addr;
+       enum ntb_bar b2b_bar_num, i;
+
+       if (ntb->b2b_mw_idx == B2B_MW_DISABLED) {
+               b2b_bar = NULL;
+               b2b_bar_num = NTB_CONFIG_BAR;
+               ntb->b2b_off = 0;
+       } else {
+               b2b_bar_num = ntb_mw_to_bar(ntb, ntb->b2b_mw_idx);
+               KASSERT(b2b_bar_num > 0 && b2b_bar_num < NTB_MAX_BARS,
+                   ("invalid b2b mw bar"));
+
+               b2b_bar = &ntb->bar_info[b2b_bar_num];
+               bar_size = b2b_bar->size;
+
+               if (ntb_b2b_mw_share != 0 &&
+                   (bar_size >> 1) >= XEON_B2B_MIN_SIZE)
+                       ntb->b2b_off = bar_size >> 1;
+               else if (bar_size >= XEON_B2B_MIN_SIZE) {
+                       ntb->b2b_off = 0;
+                       ntb->mw_count--;
+               } else {
+                       device_printf(ntb->device,
+                           "B2B bar size is too small!\n");
+                       return (EIO);
+               }
        }
 
-       /* Peer addresses */
-       ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, peer_addr->bar0_addr);
-       ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, peer_addr->bar2_addr64);
+       /*
+        * Reset the secondary bar sizes to match the primary bar sizes.
+        * (Except, disable or halve the size of the B2B secondary bar.)
+        */
+       for (i = NTB_B2B_BAR_1; i < NTB_MAX_BARS; i++)
+               xeon_reset_sbar_size(ntb, i, b2b_bar_num);
+
+       bar_addr = 0;
+       if (b2b_bar_num == NTB_CONFIG_BAR)
+               bar_addr = addr->bar0_addr;
+       else if (b2b_bar_num == NTB_B2B_BAR_1)
+               bar_addr = addr->bar2_addr64;
+       else if (b2b_bar_num == NTB_B2B_BAR_2 && !HAS_FEATURE(NTB_SPLIT_BAR))
+               bar_addr = addr->bar4_addr64;
+       else if (b2b_bar_num == NTB_B2B_BAR_2)
+               bar_addr = addr->bar4_addr32;
+       else if (b2b_bar_num == NTB_B2B_BAR_3)
+               bar_addr = addr->bar5_addr32;
+       else
+               KASSERT(false, ("invalid bar"));
+
+       ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, bar_addr);
+
+       /*
+        * Other SBARs are normally hit by the PBAR xlat, except for the b2b
+        * register BAR.  The B2B BAR is either disabled above or configured
+        * half-size.  It starts at PBAR xlat + offset.
+        *
+        * Also set up incoming BAR limits == base (zero length window).
+        */
+       xeon_set_sbar_base_and_limit(ntb, addr->bar2_addr64, NTB_B2B_BAR_1,
+           b2b_bar_num);
+       if (HAS_FEATURE(NTB_SPLIT_BAR)) {
+               xeon_set_sbar_base_and_limit(ntb, addr->bar4_addr32,
+                   NTB_B2B_BAR_2, b2b_bar_num);
+               xeon_set_sbar_base_and_limit(ntb, addr->bar5_addr32,
+                   NTB_B2B_BAR_3, b2b_bar_num);
+       } else
+               xeon_set_sbar_base_and_limit(ntb, addr->bar4_addr64,
+                   NTB_B2B_BAR_2, b2b_bar_num);
+
+       /* Zero incoming translation addrs */
+       ntb_reg_write(8, XEON_SBAR2XLAT_OFFSET, 0);
+       ntb_reg_write(8, XEON_SBAR4XLAT_OFFSET, 0);
+
+       /* Zero outgoing translation limits (whole bar size windows) */
+       ntb_reg_write(8, XEON_PBAR2LMT_OFFSET, 0);
+       ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0);
+
+       /* Set outgoing translation offsets */
+       xeon_set_pbar_xlat(ntb, peer_addr->bar2_addr64, NTB_B2B_BAR_1);
        if (HAS_FEATURE(NTB_SPLIT_BAR)) {
-               ntb_reg_write(4, XEON_SBAR4BASE_OFFSET,
-                   peer_addr->bar4_addr32);
-               ntb_reg_write(4, XEON_SBAR5BASE_OFFSET,
-                   peer_addr->bar5_addr32);
+               xeon_set_pbar_xlat(ntb, peer_addr->bar4_addr32, NTB_B2B_BAR_2);
+               xeon_set_pbar_xlat(ntb, peer_addr->bar5_addr32, NTB_B2B_BAR_3);
        } else
-               ntb_reg_write(8, XEON_SBAR4BASE_OFFSET,
-                   peer_addr->bar4_addr64);
+               xeon_set_pbar_xlat(ntb, peer_addr->bar4_addr64, NTB_B2B_BAR_2);
+
+       /* Set the translation offset for B2B registers */
+       bar_addr = 0;
+       if (b2b_bar_num == NTB_CONFIG_BAR)
+               bar_addr = peer_addr->bar0_addr;
+       else if (b2b_bar_num == NTB_B2B_BAR_1)
+               bar_addr = peer_addr->bar2_addr64;
+       else if (b2b_bar_num == NTB_B2B_BAR_2 && !HAS_FEATURE(NTB_SPLIT_BAR))
+               bar_addr = peer_addr->bar4_addr64;
+       else if (b2b_bar_num == NTB_B2B_BAR_2)
+               bar_addr = peer_addr->bar4_addr32;
+       else if (b2b_bar_num == NTB_B2B_BAR_3)
+               bar_addr = peer_addr->bar5_addr32;
+       else
+               KASSERT(false, ("invalid bar"));
+
+       /*
+        * B2B_XLAT_OFFSET is a 64-bit register but can only be written 32 bits
+        * at a time.
+        */
+       ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, bar_addr & 0xffffffff);
+       ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, bar_addr >> 32);
        return (0);
 }
 
@@ -1966,7 +2125,8 @@ ntb_get_peer_db_addr(struct ntb_softc *n
                KASSERT((HAS_FEATURE(NTB_SPLIT_BAR) && ntb->mw_count == 2) ||
                    (!HAS_FEATURE(NTB_SPLIT_BAR) && ntb->mw_count == 1),
                    ("mw_count invalid after setup"));
-               KASSERT(ntb->b2b_mw_idx != UINT8_MAX, ("invalid b2b idx"));
+               KASSERT(ntb->b2b_mw_idx != B2B_MW_DISABLED,
+                   ("invalid b2b idx"));
 
                bar = &ntb->bar_info[ntb_mw_to_bar(ntb, ntb->b2b_mw_idx)];
                regoff = XEON_SHADOW_PDOORBELL_OFFSET;

Modified: head/sys/dev/ntb/ntb_hw/ntb_regs.h
==============================================================================
--- head/sys/dev/ntb/ntb_hw/ntb_regs.h  Sun Oct 18 20:20:20 2015        
(r289542)
+++ head/sys/dev/ntb/ntb_hw/ntb_regs.h  Sun Oct 18 20:20:29 2015        
(r289543)
@@ -135,6 +135,11 @@
 
 #define XEON_PBAR23SZ_OFFSET   0x00d0
 #define XEON_PBAR45SZ_OFFSET   0x00d1
+#define XEON_PBAR4SZ_OFFSET    0x00d1
+#define XEON_PBAR5SZ_OFFSET    0x00d5
+#define XEON_SBAR23SZ_OFFSET   0x00d2
+#define XEON_SBAR4SZ_OFFSET    0x00d3
+#define XEON_SBAR5SZ_OFFSET    0x00d6
 #define NTB_PPD_OFFSET         0x00d4
 #define XEON_PPD_CONN_TYPE     0x0003
 #define XEON_PPD_DEV_TYPE      0x0010
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to