1323032Smav/*- 2355041Smav * Copyright (c) 2017-2019 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 355152 2019-11-28 00:41:42Z 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. */ 59355041Smav#define PLX_MAX_SPLIT 128 /* Allow are at most 128 splits. */ 60323032Smav 61323032Smavstruct ntb_plx_mw_info { 62323032Smav int mw_bar; 63323032Smav int mw_64bit; 64323032Smav int mw_rid; 65323032Smav struct resource *mw_res; 66323032Smav vm_paddr_t mw_pbase; 67323032Smav caddr_t mw_vbase; 68323032Smav vm_size_t mw_size; 69355041Smav struct { 70355041Smav vm_memattr_t mw_map_mode; 71355041Smav bus_addr_t mw_xlat_addr; 72355041Smav bus_size_t mw_xlat_size; 73355041Smav } splits[PLX_MAX_SPLIT]; 74323032Smav}; 75323032Smav 76323032Smavstruct ntb_plx_softc { 77323032Smav /* ntb.c context. Do not move! Must go first! */ 78323032Smav void *ntb_store; 79323032Smav 80323032Smav device_t dev; 81323032Smav struct resource *conf_res; 82323032Smav int conf_rid; 83323032Smav u_int ntx; /* NTx number within chip. */ 84323032Smav u_int link; /* Link v/s Virtual side. */ 85323032Smav u_int port; /* Port number within chip. */ 86324407Smav u_int alut; /* A-LUT is enabled for NTx */ 87355041Smav u_int split; /* split BAR2 into 2^x parts */ 88323032Smav 89323032Smav int int_rid; 90323032Smav struct resource *int_res; 91323032Smav void *int_tag; 92323032Smav 93323032Smav struct ntb_plx_mw_info mw_info[PLX_MAX_BARS]; 94323032Smav int mw_count; /* Number of memory windows. */ 95323032Smav 96323032Smav int spad_count1; /* Number of standard spads. */ 97323032Smav int spad_count2; /* Number of extra spads. */ 98323032Smav uint32_t spad_off1; /* Offset of our spads. */ 99323032Smav uint32_t spad_off2; /* Offset of our extra spads. */ 100323032Smav uint32_t spad_offp1; /* Offset of peer spads. */ 101323032Smav uint32_t spad_offp2; /* Offset of peer extra spads. */ 102323032Smav 103323032Smav /* Parameters of window shared with peer config access in B2B mode. */ 104323032Smav int b2b_mw; /* Shared window number. */ 105323032Smav uint64_t b2b_off; /* Offset in shared window. */ 106323032Smav}; 107323032Smav 108323032Smav#define PLX_NT0_BASE 0x3E000 109323032Smav#define PLX_NT1_BASE 0x3C000 110323032Smav#define PLX_NTX_BASE(sc) ((sc)->ntx ? PLX_NT1_BASE : PLX_NT0_BASE) 111323032Smav#define PLX_NTX_LINK_OFFSET 0x01000 112323032Smav 113323032Smav/* Bases of NTx our/peer interface registers */ 114323453Smav#define PLX_NTX_OUR_BASE(sc) \ 115323032Smav (PLX_NTX_BASE(sc) + ((sc)->link ? PLX_NTX_LINK_OFFSET : 0)) 116323453Smav#define PLX_NTX_PEER_BASE(sc) \ 117323032Smav (PLX_NTX_BASE(sc) + ((sc)->link ? 0 : PLX_NTX_LINK_OFFSET)) 118323032Smav 119323032Smav/* Read/write NTx our interface registers */ 120323453Smav#define NTX_READ(sc, reg) \ 121323453Smav bus_read_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg)) 122323453Smav#define NTX_WRITE(sc, reg, val) \ 123323453Smav bus_write_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg), (val)) 124323032Smav 125323032Smav/* Read/write NTx peer interface registers */ 126323453Smav#define PNTX_READ(sc, reg) \ 127323453Smav bus_read_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg)) 128323453Smav#define PNTX_WRITE(sc, reg, val) \ 129323453Smav bus_write_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg), (val)) 130323032Smav 131323032Smav/* Read/write B2B NTx registers */ 132323453Smav#define BNTX_READ(sc, reg) \ 133323032Smav bus_read_4((sc)->mw_info[(sc)->b2b_mw].mw_res, \ 134323032Smav PLX_NTX_BASE(sc) + (reg)) 135323453Smav#define BNTX_WRITE(sc, reg, val) \ 136323032Smav bus_write_4((sc)->mw_info[(sc)->b2b_mw].mw_res, \ 137323032Smav PLX_NTX_BASE(sc) + (reg), (val)) 138323032Smav 139323453Smav#define PLX_PORT_BASE(p) ((p) << 12) 140323453Smav#define PLX_STATION_PORT_BASE(sc) PLX_PORT_BASE((sc)->port & ~7) 141323453Smav 142323453Smav#define PLX_PORT_CONTROL(sc) (PLX_STATION_PORT_BASE(sc) + 0x208) 143323453Smav 144323032Smavstatic int ntb_plx_init(device_t dev); 145323032Smavstatic int ntb_plx_detach(device_t dev); 146323032Smavstatic int ntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx); 147323032Smav 148323032Smavstatic int 149323032Smavntb_plx_probe(device_t dev) 150323032Smav{ 151323032Smav 152323032Smav switch (pci_get_devid(dev)) { 153323032Smav case 0x87a010b5: 154323032Smav device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Link"); 155323032Smav return (BUS_PROBE_DEFAULT); 156323032Smav case 0x87a110b5: 157323032Smav device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Link"); 158323032Smav return (BUS_PROBE_DEFAULT); 159323032Smav case 0x87b010b5: 160323032Smav device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Virtual"); 161323032Smav return (BUS_PROBE_DEFAULT); 162323032Smav case 0x87b110b5: 163323032Smav device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Virtual"); 164323032Smav return (BUS_PROBE_DEFAULT); 165323032Smav } 166323032Smav return (ENXIO); 167323032Smav} 168323032Smav 169323032Smavstatic int 170323032Smavntb_plx_init(device_t dev) 171323032Smav{ 172323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 173323032Smav struct ntb_plx_mw_info *mw; 174323032Smav uint64_t val64; 175323032Smav int i; 176323032Smav uint32_t val; 177323032Smav 178323032Smav if (sc->b2b_mw >= 0) { 179323032Smav /* Set peer BAR0/1 size and address for B2B NTx access. */ 180323032Smav mw = &sc->mw_info[sc->b2b_mw]; 181323032Smav if (mw->mw_64bit) { 182323032Smav PNTX_WRITE(sc, 0xe4, 0x3); /* 64-bit */ 183323032Smav val64 = 0x2000000000000000 * mw->mw_bar | 0x4; 184323032Smav PNTX_WRITE(sc, PCIR_BAR(0), val64); 185323032Smav PNTX_WRITE(sc, PCIR_BAR(0) + 4, val64 >> 32); 186323032Smav } else { 187323032Smav PNTX_WRITE(sc, 0xe4, 0x2); /* 32-bit */ 188323032Smav val = 0x20000000 * mw->mw_bar; 189323032Smav PNTX_WRITE(sc, PCIR_BAR(0), val); 190323032Smav } 191323032Smav 192323032Smav /* Set Virtual to Link address translation for B2B. */ 193323032Smav for (i = 0; i < sc->mw_count; i++) { 194323032Smav mw = &sc->mw_info[i]; 195323032Smav if (mw->mw_64bit) { 196323032Smav val64 = 0x2000000000000000 * mw->mw_bar; 197323032Smav NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val64); 198323032Smav NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, val64 >> 32); 199323032Smav } else { 200323032Smav val = 0x20000000 * mw->mw_bar; 201323032Smav NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val); 202323032Smav } 203323032Smav } 204323032Smav 205324407Smav /* Make sure Virtual to Link A-LUT is disabled. */ 206324407Smav if (sc->alut) 207324407Smav PNTX_WRITE(sc, 0xc94, 0); 208324407Smav 209344652Smav /* Enable all Link Interface LUT entries for peer. */ 210344652Smav for (i = 0; i < 32; i += 2) { 211344652Smav PNTX_WRITE(sc, 0xdb4 + i * 2, 212344652Smav 0x00010001 | ((i + 1) << 19) | (i << 3)); 213344652Smav } 214323032Smav } 215323032Smav 216323032Smav /* 217344652Smav * Enable Virtual Interface LUT entry 0 for 0:0.*. 218344652Smav * entry 1 for our Requester ID reported by the chip, 219344652Smav * entries 2-5 for 0/64/128/192:4.* of I/OAT DMA engines. 220344652Smav * XXX: Its a hack, we can't know all DMA engines, but this covers all 221344652Smav * I/OAT of Xeon E5/E7 at least from Sandy Bridge till Skylake I saw. 222323032Smav */ 223323032Smav val = (NTX_READ(sc, 0xc90) << 16) | 0x00010001; 224323032Smav NTX_WRITE(sc, sc->link ? 0xdb4 : 0xd94, val); 225344652Smav NTX_WRITE(sc, sc->link ? 0xdb8 : 0xd98, 0x40210021); 226344652Smav NTX_WRITE(sc, sc->link ? 0xdbc : 0xd9c, 0xc0218021); 227323032Smav 228323032Smav /* Set Link to Virtual address translation. */ 229355041Smav for (i = 0; i < sc->mw_count; i++) 230355041Smav ntb_plx_mw_set_trans_internal(dev, i); 231323032Smav 232323032Smav pci_enable_busmaster(dev); 233323032Smav if (sc->b2b_mw >= 0) 234323032Smav PNTX_WRITE(sc, PCIR_COMMAND, PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 235323032Smav 236323032Smav return (0); 237323032Smav} 238323032Smav 239323032Smavstatic void 240323032Smavntb_plx_isr(void *arg) 241323032Smav{ 242323032Smav device_t dev = arg; 243323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 244323032Smav uint32_t val; 245323032Smav 246323032Smav ntb_db_event((device_t)arg, 0); 247323032Smav 248323453Smav if (sc->link) /* Link Interface has no Link Error registers. */ 249323453Smav return; 250323453Smav 251323032Smav val = NTX_READ(sc, 0xfe0); 252323032Smav if (val == 0) 253323032Smav return; 254323032Smav NTX_WRITE(sc, 0xfe0, val); 255323032Smav if (val & 1) 256323032Smav device_printf(dev, "Correctable Error\n"); 257323032Smav if (val & 2) 258323032Smav device_printf(dev, "Uncorrectable Error\n"); 259323032Smav if (val & 4) { 260323032Smav /* DL_Down resets link side registers, have to reinit. */ 261323032Smav ntb_plx_init(dev); 262323032Smav ntb_link_event(dev); 263323032Smav } 264323032Smav if (val & 8) 265323032Smav device_printf(dev, "Uncorrectable Error Message Drop\n"); 266323032Smav} 267323032Smav 268323032Smavstatic int 269323032Smavntb_plx_setup_intr(device_t dev) 270323032Smav{ 271323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 272323032Smav int error; 273323032Smav 274323032Smav /* 275323032Smav * XXX: This hardware supports MSI, but I found it unusable. 276323032Smav * It generates new MSI only when doorbell register goes from 277323032Smav * zero, but does not generate it when another bit is set or on 278323032Smav * partial clear. It makes operation very racy and unreliable. 279323032Smav * The data book mentions some mask juggling magic to workaround 280323032Smav * that, but I failed to make it work. 281323032Smav */ 282323032Smav sc->int_rid = 0; 283323032Smav sc->int_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 284323032Smav &sc->int_rid, RF_SHAREABLE|RF_ACTIVE); 285323032Smav if (sc->int_res == NULL) { 286323032Smav device_printf(dev, "bus_alloc_resource failed\n"); 287323032Smav return (ENOMEM); 288323032Smav } 289323032Smav error = bus_setup_intr(dev, sc->int_res, INTR_MPSAFE | INTR_TYPE_MISC, 290323032Smav NULL, ntb_plx_isr, dev, &sc->int_tag); 291323032Smav if (error != 0) { 292323032Smav device_printf(dev, "bus_setup_intr failed: %d\n", error); 293323032Smav return (error); 294323032Smav } 295323453Smav 296323453Smav if (!sc->link) { /* Link Interface has no Link Error registers. */ 297323453Smav NTX_WRITE(sc, 0xfe0, 0xf); /* Clear link interrupts. */ 298323453Smav NTX_WRITE(sc, 0xfe4, 0x0); /* Unmask link interrupts. */ 299323453Smav } 300323032Smav return (0); 301323032Smav} 302323032Smav 303323032Smavstatic void 304323032Smavntb_plx_teardown_intr(device_t dev) 305323032Smav{ 306323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 307323032Smav 308323453Smav if (!sc->link) /* Link Interface has no Link Error registers. */ 309323453Smav NTX_WRITE(sc, 0xfe4, 0xf); /* Mask link interrupts. */ 310323453Smav 311323032Smav if (sc->int_res) { 312323032Smav bus_teardown_intr(dev, sc->int_res, sc->int_tag); 313323032Smav bus_release_resource(dev, SYS_RES_IRQ, sc->int_rid, 314323032Smav sc->int_res); 315323032Smav } 316323032Smav} 317323032Smav 318323032Smavstatic int 319323032Smavntb_plx_attach(device_t dev) 320323032Smav{ 321323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 322323032Smav struct ntb_plx_mw_info *mw; 323355041Smav int error = 0, i, j; 324323032Smav uint32_t val; 325323032Smav char buf[32]; 326323032Smav 327323032Smav /* Identify what we are (what side of what NTx). */ 328323032Smav sc->dev = dev; 329323032Smav val = pci_read_config(dev, 0xc8c, 4); 330323032Smav sc->ntx = (val & 1) != 0; 331323032Smav sc->link = (val & 0x80000000) != 0; 332323032Smav 333323032Smav /* Get access to whole 256KB of chip configuration space via BAR0/1. */ 334323032Smav sc->conf_rid = PCIR_BAR(0); 335323032Smav sc->conf_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 336323032Smav &sc->conf_rid, RF_ACTIVE); 337323032Smav if (sc->conf_res == NULL) { 338323032Smav device_printf(dev, "Can't allocate configuration BAR.\n"); 339323032Smav return (ENXIO); 340323032Smav } 341323032Smav 342323032Smav /* Identify chip port we are connected to. */ 343323032Smav val = bus_read_4(sc->conf_res, 0x360); 344323032Smav sc->port = (val >> ((sc->ntx == 0) ? 8 : 16)) & 0x1f; 345323032Smav 346324407Smav /* Detect A-LUT enable and size. */ 347324407Smav val >>= 30; 348324407Smav sc->alut = (val == 0x3) ? 1 : ((val & (1 << sc->ntx)) ? 2 : 0); 349324407Smav if (sc->alut) 350324407Smav device_printf(dev, "%u A-LUT entries\n", 128 * sc->alut); 351324407Smav 352323032Smav /* Find configured memory windows at BAR2-5. */ 353323032Smav sc->mw_count = 0; 354323032Smav for (i = 2; i <= 5; i++) { 355323032Smav mw = &sc->mw_info[sc->mw_count]; 356323032Smav mw->mw_bar = i; 357323032Smav mw->mw_rid = PCIR_BAR(mw->mw_bar); 358323032Smav mw->mw_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 359323032Smav &mw->mw_rid, RF_ACTIVE); 360323032Smav if (mw->mw_res == NULL) 361323032Smav continue; 362323032Smav mw->mw_pbase = rman_get_start(mw->mw_res); 363323032Smav mw->mw_size = rman_get_size(mw->mw_res); 364323032Smav mw->mw_vbase = rman_get_virtual(mw->mw_res); 365355041Smav for (j = 0; j < PLX_MAX_SPLIT; j++) 366355041Smav mw->splits[j].mw_map_mode = VM_MEMATTR_UNCACHEABLE; 367323032Smav sc->mw_count++; 368323032Smav 369323032Smav /* Skip over adjacent BAR for 64-bit BARs. */ 370323032Smav val = pci_read_config(dev, PCIR_BAR(mw->mw_bar), 4); 371323032Smav if ((val & PCIM_BAR_MEM_TYPE) == PCIM_BAR_MEM_64) { 372323032Smav mw->mw_64bit = 1; 373323032Smav i++; 374323032Smav } 375323032Smav } 376323032Smav 377323032Smav /* Try to identify B2B mode. */ 378323032Smav i = 1; 379323032Smav snprintf(buf, sizeof(buf), "hint.%s.%d.b2b", device_get_name(dev), 380323032Smav device_get_unit(dev)); 381323032Smav TUNABLE_INT_FETCH(buf, &i); 382323032Smav if (sc->link) { 383323032Smav device_printf(dev, "NTB-to-Root Port mode (Link Interface)\n"); 384323032Smav sc->b2b_mw = -1; 385323032Smav } else if (i == 0) { 386323032Smav device_printf(dev, "NTB-to-Root Port mode (Virtual Interface)\n"); 387323032Smav sc->b2b_mw = -1; 388323032Smav } else { 389323032Smav device_printf(dev, "NTB-to-NTB (back-to-back) mode\n"); 390323032Smav 391323032Smav /* We need at least one memory window for B2B peer access. */ 392323032Smav if (sc->mw_count == 0) { 393323032Smav device_printf(dev, "No memory window BARs enabled.\n"); 394323032Smav error = ENXIO; 395323032Smav goto out; 396323032Smav } 397323032Smav sc->b2b_mw = sc->mw_count - 1; 398323032Smav 399323032Smav /* Use half of the window for B2B, but no less then 1MB. */ 400323032Smav mw = &sc->mw_info[sc->b2b_mw]; 401323032Smav if (mw->mw_size >= 2 * 1024 * 1024) 402323032Smav sc->b2b_off = mw->mw_size / 2; 403323032Smav else 404323032Smav sc->b2b_off = 0; 405323032Smav } 406323032Smav 407355041Smav snprintf(buf, sizeof(buf), "hint.%s.%d.split", device_get_name(dev), 408355041Smav device_get_unit(dev)); 409355041Smav TUNABLE_INT_FETCH(buf, &sc->split); 410355041Smav if (sc->split > 7) { 411355041Smav device_printf(dev, "Split value is too high (%u)\n", sc->split); 412355041Smav sc->split = 0; 413355041Smav } else if (sc->split > 0 && sc->alut == 0) { 414355041Smav device_printf(dev, "Can't split with disabled A-LUT\n"); 415355041Smav sc->split = 0; 416355041Smav } else if (sc->split > 0 && (sc->mw_count == 0 || sc->mw_info[0].mw_bar != 2)) { 417355041Smav device_printf(dev, "Can't split disabled BAR2\n"); 418355041Smav sc->split = 0; 419355041Smav } else if (sc->split > 0 && (sc->b2b_mw == 0 && sc->b2b_off == 0)) { 420355041Smav device_printf(dev, "Can't split BAR2 consumed by B2B\n"); 421355041Smav sc->split = 0; 422355041Smav } else if (sc->split > 0) { 423355041Smav device_printf(dev, "Splitting BAR2 into %d memory windows\n", 424355041Smav 1 << sc->split); 425355041Smav } 426355041Smav 427323032Smav /* 428323032Smav * Use Physical Layer User Test Pattern as additional scratchpad. 429323032Smav * Make sure they are present and enabled by writing to them. 430323032Smav * XXX: Its a hack, but standard 8 registers are not enough. 431323032Smav */ 432323453Smav sc->spad_offp1 = sc->spad_off1 = PLX_NTX_OUR_BASE(sc) + 0xc6c; 433323453Smav sc->spad_offp2 = sc->spad_off2 = PLX_PORT_BASE(sc->ntx * 8) + 0x20c; 434323032Smav if (sc->b2b_mw >= 0) { 435323453Smav /* In NTB-to-NTB mode each side has own scratchpads. */ 436323032Smav sc->spad_count1 = PLX_NUM_SPAD; 437323032Smav bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678); 438323032Smav if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678) 439323032Smav sc->spad_count2 = PLX_NUM_SPAD_PATT; 440323032Smav } else { 441323453Smav /* Otherwise we have share scratchpads with the peer. */ 442323032Smav if (sc->link) { 443323032Smav sc->spad_off1 += PLX_NUM_SPAD / 2 * 4; 444323032Smav sc->spad_off2 += PLX_NUM_SPAD_PATT / 2 * 4; 445323032Smav } else { 446323032Smav sc->spad_offp1 += PLX_NUM_SPAD / 2 * 4; 447323032Smav sc->spad_offp2 += PLX_NUM_SPAD_PATT / 2 * 4; 448323032Smav } 449323453Smav sc->spad_count1 = PLX_NUM_SPAD / 2; 450323032Smav bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678); 451323032Smav if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678) 452323032Smav sc->spad_count2 = PLX_NUM_SPAD_PATT / 2; 453323032Smav } 454323032Smav 455323032Smav /* Apply static part of NTB configuration. */ 456323032Smav ntb_plx_init(dev); 457323032Smav 458323032Smav /* Allocate and setup interrupts. */ 459323032Smav error = ntb_plx_setup_intr(dev); 460323032Smav if (error) 461323032Smav goto out; 462323032Smav 463323032Smav /* Attach children to this controller */ 464323032Smav error = ntb_register_device(dev); 465323032Smav 466323032Smavout: 467323032Smav if (error != 0) 468323032Smav ntb_plx_detach(dev); 469323032Smav return (error); 470323032Smav} 471323032Smav 472323032Smavstatic int 473323032Smavntb_plx_detach(device_t dev) 474323032Smav{ 475323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 476323032Smav struct ntb_plx_mw_info *mw; 477323032Smav int i; 478323032Smav 479323032Smav /* Detach & delete all children */ 480323032Smav ntb_unregister_device(dev); 481323032Smav 482323032Smav /* Disable and free interrupts. */ 483323032Smav ntb_plx_teardown_intr(dev); 484323032Smav 485323032Smav /* Free memory resources. */ 486323032Smav for (i = 0; i < sc->mw_count; i++) { 487323032Smav mw = &sc->mw_info[i]; 488323032Smav bus_release_resource(dev, SYS_RES_MEMORY, mw->mw_rid, 489323032Smav mw->mw_res); 490323032Smav } 491323032Smav bus_release_resource(dev, SYS_RES_MEMORY, sc->conf_rid, sc->conf_res); 492323032Smav return (0); 493323032Smav} 494323032Smav 495323032Smav 496323032Smavstatic bool 497323032Smavntb_plx_link_is_up(device_t dev, enum ntb_speed *speed, enum ntb_width *width) 498323032Smav{ 499323032Smav uint16_t link; 500323032Smav 501323032Smav link = pcie_read_config(dev, PCIER_LINK_STA, 2); 502323032Smav if (speed != NULL) 503323032Smav *speed = (link & PCIEM_LINK_STA_SPEED); 504323032Smav if (width != NULL) 505323032Smav *width = (link & PCIEM_LINK_STA_WIDTH) >> 4; 506323032Smav return ((link & PCIEM_LINK_STA_WIDTH) != 0); 507323032Smav} 508323032Smav 509323032Smavstatic int 510323032Smavntb_plx_link_enable(device_t dev, enum ntb_speed speed __unused, 511323032Smav enum ntb_width width __unused) 512323032Smav{ 513323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 514323032Smav uint32_t reg, val; 515323032Smav 516323032Smav /* The fact that we see the Link Interface means link is enabled. */ 517323032Smav if (sc->link) { 518323032Smav ntb_link_event(dev); 519323032Smav return (0); 520323032Smav } 521323032Smav 522323453Smav reg = PLX_PORT_CONTROL(sc); 523323032Smav val = bus_read_4(sc->conf_res, reg); 524323032Smav if ((val & (1 << (sc->port & 7))) == 0) { 525323032Smav /* If already enabled, generate fake link event and exit. */ 526323032Smav ntb_link_event(dev); 527323032Smav return (0); 528323032Smav } 529323032Smav val &= ~(1 << (sc->port & 7)); 530323032Smav bus_write_4(sc->conf_res, reg, val); 531323032Smav return (0); 532323032Smav} 533323032Smav 534323032Smavstatic int 535323032Smavntb_plx_link_disable(device_t dev) 536323032Smav{ 537323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 538323032Smav uint32_t reg, val; 539323032Smav 540323032Smav /* Link disable for Link Interface would be suicidal. */ 541323032Smav if (sc->link) 542323032Smav return (0); 543323032Smav 544323453Smav reg = PLX_PORT_CONTROL(sc); 545323032Smav val = bus_read_4(sc->conf_res, reg); 546323032Smav val |= (1 << (sc->port & 7)); 547323032Smav bus_write_4(sc->conf_res, reg, val); 548323032Smav return (0); 549323032Smav} 550323032Smav 551323032Smavstatic bool 552323032Smavntb_plx_link_enabled(device_t dev) 553323032Smav{ 554323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 555323032Smav uint32_t reg, val; 556323032Smav 557323032Smav /* The fact that we see the Link Interface means link is enabled. */ 558323032Smav if (sc->link) 559323032Smav return (TRUE); 560323032Smav 561323453Smav reg = PLX_PORT_CONTROL(sc); 562323032Smav val = bus_read_4(sc->conf_res, reg); 563323032Smav return ((val & (1 << (sc->port & 7))) == 0); 564323032Smav} 565323032Smav 566323032Smavstatic uint8_t 567323032Smavntb_plx_mw_count(device_t dev) 568323032Smav{ 569323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 570355041Smav uint8_t res; 571323032Smav 572355041Smav res = sc->mw_count; 573355041Smav res += (1 << sc->split) - 1; 574323032Smav if (sc->b2b_mw >= 0 && sc->b2b_off == 0) 575355041Smav res--; /* B2B consumed whole window. */ 576355041Smav return (res); 577323032Smav} 578323032Smav 579355041Smavstatic unsigned 580355041Smavntb_plx_user_mw_to_idx(struct ntb_plx_softc *sc, unsigned uidx, unsigned *sp) 581355041Smav{ 582355041Smav unsigned t; 583355041Smav 584355041Smav t = 1 << sc->split; 585355041Smav if (uidx < t) { 586355041Smav *sp = uidx; 587355041Smav return (0); 588355041Smav } 589355041Smav *sp = 0; 590355041Smav return (uidx - (t - 1)); 591355041Smav} 592355041Smav 593323032Smavstatic int 594323032Smavntb_plx_mw_get_range(device_t dev, unsigned mw_idx, vm_paddr_t *base, 595323032Smav caddr_t *vbase, size_t *size, size_t *align, size_t *align_size, 596323032Smav bus_addr_t *plimit) 597323032Smav{ 598323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 599323032Smav struct ntb_plx_mw_info *mw; 600355041Smav size_t off, ss; 601355041Smav unsigned sp, split; 602323032Smav 603355041Smav mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp); 604323032Smav if (mw_idx >= sc->mw_count) 605323032Smav return (EINVAL); 606323032Smav off = 0; 607323032Smav if (mw_idx == sc->b2b_mw) { 608323032Smav KASSERT(sc->b2b_off != 0, 609323032Smav ("user shouldn't get non-shared b2b mw")); 610323032Smav off = sc->b2b_off; 611323032Smav } 612323032Smav mw = &sc->mw_info[mw_idx]; 613355041Smav split = (mw->mw_bar == 2) ? sc->split : 0; 614355041Smav ss = (mw->mw_size - off) >> split; 615323032Smav 616323032Smav /* Local to remote memory window parameters. */ 617323032Smav if (base != NULL) 618355041Smav *base = mw->mw_pbase + off + ss * sp; 619323032Smav if (vbase != NULL) 620355041Smav *vbase = mw->mw_vbase + off + ss * sp; 621323032Smav if (size != NULL) 622355041Smav *size = ss; 623323032Smav 624323032Smav /* 625323032Smav * Remote to local memory window translation address alignment. 626324407Smav * Translation address has to be aligned to the BAR size, but A-LUT 627324407Smav * entries re-map addresses can be aligned to 1/128 or 1/256 of it. 628324407Smav * XXX: In B2B mode we can change BAR size (and so alignmet) live, 629324407Smav * but there is no way to report it here, so report safe value. 630323032Smav */ 631324407Smav if (align != NULL) { 632324407Smav if (sc->alut && mw->mw_bar == 2) 633324407Smav *align = (mw->mw_size - off) / 128 / sc->alut; 634324407Smav else 635324407Smav *align = mw->mw_size - off; 636324407Smav } 637323032Smav 638323032Smav /* 639323032Smav * Remote to local memory window size alignment. 640324407Smav * The chip has no limit registers, but A-LUT, when available, allows 641324407Smav * access control with granularity of 1/128 or 1/256 of the BAR size. 642324407Smav * XXX: In B2B case we can change BAR size live, but there is no way 643324407Smav * to report it, so report half of the BAR size, that should be safe. 644324407Smav * In non-B2B case there is no control at all, so report the BAR size. 645323032Smav */ 646323032Smav if (align_size != NULL) { 647324407Smav if (sc->alut && mw->mw_bar == 2) 648324407Smav *align_size = (mw->mw_size - off) / 128 / sc->alut; 649324407Smav else if (sc->b2b_mw >= 0) 650324407Smav *align_size = (mw->mw_size - off) / 2; 651323032Smav else 652323032Smav *align_size = mw->mw_size - off; 653323032Smav } 654323032Smav 655323032Smav /* Remote to local memory window translation address upper limit. */ 656323032Smav if (plimit != NULL) 657323032Smav *plimit = mw->mw_64bit ? BUS_SPACE_MAXADDR : 658323032Smav BUS_SPACE_MAXADDR_32BIT; 659323032Smav return (0); 660323032Smav} 661323032Smav 662323032Smavstatic int 663323032Smavntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx) 664323032Smav{ 665323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 666323032Smav struct ntb_plx_mw_info *mw; 667324407Smav uint64_t addr, eaddr, off, size, bsize, esize, val64; 668323032Smav uint32_t val; 669355041Smav unsigned i, sp, split; 670323032Smav 671323032Smav mw = &sc->mw_info[mw_idx]; 672355041Smav off = (mw_idx == sc->b2b_mw) ? sc->b2b_off : 0; 673355041Smav split = (mw->mw_bar == 2) ? sc->split : 0; 674323032Smav 675355041Smav /* Get BAR size. In case of split or B2RP we can't change it. */ 676355041Smav if (split || sc->b2b_mw < 0) { 677355041Smav bsize = mw->mw_size - off; 678355041Smav } else { 679355041Smav bsize = mw->splits[0].mw_xlat_size; 680324407Smav if (!powerof2(bsize)) 681324407Smav bsize = 1LL << flsll(bsize); 682355041Smav if (bsize > 0 && bsize < 1024 * 1024) 683324407Smav bsize = 1024 * 1024; 684355041Smav } 685323032Smav 686355041Smav /* 687355041Smav * While for B2B we can set any BAR size on a link side, for shared 688355041Smav * window we can't go above preconfigured size due to BAR address 689355041Smav * alignment requirements. 690355041Smav */ 691355041Smav if ((off & (bsize - 1)) != 0) 692355041Smav return (EINVAL); 693324407Smav 694355041Smav /* In B2B mode set Link Interface BAR size/address. */ 695355041Smav if (sc->b2b_mw >= 0 && mw->mw_64bit) { 696355041Smav val64 = 0; 697355041Smav if (bsize > 0) 698355041Smav val64 = (~(bsize - 1) & ~0xfffff); 699355041Smav val64 |= 0xc; 700355041Smav PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val64); 701355041Smav PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4 + 4, val64 >> 32); 702323032Smav 703355041Smav val64 = 0x2000000000000000 * mw->mw_bar + off; 704355041Smav PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64); 705355041Smav PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar) + 4, val64 >> 32); 706355041Smav } else if (sc->b2b_mw >= 0) { 707355041Smav val = 0; 708355041Smav if (bsize > 0) 709355041Smav val = (~(bsize - 1) & ~0xfffff); 710355041Smav PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val); 711323032Smav 712355041Smav val64 = 0x20000000 * mw->mw_bar + off; 713355041Smav PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64); 714355041Smav } 715323032Smav 716355041Smav /* Set BARs address translation */ 717355041Smav addr = split ? UINT64_MAX : mw->splits[0].mw_xlat_addr; 718355041Smav if (mw->mw_64bit) { 719323032Smav PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr); 720323032Smav PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, addr >> 32); 721323032Smav } else { 722323032Smav PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr); 723323032Smav } 724324407Smav 725355041Smav /* Configure and enable A-LUT if we need it. */ 726355041Smav size = split ? 0 : mw->splits[0].mw_xlat_size; 727355041Smav if (sc->alut && mw->mw_bar == 2 && (sc->split > 0 || 728355041Smav ((addr & (bsize - 1)) != 0 || size != bsize))) { 729355041Smav esize = bsize / (128 * sc->alut); 730355041Smav for (i = sp = 0; i < 128 * sc->alut; i++) { 731355041Smav if (i % (128 * sc->alut >> sc->split) == 0) { 732355041Smav eaddr = addr = mw->splits[sp].mw_xlat_addr; 733355041Smav size = mw->splits[sp++].mw_xlat_size; 734355041Smav } 735324407Smav val = sc->link ? 0 : 1; 736324407Smav if (sc->alut == 1) 737324407Smav val += 2 * sc->ntx; 738324407Smav val *= 0x1000 * sc->alut; 739324407Smav val += 0x38000 + i * 4 + (i >= 128 ? 0x0e00 : 0); 740324407Smav bus_write_4(sc->conf_res, val, eaddr); 741324407Smav bus_write_4(sc->conf_res, val + 0x400, eaddr >> 32); 742324407Smav bus_write_4(sc->conf_res, val + 0x800, 743324407Smav (eaddr < addr + size) ? 0x3 : 0); 744324407Smav eaddr += esize; 745324407Smav } 746324407Smav NTX_WRITE(sc, 0xc94, 0x10000000); 747324407Smav } else if (sc->alut && mw->mw_bar == 2) 748324407Smav NTX_WRITE(sc, 0xc94, 0); 749324407Smav 750323032Smav return (0); 751323032Smav} 752323032Smav 753323032Smavstatic int 754323032Smavntb_plx_mw_set_trans(device_t dev, unsigned mw_idx, bus_addr_t addr, size_t size) 755323032Smav{ 756323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 757323032Smav struct ntb_plx_mw_info *mw; 758355041Smav unsigned sp; 759323032Smav 760355041Smav mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp); 761323032Smav if (mw_idx >= sc->mw_count) 762323032Smav return (EINVAL); 763323032Smav mw = &sc->mw_info[mw_idx]; 764355041Smav if (!mw->mw_64bit && 765355041Smav ((addr & UINT32_MAX) != addr || 766355041Smav ((addr + size) & UINT32_MAX) != (addr + size))) 767355041Smav return (ERANGE); 768355041Smav mw->splits[sp].mw_xlat_addr = addr; 769355041Smav mw->splits[sp].mw_xlat_size = size; 770323032Smav return (ntb_plx_mw_set_trans_internal(dev, mw_idx)); 771323032Smav} 772323032Smav 773323032Smavstatic int 774323032Smavntb_plx_mw_clear_trans(device_t dev, unsigned mw_idx) 775323032Smav{ 776323032Smav 777323032Smav return (ntb_plx_mw_set_trans(dev, mw_idx, 0, 0)); 778323032Smav} 779323032Smav 780323032Smavstatic int 781355041Smavntb_plx_mw_get_wc(device_t dev, unsigned mw_idx, vm_memattr_t *mode) 782323032Smav{ 783323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 784323032Smav struct ntb_plx_mw_info *mw; 785355041Smav unsigned sp; 786323032Smav 787355041Smav mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp); 788355041Smav if (mw_idx >= sc->mw_count) 789323032Smav return (EINVAL); 790355041Smav mw = &sc->mw_info[mw_idx]; 791355041Smav *mode = mw->splits[sp].mw_map_mode; 792323032Smav return (0); 793323032Smav} 794323032Smav 795323032Smavstatic int 796355041Smavntb_plx_mw_set_wc(device_t dev, unsigned mw_idx, vm_memattr_t mode) 797323032Smav{ 798323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 799323032Smav struct ntb_plx_mw_info *mw; 800355041Smav uint64_t off, ss; 801323032Smav int rc; 802355041Smav unsigned sp, split; 803323032Smav 804355041Smav mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp); 805355041Smav if (mw_idx >= sc->mw_count) 806323032Smav return (EINVAL); 807355041Smav mw = &sc->mw_info[mw_idx]; 808355041Smav if (mw->splits[sp].mw_map_mode == mode) 809323032Smav return (0); 810323032Smav 811323032Smav off = 0; 812355041Smav if (mw_idx == sc->b2b_mw) { 813323032Smav KASSERT(sc->b2b_off != 0, 814323032Smav ("user shouldn't get non-shared b2b mw")); 815323032Smav off = sc->b2b_off; 816323032Smav } 817323032Smav 818355041Smav split = (mw->mw_bar == 2) ? sc->split : 0; 819355041Smav ss = (mw->mw_size - off) >> split; 820355041Smav rc = pmap_change_attr((vm_offset_t)mw->mw_vbase + off + ss * sp, 821355041Smav ss, mode); 822323032Smav if (rc == 0) 823355041Smav mw->splits[sp].mw_map_mode = mode; 824323032Smav return (rc); 825323032Smav} 826323032Smav 827323032Smavstatic uint8_t 828323032Smavntb_plx_spad_count(device_t dev) 829323032Smav{ 830323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 831323032Smav 832323032Smav return (sc->spad_count1 + sc->spad_count2); 833323032Smav} 834323032Smav 835323032Smavstatic int 836323032Smavntb_plx_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_off1 + idx * 4; 846323032Smav else 847323032Smav off = sc->spad_off2 + (idx - sc->spad_count1) * 4; 848323032Smav bus_write_4(sc->conf_res, off, val); 849323032Smav return (0); 850323032Smav} 851323032Smav 852323032Smavstatic void 853323032Smavntb_plx_spad_clear(device_t dev) 854323032Smav{ 855323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 856323032Smav int i; 857323032Smav 858323032Smav for (i = 0; i < sc->spad_count1 + sc->spad_count2; i++) 859323032Smav ntb_plx_spad_write(dev, i, 0); 860323032Smav} 861323032Smav 862323032Smavstatic int 863323032Smavntb_plx_spad_read(device_t dev, unsigned int idx, uint32_t *val) 864323032Smav{ 865323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 866323032Smav u_int off; 867323032Smav 868323032Smav if (idx >= sc->spad_count1 + sc->spad_count2) 869323032Smav return (EINVAL); 870323032Smav 871323032Smav if (idx < sc->spad_count1) 872323032Smav off = sc->spad_off1 + idx * 4; 873323032Smav else 874323032Smav off = sc->spad_off2 + (idx - sc->spad_count1) * 4; 875323032Smav *val = bus_read_4(sc->conf_res, off); 876323032Smav return (0); 877323032Smav} 878323032Smav 879323032Smavstatic int 880323032Smavntb_plx_peer_spad_write(device_t dev, unsigned int idx, uint32_t val) 881323032Smav{ 882323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 883323032Smav u_int off; 884323032Smav 885323032Smav if (idx >= sc->spad_count1 + sc->spad_count2) 886323032Smav return (EINVAL); 887323032Smav 888323032Smav if (idx < sc->spad_count1) 889323032Smav off = sc->spad_offp1 + idx * 4; 890323032Smav else 891323032Smav off = sc->spad_offp2 + (idx - sc->spad_count1) * 4; 892323032Smav if (sc->b2b_mw >= 0) 893323032Smav bus_write_4(sc->mw_info[sc->b2b_mw].mw_res, off, val); 894323032Smav else 895323032Smav bus_write_4(sc->conf_res, off, val); 896323032Smav return (0); 897323032Smav} 898323032Smav 899323032Smavstatic int 900323032Smavntb_plx_peer_spad_read(device_t dev, unsigned int idx, uint32_t *val) 901323032Smav{ 902323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 903323032Smav u_int off; 904323032Smav 905323032Smav if (idx >= sc->spad_count1 + sc->spad_count2) 906323032Smav return (EINVAL); 907323032Smav 908323032Smav if (idx < sc->spad_count1) 909323032Smav off = sc->spad_offp1 + idx * 4; 910323032Smav else 911323032Smav off = sc->spad_offp2 + (idx - sc->spad_count1) * 4; 912323032Smav if (sc->b2b_mw >= 0) 913323032Smav *val = bus_read_4(sc->mw_info[sc->b2b_mw].mw_res, off); 914323032Smav else 915323032Smav *val = bus_read_4(sc->conf_res, off); 916323032Smav return (0); 917323032Smav} 918323032Smav 919323032Smavstatic uint64_t 920323032Smavntb_plx_db_valid_mask(device_t dev) 921323032Smav{ 922323032Smav 923323032Smav return ((1LL << PLX_NUM_DB) - 1); 924323032Smav} 925323032Smav 926323032Smavstatic int 927323032Smavntb_plx_db_vector_count(device_t dev) 928323032Smav{ 929323032Smav 930323032Smav return (1); 931323032Smav} 932323032Smav 933323032Smavstatic uint64_t 934323032Smavntb_plx_db_vector_mask(device_t dev, uint32_t vector) 935323032Smav{ 936323032Smav 937323032Smav if (vector > 0) 938323032Smav return (0); 939323032Smav return ((1LL << PLX_NUM_DB) - 1); 940323032Smav} 941323032Smav 942323032Smavstatic void 943323032Smavntb_plx_db_clear(device_t dev, uint64_t bits) 944323032Smav{ 945323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 946323032Smav 947323032Smav NTX_WRITE(sc, sc->link ? 0xc60 : 0xc50, bits); 948323032Smav} 949323032Smav 950323032Smavstatic void 951323032Smavntb_plx_db_clear_mask(device_t dev, uint64_t bits) 952323032Smav{ 953323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 954323032Smav 955323032Smav NTX_WRITE(sc, sc->link ? 0xc68 : 0xc58, bits); 956323032Smav} 957323032Smav 958323032Smavstatic uint64_t 959323032Smavntb_plx_db_read(device_t dev) 960323032Smav{ 961323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 962323032Smav 963323032Smav return (NTX_READ(sc, sc->link ? 0xc5c : 0xc4c)); 964323032Smav} 965323032Smav 966323032Smavstatic void 967323032Smavntb_plx_db_set_mask(device_t dev, uint64_t bits) 968323032Smav{ 969323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 970323032Smav 971323032Smav NTX_WRITE(sc, sc->link ? 0xc64 : 0xc54, bits); 972323032Smav} 973323032Smav 974323032Smavstatic int 975323032Smavntb_plx_peer_db_addr(device_t dev, bus_addr_t *db_addr, vm_size_t *db_size) 976323032Smav{ 977323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 978323032Smav struct ntb_plx_mw_info *mw; 979323032Smav 980323032Smav KASSERT((db_addr != NULL && db_size != NULL), ("must be non-NULL")); 981323032Smav 982323032Smav if (sc->b2b_mw >= 0) { 983323032Smav mw = &sc->mw_info[sc->b2b_mw]; 984323032Smav *db_addr = (uint64_t)mw->mw_pbase + PLX_NTX_BASE(sc) + 0xc4c; 985323032Smav } else { 986323032Smav *db_addr = rman_get_start(sc->conf_res) + PLX_NTX_BASE(sc); 987323032Smav *db_addr += sc->link ? 0xc4c : 0xc5c; 988323032Smav } 989323032Smav *db_size = 4; 990323032Smav return (0); 991323032Smav} 992323032Smav 993323032Smavstatic void 994323032Smavntb_plx_peer_db_set(device_t dev, uint64_t bit) 995323032Smav{ 996323032Smav struct ntb_plx_softc *sc = device_get_softc(dev); 997323032Smav 998323032Smav if (sc->b2b_mw >= 0) 999323032Smav BNTX_WRITE(sc, 0xc4c, bit); 1000323032Smav else 1001323032Smav NTX_WRITE(sc, sc->link ? 0xc4c : 0xc5c, bit); 1002323032Smav} 1003323032Smav 1004323032Smavstatic device_method_t ntb_plx_methods[] = { 1005323032Smav /* Device interface */ 1006323032Smav DEVMETHOD(device_probe, ntb_plx_probe), 1007323032Smav DEVMETHOD(device_attach, ntb_plx_attach), 1008323032Smav DEVMETHOD(device_detach, ntb_plx_detach), 1009323455Smav /* Bus interface */ 1010323455Smav DEVMETHOD(bus_child_location_str, ntb_child_location_str), 1011323455Smav DEVMETHOD(bus_print_child, ntb_print_child), 1012355152Smav DEVMETHOD(bus_get_dma_tag, ntb_get_dma_tag), 1013323032Smav /* NTB interface */ 1014323032Smav DEVMETHOD(ntb_link_is_up, ntb_plx_link_is_up), 1015323032Smav DEVMETHOD(ntb_link_enable, ntb_plx_link_enable), 1016323032Smav DEVMETHOD(ntb_link_disable, ntb_plx_link_disable), 1017323032Smav DEVMETHOD(ntb_link_enabled, ntb_plx_link_enabled), 1018323032Smav DEVMETHOD(ntb_mw_count, ntb_plx_mw_count), 1019323032Smav DEVMETHOD(ntb_mw_get_range, ntb_plx_mw_get_range), 1020323032Smav DEVMETHOD(ntb_mw_set_trans, ntb_plx_mw_set_trans), 1021323032Smav DEVMETHOD(ntb_mw_clear_trans, ntb_plx_mw_clear_trans), 1022323032Smav DEVMETHOD(ntb_mw_get_wc, ntb_plx_mw_get_wc), 1023323032Smav DEVMETHOD(ntb_mw_set_wc, ntb_plx_mw_set_wc), 1024323032Smav DEVMETHOD(ntb_spad_count, ntb_plx_spad_count), 1025323032Smav DEVMETHOD(ntb_spad_clear, ntb_plx_spad_clear), 1026323032Smav DEVMETHOD(ntb_spad_write, ntb_plx_spad_write), 1027323032Smav DEVMETHOD(ntb_spad_read, ntb_plx_spad_read), 1028323032Smav DEVMETHOD(ntb_peer_spad_write, ntb_plx_peer_spad_write), 1029323032Smav DEVMETHOD(ntb_peer_spad_read, ntb_plx_peer_spad_read), 1030323032Smav DEVMETHOD(ntb_db_valid_mask, ntb_plx_db_valid_mask), 1031323032Smav DEVMETHOD(ntb_db_vector_count, ntb_plx_db_vector_count), 1032323032Smav DEVMETHOD(ntb_db_vector_mask, ntb_plx_db_vector_mask), 1033323032Smav DEVMETHOD(ntb_db_clear, ntb_plx_db_clear), 1034323032Smav DEVMETHOD(ntb_db_clear_mask, ntb_plx_db_clear_mask), 1035323032Smav DEVMETHOD(ntb_db_read, ntb_plx_db_read), 1036323032Smav DEVMETHOD(ntb_db_set_mask, ntb_plx_db_set_mask), 1037323032Smav DEVMETHOD(ntb_peer_db_addr, ntb_plx_peer_db_addr), 1038323032Smav DEVMETHOD(ntb_peer_db_set, ntb_plx_peer_db_set), 1039323032Smav DEVMETHOD_END 1040323032Smav}; 1041323032Smav 1042323032Smavstatic DEFINE_CLASS_0(ntb_hw, ntb_plx_driver, ntb_plx_methods, 1043323032Smav sizeof(struct ntb_plx_softc)); 1044323032SmavDRIVER_MODULE(ntb_hw_plx, pci, ntb_plx_driver, ntb_hw_devclass, NULL, NULL); 1045323032SmavMODULE_DEPEND(ntb_hw_plx, ntb, 1, 1, 1); 1046323032SmavMODULE_VERSION(ntb_hw_plx, 1); 1047