The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ntb/ntb_hw/ntb_hw_plx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2017-2019 Alexander Motin <mav@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * The Non-Transparent Bridge (NTB) is a device that allows you to connect
   29  * two or more systems using a PCI-e links, providing remote memory access.
   30  *
   31  * This module contains a driver for NTBs in PLX/Avago/Broadcom PCIe bridges.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/kernel.h>
   39 #include <sys/systm.h>
   40 #include <sys/bus.h>
   41 #include <sys/interrupt.h>
   42 #include <sys/module.h>
   43 #include <sys/rman.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/taskqueue.h>
   46 #include <sys/tree.h>
   47 #include <vm/vm.h>
   48 #include <vm/pmap.h>
   49 #include <machine/bus.h>
   50 #include <machine/intr_machdep.h>
   51 #include <machine/resource.h>
   52 #include <dev/pci/pcireg.h>
   53 #include <dev/pci/pcivar.h>
   54 #include <dev/iommu/iommu.h>
   55 
   56 #include "../ntb.h"
   57 
   58 #define PLX_MAX_BARS            4       /* There are at most 4 data BARs. */
   59 #define PLX_NUM_SPAD            8       /* There are 8 scratchpads. */
   60 #define PLX_NUM_SPAD_PATT       4       /* Use test pattern as 4 more. */
   61 #define PLX_NUM_DB              16      /* There are 16 doorbells. */
   62 #define PLX_MAX_SPLIT           128     /* Allow are at most 128 splits. */
   63 
   64 struct ntb_plx_mw_info {
   65         int                      mw_bar;
   66         int                      mw_64bit;
   67         int                      mw_rid;
   68         struct resource         *mw_res;
   69         vm_paddr_t               mw_pbase;
   70         caddr_t                  mw_vbase;
   71         vm_size_t                mw_size;
   72         struct {
   73                 vm_memattr_t     mw_map_mode;
   74                 bus_addr_t       mw_xlat_addr;
   75                 bus_size_t       mw_xlat_size;
   76         } splits[PLX_MAX_SPLIT];
   77 };
   78 
   79 struct ntb_plx_softc {
   80         /* ntb.c context. Do not move! Must go first! */
   81         void                    *ntb_store;
   82 
   83         device_t                 dev;
   84         struct resource         *conf_res;
   85         int                      conf_rid;
   86         u_int                    ntx;           /* NTx number within chip. */
   87         u_int                    link;          /* Link v/s Virtual side. */
   88         u_int                    port;          /* Port number within chip. */
   89         u_int                    alut;          /* A-LUT is enabled for NTx */
   90         u_int                    split;         /* split BAR2 into 2^x parts */
   91 
   92         int                      int_rid;
   93         struct resource         *int_res;
   94         void                    *int_tag;
   95 
   96         struct ntb_plx_mw_info   mw_info[PLX_MAX_BARS];
   97         int                      mw_count;      /* Number of memory windows. */
   98 
   99         int                      spad_count1;   /* Number of standard spads. */
  100         int                      spad_count2;   /* Number of extra spads. */
  101         uint32_t                 spad_off1;     /* Offset of our spads. */
  102         uint32_t                 spad_off2;     /* Offset of our extra spads. */
  103         uint32_t                 spad_offp1;    /* Offset of peer spads. */
  104         uint32_t                 spad_offp2;    /* Offset of peer extra spads. */
  105 
  106         /* Parameters of window shared with peer config access in B2B mode. */
  107         int                      b2b_mw;        /* Shared window number. */
  108         uint64_t                 b2b_off;       /* Offset in shared window. */
  109 };
  110 
  111 #define PLX_NT0_BASE            0x3E000
  112 #define PLX_NT1_BASE            0x3C000
  113 #define PLX_NTX_BASE(sc)        ((sc)->ntx ? PLX_NT1_BASE : PLX_NT0_BASE)
  114 #define PLX_NTX_LINK_OFFSET     0x01000
  115 
  116 /* Bases of NTx our/peer interface registers */
  117 #define PLX_NTX_OUR_BASE(sc)                            \
  118     (PLX_NTX_BASE(sc) + ((sc)->link ? PLX_NTX_LINK_OFFSET : 0))
  119 #define PLX_NTX_PEER_BASE(sc)                           \
  120     (PLX_NTX_BASE(sc) + ((sc)->link ? 0 : PLX_NTX_LINK_OFFSET))
  121 
  122 /* Read/write NTx our interface registers */
  123 #define NTX_READ(sc, reg)                               \
  124     bus_read_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg))
  125 #define NTX_WRITE(sc, reg, val)                         \
  126     bus_write_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg), (val))
  127 
  128 /* Read/write NTx peer interface registers */
  129 #define PNTX_READ(sc, reg)                              \
  130     bus_read_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg))
  131 #define PNTX_WRITE(sc, reg, val)                        \
  132     bus_write_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg), (val))
  133 
  134 /* Read/write B2B NTx registers */
  135 #define BNTX_READ(sc, reg)                              \
  136     bus_read_4((sc)->mw_info[(sc)->b2b_mw].mw_res,      \
  137     PLX_NTX_BASE(sc) + (reg))
  138 #define BNTX_WRITE(sc, reg, val)                        \
  139     bus_write_4((sc)->mw_info[(sc)->b2b_mw].mw_res,     \
  140     PLX_NTX_BASE(sc) + (reg), (val))
  141 
  142 #define PLX_PORT_BASE(p)                ((p) << 12)
  143 #define PLX_STATION_PORT_BASE(sc)       PLX_PORT_BASE((sc)->port & ~7)
  144 
  145 #define PLX_PORT_CONTROL(sc)            (PLX_STATION_PORT_BASE(sc) + 0x208)
  146 
  147 static int ntb_plx_init(device_t dev);
  148 static int ntb_plx_detach(device_t dev);
  149 static int ntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx);
  150 
  151 static int
  152 ntb_plx_probe(device_t dev)
  153 {
  154 
  155         switch (pci_get_devid(dev)) {
  156         case 0x87a010b5:
  157                 device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Link");
  158                 return (BUS_PROBE_DEFAULT);
  159         case 0x87a110b5:
  160                 device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Link");
  161                 return (BUS_PROBE_DEFAULT);
  162         case 0x87b010b5:
  163                 device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Virtual");
  164                 return (BUS_PROBE_DEFAULT);
  165         case 0x87b110b5:
  166                 device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Virtual");
  167                 return (BUS_PROBE_DEFAULT);
  168         }
  169         return (ENXIO);
  170 }
  171 
  172 static int
  173 ntb_plx_init(device_t dev)
  174 {
  175         struct ntb_plx_softc *sc = device_get_softc(dev);
  176         struct ntb_plx_mw_info *mw;
  177         uint64_t val64;
  178         int i;
  179         uint32_t val;
  180 
  181         if (sc->b2b_mw >= 0) {
  182                 /* Set peer BAR0/1 size and address for B2B NTx access. */
  183                 mw = &sc->mw_info[sc->b2b_mw];
  184                 if (mw->mw_64bit) {
  185                         PNTX_WRITE(sc, 0xe4, 0x3);      /* 64-bit */
  186                         val64 = 0x2000000000000000 * mw->mw_bar | 0x4;
  187                         PNTX_WRITE(sc, PCIR_BAR(0), val64);
  188                         PNTX_WRITE(sc, PCIR_BAR(0) + 4, val64 >> 32);
  189                 } else {
  190                         PNTX_WRITE(sc, 0xe4, 0x2);      /* 32-bit */
  191                         val = 0x20000000 * mw->mw_bar;
  192                         PNTX_WRITE(sc, PCIR_BAR(0), val);
  193                 }
  194 
  195                 /* Set Virtual to Link address translation for B2B. */
  196                 for (i = 0; i < sc->mw_count; i++) {
  197                         mw = &sc->mw_info[i];
  198                         if (mw->mw_64bit) {
  199                                 val64 = 0x2000000000000000 * mw->mw_bar;
  200                                 NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val64);
  201                                 NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, val64 >> 32);
  202                         } else {
  203                                 val = 0x20000000 * mw->mw_bar;
  204                                 NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val);
  205                         }
  206                 }
  207 
  208                 /* Make sure Virtual to Link A-LUT is disabled. */
  209                 if (sc->alut)
  210                         PNTX_WRITE(sc, 0xc94, 0);
  211 
  212                 /* Enable all Link Interface LUT entries for peer. */
  213                 for (i = 0; i < 32; i += 2) {
  214                         PNTX_WRITE(sc, 0xdb4 + i * 2,
  215                             0x00010001 | ((i + 1) << 19) | (i << 3));
  216                 }
  217         }
  218 
  219         /*
  220          * Enable Virtual Interface LUT entry 0 for 0:0.*.
  221          * entry 1 for our Requester ID reported by the chip,
  222          * entries 2-5 for 0/64/128/192:4.* of I/OAT DMA engines.
  223          * XXX: Its a hack, we can't know all DMA engines, but this covers all
  224          * I/OAT of Xeon E5/E7 at least from Sandy Bridge till Skylake I saw.
  225          */
  226         val = (NTX_READ(sc, 0xc90) << 16) | 0x00010001;
  227         NTX_WRITE(sc, sc->link ? 0xdb4 : 0xd94, val);
  228         NTX_WRITE(sc, sc->link ? 0xdb8 : 0xd98, 0x40210021);
  229         NTX_WRITE(sc, sc->link ? 0xdbc : 0xd9c, 0xc0218021);
  230 
  231         /* Set Link to Virtual address translation. */
  232         for (i = 0; i < sc->mw_count; i++)
  233                 ntb_plx_mw_set_trans_internal(dev, i);
  234 
  235         pci_enable_busmaster(dev);
  236         if (sc->b2b_mw >= 0)
  237                 PNTX_WRITE(sc, PCIR_COMMAND, PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
  238 
  239         return (0);
  240 }
  241 
  242 static void
  243 ntb_plx_isr(void *arg)
  244 {
  245         device_t dev = arg;
  246         struct ntb_plx_softc *sc = device_get_softc(dev);
  247         uint32_t val;
  248 
  249         ntb_db_event((device_t)arg, 0);
  250 
  251         if (sc->link)   /* Link Interface has no Link Error registers. */
  252                 return;
  253 
  254         val = NTX_READ(sc, 0xfe0);
  255         if (val == 0)
  256                 return;
  257         NTX_WRITE(sc, 0xfe0, val);
  258         if (val & 1)
  259                 device_printf(dev, "Correctable Error\n");
  260         if (val & 2)
  261                 device_printf(dev, "Uncorrectable Error\n");
  262         if (val & 4) {
  263                 /* DL_Down resets link side registers, have to reinit. */
  264                 ntb_plx_init(dev);
  265                 ntb_link_event(dev);
  266         }
  267         if (val & 8)
  268                 device_printf(dev, "Uncorrectable Error Message Drop\n");
  269 }
  270 
  271 static int
  272 ntb_plx_setup_intr(device_t dev)
  273 {
  274         struct ntb_plx_softc *sc = device_get_softc(dev);
  275         int error;
  276 
  277         /*
  278          * XXX: This hardware supports MSI, but I found it unusable.
  279          * It generates new MSI only when doorbell register goes from
  280          * zero, but does not generate it when another bit is set or on
  281          * partial clear.  It makes operation very racy and unreliable.
  282          * The data book mentions some mask juggling magic to workaround
  283          * that, but I failed to make it work.
  284          */
  285         sc->int_rid = 0;
  286         sc->int_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  287             &sc->int_rid, RF_SHAREABLE|RF_ACTIVE);
  288         if (sc->int_res == NULL) {
  289                 device_printf(dev, "bus_alloc_resource failed\n");
  290                 return (ENOMEM);
  291         }
  292         error = bus_setup_intr(dev, sc->int_res, INTR_MPSAFE | INTR_TYPE_MISC,
  293             NULL, ntb_plx_isr, dev, &sc->int_tag);
  294         if (error != 0) {
  295                 device_printf(dev, "bus_setup_intr failed: %d\n", error);
  296                 return (error);
  297         }
  298 
  299         if (!sc->link) { /* Link Interface has no Link Error registers. */
  300                 NTX_WRITE(sc, 0xfe0, 0xf);      /* Clear link interrupts. */
  301                 NTX_WRITE(sc, 0xfe4, 0x0);      /* Unmask link interrupts. */
  302         }
  303         return (0);
  304 }
  305 
  306 static void
  307 ntb_plx_teardown_intr(device_t dev)
  308 {
  309         struct ntb_plx_softc *sc = device_get_softc(dev);
  310 
  311         if (!sc->link)  /* Link Interface has no Link Error registers. */
  312                 NTX_WRITE(sc, 0xfe4, 0xf);      /* Mask link interrupts. */
  313 
  314         if (sc->int_res) {
  315                 bus_teardown_intr(dev, sc->int_res, sc->int_tag);
  316                 bus_release_resource(dev, SYS_RES_IRQ, sc->int_rid,
  317                     sc->int_res);
  318         }
  319 }
  320 
  321 static int
  322 ntb_plx_attach(device_t dev)
  323 {
  324         struct ntb_plx_softc *sc = device_get_softc(dev);
  325         struct ntb_plx_mw_info *mw;
  326         int error = 0, i, j;
  327         uint32_t val;
  328         char buf[32];
  329 
  330         /* Identify what we are (what side of what NTx). */
  331         sc->dev = dev;
  332         val = pci_read_config(dev, 0xc8c, 4);
  333         sc->ntx = (val & 1) != 0;
  334         sc->link = (val & 0x80000000) != 0;
  335 
  336         /* Get access to whole 256KB of chip configuration space via BAR0/1. */
  337         sc->conf_rid = PCIR_BAR(0);
  338         sc->conf_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  339             &sc->conf_rid, RF_ACTIVE);
  340         if (sc->conf_res == NULL) {
  341                 device_printf(dev, "Can't allocate configuration BAR.\n");
  342                 return (ENXIO);
  343         }
  344 
  345         /*
  346          * The device occupies whole bus.  In translated TLP slot field
  347          * keeps LUT index (original bus/slot), function is passed through.
  348          */
  349         bus_dma_iommu_set_buswide(dev);
  350 
  351         /* Identify chip port we are connected to. */
  352         val = bus_read_4(sc->conf_res, 0x360);
  353         sc->port = (val >> ((sc->ntx == 0) ? 8 : 16)) & 0x1f;
  354 
  355         /* Detect A-LUT enable and size. */
  356         val >>= 30;
  357         sc->alut = (val == 0x3) ? 1 : ((val & (1 << sc->ntx)) ? 2 : 0);
  358         if (sc->alut)
  359                 device_printf(dev, "%u A-LUT entries\n", 128 * sc->alut);
  360 
  361         /* Find configured memory windows at BAR2-5. */
  362         sc->mw_count = 0;
  363         for (i = 2; i <= 5; i++) {
  364                 mw = &sc->mw_info[sc->mw_count];
  365                 mw->mw_bar = i;
  366                 mw->mw_rid = PCIR_BAR(mw->mw_bar);
  367                 mw->mw_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  368                     &mw->mw_rid, RF_ACTIVE);
  369                 if (mw->mw_res == NULL)
  370                         continue;
  371                 mw->mw_pbase = rman_get_start(mw->mw_res);
  372                 mw->mw_size = rman_get_size(mw->mw_res);
  373                 mw->mw_vbase = rman_get_virtual(mw->mw_res);
  374                 for (j = 0; j < PLX_MAX_SPLIT; j++)
  375                         mw->splits[j].mw_map_mode = VM_MEMATTR_UNCACHEABLE;
  376                 sc->mw_count++;
  377 
  378                 /* Skip over adjacent BAR for 64-bit BARs. */
  379                 val = pci_read_config(dev, PCIR_BAR(mw->mw_bar), 4);
  380                 if ((val & PCIM_BAR_MEM_TYPE) == PCIM_BAR_MEM_64) {
  381                         mw->mw_64bit = 1;
  382                         i++;
  383                 }
  384         }
  385 
  386         /* Try to identify B2B mode. */
  387         i = 1;
  388         snprintf(buf, sizeof(buf), "hint.%s.%d.b2b", device_get_name(dev),
  389             device_get_unit(dev));
  390         TUNABLE_INT_FETCH(buf, &i);
  391         if (sc->link) {
  392                 device_printf(dev, "NTB-to-Root Port mode (Link Interface)\n");
  393                 sc->b2b_mw = -1;
  394         } else if (i == 0) {
  395                 device_printf(dev, "NTB-to-Root Port mode (Virtual Interface)\n");
  396                 sc->b2b_mw = -1;
  397         } else {
  398                 device_printf(dev, "NTB-to-NTB (back-to-back) mode\n");
  399 
  400                 /* We need at least one memory window for B2B peer access. */
  401                 if (sc->mw_count == 0) {
  402                         device_printf(dev, "No memory window BARs enabled.\n");
  403                         error = ENXIO;
  404                         goto out;
  405                 }
  406                 sc->b2b_mw = sc->mw_count - 1;
  407 
  408                 /* Use half of the window for B2B, but no less then 1MB. */
  409                 mw = &sc->mw_info[sc->b2b_mw];
  410                 if (mw->mw_size >= 2 * 1024 * 1024)
  411                         sc->b2b_off = mw->mw_size / 2;
  412                 else
  413                         sc->b2b_off = 0;
  414         }
  415 
  416         snprintf(buf, sizeof(buf), "hint.%s.%d.split", device_get_name(dev),
  417             device_get_unit(dev));
  418         TUNABLE_INT_FETCH(buf, &sc->split);
  419         if (sc->split > 7) {
  420                 device_printf(dev, "Split value is too high (%u)\n", sc->split);
  421                 sc->split = 0;
  422         } else if (sc->split > 0 && sc->alut == 0) {
  423                 device_printf(dev, "Can't split with disabled A-LUT\n");
  424                 sc->split = 0;
  425         } else if (sc->split > 0 && (sc->mw_count == 0 || sc->mw_info[0].mw_bar != 2)) {
  426                 device_printf(dev, "Can't split disabled BAR2\n");
  427                 sc->split = 0;
  428         } else if (sc->split > 0 && (sc->b2b_mw == 0 && sc->b2b_off == 0)) {
  429                 device_printf(dev, "Can't split BAR2 consumed by B2B\n");
  430                 sc->split = 0;
  431         } else if (sc->split > 0) {
  432                 device_printf(dev, "Splitting BAR2 into %d memory windows\n",
  433                     1 << sc->split);
  434         }
  435 
  436         /*
  437          * Use Physical Layer User Test Pattern as additional scratchpad.
  438          * Make sure they are present and enabled by writing to them.
  439          * XXX: Its a hack, but standard 8 registers are not enough.
  440          */
  441         sc->spad_offp1 = sc->spad_off1 = PLX_NTX_OUR_BASE(sc) + 0xc6c;
  442         sc->spad_offp2 = sc->spad_off2 = PLX_PORT_BASE(sc->ntx * 8) + 0x20c;
  443         if (sc->b2b_mw >= 0) {
  444                 /* In NTB-to-NTB mode each side has own scratchpads. */
  445                 sc->spad_count1 = PLX_NUM_SPAD;
  446                 bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678);
  447                 if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678)
  448                         sc->spad_count2 = PLX_NUM_SPAD_PATT;
  449         } else {
  450                 /* Otherwise we have share scratchpads with the peer. */
  451                 if (sc->link) {
  452                         sc->spad_off1 += PLX_NUM_SPAD / 2 * 4;
  453                         sc->spad_off2 += PLX_NUM_SPAD_PATT / 2 * 4;
  454                 } else {
  455                         sc->spad_offp1 += PLX_NUM_SPAD / 2 * 4;
  456                         sc->spad_offp2 += PLX_NUM_SPAD_PATT / 2 * 4;
  457                 }
  458                 sc->spad_count1 = PLX_NUM_SPAD / 2;
  459                 bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678);
  460                 if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678)
  461                         sc->spad_count2 = PLX_NUM_SPAD_PATT / 2;
  462         }
  463 
  464         /* Apply static part of NTB configuration. */
  465         ntb_plx_init(dev);
  466 
  467         /* Allocate and setup interrupts. */
  468         error = ntb_plx_setup_intr(dev);
  469         if (error)
  470                 goto out;
  471 
  472         /* Attach children to this controller */
  473         error = ntb_register_device(dev);
  474 
  475 out:
  476         if (error != 0)
  477                 ntb_plx_detach(dev);
  478         return (error);
  479 }
  480 
  481 static int
  482 ntb_plx_detach(device_t dev)
  483 {
  484         struct ntb_plx_softc *sc = device_get_softc(dev);
  485         struct ntb_plx_mw_info *mw;
  486         int i;
  487 
  488         /* Detach & delete all children */
  489         ntb_unregister_device(dev);
  490 
  491         /* Disable and free interrupts. */
  492         ntb_plx_teardown_intr(dev);
  493 
  494         /* Free memory resources. */
  495         for (i = 0; i < sc->mw_count; i++) {
  496                 mw = &sc->mw_info[i];
  497                 bus_release_resource(dev, SYS_RES_MEMORY, mw->mw_rid,
  498                     mw->mw_res);
  499         }
  500         bus_release_resource(dev, SYS_RES_MEMORY, sc->conf_rid, sc->conf_res);
  501         return (0);
  502 }
  503 
  504 static int
  505 ntb_plx_port_number(device_t dev)
  506 {
  507         struct ntb_plx_softc *sc = device_get_softc(dev);
  508 
  509         return (sc->link ? 1 : 0);
  510 }
  511 
  512 static int
  513 ntb_plx_peer_port_count(device_t dev)
  514 {
  515 
  516         return (1);
  517 }
  518 
  519 static int
  520 ntb_plx_peer_port_number(device_t dev, int pidx)
  521 {
  522         struct ntb_plx_softc *sc = device_get_softc(dev);
  523 
  524         if (pidx != 0)
  525                 return (-EINVAL);
  526 
  527         return (sc->link ? 0 : 1);
  528 }
  529 
  530 static int
  531 ntb_plx_peer_port_idx(device_t dev, int port)
  532 {
  533         int peer_port;
  534 
  535         peer_port = ntb_plx_peer_port_number(dev, 0);
  536         if (peer_port == -EINVAL || port != peer_port)
  537                 return (-EINVAL);
  538 
  539         return (0);
  540 }
  541 
  542 static bool
  543 ntb_plx_link_is_up(device_t dev, enum ntb_speed *speed, enum ntb_width *width)
  544 {
  545         uint16_t link;
  546 
  547         link = pcie_read_config(dev, PCIER_LINK_STA, 2);
  548         if (speed != NULL)
  549                 *speed = (link & PCIEM_LINK_STA_SPEED);
  550         if (width != NULL)
  551                 *width = (link & PCIEM_LINK_STA_WIDTH) >> 4;
  552         return ((link & PCIEM_LINK_STA_WIDTH) != 0);
  553 }
  554 
  555 static int
  556 ntb_plx_link_enable(device_t dev, enum ntb_speed speed __unused,
  557     enum ntb_width width __unused)
  558 {
  559         struct ntb_plx_softc *sc = device_get_softc(dev);
  560         uint32_t reg, val;
  561 
  562         /* The fact that we see the Link Interface means link is enabled. */
  563         if (sc->link) {
  564                 ntb_link_event(dev);
  565                 return (0);
  566         }
  567 
  568         reg = PLX_PORT_CONTROL(sc);
  569         val = bus_read_4(sc->conf_res, reg);
  570         if ((val & (1 << (sc->port & 7))) == 0) {
  571                 /* If already enabled, generate fake link event and exit. */
  572                 ntb_link_event(dev);
  573                 return (0);
  574         }
  575         val &= ~(1 << (sc->port & 7));
  576         bus_write_4(sc->conf_res, reg, val);
  577         return (0);
  578 }
  579 
  580 static int
  581 ntb_plx_link_disable(device_t dev)
  582 {
  583         struct ntb_plx_softc *sc = device_get_softc(dev);
  584         uint32_t reg, val;
  585 
  586         /* Link disable for Link Interface would be suicidal. */
  587         if (sc->link)
  588                 return (0);
  589 
  590         reg = PLX_PORT_CONTROL(sc);
  591         val = bus_read_4(sc->conf_res, reg);
  592         val |= (1 << (sc->port & 7));
  593         bus_write_4(sc->conf_res, reg, val);
  594         return (0);
  595 }
  596 
  597 static bool
  598 ntb_plx_link_enabled(device_t dev)
  599 {
  600         struct ntb_plx_softc *sc = device_get_softc(dev);
  601         uint32_t reg, val;
  602 
  603         /* The fact that we see the Link Interface means link is enabled. */
  604         if (sc->link)
  605                 return (TRUE);
  606 
  607         reg = PLX_PORT_CONTROL(sc);
  608         val = bus_read_4(sc->conf_res, reg);
  609         return ((val & (1 << (sc->port & 7))) == 0);
  610 }
  611 
  612 static uint8_t
  613 ntb_plx_mw_count(device_t dev)
  614 {
  615         struct ntb_plx_softc *sc = device_get_softc(dev);
  616         uint8_t res;
  617 
  618         res = sc->mw_count;
  619         res += (1 << sc->split) - 1;
  620         if (sc->b2b_mw >= 0 && sc->b2b_off == 0)
  621                 res--; /* B2B consumed whole window. */
  622         return (res);
  623 }
  624 
  625 static unsigned
  626 ntb_plx_user_mw_to_idx(struct ntb_plx_softc *sc, unsigned uidx, unsigned *sp)
  627 {
  628         unsigned t;
  629 
  630         t = 1 << sc->split;
  631         if (uidx < t) {
  632                 *sp = uidx;
  633                 return (0);
  634         }
  635         *sp = 0;
  636         return (uidx - (t - 1));
  637 }
  638 
  639 static int
  640 ntb_plx_mw_get_range(device_t dev, unsigned mw_idx, vm_paddr_t *base,
  641     caddr_t *vbase, size_t *size, size_t *align, size_t *align_size,
  642     bus_addr_t *plimit)
  643 {
  644         struct ntb_plx_softc *sc = device_get_softc(dev);
  645         struct ntb_plx_mw_info *mw;
  646         size_t off, ss;
  647         unsigned sp, split;
  648 
  649         mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp);
  650         if (mw_idx >= sc->mw_count)
  651                 return (EINVAL);
  652         off = 0;
  653         if (mw_idx == sc->b2b_mw) {
  654                 KASSERT(sc->b2b_off != 0,
  655                     ("user shouldn't get non-shared b2b mw"));
  656                 off = sc->b2b_off;
  657         }
  658         mw = &sc->mw_info[mw_idx];
  659         split = (mw->mw_bar == 2) ? sc->split : 0;
  660         ss = (mw->mw_size - off) >> split;
  661 
  662         /* Local to remote memory window parameters. */
  663         if (base != NULL)
  664                 *base = mw->mw_pbase + off + ss * sp;
  665         if (vbase != NULL)
  666                 *vbase = mw->mw_vbase + off + ss * sp;
  667         if (size != NULL)
  668                 *size = ss;
  669 
  670         /*
  671          * Remote to local memory window translation address alignment.
  672          * Translation address has to be aligned to the BAR size, but A-LUT
  673          * entries re-map addresses can be aligned to 1/128 or 1/256 of it.
  674          * XXX: In B2B mode we can change BAR size (and so alignmet) live,
  675          * but there is no way to report it here, so report safe value.
  676          */
  677         if (align != NULL) {
  678                 if (sc->alut && mw->mw_bar == 2)
  679                         *align = (mw->mw_size - off) / 128 / sc->alut;
  680                 else
  681                         *align = mw->mw_size - off;
  682         }
  683 
  684         /*
  685          * Remote to local memory window size alignment.
  686          * The chip has no limit registers, but A-LUT, when available, allows
  687          * access control with granularity of 1/128 or 1/256 of the BAR size.
  688          * XXX: In B2B case we can change BAR size live, but there is no way
  689          * to report it, so report half of the BAR size, that should be safe.
  690          * In non-B2B case there is no control at all, so report the BAR size.
  691          */
  692         if (align_size != NULL) {
  693                 if (sc->alut && mw->mw_bar == 2)
  694                         *align_size = (mw->mw_size - off) / 128 / sc->alut;
  695                 else if (sc->b2b_mw >= 0)
  696                         *align_size = (mw->mw_size - off) / 2;
  697                 else
  698                         *align_size = mw->mw_size - off;
  699         }
  700 
  701         /* Remote to local memory window translation address upper limit. */
  702         if (plimit != NULL)
  703                 *plimit = mw->mw_64bit ? BUS_SPACE_MAXADDR :
  704                     BUS_SPACE_MAXADDR_32BIT;
  705         return (0);
  706 }
  707 
  708 static int
  709 ntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx)
  710 {
  711         struct ntb_plx_softc *sc = device_get_softc(dev);
  712         struct ntb_plx_mw_info *mw;
  713         uint64_t addr, eaddr, off, size, bsize, esize, val64;
  714         uint32_t val;
  715         unsigned i, sp, split;
  716 
  717         mw = &sc->mw_info[mw_idx];
  718         off = (mw_idx == sc->b2b_mw) ? sc->b2b_off : 0;
  719         split = (mw->mw_bar == 2) ? sc->split : 0;
  720 
  721         /* Get BAR size.  In case of split or B2RP we can't change it. */
  722         if (split || sc->b2b_mw < 0) {
  723                 bsize = mw->mw_size - off;
  724         } else {
  725                 bsize = mw->splits[0].mw_xlat_size;
  726                 if (!powerof2(bsize))
  727                         bsize = 1LL << flsll(bsize);
  728                 if (bsize > 0 && bsize < 1024 * 1024)
  729                         bsize = 1024 * 1024;
  730         }
  731 
  732         /*
  733          * While for B2B we can set any BAR size on a link side, for shared
  734          * window we can't go above preconfigured size due to BAR address
  735          * alignment requirements.
  736          */
  737         if ((off & (bsize - 1)) != 0)
  738                 return (EINVAL);
  739 
  740         /* In B2B mode set Link Interface BAR size/address. */
  741         if (sc->b2b_mw >= 0 && mw->mw_64bit) {
  742                 val64 = 0;
  743                 if (bsize > 0)
  744                         val64 = (~(bsize - 1) & ~0xfffff);
  745                 val64 |= 0xc;
  746                 PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val64);
  747                 PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4 + 4, val64 >> 32);
  748 
  749                 val64 = 0x2000000000000000 * mw->mw_bar + off;
  750                 PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64);
  751                 PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar) + 4, val64 >> 32);
  752         } else if (sc->b2b_mw >= 0) {
  753                 val = 0;
  754                 if (bsize > 0)
  755                         val = (~(bsize - 1) & ~0xfffff);
  756                 PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val);
  757 
  758                 val64 = 0x20000000 * mw->mw_bar + off;
  759                 PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64);
  760         }
  761 
  762         /* Set BARs address translation */
  763         addr = split ? UINT64_MAX : mw->splits[0].mw_xlat_addr;
  764         if (mw->mw_64bit) {
  765                 PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr);
  766                 PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, addr >> 32);
  767         } else {
  768                 PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr);
  769         }
  770 
  771         /* Configure and enable A-LUT if we need it. */
  772         size = split ? 0 : mw->splits[0].mw_xlat_size;
  773         if (sc->alut && mw->mw_bar == 2 && (sc->split > 0 ||
  774             ((addr & (bsize - 1)) != 0 || size != bsize))) {
  775                 esize = bsize / (128 * sc->alut);
  776                 for (i = sp = 0; i < 128 * sc->alut; i++) {
  777                         if (i % (128 * sc->alut >> sc->split) == 0) {
  778                                 eaddr = addr = mw->splits[sp].mw_xlat_addr;
  779                                 size = mw->splits[sp++].mw_xlat_size;
  780                         }
  781                         val = sc->link ? 0 : 1;
  782                         if (sc->alut == 1)
  783                                 val += 2 * sc->ntx;
  784                         val *= 0x1000 * sc->alut;
  785                         val += 0x38000 + i * 4 + (i >= 128 ? 0x0e00 : 0);
  786                         bus_write_4(sc->conf_res, val, eaddr);
  787                         bus_write_4(sc->conf_res, val + 0x400, eaddr >> 32);
  788                         bus_write_4(sc->conf_res, val + 0x800,
  789                             (eaddr < addr + size) ? 0x3 : 0);
  790                         eaddr += esize;
  791                 }
  792                 NTX_WRITE(sc, 0xc94, 0x10000000);
  793         } else if (sc->alut && mw->mw_bar == 2)
  794                 NTX_WRITE(sc, 0xc94, 0);
  795 
  796         return (0);
  797 }
  798 
  799 static int
  800 ntb_plx_mw_set_trans(device_t dev, unsigned mw_idx, bus_addr_t addr, size_t size)
  801 {
  802         struct ntb_plx_softc *sc = device_get_softc(dev);
  803         struct ntb_plx_mw_info *mw;
  804         unsigned sp;
  805 
  806         mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp);
  807         if (mw_idx >= sc->mw_count)
  808                 return (EINVAL);
  809         mw = &sc->mw_info[mw_idx];
  810         if (!mw->mw_64bit &&
  811             ((addr & UINT32_MAX) != addr ||
  812              ((addr + size) & UINT32_MAX) != (addr + size)))
  813                 return (ERANGE);
  814         mw->splits[sp].mw_xlat_addr = addr;
  815         mw->splits[sp].mw_xlat_size = size;
  816         return (ntb_plx_mw_set_trans_internal(dev, mw_idx));
  817 }
  818 
  819 static int
  820 ntb_plx_mw_clear_trans(device_t dev, unsigned mw_idx)
  821 {
  822 
  823         return (ntb_plx_mw_set_trans(dev, mw_idx, 0, 0));
  824 }
  825 
  826 static int
  827 ntb_plx_mw_get_wc(device_t dev, unsigned mw_idx, vm_memattr_t *mode)
  828 {
  829         struct ntb_plx_softc *sc = device_get_softc(dev);
  830         struct ntb_plx_mw_info *mw;
  831         unsigned sp;
  832 
  833         mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp);
  834         if (mw_idx >= sc->mw_count)
  835                 return (EINVAL);
  836         mw = &sc->mw_info[mw_idx];
  837         *mode = mw->splits[sp].mw_map_mode;
  838         return (0);
  839 }
  840 
  841 static int
  842 ntb_plx_mw_set_wc(device_t dev, unsigned mw_idx, vm_memattr_t mode)
  843 {
  844         struct ntb_plx_softc *sc = device_get_softc(dev);
  845         struct ntb_plx_mw_info *mw;
  846         uint64_t off, ss;
  847         int rc;
  848         unsigned sp, split;
  849 
  850         mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp);
  851         if (mw_idx >= sc->mw_count)
  852                 return (EINVAL);
  853         mw = &sc->mw_info[mw_idx];
  854         if (mw->splits[sp].mw_map_mode == mode)
  855                 return (0);
  856 
  857         off = 0;
  858         if (mw_idx == sc->b2b_mw) {
  859                 KASSERT(sc->b2b_off != 0,
  860                     ("user shouldn't get non-shared b2b mw"));
  861                 off = sc->b2b_off;
  862         }
  863 
  864         split = (mw->mw_bar == 2) ? sc->split : 0;
  865         ss = (mw->mw_size - off) >> split;
  866         rc = pmap_change_attr((vm_offset_t)mw->mw_vbase + off + ss * sp,
  867             ss, mode);
  868         if (rc == 0)
  869                 mw->splits[sp].mw_map_mode = mode;
  870         return (rc);
  871 }
  872 
  873 static uint8_t
  874 ntb_plx_spad_count(device_t dev)
  875 {
  876         struct ntb_plx_softc *sc = device_get_softc(dev);
  877 
  878         return (sc->spad_count1 + sc->spad_count2);
  879 }
  880 
  881 static int
  882 ntb_plx_spad_write(device_t dev, unsigned int idx, uint32_t val)
  883 {
  884         struct ntb_plx_softc *sc = device_get_softc(dev);
  885         u_int off;
  886 
  887         if (idx >= sc->spad_count1 + sc->spad_count2)
  888                 return (EINVAL);
  889 
  890         if (idx < sc->spad_count1)
  891                 off = sc->spad_off1 + idx * 4;
  892         else
  893                 off = sc->spad_off2 + (idx - sc->spad_count1) * 4;
  894         bus_write_4(sc->conf_res, off, val);
  895         return (0);
  896 }
  897 
  898 static void
  899 ntb_plx_spad_clear(device_t dev)
  900 {
  901         struct ntb_plx_softc *sc = device_get_softc(dev);
  902         int i;
  903 
  904         for (i = 0; i < sc->spad_count1 + sc->spad_count2; i++)
  905                 ntb_plx_spad_write(dev, i, 0);
  906 }
  907 
  908 static int
  909 ntb_plx_spad_read(device_t dev, unsigned int idx, uint32_t *val)
  910 {
  911         struct ntb_plx_softc *sc = device_get_softc(dev);
  912         u_int off;
  913 
  914         if (idx >= sc->spad_count1 + sc->spad_count2)
  915                 return (EINVAL);
  916 
  917         if (idx < sc->spad_count1)
  918                 off = sc->spad_off1 + idx * 4;
  919         else
  920                 off = sc->spad_off2 + (idx - sc->spad_count1) * 4;
  921         *val = bus_read_4(sc->conf_res, off);
  922         return (0);
  923 }
  924 
  925 static int
  926 ntb_plx_peer_spad_write(device_t dev, unsigned int idx, uint32_t val)
  927 {
  928         struct ntb_plx_softc *sc = device_get_softc(dev);
  929         u_int off;
  930 
  931         if (idx >= sc->spad_count1 + sc->spad_count2)
  932                 return (EINVAL);
  933 
  934         if (idx < sc->spad_count1)
  935                 off = sc->spad_offp1 + idx * 4;
  936         else
  937                 off = sc->spad_offp2 + (idx - sc->spad_count1) * 4;
  938         if (sc->b2b_mw >= 0)
  939                 bus_write_4(sc->mw_info[sc->b2b_mw].mw_res, off, val);
  940         else
  941                 bus_write_4(sc->conf_res, off, val);
  942         return (0);
  943 }
  944 
  945 static int
  946 ntb_plx_peer_spad_read(device_t dev, unsigned int idx, uint32_t *val)
  947 {
  948         struct ntb_plx_softc *sc = device_get_softc(dev);
  949         u_int off;
  950 
  951         if (idx >= sc->spad_count1 + sc->spad_count2)
  952                 return (EINVAL);
  953 
  954         if (idx < sc->spad_count1)
  955                 off = sc->spad_offp1 + idx * 4;
  956         else
  957                 off = sc->spad_offp2 + (idx - sc->spad_count1) * 4;
  958         if (sc->b2b_mw >= 0)
  959                 *val = bus_read_4(sc->mw_info[sc->b2b_mw].mw_res, off);
  960         else
  961                 *val = bus_read_4(sc->conf_res, off);
  962         return (0);
  963 }
  964 
  965 static uint64_t
  966 ntb_plx_db_valid_mask(device_t dev)
  967 {
  968 
  969         return ((1LL << PLX_NUM_DB) - 1);
  970 }
  971 
  972 static int
  973 ntb_plx_db_vector_count(device_t dev)
  974 {
  975 
  976         return (1);
  977 }
  978 
  979 static uint64_t
  980 ntb_plx_db_vector_mask(device_t dev, uint32_t vector)
  981 {
  982 
  983         if (vector > 0)
  984                 return (0);
  985         return ((1LL << PLX_NUM_DB) - 1);
  986 }
  987 
  988 static void
  989 ntb_plx_db_clear(device_t dev, uint64_t bits)
  990 {
  991         struct ntb_plx_softc *sc = device_get_softc(dev);
  992 
  993         NTX_WRITE(sc, sc->link ? 0xc60 : 0xc50, bits);
  994 }
  995 
  996 static void
  997 ntb_plx_db_clear_mask(device_t dev, uint64_t bits)
  998 {
  999         struct ntb_plx_softc *sc = device_get_softc(dev);
 1000 
 1001         NTX_WRITE(sc, sc->link ? 0xc68 : 0xc58, bits);
 1002 }
 1003 
 1004 static uint64_t
 1005 ntb_plx_db_read(device_t dev)
 1006 {
 1007         struct ntb_plx_softc *sc = device_get_softc(dev);
 1008 
 1009         return (NTX_READ(sc, sc->link ? 0xc5c : 0xc4c));
 1010 }
 1011 
 1012 static void
 1013 ntb_plx_db_set_mask(device_t dev, uint64_t bits)
 1014 {
 1015         struct ntb_plx_softc *sc = device_get_softc(dev);
 1016 
 1017         NTX_WRITE(sc, sc->link ? 0xc64 : 0xc54, bits);
 1018 }
 1019 
 1020 static int
 1021 ntb_plx_peer_db_addr(device_t dev, bus_addr_t *db_addr, vm_size_t *db_size)
 1022 {
 1023         struct ntb_plx_softc *sc = device_get_softc(dev);
 1024         struct ntb_plx_mw_info *mw;
 1025 
 1026         KASSERT((db_addr != NULL && db_size != NULL), ("must be non-NULL"));
 1027 
 1028         if (sc->b2b_mw >= 0) {
 1029                 mw = &sc->mw_info[sc->b2b_mw];
 1030                 *db_addr = (uint64_t)mw->mw_pbase + PLX_NTX_BASE(sc) + 0xc4c;
 1031         } else {
 1032                 *db_addr = rman_get_start(sc->conf_res) + PLX_NTX_BASE(sc);
 1033                 *db_addr += sc->link ? 0xc4c : 0xc5c;
 1034         }
 1035         *db_size = 4;
 1036         return (0);
 1037 }
 1038 
 1039 static void
 1040 ntb_plx_peer_db_set(device_t dev, uint64_t bit)
 1041 {
 1042         struct ntb_plx_softc *sc = device_get_softc(dev);
 1043 
 1044         if (sc->b2b_mw >= 0)
 1045                 BNTX_WRITE(sc, 0xc4c, bit);
 1046         else
 1047                 NTX_WRITE(sc, sc->link ? 0xc4c : 0xc5c, bit);
 1048 }
 1049 
 1050 static device_method_t ntb_plx_methods[] = {
 1051         /* Device interface */
 1052         DEVMETHOD(device_probe,         ntb_plx_probe),
 1053         DEVMETHOD(device_attach,        ntb_plx_attach),
 1054         DEVMETHOD(device_detach,        ntb_plx_detach),
 1055         /* Bus interface */
 1056         DEVMETHOD(bus_child_location,   ntb_child_location),
 1057         DEVMETHOD(bus_print_child,      ntb_print_child),
 1058         DEVMETHOD(bus_get_dma_tag,      ntb_get_dma_tag),
 1059         /* NTB interface */
 1060         DEVMETHOD(ntb_port_number,      ntb_plx_port_number),
 1061         DEVMETHOD(ntb_peer_port_count,  ntb_plx_peer_port_count),
 1062         DEVMETHOD(ntb_peer_port_number, ntb_plx_peer_port_number),
 1063         DEVMETHOD(ntb_peer_port_idx,    ntb_plx_peer_port_idx),
 1064         DEVMETHOD(ntb_link_is_up,       ntb_plx_link_is_up),
 1065         DEVMETHOD(ntb_link_enable,      ntb_plx_link_enable),
 1066         DEVMETHOD(ntb_link_disable,     ntb_plx_link_disable),
 1067         DEVMETHOD(ntb_link_enabled,     ntb_plx_link_enabled),
 1068         DEVMETHOD(ntb_mw_count,         ntb_plx_mw_count),
 1069         DEVMETHOD(ntb_mw_get_range,     ntb_plx_mw_get_range),
 1070         DEVMETHOD(ntb_mw_set_trans,     ntb_plx_mw_set_trans),
 1071         DEVMETHOD(ntb_mw_clear_trans,   ntb_plx_mw_clear_trans),
 1072         DEVMETHOD(ntb_mw_get_wc,        ntb_plx_mw_get_wc),
 1073         DEVMETHOD(ntb_mw_set_wc,        ntb_plx_mw_set_wc),
 1074         DEVMETHOD(ntb_spad_count,       ntb_plx_spad_count),
 1075         DEVMETHOD(ntb_spad_clear,       ntb_plx_spad_clear),
 1076         DEVMETHOD(ntb_spad_write,       ntb_plx_spad_write),
 1077         DEVMETHOD(ntb_spad_read,        ntb_plx_spad_read),
 1078         DEVMETHOD(ntb_peer_spad_write,  ntb_plx_peer_spad_write),
 1079         DEVMETHOD(ntb_peer_spad_read,   ntb_plx_peer_spad_read),
 1080         DEVMETHOD(ntb_db_valid_mask,    ntb_plx_db_valid_mask),
 1081         DEVMETHOD(ntb_db_vector_count,  ntb_plx_db_vector_count),
 1082         DEVMETHOD(ntb_db_vector_mask,   ntb_plx_db_vector_mask),
 1083         DEVMETHOD(ntb_db_clear,         ntb_plx_db_clear),
 1084         DEVMETHOD(ntb_db_clear_mask,    ntb_plx_db_clear_mask),
 1085         DEVMETHOD(ntb_db_read,          ntb_plx_db_read),
 1086         DEVMETHOD(ntb_db_set_mask,      ntb_plx_db_set_mask),
 1087         DEVMETHOD(ntb_peer_db_addr,     ntb_plx_peer_db_addr),
 1088         DEVMETHOD(ntb_peer_db_set,      ntb_plx_peer_db_set),
 1089         DEVMETHOD_END
 1090 };
 1091 
 1092 static DEFINE_CLASS_0(ntb_hw, ntb_plx_driver, ntb_plx_methods,
 1093     sizeof(struct ntb_plx_softc));
 1094 DRIVER_MODULE(ntb_hw_plx, pci, ntb_plx_driver, NULL, NULL);
 1095 MODULE_DEPEND(ntb_hw_plx, ntb, 1, 1, 1);
 1096 MODULE_VERSION(ntb_hw_plx, 1);

Cache object: fc30f233a5446901d4172ea13ea19938


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.