ntb_hw_plx.c revision 324407
1323032Smav/*- 2323032Smav * Copyright (c) 2017 Alexander Motin <mav@FreeBSD.org> 3323032Smav * All rights reserved. 4323032Smav * 5323032Smav * Redistribution and use in source and binary forms, with or without 6323032Smav * modification, are permitted provided that the following conditions 7323032Smav * are met: 8323032Smav * 1. Redistributions of source code must retain the above copyright 9323032Smav * notice, this list of conditions and the following disclaimer. 10323032Smav * 2. Redistributions in binary form must reproduce the above copyright 11323032Smav * notice, this list of conditions and the following disclaimer in the 12323032Smav * documentation and/or other materials provided with the distribution. 13323032Smav * 14323032Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15323032Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16323032Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17323032Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18323032Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19323032Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20323032Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21323032Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22323032Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23323032Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24323032Smav * SUCH DAMAGE. 25323032Smav */ 26323032Smav 27323032Smav/* 28323032Smav * The Non-Transparent Bridge (NTB) is a device that allows you to connect 29323032Smav * two or more systems using a PCI-e links, providing remote memory access. 30323032Smav * 31323032Smav * This module contains a driver for NTBs in PLX/Avago/Broadcom PCIe bridges. 32323032Smav */ 33323032Smav 34323032Smav#include <sys/cdefs.h> 35323032Smav__FBSDID("$FreeBSD: stable/11/sys/dev/ntb/ntb_hw/ntb_hw_plx.c 324407 2017-10-08 07:19:59Z mav $"); 36323032Smav 37323032Smav#include <sys/param.h> 38323032Smav#include <sys/kernel.h> 39323032Smav#include <sys/systm.h> 40323032Smav#include <sys/bus.h> 41323032Smav#include <sys/interrupt.h> 42323032Smav#include <sys/module.h> 43323032Smav#include <sys/rman.h> 44323032Smav#include <sys/sysctl.h> 45323032Smav#include <vm/vm.h> 46323032Smav#include <vm/pmap.h> 47323032Smav#include <machine/bus.h> 48323032Smav#include <machine/intr_machdep.h> 49323032Smav#include <machine/resource.h> 50323032Smav#include <dev/pci/pcireg.h> 51323032Smav#include <dev/pci/pcivar.h> 52323032Smav 53323032Smav#include "../ntb.h" 54323032Smav 55323032Smav#define PLX_MAX_BARS 4 /* There are at most 4 data BARs. */ 56323032Smav#define PLX_NUM_SPAD 8 /* There are 8 scratchpads. */ 57323032Smav#define PLX_NUM_SPAD_PATT 4 /* Use test pattern as 4 more. */ 58323032Smav#define PLX_NUM_DB 16 /* There are 16 doorbells. */ 59323032Smav 60323032Smavstruct ntb_plx_mw_info { 61323032Smav int mw_bar; 62323032Smav int mw_64bit; 63323032Smav int mw_rid; 64323032Smav struct resource *mw_res; 65323032Smav vm_paddr_t mw_pbase; 66323032Smav caddr_t mw_vbase; 67323032Smav vm_size_t mw_size; 68323032Smav vm_memattr_t mw_map_mode; 69323032Smav bus_addr_t mw_xlat_addr; 70323032Smav size_t mw_xlat_size; 71323032Smav}; 72323032Smav 73323032Smavstruct ntb_plx_softc { 74323032Smav /* ntb.c context. Do not move! Must go first! */ 75323032Smav void *ntb_store; 76323032Smav 77323032Smav device_t dev; 78323032Smav struct resource *conf_res; 79323032Smav int conf_rid; 80323032Smav u_int ntx; /* NTx number within chip. */ 81323032Smav u_int link; /* Link v/s Virtual side. */ 82323032Smav u_int port; /* Port number within chip. */ 83324407Smav u_int alut; /* A-LUT is enabled for NTx */ 84323032Smav 85323032Smav int int_rid; 86323032Smav struct resource *int_res; 87323032Smav void *int_tag; 88323032Smav 89323032Smav struct ntb_plx_mw_info mw_info[PLX_MAX_BARS]; 90323032Smav int mw_count; /* Number of memory windows. */ 91323032Smav 92323032Smav int spad_count1; /* Number of standard spads. */ 93323032Smav int spad_count2; /* Number of extra spads. */ 94323032Smav uint32_t spad_off1; /* Offset of our spads. */ 95323032Smav uint32_t spad_off2; /* Offset of our extra spads. */ 96323032Smav uint32_t spad_offp1; /* Offset of peer spads. */ 97323032Smav uint32_t spad_offp2; /* Offset of peer extra spads. */ 98323032Smav 99323032Smav /* Parameters of window shared with peer config access in B2B mode. */ 100323032Smav int b2b_mw; /* Shared window number. */ 101323032Smav uint64_t b2b_off; /* Offset in shared window. */ 102323032Smav}; 103323032Smav 104323032Smav#define PLX_NT0_BASE 0x3E000 105323032Smav#define PLX_NT1_BASE 0x3C000 106323032Smav#define PLX_NTX_BASE(sc) ((sc)->ntx ? PLX_NT1_BASE : PLX_NT0_BASE) 107323032Smav#define PLX_NTX_LINK_OFFSET 0x01000 108323032Smav 109323032Smav/* Bases of NTx our/peer interface registers */ 110323453Smav#define PLX_NTX_OUR_BASE(sc) \ 111323032Smav (PLX_NTX_BASE(sc) + ((sc)->link ? PLX_NTX_LINK_OFFSET : 0)) 112323453Smav#define PLX_NTX_PEER_BASE(sc) \ 113323032Smav (PLX_NTX_BASE(sc) + ((sc)->link ? 0 : PLX_NTX_LINK_OFFSET)) 114323032Smav 115323032Smav/* Read/write NTx our interface registers */ 116323453Smav#define NTX_READ(sc, reg) \ 117323453Smav bus_read_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg)) 118323453Smav#define NTX_WRITE(sc, reg, val) \ 119323453Smav bus_write_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg), (val)) 120323032Smav 121323032Smav/* Read/write NTx peer interface registers */ 122323453Smav#define PNTX_READ(sc, reg) \ 123323453Smav bus_read_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg)) 124323453Smav#define PNTX_WRITE(sc, reg, val) \ 125323453Smav bus_write_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg), (val)) 126323032Smav 127323032Smav/* Read/write B2B NTx registers */ 128323453Smav#define BNTX_READ(sc, reg) \ 129323032Smav bus_read_4((sc)->mw_info[(sc)->b2b_mw].mw_res, \ 130323032Smav PLX_NTX_BASE(sc) + (reg)) 131323453Smav#define BNTX_WRITE(sc, reg, val) \ 132323032Smav bus_write_4((sc)->mw_info[(sc)->b2b_mw].mw_res, \ 133323032Smav PLX_NTX_BASE(sc) + (reg), (val)) 134323032Smav 135323453Smav#define PLX_PORT_BASE(p) ((p) << 12) 136323453Smav#define PLX_STATION_PORT_BASE(sc) PLX_PORT_BASE((sc)->port & ~7) 137323453Smav 138323453Smav#define PLX_PORT_CONTROL(sc) (PLX_STATION_PORT_BASE(sc) + 0x208) 139323453Smav 140323032Smavstatic int ntb_plx_init(device_t dev); 141323032Smavstatic int ntb_plx_detach(device_t dev); 142323032Smavstatic int ntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx); 143323032Smav 144323032Smavstatic int 145323032Smavntb_plx_probe(device_t dev) 146323032Smav{ 147323032Smav 148323032Smav switch (pci_get_devid(dev)) { 149323032Smav case 0x87a010b5: 150323032Smav device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Link"); 151323032Smav return (BUS_PROBE_DEFAULT); 152323032Smav case 0x87a110b5: 153323032Smav device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Link"); 154323032Smav return (BUS_PROBE_DEFAULT); 155323032Smav case 0x87b010b5: 156323032Smav device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Virtual"); 157323032Smav return (BUS_PROBE_DEFAULT); 158323032Smav case 0x87b110b5: 159323032Smav device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Virtual"); 160323032Smav return (BUS_PROBE_DEFAULT); 161323032Smav } 162323032Smav return (ENXIO); 163323032Smav} 164323032Smav 165323032Smavstatic int 166323032Smavntb_plx_init(device_t dev) 167323032Smav{ 168323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 169323032Smav struct ntb_plx_mw_info *mw; 170323032Smav uint64_t val64; 171323032Smav int i; 172323032Smav uint32_t val; 173323032Smav 174323032Smav if (sc->b2b_mw >= 0) { 175323032Smav /* Set peer BAR0/1 size and address for B2B NTx access. */ 176323032Smav mw = &sc->mw_info[sc->b2b_mw]; 177323032Smav if (mw->mw_64bit) { 178323032Smav PNTX_WRITE(sc, 0xe4, 0x3); /* 64-bit */ 179323032Smav val64 = 0x2000000000000000 * mw->mw_bar | 0x4; 180323032Smav PNTX_WRITE(sc, PCIR_BAR(0), val64); 181323032Smav PNTX_WRITE(sc, PCIR_BAR(0) + 4, val64 >> 32); 182323032Smav } else { 183323032Smav PNTX_WRITE(sc, 0xe4, 0x2); /* 32-bit */ 184323032Smav val = 0x20000000 * mw->mw_bar; 185323032Smav PNTX_WRITE(sc, PCIR_BAR(0), val); 186323032Smav } 187323032Smav 188323032Smav /* Set Virtual to Link address translation for B2B. */ 189323032Smav for (i = 0; i < sc->mw_count; i++) { 190323032Smav mw = &sc->mw_info[i]; 191323032Smav if (mw->mw_64bit) { 192323032Smav val64 = 0x2000000000000000 * mw->mw_bar; 193323032Smav NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val64); 194323032Smav NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, val64 >> 32); 195323032Smav } else { 196323032Smav val = 0x20000000 * mw->mw_bar; 197323032Smav NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val); 198323032Smav } 199323032Smav } 200323032Smav 201324407Smav /* Make sure Virtual to Link A-LUT is disabled. */ 202324407Smav if (sc->alut) 203324407Smav PNTX_WRITE(sc, 0xc94, 0); 204324407Smav 205323844Smav /* Enable Link Interface LUT entries 0/1 for peer 0/1. */ 206323844Smav PNTX_WRITE(sc, 0xdb4, 0x00090001); 207323032Smav } 208323032Smav 209323032Smav /* 210323032Smav * Enable Virtual Interface LUT entry 0 for 0:0.0 and 211323032Smav * entry 1 for our Requester ID reported by chip. 212323032Smav */ 213323032Smav val = (NTX_READ(sc, 0xc90) << 16) | 0x00010001; 214323032Smav NTX_WRITE(sc, sc->link ? 0xdb4 : 0xd94, val); 215323032Smav 216323032Smav /* Set Link to Virtual address translation. */ 217323032Smav for (i = 0; i < sc->mw_count; i++) { 218323032Smav mw = &sc->mw_info[i]; 219323032Smav if (mw->mw_xlat_size != 0) 220323032Smav ntb_plx_mw_set_trans_internal(dev, i); 221323032Smav } 222323032Smav 223323032Smav pci_enable_busmaster(dev); 224323032Smav if (sc->b2b_mw >= 0) 225323032Smav PNTX_WRITE(sc, PCIR_COMMAND, PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 226323032Smav 227323032Smav return (0); 228323032Smav} 229323032Smav 230323032Smavstatic void 231323032Smavntb_plx_isr(void *arg) 232323032Smav{ 233323032Smav device_t dev = arg; 234323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 235323032Smav uint32_t val; 236323032Smav 237323032Smav ntb_db_event((device_t)arg, 0); 238323032Smav 239323453Smav if (sc->link) /* Link Interface has no Link Error registers. */ 240323453Smav return; 241323453Smav 242323032Smav val = NTX_READ(sc, 0xfe0); 243323032Smav if (val == 0) 244323032Smav return; 245323032Smav NTX_WRITE(sc, 0xfe0, val); 246323032Smav if (val & 1) 247323032Smav device_printf(dev, "Correctable Error\n"); 248323032Smav if (val & 2) 249323032Smav device_printf(dev, "Uncorrectable Error\n"); 250323032Smav if (val & 4) { 251323032Smav /* DL_Down resets link side registers, have to reinit. */ 252323032Smav ntb_plx_init(dev); 253323032Smav ntb_link_event(dev); 254323032Smav } 255323032Smav if (val & 8) 256323032Smav device_printf(dev, "Uncorrectable Error Message Drop\n"); 257323032Smav} 258323032Smav 259323032Smavstatic int 260323032Smavntb_plx_setup_intr(device_t dev) 261323032Smav{ 262323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 263323032Smav int error; 264323032Smav 265323032Smav /* 266323032Smav * XXX: This hardware supports MSI, but I found it unusable. 267323032Smav * It generates new MSI only when doorbell register goes from 268323032Smav * zero, but does not generate it when another bit is set or on 269323032Smav * partial clear. It makes operation very racy and unreliable. 270323032Smav * The data book mentions some mask juggling magic to workaround 271323032Smav * that, but I failed to make it work. 272323032Smav */ 273323032Smav sc->int_rid = 0; 274323032Smav sc->int_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 275323032Smav &sc->int_rid, RF_SHAREABLE|RF_ACTIVE); 276323032Smav if (sc->int_res == NULL) { 277323032Smav device_printf(dev, "bus_alloc_resource failed\n"); 278323032Smav return (ENOMEM); 279323032Smav } 280323032Smav error = bus_setup_intr(dev, sc->int_res, INTR_MPSAFE | INTR_TYPE_MISC, 281323032Smav NULL, ntb_plx_isr, dev, &sc->int_tag); 282323032Smav if (error != 0) { 283323032Smav device_printf(dev, "bus_setup_intr failed: %d\n", error); 284323032Smav return (error); 285323032Smav } 286323453Smav 287323453Smav if (!sc->link) { /* Link Interface has no Link Error registers. */ 288323453Smav NTX_WRITE(sc, 0xfe0, 0xf); /* Clear link interrupts. */ 289323453Smav NTX_WRITE(sc, 0xfe4, 0x0); /* Unmask link interrupts. */ 290323453Smav } 291323032Smav return (0); 292323032Smav} 293323032Smav 294323032Smavstatic void 295323032Smavntb_plx_teardown_intr(device_t dev) 296323032Smav{ 297323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 298323032Smav 299323453Smav if (!sc->link) /* Link Interface has no Link Error registers. */ 300323453Smav NTX_WRITE(sc, 0xfe4, 0xf); /* Mask link interrupts. */ 301323453Smav 302323032Smav if (sc->int_res) { 303323032Smav bus_teardown_intr(dev, sc->int_res, sc->int_tag); 304323032Smav bus_release_resource(dev, SYS_RES_IRQ, sc->int_rid, 305323032Smav sc->int_res); 306323032Smav } 307323032Smav} 308323032Smav 309323032Smavstatic int 310323032Smavntb_plx_attach(device_t dev) 311323032Smav{ 312323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 313323032Smav struct ntb_plx_mw_info *mw; 314323032Smav int error = 0, i; 315323032Smav uint32_t val; 316323032Smav char buf[32]; 317323032Smav 318323032Smav /* Identify what we are (what side of what NTx). */ 319323032Smav sc->dev = dev; 320323032Smav val = pci_read_config(dev, 0xc8c, 4); 321323032Smav sc->ntx = (val & 1) != 0; 322323032Smav sc->link = (val & 0x80000000) != 0; 323323032Smav 324323032Smav /* Get access to whole 256KB of chip configuration space via BAR0/1. */ 325323032Smav sc->conf_rid = PCIR_BAR(0); 326323032Smav sc->conf_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 327323032Smav &sc->conf_rid, RF_ACTIVE); 328323032Smav if (sc->conf_res == NULL) { 329323032Smav device_printf(dev, "Can't allocate configuration BAR.\n"); 330323032Smav return (ENXIO); 331323032Smav } 332323032Smav 333323032Smav /* Identify chip port we are connected to. */ 334323032Smav val = bus_read_4(sc->conf_res, 0x360); 335323032Smav sc->port = (val >> ((sc->ntx == 0) ? 8 : 16)) & 0x1f; 336323032Smav 337324407Smav /* Detect A-LUT enable and size. */ 338324407Smav val >>= 30; 339324407Smav sc->alut = (val == 0x3) ? 1 : ((val & (1 << sc->ntx)) ? 2 : 0); 340324407Smav if (sc->alut) 341324407Smav device_printf(dev, "%u A-LUT entries\n", 128 * sc->alut); 342324407Smav 343323032Smav /* Find configured memory windows at BAR2-5. */ 344323032Smav sc->mw_count = 0; 345323032Smav for (i = 2; i <= 5; i++) { 346323032Smav mw = &sc->mw_info[sc->mw_count]; 347323032Smav mw->mw_bar = i; 348323032Smav mw->mw_rid = PCIR_BAR(mw->mw_bar); 349323032Smav mw->mw_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 350323032Smav &mw->mw_rid, RF_ACTIVE); 351323032Smav if (mw->mw_res == NULL) 352323032Smav continue; 353323032Smav mw->mw_pbase = rman_get_start(mw->mw_res); 354323032Smav mw->mw_size = rman_get_size(mw->mw_res); 355323032Smav mw->mw_vbase = rman_get_virtual(mw->mw_res); 356323032Smav mw->mw_map_mode = VM_MEMATTR_UNCACHEABLE; 357323032Smav sc->mw_count++; 358323032Smav 359323032Smav /* Skip over adjacent BAR for 64-bit BARs. */ 360323032Smav val = pci_read_config(dev, PCIR_BAR(mw->mw_bar), 4); 361323032Smav if ((val & PCIM_BAR_MEM_TYPE) == PCIM_BAR_MEM_64) { 362323032Smav mw->mw_64bit = 1; 363323032Smav i++; 364323032Smav } 365323032Smav } 366323032Smav 367323032Smav /* Try to identify B2B mode. */ 368323032Smav i = 1; 369323032Smav snprintf(buf, sizeof(buf), "hint.%s.%d.b2b", device_get_name(dev), 370323032Smav device_get_unit(dev)); 371323032Smav TUNABLE_INT_FETCH(buf, &i); 372323032Smav if (sc->link) { 373323032Smav device_printf(dev, "NTB-to-Root Port mode (Link Interface)\n"); 374323032Smav sc->b2b_mw = -1; 375323032Smav } else if (i == 0) { 376323032Smav device_printf(dev, "NTB-to-Root Port mode (Virtual Interface)\n"); 377323032Smav sc->b2b_mw = -1; 378323032Smav } else { 379323032Smav device_printf(dev, "NTB-to-NTB (back-to-back) mode\n"); 380323032Smav 381323032Smav /* We need at least one memory window for B2B peer access. */ 382323032Smav if (sc->mw_count == 0) { 383323032Smav device_printf(dev, "No memory window BARs enabled.\n"); 384323032Smav error = ENXIO; 385323032Smav goto out; 386323032Smav } 387323032Smav sc->b2b_mw = sc->mw_count - 1; 388323032Smav 389323032Smav /* Use half of the window for B2B, but no less then 1MB. */ 390323032Smav mw = &sc->mw_info[sc->b2b_mw]; 391323032Smav if (mw->mw_size >= 2 * 1024 * 1024) 392323032Smav sc->b2b_off = mw->mw_size / 2; 393323032Smav else 394323032Smav sc->b2b_off = 0; 395323032Smav } 396323032Smav 397323032Smav /* 398323032Smav * Use Physical Layer User Test Pattern as additional scratchpad. 399323032Smav * Make sure they are present and enabled by writing to them. 400323032Smav * XXX: Its a hack, but standard 8 registers are not enough. 401323032Smav */ 402323453Smav sc->spad_offp1 = sc->spad_off1 = PLX_NTX_OUR_BASE(sc) + 0xc6c; 403323453Smav sc->spad_offp2 = sc->spad_off2 = PLX_PORT_BASE(sc->ntx * 8) + 0x20c; 404323032Smav if (sc->b2b_mw >= 0) { 405323453Smav /* In NTB-to-NTB mode each side has own scratchpads. */ 406323032Smav sc->spad_count1 = PLX_NUM_SPAD; 407323032Smav bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678); 408323032Smav if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678) 409323032Smav sc->spad_count2 = PLX_NUM_SPAD_PATT; 410323032Smav } else { 411323453Smav /* Otherwise we have share scratchpads with the peer. */ 412323032Smav if (sc->link) { 413323032Smav sc->spad_off1 += PLX_NUM_SPAD / 2 * 4; 414323032Smav sc->spad_off2 += PLX_NUM_SPAD_PATT / 2 * 4; 415323032Smav } else { 416323032Smav sc->spad_offp1 += PLX_NUM_SPAD / 2 * 4; 417323032Smav sc->spad_offp2 += PLX_NUM_SPAD_PATT / 2 * 4; 418323032Smav } 419323453Smav sc->spad_count1 = PLX_NUM_SPAD / 2; 420323032Smav bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678); 421323032Smav if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678) 422323032Smav sc->spad_count2 = PLX_NUM_SPAD_PATT / 2; 423323032Smav } 424323032Smav 425323032Smav /* Apply static part of NTB configuration. */ 426323032Smav ntb_plx_init(dev); 427323032Smav 428323032Smav /* Allocate and setup interrupts. */ 429323032Smav error = ntb_plx_setup_intr(dev); 430323032Smav if (error) 431323032Smav goto out; 432323032Smav 433323032Smav /* Attach children to this controller */ 434323032Smav error = ntb_register_device(dev); 435323032Smav 436323032Smavout: 437323032Smav if (error != 0) 438323032Smav ntb_plx_detach(dev); 439323032Smav return (error); 440323032Smav} 441323032Smav 442323032Smavstatic int 443323032Smavntb_plx_detach(device_t dev) 444323032Smav{ 445323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 446323032Smav struct ntb_plx_mw_info *mw; 447323032Smav int i; 448323032Smav 449323032Smav /* Detach & delete all children */ 450323032Smav ntb_unregister_device(dev); 451323032Smav 452323032Smav /* Disable and free interrupts. */ 453323032Smav ntb_plx_teardown_intr(dev); 454323032Smav 455323032Smav /* Free memory resources. */ 456323032Smav for (i = 0; i < sc->mw_count; i++) { 457323032Smav mw = &sc->mw_info[i]; 458323032Smav bus_release_resource(dev, SYS_RES_MEMORY, mw->mw_rid, 459323032Smav mw->mw_res); 460323032Smav } 461323032Smav bus_release_resource(dev, SYS_RES_MEMORY, sc->conf_rid, sc->conf_res); 462323032Smav return (0); 463323032Smav} 464323032Smav 465323032Smav 466323032Smavstatic bool 467323032Smavntb_plx_link_is_up(device_t dev, enum ntb_speed *speed, enum ntb_width *width) 468323032Smav{ 469323032Smav uint16_t link; 470323032Smav 471323032Smav link = pcie_read_config(dev, PCIER_LINK_STA, 2); 472323032Smav if (speed != NULL) 473323032Smav *speed = (link & PCIEM_LINK_STA_SPEED); 474323032Smav if (width != NULL) 475323032Smav *width = (link & PCIEM_LINK_STA_WIDTH) >> 4; 476323032Smav return ((link & PCIEM_LINK_STA_WIDTH) != 0); 477323032Smav} 478323032Smav 479323032Smavstatic int 480323032Smavntb_plx_link_enable(device_t dev, enum ntb_speed speed __unused, 481323032Smav enum ntb_width width __unused) 482323032Smav{ 483323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 484323032Smav uint32_t reg, val; 485323032Smav 486323032Smav /* The fact that we see the Link Interface means link is enabled. */ 487323032Smav if (sc->link) { 488323032Smav ntb_link_event(dev); 489323032Smav return (0); 490323032Smav } 491323032Smav 492323453Smav reg = PLX_PORT_CONTROL(sc); 493323032Smav val = bus_read_4(sc->conf_res, reg); 494323032Smav if ((val & (1 << (sc->port & 7))) == 0) { 495323032Smav /* If already enabled, generate fake link event and exit. */ 496323032Smav ntb_link_event(dev); 497323032Smav return (0); 498323032Smav } 499323032Smav val &= ~(1 << (sc->port & 7)); 500323032Smav bus_write_4(sc->conf_res, reg, val); 501323032Smav return (0); 502323032Smav} 503323032Smav 504323032Smavstatic int 505323032Smavntb_plx_link_disable(device_t dev) 506323032Smav{ 507323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 508323032Smav uint32_t reg, val; 509323032Smav 510323032Smav /* Link disable for Link Interface would be suicidal. */ 511323032Smav if (sc->link) 512323032Smav return (0); 513323032Smav 514323453Smav reg = PLX_PORT_CONTROL(sc); 515323032Smav val = bus_read_4(sc->conf_res, reg); 516323032Smav val |= (1 << (sc->port & 7)); 517323032Smav bus_write_4(sc->conf_res, reg, val); 518323032Smav return (0); 519323032Smav} 520323032Smav 521323032Smavstatic bool 522323032Smavntb_plx_link_enabled(device_t dev) 523323032Smav{ 524323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 525323032Smav uint32_t reg, val; 526323032Smav 527323032Smav /* The fact that we see the Link Interface means link is enabled. */ 528323032Smav if (sc->link) 529323032Smav return (TRUE); 530323032Smav 531323453Smav reg = PLX_PORT_CONTROL(sc); 532323032Smav val = bus_read_4(sc->conf_res, reg); 533323032Smav return ((val & (1 << (sc->port & 7))) == 0); 534323032Smav} 535323032Smav 536323032Smavstatic uint8_t 537323032Smavntb_plx_mw_count(device_t dev) 538323032Smav{ 539323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 540323032Smav 541323032Smav if (sc->b2b_mw >= 0 && sc->b2b_off == 0) 542323032Smav return (sc->mw_count - 1); /* B2B consumed whole window. */ 543323032Smav return (sc->mw_count); 544323032Smav} 545323032Smav 546323032Smavstatic int 547323032Smavntb_plx_mw_get_range(device_t dev, unsigned mw_idx, vm_paddr_t *base, 548323032Smav caddr_t *vbase, size_t *size, size_t *align, size_t *align_size, 549323032Smav bus_addr_t *plimit) 550323032Smav{ 551323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 552323032Smav struct ntb_plx_mw_info *mw; 553323032Smav size_t off; 554323032Smav 555323032Smav if (mw_idx >= sc->mw_count) 556323032Smav return (EINVAL); 557323032Smav off = 0; 558323032Smav if (mw_idx == sc->b2b_mw) { 559323032Smav KASSERT(sc->b2b_off != 0, 560323032Smav ("user shouldn't get non-shared b2b mw")); 561323032Smav off = sc->b2b_off; 562323032Smav } 563323032Smav mw = &sc->mw_info[mw_idx]; 564323032Smav 565323032Smav /* Local to remote memory window parameters. */ 566323032Smav if (base != NULL) 567323032Smav *base = mw->mw_pbase + off; 568323032Smav if (vbase != NULL) 569323032Smav *vbase = mw->mw_vbase + off; 570323032Smav if (size != NULL) 571323032Smav *size = mw->mw_size - off; 572323032Smav 573323032Smav /* 574323032Smav * Remote to local memory window translation address alignment. 575324407Smav * Translation address has to be aligned to the BAR size, but A-LUT 576324407Smav * entries re-map addresses can be aligned to 1/128 or 1/256 of it. 577324407Smav * XXX: In B2B mode we can change BAR size (and so alignmet) live, 578324407Smav * but there is no way to report it here, so report safe value. 579323032Smav */ 580324407Smav if (align != NULL) { 581324407Smav if (sc->alut && mw->mw_bar == 2) 582324407Smav *align = (mw->mw_size - off) / 128 / sc->alut; 583324407Smav else 584324407Smav *align = mw->mw_size - off; 585324407Smav } 586323032Smav 587323032Smav /* 588323032Smav * Remote to local memory window size alignment. 589324407Smav * The chip has no limit registers, but A-LUT, when available, allows 590324407Smav * access control with granularity of 1/128 or 1/256 of the BAR size. 591324407Smav * XXX: In B2B case we can change BAR size live, but there is no way 592324407Smav * to report it, so report half of the BAR size, that should be safe. 593324407Smav * In non-B2B case there is no control at all, so report the BAR size. 594323032Smav */ 595323032Smav if (align_size != NULL) { 596324407Smav if (sc->alut && mw->mw_bar == 2) 597324407Smav *align_size = (mw->mw_size - off) / 128 / sc->alut; 598324407Smav else if (sc->b2b_mw >= 0) 599324407Smav *align_size = (mw->mw_size - off) / 2; 600323032Smav else 601323032Smav *align_size = mw->mw_size - off; 602323032Smav } 603323032Smav 604323032Smav /* Remote to local memory window translation address upper limit. */ 605323032Smav if (plimit != NULL) 606323032Smav *plimit = mw->mw_64bit ? BUS_SPACE_MAXADDR : 607323032Smav BUS_SPACE_MAXADDR_32BIT; 608323032Smav return (0); 609323032Smav} 610323032Smav 611323032Smavstatic int 612323032Smavntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx) 613323032Smav{ 614323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 615323032Smav struct ntb_plx_mw_info *mw; 616324407Smav uint64_t addr, eaddr, off, size, bsize, esize, val64; 617323032Smav uint32_t val; 618324407Smav int i; 619323032Smav 620323032Smav mw = &sc->mw_info[mw_idx]; 621323032Smav addr = mw->mw_xlat_addr; 622323032Smav size = mw->mw_xlat_size; 623323032Smav off = 0; 624323032Smav if (mw_idx == sc->b2b_mw) { 625323032Smav off = sc->b2b_off; 626323032Smav KASSERT(off != 0, ("user shouldn't get non-shared b2b mw")); 627323032Smav 628323032Smav /* 629323032Smav * While generally we can set any BAR size on link side, 630323032Smav * for B2B shared window we can't go above preconfigured 631323032Smav * size due to BAR address alignment requirements. 632323032Smav */ 633323032Smav if (size > mw->mw_size - off) 634323032Smav return (EINVAL); 635323032Smav } 636323032Smav 637323032Smav if (size > 0) { 638323032Smav /* Round BAR size to next power of 2 or at least 1MB. */ 639324407Smav bsize = size; 640324407Smav if (!powerof2(bsize)) 641324407Smav bsize = 1LL << flsll(bsize); 642324407Smav if (bsize < 1024 * 1024) 643324407Smav bsize = 1024 * 1024; 644323032Smav 645324407Smav /* A-LUT has 128 or 256 times better granularity. */ 646324407Smav esize = bsize; 647324407Smav if (sc->alut && mw->mw_bar == 2) 648324407Smav esize /= 128 * sc->alut; 649324407Smav 650324407Smav /* addr should be aligned to BAR or A-LUT element size. */ 651324407Smav if ((addr & (esize - 1)) != 0) 652323032Smav return (EINVAL); 653324407Smav } else 654324407Smav esize = bsize = 0; 655323032Smav 656323032Smav if (mw->mw_64bit) { 657323032Smav if (sc->b2b_mw >= 0) { 658323032Smav /* Set Link Interface BAR size and enable/disable it. */ 659323032Smav val64 = 0; 660324407Smav if (bsize > 0) 661324407Smav val64 = (~(bsize - 1) & ~0xfffff); 662323844Smav val64 |= 0xc; 663323032Smav PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val64); 664323032Smav PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4 + 4, val64 >> 32); 665323032Smav 666323032Smav /* Set Link Interface BAR address. */ 667323032Smav val64 = 0x2000000000000000 * mw->mw_bar + off; 668323032Smav PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64); 669323032Smav PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar) + 4, val64 >> 32); 670323032Smav } 671323032Smav 672323032Smav /* Set Virtual Interface BARs address translation */ 673323032Smav PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr); 674323032Smav PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, addr >> 32); 675323032Smav } else { 676323032Smav /* Make sure we fit into 32-bit address space. */ 677323032Smav if ((addr & UINT32_MAX) != addr) 678323032Smav return (ERANGE); 679324407Smav if (((addr + bsize) & UINT32_MAX) != (addr + bsize)) 680323032Smav return (ERANGE); 681323032Smav 682323032Smav if (sc->b2b_mw >= 0) { 683323032Smav /* Set Link Interface BAR size and enable/disable it. */ 684323032Smav val = 0; 685324407Smav if (bsize > 0) 686324407Smav val = (~(bsize - 1) & ~0xfffff); 687323032Smav PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val); 688323032Smav 689323032Smav /* Set Link Interface BAR address. */ 690323032Smav val64 = 0x20000000 * mw->mw_bar + off; 691323032Smav PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64); 692323032Smav } 693323032Smav 694323032Smav /* Set Virtual Interface BARs address translation */ 695323032Smav PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr); 696323032Smav } 697324407Smav 698324407Smav /* Configure and enable Link to Virtual A-LUT if we need it. */ 699324407Smav if (sc->alut && mw->mw_bar == 2 && 700324407Smav ((addr & (bsize - 1)) != 0 || size != bsize)) { 701324407Smav eaddr = addr; 702324407Smav for (i = 0; i < 128 * sc->alut; i++) { 703324407Smav val = sc->link ? 0 : 1; 704324407Smav if (sc->alut == 1) 705324407Smav val += 2 * sc->ntx; 706324407Smav val *= 0x1000 * sc->alut; 707324407Smav val += 0x38000 + i * 4 + (i >= 128 ? 0x0e00 : 0); 708324407Smav bus_write_4(sc->conf_res, val, eaddr); 709324407Smav bus_write_4(sc->conf_res, val + 0x400, eaddr >> 32); 710324407Smav bus_write_4(sc->conf_res, val + 0x800, 711324407Smav (eaddr < addr + size) ? 0x3 : 0); 712324407Smav eaddr += esize; 713324407Smav } 714324407Smav NTX_WRITE(sc, 0xc94, 0x10000000); 715324407Smav } else if (sc->alut && mw->mw_bar == 2) 716324407Smav NTX_WRITE(sc, 0xc94, 0); 717324407Smav 718323032Smav return (0); 719323032Smav} 720323032Smav 721323032Smavstatic int 722323032Smavntb_plx_mw_set_trans(device_t dev, unsigned mw_idx, bus_addr_t addr, size_t size) 723323032Smav{ 724323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 725323032Smav struct ntb_plx_mw_info *mw; 726323032Smav 727323032Smav if (mw_idx >= sc->mw_count) 728323032Smav return (EINVAL); 729323032Smav mw = &sc->mw_info[mw_idx]; 730323032Smav mw->mw_xlat_addr = addr; 731323032Smav mw->mw_xlat_size = size; 732323032Smav return (ntb_plx_mw_set_trans_internal(dev, mw_idx)); 733323032Smav} 734323032Smav 735323032Smavstatic int 736323032Smavntb_plx_mw_clear_trans(device_t dev, unsigned mw_idx) 737323032Smav{ 738323032Smav 739323032Smav return (ntb_plx_mw_set_trans(dev, mw_idx, 0, 0)); 740323032Smav} 741323032Smav 742323032Smavstatic int 743323032Smavntb_plx_mw_get_wc(device_t dev, unsigned idx, vm_memattr_t *mode) 744323032Smav{ 745323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 746323032Smav struct ntb_plx_mw_info *mw; 747323032Smav 748323032Smav if (idx >= sc->mw_count) 749323032Smav return (EINVAL); 750323032Smav mw = &sc->mw_info[idx]; 751323032Smav *mode = mw->mw_map_mode; 752323032Smav return (0); 753323032Smav} 754323032Smav 755323032Smavstatic int 756323032Smavntb_plx_mw_set_wc(device_t dev, unsigned idx, vm_memattr_t mode) 757323032Smav{ 758323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 759323032Smav struct ntb_plx_mw_info *mw; 760323032Smav uint64_t off; 761323032Smav int rc; 762323032Smav 763323032Smav if (idx >= sc->mw_count) 764323032Smav return (EINVAL); 765323032Smav mw = &sc->mw_info[idx]; 766323032Smav if (mw->mw_map_mode == mode) 767323032Smav return (0); 768323032Smav 769323032Smav off = 0; 770323032Smav if (idx == sc->b2b_mw) { 771323032Smav KASSERT(sc->b2b_off != 0, 772323032Smav ("user shouldn't get non-shared b2b mw")); 773323032Smav off = sc->b2b_off; 774323032Smav } 775323032Smav 776323032Smav rc = pmap_change_attr((vm_offset_t)mw->mw_vbase + off, 777323032Smav mw->mw_size - off, mode); 778323032Smav if (rc == 0) 779323032Smav mw->mw_map_mode = mode; 780323032Smav return (rc); 781323032Smav} 782323032Smav 783323032Smavstatic uint8_t 784323032Smavntb_plx_spad_count(device_t dev) 785323032Smav{ 786323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 787323032Smav 788323032Smav return (sc->spad_count1 + sc->spad_count2); 789323032Smav} 790323032Smav 791323032Smavstatic int 792323032Smavntb_plx_spad_write(device_t dev, unsigned int idx, uint32_t val) 793323032Smav{ 794323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 795323032Smav u_int off; 796323032Smav 797323032Smav if (idx >= sc->spad_count1 + sc->spad_count2) 798323032Smav return (EINVAL); 799323032Smav 800323032Smav if (idx < sc->spad_count1) 801323032Smav off = sc->spad_off1 + idx * 4; 802323032Smav else 803323032Smav off = sc->spad_off2 + (idx - sc->spad_count1) * 4; 804323032Smav bus_write_4(sc->conf_res, off, val); 805323032Smav return (0); 806323032Smav} 807323032Smav 808323032Smavstatic void 809323032Smavntb_plx_spad_clear(device_t dev) 810323032Smav{ 811323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 812323032Smav int i; 813323032Smav 814323032Smav for (i = 0; i < sc->spad_count1 + sc->spad_count2; i++) 815323032Smav ntb_plx_spad_write(dev, i, 0); 816323032Smav} 817323032Smav 818323032Smavstatic int 819323032Smavntb_plx_spad_read(device_t dev, unsigned int idx, uint32_t *val) 820323032Smav{ 821323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 822323032Smav u_int off; 823323032Smav 824323032Smav if (idx >= sc->spad_count1 + sc->spad_count2) 825323032Smav return (EINVAL); 826323032Smav 827323032Smav if (idx < sc->spad_count1) 828323032Smav off = sc->spad_off1 + idx * 4; 829323032Smav else 830323032Smav off = sc->spad_off2 + (idx - sc->spad_count1) * 4; 831323032Smav *val = bus_read_4(sc->conf_res, off); 832323032Smav return (0); 833323032Smav} 834323032Smav 835323032Smavstatic int 836323032Smavntb_plx_peer_spad_write(device_t dev, unsigned int idx, uint32_t val) 837323032Smav{ 838323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 839323032Smav u_int off; 840323032Smav 841323032Smav if (idx >= sc->spad_count1 + sc->spad_count2) 842323032Smav return (EINVAL); 843323032Smav 844323032Smav if (idx < sc->spad_count1) 845323032Smav off = sc->spad_offp1 + idx * 4; 846323032Smav else 847323032Smav off = sc->spad_offp2 + (idx - sc->spad_count1) * 4; 848323032Smav if (sc->b2b_mw >= 0) 849323032Smav bus_write_4(sc->mw_info[sc->b2b_mw].mw_res, off, val); 850323032Smav else 851323032Smav bus_write_4(sc->conf_res, off, val); 852323032Smav return (0); 853323032Smav} 854323032Smav 855323032Smavstatic int 856323032Smavntb_plx_peer_spad_read(device_t dev, unsigned int idx, uint32_t *val) 857323032Smav{ 858323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 859323032Smav u_int off; 860323032Smav 861323032Smav if (idx >= sc->spad_count1 + sc->spad_count2) 862323032Smav return (EINVAL); 863323032Smav 864323032Smav if (idx < sc->spad_count1) 865323032Smav off = sc->spad_offp1 + idx * 4; 866323032Smav else 867323032Smav off = sc->spad_offp2 + (idx - sc->spad_count1) * 4; 868323032Smav if (sc->b2b_mw >= 0) 869323032Smav *val = bus_read_4(sc->mw_info[sc->b2b_mw].mw_res, off); 870323032Smav else 871323032Smav *val = bus_read_4(sc->conf_res, off); 872323032Smav return (0); 873323032Smav} 874323032Smav 875323032Smavstatic uint64_t 876323032Smavntb_plx_db_valid_mask(device_t dev) 877323032Smav{ 878323032Smav 879323032Smav return ((1LL << PLX_NUM_DB) - 1); 880323032Smav} 881323032Smav 882323032Smavstatic int 883323032Smavntb_plx_db_vector_count(device_t dev) 884323032Smav{ 885323032Smav 886323032Smav return (1); 887323032Smav} 888323032Smav 889323032Smavstatic uint64_t 890323032Smavntb_plx_db_vector_mask(device_t dev, uint32_t vector) 891323032Smav{ 892323032Smav 893323032Smav if (vector > 0) 894323032Smav return (0); 895323032Smav return ((1LL << PLX_NUM_DB) - 1); 896323032Smav} 897323032Smav 898323032Smavstatic void 899323032Smavntb_plx_db_clear(device_t dev, uint64_t bits) 900323032Smav{ 901323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 902323032Smav 903323032Smav NTX_WRITE(sc, sc->link ? 0xc60 : 0xc50, bits); 904323032Smav} 905323032Smav 906323032Smavstatic void 907323032Smavntb_plx_db_clear_mask(device_t dev, uint64_t bits) 908323032Smav{ 909323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 910323032Smav 911323032Smav NTX_WRITE(sc, sc->link ? 0xc68 : 0xc58, bits); 912323032Smav} 913323032Smav 914323032Smavstatic uint64_t 915323032Smavntb_plx_db_read(device_t dev) 916323032Smav{ 917323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 918323032Smav 919323032Smav return (NTX_READ(sc, sc->link ? 0xc5c : 0xc4c)); 920323032Smav} 921323032Smav 922323032Smavstatic void 923323032Smavntb_plx_db_set_mask(device_t dev, uint64_t bits) 924323032Smav{ 925323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 926323032Smav 927323032Smav NTX_WRITE(sc, sc->link ? 0xc64 : 0xc54, bits); 928323032Smav} 929323032Smav 930323032Smavstatic int 931323032Smavntb_plx_peer_db_addr(device_t dev, bus_addr_t *db_addr, vm_size_t *db_size) 932323032Smav{ 933323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 934323032Smav struct ntb_plx_mw_info *mw; 935323032Smav 936323032Smav KASSERT((db_addr != NULL && db_size != NULL), ("must be non-NULL")); 937323032Smav 938323032Smav if (sc->b2b_mw >= 0) { 939323032Smav mw = &sc->mw_info[sc->b2b_mw]; 940323032Smav *db_addr = (uint64_t)mw->mw_pbase + PLX_NTX_BASE(sc) + 0xc4c; 941323032Smav } else { 942323032Smav *db_addr = rman_get_start(sc->conf_res) + PLX_NTX_BASE(sc); 943323032Smav *db_addr += sc->link ? 0xc4c : 0xc5c; 944323032Smav } 945323032Smav *db_size = 4; 946323032Smav return (0); 947323032Smav} 948323032Smav 949323032Smavstatic void 950323032Smavntb_plx_peer_db_set(device_t dev, uint64_t bit) 951323032Smav{ 952323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 953323032Smav 954323032Smav if (sc->b2b_mw >= 0) 955323032Smav BNTX_WRITE(sc, 0xc4c, bit); 956323032Smav else 957323032Smav NTX_WRITE(sc, sc->link ? 0xc4c : 0xc5c, bit); 958323032Smav} 959323032Smav 960323032Smavstatic device_method_t ntb_plx_methods[] = { 961323032Smav /* Device interface */ 962323032Smav DEVMETHOD(device_probe, ntb_plx_probe), 963323032Smav DEVMETHOD(device_attach, ntb_plx_attach), 964323032Smav DEVMETHOD(device_detach, ntb_plx_detach), 965323455Smav /* Bus interface */ 966323455Smav DEVMETHOD(bus_child_location_str, ntb_child_location_str), 967323455Smav DEVMETHOD(bus_print_child, ntb_print_child), 968323032Smav /* NTB interface */ 969323032Smav DEVMETHOD(ntb_link_is_up, ntb_plx_link_is_up), 970323032Smav DEVMETHOD(ntb_link_enable, ntb_plx_link_enable), 971323032Smav DEVMETHOD(ntb_link_disable, ntb_plx_link_disable), 972323032Smav DEVMETHOD(ntb_link_enabled, ntb_plx_link_enabled), 973323032Smav DEVMETHOD(ntb_mw_count, ntb_plx_mw_count), 974323032Smav DEVMETHOD(ntb_mw_get_range, ntb_plx_mw_get_range), 975323032Smav DEVMETHOD(ntb_mw_set_trans, ntb_plx_mw_set_trans), 976323032Smav DEVMETHOD(ntb_mw_clear_trans, ntb_plx_mw_clear_trans), 977323032Smav DEVMETHOD(ntb_mw_get_wc, ntb_plx_mw_get_wc), 978323032Smav DEVMETHOD(ntb_mw_set_wc, ntb_plx_mw_set_wc), 979323032Smav DEVMETHOD(ntb_spad_count, ntb_plx_spad_count), 980323032Smav DEVMETHOD(ntb_spad_clear, ntb_plx_spad_clear), 981323032Smav DEVMETHOD(ntb_spad_write, ntb_plx_spad_write), 982323032Smav DEVMETHOD(ntb_spad_read, ntb_plx_spad_read), 983323032Smav DEVMETHOD(ntb_peer_spad_write, ntb_plx_peer_spad_write), 984323032Smav DEVMETHOD(ntb_peer_spad_read, ntb_plx_peer_spad_read), 985323032Smav DEVMETHOD(ntb_db_valid_mask, ntb_plx_db_valid_mask), 986323032Smav DEVMETHOD(ntb_db_vector_count, ntb_plx_db_vector_count), 987323032Smav DEVMETHOD(ntb_db_vector_mask, ntb_plx_db_vector_mask), 988323032Smav DEVMETHOD(ntb_db_clear, ntb_plx_db_clear), 989323032Smav DEVMETHOD(ntb_db_clear_mask, ntb_plx_db_clear_mask), 990323032Smav DEVMETHOD(ntb_db_read, ntb_plx_db_read), 991323032Smav DEVMETHOD(ntb_db_set_mask, ntb_plx_db_set_mask), 992323032Smav DEVMETHOD(ntb_peer_db_addr, ntb_plx_peer_db_addr), 993323032Smav DEVMETHOD(ntb_peer_db_set, ntb_plx_peer_db_set), 994323032Smav DEVMETHOD_END 995323032Smav}; 996323032Smav 997323032Smavstatic DEFINE_CLASS_0(ntb_hw, ntb_plx_driver, ntb_plx_methods, 998323032Smav sizeof(struct ntb_plx_softc)); 999323032SmavDRIVER_MODULE(ntb_hw_plx, pci, ntb_plx_driver, ntb_hw_devclass, NULL, NULL); 1000323032SmavMODULE_DEPEND(ntb_hw_plx, ntb, 1, 1, 1); 1001323032SmavMODULE_VERSION(ntb_hw_plx, 1); 1002