ntb_hw_intel.c revision 289538
1250079Scarl/*- 2250079Scarl * Copyright (C) 2013 Intel Corporation 3250079Scarl * All rights reserved. 4250079Scarl * 5250079Scarl * Redistribution and use in source and binary forms, with or without 6250079Scarl * modification, are permitted provided that the following conditions 7250079Scarl * are met: 8250079Scarl * 1. Redistributions of source code must retain the above copyright 9250079Scarl * notice, this list of conditions and the following disclaimer. 10250079Scarl * 2. Redistributions in binary form must reproduce the above copyright 11250079Scarl * notice, this list of conditions and the following disclaimer in the 12250079Scarl * documentation and/or other materials provided with the distribution. 13250079Scarl * 14250079Scarl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15250079Scarl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16250079Scarl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17250079Scarl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18250079Scarl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19250079Scarl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20250079Scarl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21250079Scarl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22250079Scarl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23250079Scarl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24250079Scarl * SUCH DAMAGE. 25250079Scarl */ 26250079Scarl 27250079Scarl#include <sys/cdefs.h> 28250079Scarl__FBSDID("$FreeBSD: head/sys/dev/ntb/ntb_hw/ntb_hw.c 289538 2015-10-18 20:19:44Z cem $"); 29250079Scarl 30250079Scarl#include <sys/param.h> 31250079Scarl#include <sys/kernel.h> 32250079Scarl#include <sys/systm.h> 33250079Scarl#include <sys/bus.h> 34250079Scarl#include <sys/malloc.h> 35250079Scarl#include <sys/module.h> 36250079Scarl#include <sys/queue.h> 37250079Scarl#include <sys/rman.h> 38289207Scem#include <sys/sysctl.h> 39250079Scarl#include <vm/vm.h> 40250079Scarl#include <vm/pmap.h> 41250079Scarl#include <machine/bus.h> 42250079Scarl#include <machine/pmap.h> 43250079Scarl#include <machine/resource.h> 44250079Scarl#include <dev/pci/pcireg.h> 45250079Scarl#include <dev/pci/pcivar.h> 46250079Scarl 47250079Scarl#include "ntb_regs.h" 48250079Scarl#include "ntb_hw.h" 49250079Scarl 50250079Scarl/* 51250079Scarl * The Non-Transparent Bridge (NTB) is a device on some Intel processors that 52250079Scarl * allows you to connect two systems using a PCI-e link. 53250079Scarl * 54250079Scarl * This module contains the hardware abstraction layer for the NTB. It allows 55250079Scarl * you to send and recieve interrupts, map the memory windows and send and 56250079Scarl * receive messages in the scratch-pad registers. 57250079Scarl * 58250079Scarl * NOTE: Much of the code in this module is shared with Linux. Any patches may 59250079Scarl * be picked up and redistributed in Linux with a dual GPL/BSD license. 60250079Scarl */ 61250079Scarl 62250079Scarl#define NTB_CONFIG_BAR 0 63250079Scarl#define NTB_B2B_BAR_1 1 64250079Scarl#define NTB_B2B_BAR_2 2 65289397Scem#define NTB_B2B_BAR_3 3 66289397Scem#define NTB_MAX_BARS 4 67250079Scarl#define NTB_MW_TO_BAR(mw) ((mw) + 1) 68250079Scarl 69289538Scem#define MAX_MSIX_INTERRUPTS MAX(XEON_DB_COUNT, SOC_DB_COUNT) 70250079Scarl 71250079Scarl#define NTB_HB_TIMEOUT 1 /* second */ 72250079Scarl#define SOC_LINK_RECOVERY_TIME 500 73250079Scarl 74250079Scarl#define DEVICE2SOFTC(dev) ((struct ntb_softc *) device_get_softc(dev)) 75250079Scarl 76250079Scarlenum ntb_device_type { 77250079Scarl NTB_XEON, 78250079Scarl NTB_SOC 79250079Scarl}; 80250079Scarl 81255274Scarl/* Device features and workarounds */ 82255274Scarl#define HAS_FEATURE(feature) \ 83255274Scarl ((ntb->features & (feature)) != 0) 84255274Scarl 85250079Scarlstruct ntb_hw_info { 86250079Scarl uint32_t device_id; 87255274Scarl const char *desc; 88250079Scarl enum ntb_device_type type; 89289397Scem uint32_t features; 90250079Scarl}; 91250079Scarl 92250079Scarlstruct ntb_pci_bar_info { 93250079Scarl bus_space_tag_t pci_bus_tag; 94250079Scarl bus_space_handle_t pci_bus_handle; 95250079Scarl int pci_resource_id; 96250079Scarl struct resource *pci_resource; 97250079Scarl vm_paddr_t pbase; 98250079Scarl void *vbase; 99250079Scarl u_long size; 100250079Scarl}; 101250079Scarl 102250079Scarlstruct ntb_int_info { 103250079Scarl struct resource *res; 104250079Scarl int rid; 105250079Scarl void *tag; 106250079Scarl}; 107250079Scarl 108250079Scarlstruct ntb_db_cb { 109250079Scarl ntb_db_callback callback; 110250079Scarl unsigned int db_num; 111250079Scarl void *data; 112250079Scarl struct ntb_softc *ntb; 113289281Scem struct callout irq_work; 114289343Scem bool reserved; 115250079Scarl}; 116250079Scarl 117250079Scarlstruct ntb_softc { 118250079Scarl device_t device; 119250079Scarl enum ntb_device_type type; 120255274Scarl uint64_t features; 121250079Scarl 122250079Scarl struct ntb_pci_bar_info bar_info[NTB_MAX_BARS]; 123250079Scarl struct ntb_int_info int_info[MAX_MSIX_INTERRUPTS]; 124250079Scarl uint32_t allocated_interrupts; 125250079Scarl 126250079Scarl struct callout heartbeat_timer; 127250079Scarl struct callout lr_timer; 128250079Scarl 129250079Scarl void *ntb_transport; 130250079Scarl ntb_event_callback event_cb; 131289396Scem struct ntb_db_cb *db_cb; 132289396Scem uint8_t max_cbs; 133250079Scarl 134250079Scarl struct { 135289396Scem uint8_t max_mw; 136289208Scem uint8_t max_spads; 137289208Scem uint8_t max_db_bits; 138289208Scem uint8_t msix_cnt; 139250079Scarl } limits; 140250079Scarl struct { 141289255Scem uint32_t ldb; 142289255Scem uint32_t ldb_mask; 143289255Scem uint32_t rdb; 144289255Scem uint32_t bar2_xlat; 145289255Scem uint32_t bar4_xlat; 146289397Scem uint32_t bar5_xlat; 147250079Scarl uint32_t spad_remote; 148250079Scarl uint32_t spad_local; 149250079Scarl uint32_t lnk_cntl; 150250079Scarl uint32_t lnk_stat; 151250079Scarl uint32_t spci_cmd; 152250079Scarl } reg_ofs; 153289348Scem uint32_t ppd; 154250079Scarl uint8_t conn_type; 155250079Scarl uint8_t dev_type; 156250079Scarl uint8_t bits_per_vector; 157250079Scarl uint8_t link_status; 158250079Scarl uint8_t link_width; 159250079Scarl uint8_t link_speed; 160250079Scarl}; 161250079Scarl 162289234Scem#ifdef __i386__ 163289234Scemstatic __inline uint64_t 164289234Scembus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle, 165289234Scem bus_size_t offset) 166289234Scem{ 167289234Scem 168289234Scem return (bus_space_read_4(tag, handle, offset) | 169289234Scem ((uint64_t)bus_space_read_4(tag, handle, offset + 4)) << 32); 170289234Scem} 171289234Scem 172289234Scemstatic __inline void 173289234Scembus_space_write_8(bus_space_tag_t tag, bus_space_handle_t handle, 174289234Scem bus_size_t offset, uint64_t val) 175289234Scem{ 176289234Scem 177289234Scem bus_space_write_4(tag, handle, offset, val); 178289234Scem bus_space_write_4(tag, handle, offset + 4, val >> 32); 179289234Scem} 180289234Scem#endif 181289234Scem 182255279Scarl#define ntb_bar_read(SIZE, bar, offset) \ 183255279Scarl bus_space_read_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \ 184255279Scarl ntb->bar_info[(bar)].pci_bus_handle, (offset)) 185255279Scarl#define ntb_bar_write(SIZE, bar, offset, val) \ 186255279Scarl bus_space_write_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \ 187255279Scarl ntb->bar_info[(bar)].pci_bus_handle, (offset), (val)) 188255279Scarl#define ntb_reg_read(SIZE, offset) ntb_bar_read(SIZE, NTB_CONFIG_BAR, offset) 189250079Scarl#define ntb_reg_write(SIZE, offset, val) \ 190255279Scarl ntb_bar_write(SIZE, NTB_CONFIG_BAR, offset, val) 191289397Scem#define ntb_mw_read(SIZE, offset) \ 192289397Scem ntb_bar_read(SIZE, NTB_MW_TO_BAR(ntb->limits.max_mw), offset) 193255279Scarl#define ntb_mw_write(SIZE, offset, val) \ 194289397Scem ntb_bar_write(SIZE, NTB_MW_TO_BAR(ntb->limits.max_mw), \ 195289397Scem offset, val) 196250079Scarl 197255272Scarltypedef int (*bar_map_strategy)(struct ntb_softc *ntb, 198255272Scarl struct ntb_pci_bar_info *bar); 199255272Scarl 200250079Scarlstatic int ntb_probe(device_t device); 201250079Scarlstatic int ntb_attach(device_t device); 202250079Scarlstatic int ntb_detach(device_t device); 203255272Scarlstatic int ntb_map_pci_bars(struct ntb_softc *ntb); 204255272Scarlstatic int map_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, 205255272Scarl struct ntb_pci_bar_info *bar); 206255272Scarlstatic int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar); 207255272Scarlstatic int map_memory_window_bar(struct ntb_softc *ntb, 208255272Scarl struct ntb_pci_bar_info *bar); 209250079Scarlstatic void ntb_unmap_pci_bar(struct ntb_softc *ntb); 210289344Scemstatic int ntb_remap_msix(device_t, uint32_t desired, uint32_t avail); 211250079Scarlstatic int ntb_setup_interrupts(struct ntb_softc *ntb); 212289342Scemstatic int ntb_setup_legacy_interrupt(struct ntb_softc *ntb); 213289342Scemstatic int ntb_setup_xeon_msix(struct ntb_softc *ntb, uint32_t num_vectors); 214289342Scemstatic int ntb_setup_soc_msix(struct ntb_softc *ntb, uint32_t num_vectors); 215250079Scarlstatic void ntb_teardown_interrupts(struct ntb_softc *ntb); 216250079Scarlstatic void handle_soc_irq(void *arg); 217250079Scarlstatic void handle_xeon_irq(void *arg); 218250079Scarlstatic void handle_xeon_event_irq(void *arg); 219250079Scarlstatic void ntb_handle_legacy_interrupt(void *arg); 220289281Scemstatic void ntb_irq_work(void *arg); 221289347Scemstatic uint64_t db_ioread(struct ntb_softc *, uint32_t regoff); 222289347Scemstatic void db_iowrite(struct ntb_softc *, uint32_t regoff, uint64_t val); 223289281Scemstatic void mask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx); 224289281Scemstatic void unmask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx); 225289342Scemstatic int ntb_create_callbacks(struct ntb_softc *ntb, uint32_t num_vectors); 226250079Scarlstatic void ntb_free_callbacks(struct ntb_softc *ntb); 227250079Scarlstatic struct ntb_hw_info *ntb_get_device_info(uint32_t device_id); 228289397Scemstatic void ntb_detect_max_mw(struct ntb_softc *ntb); 229289348Scemstatic int ntb_detect_xeon(struct ntb_softc *ntb); 230289348Scemstatic int ntb_detect_soc(struct ntb_softc *ntb); 231250079Scarlstatic int ntb_setup_xeon(struct ntb_softc *ntb); 232250079Scarlstatic int ntb_setup_soc(struct ntb_softc *ntb); 233289272Scemstatic void ntb_teardown_xeon(struct ntb_softc *ntb); 234255279Scarlstatic void configure_soc_secondary_side_bars(struct ntb_softc *ntb); 235255279Scarlstatic void configure_xeon_secondary_side_bars(struct ntb_softc *ntb); 236250079Scarlstatic void ntb_handle_heartbeat(void *arg); 237250079Scarlstatic void ntb_handle_link_event(struct ntb_softc *ntb, int link_state); 238289272Scemstatic void ntb_hw_link_down(struct ntb_softc *ntb); 239289272Scemstatic void ntb_hw_link_up(struct ntb_softc *ntb); 240250079Scarlstatic void recover_soc_link(void *arg); 241250079Scarlstatic int ntb_check_link_status(struct ntb_softc *ntb); 242255274Scarlstatic void save_bar_parameters(struct ntb_pci_bar_info *bar); 243250079Scarl 244250079Scarlstatic struct ntb_hw_info pci_ids[] = { 245255274Scarl { 0x0C4E8086, "Atom Processor S1200 NTB Primary B2B", NTB_SOC, 0 }, 246289233Scem 247289233Scem /* XXX: PS/SS IDs left out until they are supported. */ 248289233Scem { 0x37258086, "JSF Xeon C35xx/C55xx Non-Transparent Bridge B2B", 249289538Scem NTB_XEON, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 }, 250289233Scem { 0x3C0D8086, "SNB Xeon E5/Core i7 Non-Transparent Bridge B2B", 251289538Scem NTB_XEON, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 }, 252289233Scem { 0x0E0D8086, "IVT Xeon E5 V2 Non-Transparent Bridge B2B", NTB_XEON, 253289538Scem NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 | 254289538Scem NTB_SB01BASE_LOCKUP | NTB_BAR_SIZE_4K }, 255289233Scem { 0x2F0D8086, "HSX Xeon E5 V3 Non-Transparent Bridge B2B", NTB_XEON, 256289538Scem NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 | 257289538Scem NTB_SB01BASE_LOCKUP }, 258289233Scem { 0x6F0D8086, "BDX Xeon E5 V4 Non-Transparent Bridge B2B", NTB_XEON, 259289538Scem NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 | 260289538Scem NTB_SB01BASE_LOCKUP }, 261289233Scem 262255274Scarl { 0x00000000, NULL, NTB_SOC, 0 } 263250079Scarl}; 264250079Scarl 265250079Scarl/* 266250079Scarl * OS <-> Driver interface structures 267250079Scarl */ 268250079ScarlMALLOC_DEFINE(M_NTB, "ntb_hw", "ntb_hw driver memory allocations"); 269250079Scarl 270250079Scarlstatic device_method_t ntb_pci_methods[] = { 271250079Scarl /* Device interface */ 272250079Scarl DEVMETHOD(device_probe, ntb_probe), 273250079Scarl DEVMETHOD(device_attach, ntb_attach), 274250079Scarl DEVMETHOD(device_detach, ntb_detach), 275250079Scarl DEVMETHOD_END 276250079Scarl}; 277250079Scarl 278250079Scarlstatic driver_t ntb_pci_driver = { 279250079Scarl "ntb_hw", 280250079Scarl ntb_pci_methods, 281250079Scarl sizeof(struct ntb_softc), 282250079Scarl}; 283250079Scarl 284250079Scarlstatic devclass_t ntb_devclass; 285250079ScarlDRIVER_MODULE(ntb_hw, pci, ntb_pci_driver, ntb_devclass, NULL, NULL); 286250079ScarlMODULE_VERSION(ntb_hw, 1); 287250079Scarl 288289207ScemSYSCTL_NODE(_hw, OID_AUTO, ntb, CTLFLAG_RW, 0, "NTB sysctls"); 289289207Scem 290250079Scarl/* 291250079Scarl * OS <-> Driver linkage functions 292250079Scarl */ 293250079Scarlstatic int 294250079Scarlntb_probe(device_t device) 295250079Scarl{ 296289209Scem struct ntb_hw_info *p; 297250079Scarl 298289209Scem p = ntb_get_device_info(pci_get_devid(device)); 299289209Scem if (p == NULL) 300250079Scarl return (ENXIO); 301289209Scem 302289209Scem device_set_desc(device, p->desc); 303289209Scem return (0); 304250079Scarl} 305250079Scarl 306250079Scarlstatic int 307250079Scarlntb_attach(device_t device) 308250079Scarl{ 309289209Scem struct ntb_softc *ntb; 310289209Scem struct ntb_hw_info *p; 311250079Scarl int error; 312250079Scarl 313289209Scem ntb = DEVICE2SOFTC(device); 314289209Scem p = ntb_get_device_info(pci_get_devid(device)); 315289209Scem 316250079Scarl ntb->device = device; 317250079Scarl ntb->type = p->type; 318255274Scarl ntb->features = p->features; 319250079Scarl 320250079Scarl /* Heartbeat timer for NTB_SOC since there is no link interrupt */ 321283291Sjkim callout_init(&ntb->heartbeat_timer, 1); 322283291Sjkim callout_init(&ntb->lr_timer, 1); 323250079Scarl 324289348Scem if (ntb->type == NTB_SOC) 325289348Scem error = ntb_detect_soc(ntb); 326289348Scem else 327289348Scem error = ntb_detect_xeon(ntb); 328289348Scem if (error) 329289348Scem goto out; 330289348Scem 331289397Scem ntb_detect_max_mw(ntb); 332289396Scem 333289209Scem error = ntb_map_pci_bars(ntb); 334289209Scem if (error) 335289209Scem goto out; 336289272Scem if (ntb->type == NTB_SOC) 337289272Scem error = ntb_setup_soc(ntb); 338289272Scem else 339289272Scem error = ntb_setup_xeon(ntb); 340289209Scem if (error) 341289209Scem goto out; 342289209Scem error = ntb_setup_interrupts(ntb); 343289209Scem if (error) 344289209Scem goto out; 345250079Scarl 346250079Scarl pci_enable_busmaster(ntb->device); 347250079Scarl 348289209Scemout: 349289209Scem if (error != 0) 350289209Scem ntb_detach(device); 351250079Scarl return (error); 352250079Scarl} 353250079Scarl 354250079Scarlstatic int 355250079Scarlntb_detach(device_t device) 356250079Scarl{ 357289209Scem struct ntb_softc *ntb; 358250079Scarl 359289209Scem ntb = DEVICE2SOFTC(device); 360250079Scarl callout_drain(&ntb->heartbeat_timer); 361250079Scarl callout_drain(&ntb->lr_timer); 362289272Scem if (ntb->type == NTB_XEON) 363289272Scem ntb_teardown_xeon(ntb); 364250079Scarl ntb_teardown_interrupts(ntb); 365289397Scem 366289397Scem /* 367289397Scem * Redetect total MWs so we unmap properly -- in case we lowered the 368289397Scem * maximum to work around Xeon errata. 369289397Scem */ 370289397Scem ntb_detect_max_mw(ntb); 371250079Scarl ntb_unmap_pci_bar(ntb); 372250079Scarl 373250079Scarl return (0); 374250079Scarl} 375250079Scarl 376250079Scarlstatic int 377255272Scarlntb_map_pci_bars(struct ntb_softc *ntb) 378250079Scarl{ 379255272Scarl int rc; 380250079Scarl 381250079Scarl ntb->bar_info[NTB_CONFIG_BAR].pci_resource_id = PCIR_BAR(0); 382255272Scarl rc = map_pci_bar(ntb, map_mmr_bar, &ntb->bar_info[NTB_CONFIG_BAR]); 383255272Scarl if (rc != 0) 384289209Scem return (rc); 385255272Scarl 386289209Scem ntb->bar_info[NTB_B2B_BAR_1].pci_resource_id = PCIR_BAR(2); 387255272Scarl rc = map_pci_bar(ntb, map_memory_window_bar, 388255272Scarl &ntb->bar_info[NTB_B2B_BAR_1]); 389255272Scarl if (rc != 0) 390289209Scem return (rc); 391255272Scarl 392289209Scem ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4); 393289538Scem if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP) && !HAS_FEATURE(NTB_SPLIT_BAR)) 394255279Scarl rc = map_pci_bar(ntb, map_mmr_bar, 395255279Scarl &ntb->bar_info[NTB_B2B_BAR_2]); 396255279Scarl else 397255279Scarl rc = map_pci_bar(ntb, map_memory_window_bar, 398255279Scarl &ntb->bar_info[NTB_B2B_BAR_2]); 399289397Scem if (!HAS_FEATURE(NTB_SPLIT_BAR)) 400289397Scem return (rc); 401289397Scem 402289397Scem ntb->bar_info[NTB_B2B_BAR_3].pci_resource_id = PCIR_BAR(5); 403289538Scem if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) 404289397Scem rc = map_pci_bar(ntb, map_mmr_bar, 405289397Scem &ntb->bar_info[NTB_B2B_BAR_3]); 406289397Scem else 407289397Scem rc = map_pci_bar(ntb, map_memory_window_bar, 408289397Scem &ntb->bar_info[NTB_B2B_BAR_3]); 409289209Scem return (rc); 410255272Scarl} 411250079Scarl 412255272Scarlstatic int 413255272Scarlmap_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, 414255272Scarl struct ntb_pci_bar_info *bar) 415255272Scarl{ 416255272Scarl int rc; 417255272Scarl 418255272Scarl rc = strategy(ntb, bar); 419289209Scem if (rc != 0) 420255272Scarl device_printf(ntb->device, 421255272Scarl "unable to allocate pci resource\n"); 422289209Scem else 423255279Scarl device_printf(ntb->device, 424255272Scarl "Bar size = %lx, v %p, p %p\n", 425289209Scem bar->size, bar->vbase, (void *)(bar->pbase)); 426255272Scarl return (rc); 427255272Scarl} 428255272Scarl 429255272Scarlstatic int 430255272Scarlmap_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) 431255272Scarl{ 432255272Scarl 433255275Scarl bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, 434289209Scem &bar->pci_resource_id, RF_ACTIVE); 435255272Scarl if (bar->pci_resource == NULL) 436255272Scarl return (ENXIO); 437289209Scem 438289209Scem save_bar_parameters(bar); 439289209Scem return (0); 440255272Scarl} 441255272Scarl 442255272Scarlstatic int 443255272Scarlmap_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) 444255272Scarl{ 445255272Scarl int rc; 446255276Scarl uint8_t bar_size_bits = 0; 447255272Scarl 448289209Scem bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, 449289209Scem &bar->pci_resource_id, RF_ACTIVE); 450250079Scarl 451255272Scarl if (bar->pci_resource == NULL) 452255272Scarl return (ENXIO); 453255276Scarl 454289209Scem save_bar_parameters(bar); 455289209Scem /* 456289209Scem * Ivytown NTB BAR sizes are misreported by the hardware due to a 457289209Scem * hardware issue. To work around this, query the size it should be 458289209Scem * configured to by the device and modify the resource to correspond to 459289209Scem * this new size. The BIOS on systems with this problem is required to 460289209Scem * provide enough address space to allow the driver to make this change 461289209Scem * safely. 462289209Scem * 463289209Scem * Ideally I could have just specified the size when I allocated the 464289209Scem * resource like: 465289209Scem * bus_alloc_resource(ntb->device, 466289209Scem * SYS_RES_MEMORY, &bar->pci_resource_id, 0ul, ~0ul, 467289209Scem * 1ul << bar_size_bits, RF_ACTIVE); 468289209Scem * but the PCI driver does not honor the size in this call, so we have 469289209Scem * to modify it after the fact. 470289209Scem */ 471289209Scem if (HAS_FEATURE(NTB_BAR_SIZE_4K)) { 472289209Scem if (bar->pci_resource_id == PCIR_BAR(2)) 473289209Scem bar_size_bits = pci_read_config(ntb->device, 474289209Scem XEON_PBAR23SZ_OFFSET, 1); 475289209Scem else 476289209Scem bar_size_bits = pci_read_config(ntb->device, 477289209Scem XEON_PBAR45SZ_OFFSET, 1); 478289209Scem 479289209Scem rc = bus_adjust_resource(ntb->device, SYS_RES_MEMORY, 480289209Scem bar->pci_resource, bar->pbase, 481289209Scem bar->pbase + (1ul << bar_size_bits) - 1); 482255272Scarl if (rc != 0) { 483289209Scem device_printf(ntb->device, 484289209Scem "unable to resize bar\n"); 485255272Scarl return (rc); 486250079Scarl } 487289209Scem 488289209Scem save_bar_parameters(bar); 489250079Scarl } 490289209Scem 491289209Scem /* Mark bar region as write combining to improve performance. */ 492289209Scem rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size, 493289209Scem VM_MEMATTR_WRITE_COMBINING); 494289209Scem if (rc != 0) { 495289209Scem device_printf(ntb->device, 496289209Scem "unable to mark bar as WRITE_COMBINING\n"); 497289209Scem return (rc); 498289209Scem } 499250079Scarl return (0); 500250079Scarl} 501250079Scarl 502250079Scarlstatic void 503250079Scarlntb_unmap_pci_bar(struct ntb_softc *ntb) 504250079Scarl{ 505250079Scarl struct ntb_pci_bar_info *current_bar; 506250079Scarl int i; 507250079Scarl 508289397Scem for (i = 0; i < NTB_MAX_BARS; i++) { 509250079Scarl current_bar = &ntb->bar_info[i]; 510250079Scarl if (current_bar->pci_resource != NULL) 511250079Scarl bus_release_resource(ntb->device, SYS_RES_MEMORY, 512250079Scarl current_bar->pci_resource_id, 513250079Scarl current_bar->pci_resource); 514250079Scarl } 515250079Scarl} 516250079Scarl 517250079Scarlstatic int 518289342Scemntb_setup_xeon_msix(struct ntb_softc *ntb, uint32_t num_vectors) 519250079Scarl{ 520250079Scarl void (*interrupt_handler)(void *); 521250079Scarl void *int_arg; 522289342Scem uint32_t i; 523289342Scem int rc; 524289342Scem 525289342Scem if (num_vectors < 4) 526289342Scem return (ENOSPC); 527289342Scem 528289342Scem for (i = 0; i < num_vectors; i++) { 529289342Scem ntb->int_info[i].rid = i + 1; 530289342Scem ntb->int_info[i].res = bus_alloc_resource_any(ntb->device, 531289342Scem SYS_RES_IRQ, &ntb->int_info[i].rid, RF_ACTIVE); 532289342Scem if (ntb->int_info[i].res == NULL) { 533289342Scem device_printf(ntb->device, 534289342Scem "bus_alloc_resource failed\n"); 535289342Scem return (ENOMEM); 536289342Scem } 537289342Scem ntb->int_info[i].tag = NULL; 538289342Scem ntb->allocated_interrupts++; 539289342Scem if (i == num_vectors - 1) { 540289342Scem interrupt_handler = handle_xeon_event_irq; 541289342Scem int_arg = ntb; 542289342Scem } else { 543289342Scem interrupt_handler = handle_xeon_irq; 544289342Scem int_arg = &ntb->db_cb[i]; 545289342Scem } 546289342Scem rc = bus_setup_intr(ntb->device, ntb->int_info[i].res, 547289342Scem INTR_MPSAFE | INTR_TYPE_MISC, NULL, interrupt_handler, 548289342Scem int_arg, &ntb->int_info[i].tag); 549289342Scem if (rc != 0) { 550289342Scem device_printf(ntb->device, 551289342Scem "bus_setup_intr failed\n"); 552289342Scem return (ENXIO); 553289342Scem } 554289342Scem } 555289343Scem 556289343Scem /* 557289343Scem * Prevent consumers from registering callbacks on the link event irq 558289343Scem * slot, from which they will never be called back. 559289343Scem */ 560289343Scem ntb->db_cb[num_vectors - 1].reserved = true; 561289396Scem ntb->max_cbs--; 562289342Scem return (0); 563289342Scem} 564289342Scem 565289342Scemstatic int 566289342Scemntb_setup_soc_msix(struct ntb_softc *ntb, uint32_t num_vectors) 567289342Scem{ 568289342Scem uint32_t i; 569289342Scem int rc; 570289342Scem 571289342Scem for (i = 0; i < num_vectors; i++) { 572289342Scem ntb->int_info[i].rid = i + 1; 573289342Scem ntb->int_info[i].res = bus_alloc_resource_any(ntb->device, 574289342Scem SYS_RES_IRQ, &ntb->int_info[i].rid, RF_ACTIVE); 575289342Scem if (ntb->int_info[i].res == NULL) { 576289342Scem device_printf(ntb->device, 577289342Scem "bus_alloc_resource failed\n"); 578289342Scem return (ENOMEM); 579289342Scem } 580289342Scem ntb->int_info[i].tag = NULL; 581289342Scem ntb->allocated_interrupts++; 582289342Scem rc = bus_setup_intr(ntb->device, ntb->int_info[i].res, 583289342Scem INTR_MPSAFE | INTR_TYPE_MISC, NULL, handle_soc_irq, 584289342Scem &ntb->db_cb[i], &ntb->int_info[i].tag); 585289342Scem if (rc != 0) { 586289342Scem device_printf(ntb->device, "bus_setup_intr failed\n"); 587289342Scem return (ENXIO); 588289342Scem } 589289342Scem } 590289342Scem return (0); 591289342Scem} 592289342Scem 593289344Scem/* 594289344Scem * The Linux NTB driver drops from MSI-X to legacy INTx if a unique vector 595289344Scem * cannot be allocated for each MSI-X message. JHB seems to think remapping 596289344Scem * should be okay. This tunable should enable us to test that hypothesis 597289344Scem * when someone gets their hands on some Xeon hardware. 598289344Scem */ 599289344Scemstatic int ntb_force_remap_mode; 600289344ScemSYSCTL_INT(_hw_ntb, OID_AUTO, force_remap_mode, CTLFLAG_RDTUN, 601289344Scem &ntb_force_remap_mode, 0, "If enabled, force MSI-X messages to be remapped" 602289344Scem " to a smaller number of ithreads, even if the desired number are " 603289344Scem "available"); 604289344Scem 605289344Scem/* 606289344Scem * In case it is NOT ok, give consumers an abort button. 607289344Scem */ 608289344Scemstatic int ntb_prefer_intx; 609289344ScemSYSCTL_INT(_hw_ntb, OID_AUTO, prefer_intx_to_remap, CTLFLAG_RDTUN, 610289344Scem &ntb_prefer_intx, 0, "If enabled, prefer to use legacy INTx mode rather " 611289344Scem "than remapping MSI-X messages over available slots (match Linux driver " 612289344Scem "behavior)"); 613289344Scem 614289344Scem/* 615289344Scem * Remap the desired number of MSI-X messages to available ithreads in a simple 616289344Scem * round-robin fashion. 617289344Scem */ 618289342Scemstatic int 619289344Scemntb_remap_msix(device_t dev, uint32_t desired, uint32_t avail) 620289344Scem{ 621289344Scem u_int *vectors; 622289344Scem uint32_t i; 623289344Scem int rc; 624289344Scem 625289344Scem if (ntb_prefer_intx != 0) 626289344Scem return (ENXIO); 627289344Scem 628289344Scem vectors = malloc(desired * sizeof(*vectors), M_NTB, M_ZERO | M_WAITOK); 629289344Scem 630289344Scem for (i = 0; i < desired; i++) 631289344Scem vectors[i] = (i % avail) + 1; 632289344Scem 633289344Scem rc = pci_remap_msix(dev, desired, vectors); 634289344Scem free(vectors, M_NTB); 635289344Scem return (rc); 636289344Scem} 637289344Scem 638289344Scemstatic int 639289342Scemntb_setup_interrupts(struct ntb_softc *ntb) 640289342Scem{ 641289344Scem uint32_t desired_vectors, num_vectors; 642289347Scem uint64_t mask; 643289342Scem int rc; 644250079Scarl 645250079Scarl ntb->allocated_interrupts = 0; 646289347Scem 647250079Scarl /* 648250079Scarl * On SOC, disable all interrupts. On XEON, disable all but Link 649250079Scarl * Interrupt. The rest will be unmasked as callbacks are registered. 650250079Scarl */ 651289347Scem mask = 0; 652289347Scem if (ntb->type == NTB_XEON) 653289538Scem mask = (1 << XEON_DB_LINK); 654289347Scem db_iowrite(ntb, ntb->reg_ofs.ldb_mask, ~mask); 655250079Scarl 656289344Scem num_vectors = desired_vectors = MIN(pci_msix_count(ntb->device), 657250079Scarl ntb->limits.max_db_bits); 658289344Scem if (desired_vectors >= 1) { 659289344Scem rc = pci_alloc_msix(ntb->device, &num_vectors); 660250079Scarl 661289344Scem if (ntb_force_remap_mode != 0 && rc == 0 && 662289344Scem num_vectors == desired_vectors) 663289344Scem num_vectors--; 664289344Scem 665289344Scem if (rc == 0 && num_vectors < desired_vectors) { 666289344Scem rc = ntb_remap_msix(ntb->device, desired_vectors, 667289344Scem num_vectors); 668289344Scem if (rc == 0) 669289344Scem num_vectors = desired_vectors; 670289344Scem else 671289344Scem pci_release_msi(ntb->device); 672289344Scem } 673289344Scem if (rc != 0) 674289344Scem num_vectors = 1; 675289344Scem } else 676289344Scem num_vectors = 1; 677289344Scem 678289396Scem /* 679289396Scem * If allocating MSI-X interrupts succeeds, limit callbacks to the 680289396Scem * number of MSI-X slots available. 681289396Scem */ 682250079Scarl ntb_create_callbacks(ntb, num_vectors); 683250079Scarl 684289342Scem if (ntb->type == NTB_XEON) 685289342Scem rc = ntb_setup_xeon_msix(ntb, num_vectors); 686289342Scem else 687289342Scem rc = ntb_setup_soc_msix(ntb, num_vectors); 688289396Scem if (rc != 0) { 689289342Scem device_printf(ntb->device, 690289342Scem "Error allocating MSI-X interrupts: %d\n", rc); 691250079Scarl 692289396Scem /* 693289396Scem * If allocating MSI-X interrupts failed and we're forced to 694289396Scem * use legacy INTx anyway, the only limit on individual 695289396Scem * callbacks is the number of doorbell bits. 696289396Scem * 697289396Scem * CEM: This seems odd to me but matches the behavior of the 698289396Scem * Linux driver ca. September 2013 699289396Scem */ 700289396Scem ntb_free_callbacks(ntb); 701289396Scem ntb_create_callbacks(ntb, ntb->limits.max_db_bits); 702289396Scem } 703289396Scem 704289342Scem if (ntb->type == NTB_XEON && rc == ENOSPC) 705289342Scem rc = ntb_setup_legacy_interrupt(ntb); 706289342Scem 707289342Scem return (rc); 708289342Scem} 709289342Scem 710289342Scemstatic int 711289342Scemntb_setup_legacy_interrupt(struct ntb_softc *ntb) 712289342Scem{ 713289342Scem int rc; 714289342Scem 715289342Scem ntb->int_info[0].rid = 0; 716289342Scem ntb->int_info[0].res = bus_alloc_resource_any(ntb->device, SYS_RES_IRQ, 717289342Scem &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE); 718289342Scem if (ntb->int_info[0].res == NULL) { 719289342Scem device_printf(ntb->device, "bus_alloc_resource failed\n"); 720289342Scem return (ENOMEM); 721250079Scarl } 722250079Scarl 723289342Scem ntb->int_info[0].tag = NULL; 724289342Scem ntb->allocated_interrupts = 1; 725289342Scem 726289342Scem rc = bus_setup_intr(ntb->device, ntb->int_info[0].res, 727289342Scem INTR_MPSAFE | INTR_TYPE_MISC, NULL, ntb_handle_legacy_interrupt, 728289342Scem ntb, &ntb->int_info[0].tag); 729289342Scem if (rc != 0) { 730289342Scem device_printf(ntb->device, "bus_setup_intr failed\n"); 731289342Scem return (ENXIO); 732289342Scem } 733289342Scem 734250079Scarl return (0); 735250079Scarl} 736250079Scarl 737250079Scarlstatic void 738250079Scarlntb_teardown_interrupts(struct ntb_softc *ntb) 739250079Scarl{ 740250079Scarl struct ntb_int_info *current_int; 741250079Scarl int i; 742250079Scarl 743289209Scem for (i = 0; i < ntb->allocated_interrupts; i++) { 744250079Scarl current_int = &ntb->int_info[i]; 745250079Scarl if (current_int->tag != NULL) 746250079Scarl bus_teardown_intr(ntb->device, current_int->res, 747250079Scarl current_int->tag); 748250079Scarl 749250079Scarl if (current_int->res != NULL) 750250079Scarl bus_release_resource(ntb->device, SYS_RES_IRQ, 751250079Scarl rman_get_rid(current_int->res), current_int->res); 752250079Scarl } 753250079Scarl 754250079Scarl ntb_free_callbacks(ntb); 755250079Scarl pci_release_msi(ntb->device); 756250079Scarl} 757250079Scarl 758289347Scem/* 759289347Scem * Doorbell register and mask are 64-bit on SoC, 16-bit on Xeon. Abstract it 760289347Scem * out to make code clearer. 761289347Scem */ 762289347Scemstatic uint64_t 763289347Scemdb_ioread(struct ntb_softc *ntb, uint32_t regoff) 764289347Scem{ 765289347Scem 766289347Scem if (ntb->type == NTB_SOC) 767289347Scem return (ntb_reg_read(8, regoff)); 768289347Scem 769289347Scem KASSERT(ntb->type == NTB_XEON, ("bad ntb type")); 770289347Scem 771289347Scem return (ntb_reg_read(2, regoff)); 772289347Scem} 773289347Scem 774250079Scarlstatic void 775289347Scemdb_iowrite(struct ntb_softc *ntb, uint32_t regoff, uint64_t val) 776289347Scem{ 777289347Scem 778289347Scem if (ntb->type == NTB_SOC) { 779289347Scem ntb_reg_write(8, regoff, val); 780289347Scem return; 781289347Scem } 782289347Scem 783289347Scem KASSERT(ntb->type == NTB_XEON, ("bad ntb type")); 784289347Scem ntb_reg_write(2, regoff, (uint16_t)val); 785289347Scem} 786289347Scem 787289347Scemstatic void 788289281Scemmask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx) 789289281Scem{ 790289347Scem uint64_t mask; 791289281Scem 792289347Scem mask = db_ioread(ntb, ntb->reg_ofs.ldb_mask); 793289281Scem mask |= 1 << (idx * ntb->bits_per_vector); 794289347Scem db_iowrite(ntb, ntb->reg_ofs.ldb_mask, mask); 795289281Scem} 796289281Scem 797289281Scemstatic void 798289281Scemunmask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx) 799289281Scem{ 800289347Scem uint64_t mask; 801289281Scem 802289347Scem mask = db_ioread(ntb, ntb->reg_ofs.ldb_mask); 803289281Scem mask &= ~(1 << (idx * ntb->bits_per_vector)); 804289347Scem db_iowrite(ntb, ntb->reg_ofs.ldb_mask, mask); 805289281Scem} 806289281Scem 807289281Scemstatic void 808250079Scarlhandle_soc_irq(void *arg) 809250079Scarl{ 810250079Scarl struct ntb_db_cb *db_cb = arg; 811250079Scarl struct ntb_softc *ntb = db_cb->ntb; 812250079Scarl 813289347Scem db_iowrite(ntb, ntb->reg_ofs.ldb, (uint64_t) 1 << db_cb->db_num); 814250079Scarl 815289281Scem if (db_cb->callback != NULL) { 816289281Scem mask_ldb_interrupt(ntb, db_cb->db_num); 817289281Scem callout_reset(&db_cb->irq_work, 0, ntb_irq_work, db_cb); 818289281Scem } 819250079Scarl} 820250079Scarl 821250079Scarlstatic void 822250079Scarlhandle_xeon_irq(void *arg) 823250079Scarl{ 824250079Scarl struct ntb_db_cb *db_cb = arg; 825250079Scarl struct ntb_softc *ntb = db_cb->ntb; 826250079Scarl 827250079Scarl /* 828250079Scarl * On Xeon, there are 16 bits in the interrupt register 829250079Scarl * but only 4 vectors. So, 5 bits are assigned to the first 3 830250079Scarl * vectors, with the 4th having a single bit for link 831250079Scarl * interrupts. 832250079Scarl */ 833289347Scem db_iowrite(ntb, ntb->reg_ofs.ldb, 834250079Scarl ((1 << ntb->bits_per_vector) - 1) << 835250079Scarl (db_cb->db_num * ntb->bits_per_vector)); 836250079Scarl 837289281Scem if (db_cb->callback != NULL) { 838289281Scem mask_ldb_interrupt(ntb, db_cb->db_num); 839289281Scem callout_reset(&db_cb->irq_work, 0, ntb_irq_work, db_cb); 840289281Scem } 841250079Scarl} 842250079Scarl 843250079Scarl/* Since we do not have a HW doorbell in SOC, this is only used in JF/JT */ 844250079Scarlstatic void 845250079Scarlhandle_xeon_event_irq(void *arg) 846250079Scarl{ 847250079Scarl struct ntb_softc *ntb = arg; 848250079Scarl int rc; 849250079Scarl 850250079Scarl rc = ntb_check_link_status(ntb); 851250079Scarl if (rc != 0) 852250079Scarl device_printf(ntb->device, "Error determining link status\n"); 853250079Scarl 854250079Scarl /* bit 15 is always the link bit */ 855289538Scem db_iowrite(ntb, ntb->reg_ofs.ldb, 1 << XEON_DB_LINK); 856250079Scarl} 857250079Scarl 858250079Scarlstatic void 859250079Scarlntb_handle_legacy_interrupt(void *arg) 860250079Scarl{ 861250079Scarl struct ntb_softc *ntb = arg; 862289347Scem unsigned int i; 863289347Scem uint64_t ldb; 864250079Scarl 865289347Scem ldb = db_ioread(ntb, ntb->reg_ofs.ldb); 866250079Scarl 867289538Scem if (ntb->type == NTB_XEON && (ldb & XEON_DB_LINK_BIT) != 0) { 868289347Scem handle_xeon_event_irq(ntb); 869289538Scem ldb &= ~XEON_DB_LINK_BIT; 870289347Scem } 871289347Scem 872289347Scem while (ldb != 0) { 873289347Scem i = ffs(ldb); 874289347Scem ldb &= ldb - 1; 875289347Scem if (ntb->type == NTB_SOC) 876250079Scarl handle_soc_irq(&ntb->db_cb[i]); 877289347Scem else 878250079Scarl handle_xeon_irq(&ntb->db_cb[i]); 879250079Scarl } 880250079Scarl} 881250079Scarl 882250079Scarlstatic int 883289342Scemntb_create_callbacks(struct ntb_softc *ntb, uint32_t num_vectors) 884250079Scarl{ 885289342Scem uint32_t i; 886250079Scarl 887289396Scem ntb->max_cbs = num_vectors; 888289209Scem ntb->db_cb = malloc(num_vectors * sizeof(*ntb->db_cb), M_NTB, 889250079Scarl M_ZERO | M_WAITOK); 890250079Scarl for (i = 0; i < num_vectors; i++) { 891250079Scarl ntb->db_cb[i].db_num = i; 892250079Scarl ntb->db_cb[i].ntb = ntb; 893250079Scarl } 894250079Scarl 895250079Scarl return (0); 896250079Scarl} 897250079Scarl 898250079Scarlstatic void 899250079Scarlntb_free_callbacks(struct ntb_softc *ntb) 900250079Scarl{ 901289342Scem uint8_t i; 902250079Scarl 903289396Scem for (i = 0; i < ntb->max_cbs; i++) 904250079Scarl ntb_unregister_db_callback(ntb, i); 905250079Scarl 906250079Scarl free(ntb->db_cb, M_NTB); 907289396Scem ntb->max_cbs = 0; 908250079Scarl} 909250079Scarl 910250079Scarlstatic struct ntb_hw_info * 911250079Scarlntb_get_device_info(uint32_t device_id) 912250079Scarl{ 913250079Scarl struct ntb_hw_info *ep = pci_ids; 914250079Scarl 915250079Scarl while (ep->device_id) { 916250079Scarl if (ep->device_id == device_id) 917250079Scarl return (ep); 918250079Scarl ++ep; 919250079Scarl } 920250079Scarl return (NULL); 921250079Scarl} 922250079Scarl 923289272Scemstatic void 924289272Scemntb_teardown_xeon(struct ntb_softc *ntb) 925250079Scarl{ 926250079Scarl 927289272Scem ntb_hw_link_down(ntb); 928250079Scarl} 929250079Scarl 930289397Scemstatic void 931289397Scemntb_detect_max_mw(struct ntb_softc *ntb) 932289397Scem{ 933289397Scem 934289397Scem if (ntb->type == NTB_SOC) { 935289397Scem ntb->limits.max_mw = SOC_MAX_MW; 936289397Scem return; 937289397Scem } 938289397Scem 939289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) 940289397Scem ntb->limits.max_mw = XEON_HSXSPLIT_MAX_MW; 941289397Scem else 942289397Scem ntb->limits.max_mw = XEON_SNB_MAX_MW; 943289397Scem} 944289397Scem 945250079Scarlstatic int 946289348Scemntb_detect_xeon(struct ntb_softc *ntb) 947250079Scarl{ 948289348Scem uint8_t ppd, conn_type; 949250079Scarl 950289348Scem ppd = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1); 951289348Scem ntb->ppd = ppd; 952250079Scarl 953289348Scem if ((ppd & XEON_PPD_DEV_TYPE) != 0) 954289257Scem ntb->dev_type = NTB_DEV_USD; 955289257Scem else 956289257Scem ntb->dev_type = NTB_DEV_DSD; 957289257Scem 958289397Scem if ((ppd & XEON_PPD_SPLIT_BAR) != 0) 959289397Scem ntb->features |= NTB_SPLIT_BAR; 960289397Scem 961289348Scem conn_type = ppd & XEON_PPD_CONN_TYPE; 962289348Scem switch (conn_type) { 963289348Scem case NTB_CONN_B2B: 964289348Scem ntb->conn_type = conn_type; 965289348Scem break; 966289348Scem case NTB_CONN_RP: 967289348Scem case NTB_CONN_TRANSPARENT: 968289348Scem default: 969289348Scem device_printf(ntb->device, "Unsupported connection type: %u\n", 970289348Scem (unsigned)conn_type); 971289348Scem return (ENXIO); 972289348Scem } 973289348Scem return (0); 974289348Scem} 975289348Scem 976289348Scemstatic int 977289348Scemntb_detect_soc(struct ntb_softc *ntb) 978289348Scem{ 979289348Scem uint32_t ppd, conn_type; 980289348Scem 981289348Scem ppd = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4); 982289348Scem ntb->ppd = ppd; 983289348Scem 984289348Scem if ((ppd & SOC_PPD_DEV_TYPE) != 0) 985289348Scem ntb->dev_type = NTB_DEV_DSD; 986289348Scem else 987289348Scem ntb->dev_type = NTB_DEV_USD; 988289348Scem 989289348Scem conn_type = (ppd & SOC_PPD_CONN_TYPE) >> 8; 990289348Scem switch (conn_type) { 991289348Scem case NTB_CONN_B2B: 992289348Scem ntb->conn_type = conn_type; 993289348Scem break; 994289348Scem default: 995289348Scem device_printf(ntb->device, "Unsupported NTB configuration\n"); 996289348Scem return (ENXIO); 997289348Scem } 998289348Scem return (0); 999289348Scem} 1000289348Scem 1001289348Scemstatic int 1002289348Scemntb_setup_xeon(struct ntb_softc *ntb) 1003289348Scem{ 1004289348Scem 1005289257Scem ntb->reg_ofs.ldb = XEON_PDOORBELL_OFFSET; 1006289257Scem ntb->reg_ofs.ldb_mask = XEON_PDBMSK_OFFSET; 1007289257Scem ntb->reg_ofs.spad_local = XEON_SPAD_OFFSET; 1008289257Scem ntb->reg_ofs.bar2_xlat = XEON_SBAR2XLAT_OFFSET; 1009289257Scem ntb->reg_ofs.bar4_xlat = XEON_SBAR4XLAT_OFFSET; 1010289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) 1011289397Scem ntb->reg_ofs.bar5_xlat = XEON_SBAR5XLAT_OFFSET; 1012289257Scem 1013289348Scem switch (ntb->conn_type) { 1014250079Scarl case NTB_CONN_B2B: 1015289257Scem /* 1016289257Scem * reg_ofs.rdb and reg_ofs.spad_remote are effectively ignored 1017289538Scem * with the NTB_SDOORBELL_LOCKUP errata mode enabled. (See 1018289257Scem * ntb_ring_doorbell() and ntb_read/write_remote_spad().) 1019289257Scem */ 1020289257Scem ntb->reg_ofs.rdb = XEON_B2B_DOORBELL_OFFSET; 1021289257Scem ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET; 1022289257Scem 1023289538Scem ntb->limits.max_spads = XEON_SPAD_COUNT; 1024250079Scarl break; 1025289257Scem 1026250079Scarl case NTB_CONN_RP: 1027289257Scem /* 1028289538Scem * Every Xeon today needs NTB_SDOORBELL_LOCKUP, so punt on RP for 1029289257Scem * now. 1030289257Scem */ 1031289538Scem KASSERT(HAS_FEATURE(NTB_SDOORBELL_LOCKUP), 1032289257Scem ("Xeon without MW errata unimplemented")); 1033289257Scem device_printf(ntb->device, 1034289257Scem "NTB-RP disabled to due hardware errata.\n"); 1035289257Scem return (ENXIO); 1036289257Scem 1037289257Scem case NTB_CONN_TRANSPARENT: 1038250079Scarl default: 1039250079Scarl device_printf(ntb->device, "Connection type %d not supported\n", 1040289348Scem ntb->conn_type); 1041250079Scarl return (ENXIO); 1042250079Scarl } 1043250079Scarl 1044289208Scem /* 1045289208Scem * There is a Xeon hardware errata related to writes to SDOORBELL or 1046289208Scem * B2BDOORBELL in conjunction with inbound access to NTB MMIO space, 1047289208Scem * which may hang the system. To workaround this use the second memory 1048289208Scem * window to access the interrupt and scratch pad registers on the 1049289208Scem * remote system. 1050289274Scem * 1051289274Scem * There is another HW errata on the limit registers -- they can only 1052289274Scem * be written when the base register is (?)4GB aligned and < 32-bit. 1053289274Scem * This should already be the case based on the driver defaults, but 1054289274Scem * write the limit registers first just in case. 1055289208Scem */ 1056289538Scem if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) { 1057289208Scem /* 1058289208Scem * Set the Limit register to 4k, the minimum size, to prevent 1059289208Scem * an illegal access. 1060289397Scem * 1061289397Scem * XXX: Should this be PBAR5LMT / get_mw_size(, max_mw - 1)? 1062289208Scem */ 1063289208Scem ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 1064289208Scem ntb_get_mw_size(ntb, 1) + 0x1000); 1065289397Scem /* Reserve the last MW for mapping remote spad */ 1066289397Scem ntb->limits.max_mw--; 1067289396Scem } else 1068289208Scem /* 1069289208Scem * Disable the limit register, just in case it is set to 1070289397Scem * something silly. A 64-bit write will also clear PBAR5LMT in 1071289397Scem * split-bar mode, and this is desired. 1072289208Scem */ 1073289208Scem ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0); 1074289208Scem 1075289257Scem ntb->reg_ofs.lnk_cntl = XEON_NTBCNTL_OFFSET; 1076289257Scem ntb->reg_ofs.lnk_stat = XEON_LINK_STATUS_OFFSET; 1077289257Scem ntb->reg_ofs.spci_cmd = XEON_PCICMD_OFFSET; 1078250079Scarl 1079289538Scem ntb->limits.max_db_bits = XEON_DB_COUNT; 1080289538Scem ntb->limits.msix_cnt = XEON_DB_MSIX_VECTOR_COUNT; 1081289538Scem ntb->bits_per_vector = XEON_DB_MSIX_VECTOR_SHIFT; 1082250079Scarl 1083289271Scem /* 1084289271Scem * HW Errata on bit 14 of b2bdoorbell register. Writes will not be 1085289271Scem * mirrored to the remote system. Shrink the number of bits by one, 1086289271Scem * since bit 14 is the last bit. 1087289271Scem * 1088289271Scem * On REGS_THRU_MW errata mode, we don't use the b2bdoorbell register 1089289271Scem * anyway. Nor for non-B2B connection types. 1090289271Scem */ 1091289271Scem if (HAS_FEATURE(NTB_B2BDOORBELL_BIT14) && 1092289538Scem !HAS_FEATURE(NTB_SDOORBELL_LOCKUP) && 1093289348Scem ntb->conn_type == NTB_CONN_B2B) 1094289538Scem ntb->limits.max_db_bits = XEON_DB_COUNT - 1; 1095289271Scem 1096255279Scarl configure_xeon_secondary_side_bars(ntb); 1097289209Scem 1098250079Scarl /* Enable Bus Master and Memory Space on the secondary side */ 1099289257Scem if (ntb->conn_type == NTB_CONN_B2B) 1100289257Scem ntb_reg_write(2, ntb->reg_ofs.spci_cmd, 1101289257Scem PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 1102255279Scarl 1103255269Scarl /* Enable link training */ 1104289272Scem ntb_hw_link_up(ntb); 1105250079Scarl 1106250079Scarl return (0); 1107250079Scarl} 1108250079Scarl 1109250079Scarlstatic int 1110250079Scarlntb_setup_soc(struct ntb_softc *ntb) 1111250079Scarl{ 1112250079Scarl 1113289348Scem KASSERT(ntb->conn_type == NTB_CONN_B2B, 1114289348Scem ("Unsupported NTB configuration (%d)\n", ntb->conn_type)); 1115250079Scarl 1116250079Scarl /* Initiate PCI-E link training */ 1117289348Scem pci_write_config(ntb->device, NTB_PPD_OFFSET, 1118289348Scem ntb->ppd | SOC_PPD_INIT_LINK, 4); 1119250079Scarl 1120289255Scem ntb->reg_ofs.ldb = SOC_PDOORBELL_OFFSET; 1121289255Scem ntb->reg_ofs.ldb_mask = SOC_PDBMSK_OFFSET; 1122289265Scem ntb->reg_ofs.rdb = SOC_B2B_DOORBELL_OFFSET; 1123289255Scem ntb->reg_ofs.bar2_xlat = SOC_SBAR2XLAT_OFFSET; 1124289255Scem ntb->reg_ofs.bar4_xlat = SOC_SBAR4XLAT_OFFSET; 1125250079Scarl ntb->reg_ofs.lnk_cntl = SOC_NTBCNTL_OFFSET; 1126250079Scarl ntb->reg_ofs.lnk_stat = SOC_LINK_STATUS_OFFSET; 1127250079Scarl ntb->reg_ofs.spad_local = SOC_SPAD_OFFSET; 1128289265Scem ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET; 1129250079Scarl ntb->reg_ofs.spci_cmd = SOC_PCICMD_OFFSET; 1130250079Scarl 1131289538Scem ntb->limits.max_spads = SOC_SPAD_COUNT; 1132289538Scem ntb->limits.max_db_bits = SOC_DB_COUNT; 1133289538Scem ntb->limits.msix_cnt = SOC_DB_MSIX_VECTOR_COUNT; 1134289538Scem ntb->bits_per_vector = SOC_DB_MSIX_VECTOR_SHIFT; 1135250079Scarl 1136250079Scarl /* 1137250079Scarl * FIXME - MSI-X bug on early SOC HW, remove once internal issue is 1138250079Scarl * resolved. Mask transaction layer internal parity errors. 1139250079Scarl */ 1140250079Scarl pci_write_config(ntb->device, 0xFC, 0x4, 4); 1141250079Scarl 1142255279Scarl configure_soc_secondary_side_bars(ntb); 1143250079Scarl 1144250079Scarl /* Enable Bus Master and Memory Space on the secondary side */ 1145255278Scarl ntb_reg_write(2, ntb->reg_ofs.spci_cmd, 1146250079Scarl PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 1147289209Scem 1148250079Scarl callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb); 1149250079Scarl 1150250079Scarl return (0); 1151250079Scarl} 1152250079Scarl 1153255279Scarlstatic void 1154255279Scarlconfigure_soc_secondary_side_bars(struct ntb_softc *ntb) 1155255279Scarl{ 1156255279Scarl 1157255279Scarl if (ntb->dev_type == NTB_DEV_USD) { 1158289538Scem ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, 1159289538Scem XEON_B2B_BAR2_DSD_ADDR); 1160289538Scem ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, XEON_B2B_BAR4_DSD_ADDR); 1161289538Scem ntb_reg_write(8, SOC_MBAR23_OFFSET, XEON_B2B_BAR2_USD_ADDR); 1162289538Scem ntb_reg_write(8, SOC_MBAR45_OFFSET, XEON_B2B_BAR4_USD_ADDR); 1163255279Scarl } else { 1164289538Scem ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, 1165289538Scem XEON_B2B_BAR2_USD_ADDR); 1166289538Scem ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, XEON_B2B_BAR4_USD_ADDR); 1167289538Scem ntb_reg_write(8, SOC_MBAR23_OFFSET, XEON_B2B_BAR2_DSD_ADDR); 1168289538Scem ntb_reg_write(8, SOC_MBAR45_OFFSET, XEON_B2B_BAR4_DSD_ADDR); 1169255279Scarl } 1170255279Scarl} 1171255279Scarl 1172255279Scarlstatic void 1173255279Scarlconfigure_xeon_secondary_side_bars(struct ntb_softc *ntb) 1174255279Scarl{ 1175255279Scarl 1176255279Scarl if (ntb->dev_type == NTB_DEV_USD) { 1177289538Scem ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, 1178289538Scem XEON_B2B_BAR2_DSD_ADDR); 1179289538Scem if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) 1180255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 1181289538Scem XEON_B2B_BAR0_DSD_ADDR); 1182289208Scem else { 1183289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) { 1184289397Scem ntb_reg_write(4, XEON_PBAR4XLAT_OFFSET, 1185289538Scem XEON_B2B_BAR4_DSD_ADDR); 1186289397Scem ntb_reg_write(4, XEON_PBAR5XLAT_OFFSET, 1187289538Scem XEON_B2B_BAR5_DSD_ADDR); 1188289397Scem } else 1189289397Scem ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 1190289538Scem XEON_B2B_BAR4_DSD_ADDR); 1191289208Scem /* 1192289208Scem * B2B_XLAT_OFFSET is a 64-bit register but can only be 1193289208Scem * written 32 bits at a time. 1194289208Scem */ 1195289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, 1196289538Scem XEON_B2B_BAR0_DSD_ADDR & 0xffffffff); 1197289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, 1198289538Scem XEON_B2B_BAR0_DSD_ADDR >> 32); 1199289208Scem } 1200289538Scem ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, 1201289538Scem XEON_B2B_BAR0_USD_ADDR); 1202289538Scem ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, 1203289538Scem XEON_B2B_BAR2_USD_ADDR); 1204289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) { 1205289538Scem ntb_reg_write(4, XEON_SBAR4BASE_OFFSET, 1206289538Scem XEON_B2B_BAR4_USD_ADDR); 1207289538Scem ntb_reg_write(4, XEON_SBAR5BASE_OFFSET, 1208289538Scem XEON_B2B_BAR5_USD_ADDR); 1209289397Scem } else 1210289538Scem ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, 1211289538Scem XEON_B2B_BAR4_USD_ADDR); 1212255279Scarl } else { 1213289538Scem ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, 1214289538Scem XEON_B2B_BAR2_USD_ADDR); 1215289538Scem if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) 1216255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 1217289538Scem XEON_B2B_BAR0_USD_ADDR); 1218289208Scem else { 1219289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) { 1220289397Scem ntb_reg_write(4, XEON_PBAR4XLAT_OFFSET, 1221289538Scem XEON_B2B_BAR4_USD_ADDR); 1222289397Scem ntb_reg_write(4, XEON_PBAR5XLAT_OFFSET, 1223289538Scem XEON_B2B_BAR5_USD_ADDR); 1224289397Scem } else 1225289397Scem ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 1226289538Scem XEON_B2B_BAR4_USD_ADDR); 1227289208Scem /* 1228289208Scem * B2B_XLAT_OFFSET is a 64-bit register but can only be 1229289208Scem * written 32 bits at a time. 1230289208Scem */ 1231289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, 1232289538Scem XEON_B2B_BAR0_USD_ADDR & 0xffffffff); 1233289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, 1234289538Scem XEON_B2B_BAR0_USD_ADDR >> 32); 1235289208Scem } 1236289538Scem ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, 1237289538Scem XEON_B2B_BAR0_DSD_ADDR); 1238289538Scem ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, 1239289538Scem XEON_B2B_BAR2_DSD_ADDR); 1240289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) { 1241289397Scem ntb_reg_write(4, XEON_SBAR4BASE_OFFSET, 1242289538Scem XEON_B2B_BAR4_DSD_ADDR); 1243289397Scem ntb_reg_write(4, XEON_SBAR5BASE_OFFSET, 1244289538Scem XEON_B2B_BAR5_DSD_ADDR); 1245289397Scem } else 1246289397Scem ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, 1247289538Scem XEON_B2B_BAR4_DSD_ADDR); 1248255279Scarl } 1249255279Scarl} 1250255279Scarl 1251255281Scarl/* SOC does not have link status interrupt, poll on that platform */ 1252250079Scarlstatic void 1253250079Scarlntb_handle_heartbeat(void *arg) 1254250079Scarl{ 1255250079Scarl struct ntb_softc *ntb = arg; 1256250079Scarl uint32_t status32; 1257289209Scem int rc; 1258250079Scarl 1259289209Scem rc = ntb_check_link_status(ntb); 1260250079Scarl if (rc != 0) 1261250079Scarl device_printf(ntb->device, 1262250079Scarl "Error determining link status\n"); 1263289232Scem 1264250079Scarl /* Check to see if a link error is the cause of the link down */ 1265250079Scarl if (ntb->link_status == NTB_LINK_DOWN) { 1266255278Scarl status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 1267250079Scarl if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) { 1268250079Scarl callout_reset(&ntb->lr_timer, 0, recover_soc_link, 1269250079Scarl ntb); 1270250079Scarl return; 1271250079Scarl } 1272250079Scarl } 1273250079Scarl 1274250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 1275250079Scarl ntb_handle_heartbeat, ntb); 1276250079Scarl} 1277250079Scarl 1278250079Scarlstatic void 1279250079Scarlsoc_perform_link_restart(struct ntb_softc *ntb) 1280250079Scarl{ 1281250079Scarl uint32_t status; 1282250079Scarl 1283250079Scarl /* Driver resets the NTB ModPhy lanes - magic! */ 1284255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0xe0); 1285255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x40); 1286255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x60); 1287255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0x60); 1288250079Scarl 1289250079Scarl /* Driver waits 100ms to allow the NTB ModPhy to settle */ 1290250079Scarl pause("ModPhy", hz / 10); 1291250079Scarl 1292250079Scarl /* Clear AER Errors, write to clear */ 1293255278Scarl status = ntb_reg_read(4, SOC_ERRCORSTS_OFFSET); 1294250079Scarl status &= PCIM_AER_COR_REPLAY_ROLLOVER; 1295255278Scarl ntb_reg_write(4, SOC_ERRCORSTS_OFFSET, status); 1296250079Scarl 1297250079Scarl /* Clear unexpected electrical idle event in LTSSM, write to clear */ 1298255278Scarl status = ntb_reg_read(4, SOC_LTSSMERRSTS0_OFFSET); 1299250079Scarl status |= SOC_LTSSMERRSTS0_UNEXPECTEDEI; 1300255278Scarl ntb_reg_write(4, SOC_LTSSMERRSTS0_OFFSET, status); 1301250079Scarl 1302250079Scarl /* Clear DeSkew Buffer error, write to clear */ 1303255278Scarl status = ntb_reg_read(4, SOC_DESKEWSTS_OFFSET); 1304250079Scarl status |= SOC_DESKEWSTS_DBERR; 1305255278Scarl ntb_reg_write(4, SOC_DESKEWSTS_OFFSET, status); 1306250079Scarl 1307255278Scarl status = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET); 1308250079Scarl status &= SOC_IBIST_ERR_OFLOW; 1309255278Scarl ntb_reg_write(4, SOC_IBSTERRRCRVSTS0_OFFSET, status); 1310250079Scarl 1311250079Scarl /* Releases the NTB state machine to allow the link to retrain */ 1312255278Scarl status = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 1313250079Scarl status &= ~SOC_LTSSMSTATEJMP_FORCEDETECT; 1314255278Scarl ntb_reg_write(4, SOC_LTSSMSTATEJMP_OFFSET, status); 1315250079Scarl} 1316250079Scarl 1317250079Scarlstatic void 1318250079Scarlntb_handle_link_event(struct ntb_softc *ntb, int link_state) 1319250079Scarl{ 1320250079Scarl enum ntb_hw_event event; 1321250079Scarl uint16_t status; 1322250079Scarl 1323250079Scarl if (ntb->link_status == link_state) 1324250079Scarl return; 1325250079Scarl 1326250079Scarl if (link_state == NTB_LINK_UP) { 1327250079Scarl device_printf(ntb->device, "Link Up\n"); 1328250079Scarl ntb->link_status = NTB_LINK_UP; 1329250079Scarl event = NTB_EVENT_HW_LINK_UP; 1330250079Scarl 1331289257Scem if (ntb->type == NTB_SOC || 1332289257Scem ntb->conn_type == NTB_CONN_TRANSPARENT) 1333255278Scarl status = ntb_reg_read(2, ntb->reg_ofs.lnk_stat); 1334250079Scarl else 1335250079Scarl status = pci_read_config(ntb->device, 1336250079Scarl XEON_LINK_STATUS_OFFSET, 2); 1337250079Scarl ntb->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; 1338250079Scarl ntb->link_speed = (status & NTB_LINK_SPEED_MASK); 1339250079Scarl device_printf(ntb->device, "Link Width %d, Link Speed %d\n", 1340250079Scarl ntb->link_width, ntb->link_speed); 1341250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 1342250079Scarl ntb_handle_heartbeat, ntb); 1343250079Scarl } else { 1344250079Scarl device_printf(ntb->device, "Link Down\n"); 1345250079Scarl ntb->link_status = NTB_LINK_DOWN; 1346250079Scarl event = NTB_EVENT_HW_LINK_DOWN; 1347255281Scarl /* Do not modify link width/speed, we need it in link recovery */ 1348250079Scarl } 1349250079Scarl 1350250079Scarl /* notify the upper layer if we have an event change */ 1351250079Scarl if (ntb->event_cb != NULL) 1352250079Scarl ntb->event_cb(ntb->ntb_transport, event); 1353250079Scarl} 1354250079Scarl 1355250079Scarlstatic void 1356289272Scemntb_hw_link_up(struct ntb_softc *ntb) 1357289272Scem{ 1358289280Scem uint32_t cntl; 1359289272Scem 1360289280Scem if (ntb->conn_type == NTB_CONN_TRANSPARENT) { 1361289272Scem ntb_handle_link_event(ntb, NTB_LINK_UP); 1362289280Scem return; 1363289280Scem } 1364289280Scem 1365289280Scem cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); 1366289280Scem cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); 1367289280Scem cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; 1368289397Scem cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP; 1369289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) 1370289397Scem cntl |= NTB_CNTL_P2S_BAR5_SNOOP | NTB_CNTL_S2P_BAR5_SNOOP; 1371289280Scem ntb_reg_write(4, ntb->reg_ofs.lnk_cntl, cntl); 1372289272Scem} 1373289272Scem 1374289272Scemstatic void 1375289272Scemntb_hw_link_down(struct ntb_softc *ntb) 1376289272Scem{ 1377289272Scem uint32_t cntl; 1378289272Scem 1379289272Scem if (ntb->conn_type == NTB_CONN_TRANSPARENT) { 1380289272Scem ntb_handle_link_event(ntb, NTB_LINK_DOWN); 1381289272Scem return; 1382289272Scem } 1383289272Scem 1384289272Scem cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); 1385289280Scem cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); 1386289397Scem cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP); 1387289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) 1388289397Scem cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | NTB_CNTL_S2P_BAR5_SNOOP); 1389289280Scem cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; 1390289272Scem ntb_reg_write(4, ntb->reg_ofs.lnk_cntl, cntl); 1391289272Scem} 1392289272Scem 1393289272Scemstatic void 1394250079Scarlrecover_soc_link(void *arg) 1395250079Scarl{ 1396250079Scarl struct ntb_softc *ntb = arg; 1397250079Scarl uint8_t speed, width; 1398250079Scarl uint32_t status32; 1399250079Scarl uint16_t status16; 1400250079Scarl 1401250079Scarl soc_perform_link_restart(ntb); 1402250079Scarl 1403289232Scem /* 1404289232Scem * There is a potential race between the 2 NTB devices recovering at 1405289232Scem * the same time. If the times are the same, the link will not recover 1406289232Scem * and the driver will be stuck in this loop forever. Add a random 1407289232Scem * interval to the recovery time to prevent this race. 1408289232Scem */ 1409289232Scem status32 = arc4random() % SOC_LINK_RECOVERY_TIME; 1410289232Scem pause("Link", (SOC_LINK_RECOVERY_TIME + status32) * hz / 1000); 1411289232Scem 1412255278Scarl status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 1413250079Scarl if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) 1414250079Scarl goto retry; 1415250079Scarl 1416255278Scarl status32 = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET); 1417250079Scarl if ((status32 & SOC_IBIST_ERR_OFLOW) != 0) 1418250079Scarl goto retry; 1419250079Scarl 1420289232Scem status32 = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); 1421289232Scem if ((status32 & SOC_CNTL_LINK_DOWN) != 0) 1422289232Scem goto out; 1423289232Scem 1424255278Scarl status16 = ntb_reg_read(2, ntb->reg_ofs.lnk_stat); 1425250079Scarl width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; 1426250079Scarl speed = (status16 & NTB_LINK_SPEED_MASK); 1427250079Scarl if (ntb->link_width != width || ntb->link_speed != speed) 1428250079Scarl goto retry; 1429250079Scarl 1430289232Scemout: 1431250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 1432250079Scarl ntb_handle_heartbeat, ntb); 1433250079Scarl return; 1434250079Scarl 1435250079Scarlretry: 1436250079Scarl callout_reset(&ntb->lr_timer, NTB_HB_TIMEOUT * hz, recover_soc_link, 1437250079Scarl ntb); 1438250079Scarl} 1439250079Scarl 1440250079Scarlstatic int 1441250079Scarlntb_check_link_status(struct ntb_softc *ntb) 1442250079Scarl{ 1443250079Scarl int link_state; 1444250079Scarl uint32_t ntb_cntl; 1445250079Scarl uint16_t status; 1446250079Scarl 1447250079Scarl if (ntb->type == NTB_SOC) { 1448255278Scarl ntb_cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); 1449250079Scarl if ((ntb_cntl & SOC_CNTL_LINK_DOWN) != 0) 1450250079Scarl link_state = NTB_LINK_DOWN; 1451250079Scarl else 1452250079Scarl link_state = NTB_LINK_UP; 1453250079Scarl } else { 1454250079Scarl status = pci_read_config(ntb->device, XEON_LINK_STATUS_OFFSET, 1455250079Scarl 2); 1456250079Scarl 1457250079Scarl if ((status & NTB_LINK_STATUS_ACTIVE) != 0) 1458250079Scarl link_state = NTB_LINK_UP; 1459250079Scarl else 1460250079Scarl link_state = NTB_LINK_DOWN; 1461250079Scarl } 1462250079Scarl 1463250079Scarl ntb_handle_link_event(ntb, link_state); 1464250079Scarl 1465250079Scarl return (0); 1466250079Scarl} 1467250079Scarl 1468250079Scarl/** 1469250079Scarl * ntb_register_event_callback() - register event callback 1470250079Scarl * @ntb: pointer to ntb_softc instance 1471250079Scarl * @func: callback function to register 1472250079Scarl * 1473250079Scarl * This function registers a callback for any HW driver events such as link 1474250079Scarl * up/down, power management notices and etc. 1475250079Scarl * 1476289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1477250079Scarl */ 1478250079Scarlint 1479250079Scarlntb_register_event_callback(struct ntb_softc *ntb, ntb_event_callback func) 1480250079Scarl{ 1481250079Scarl 1482250079Scarl if (ntb->event_cb != NULL) 1483250079Scarl return (EINVAL); 1484250079Scarl 1485250079Scarl ntb->event_cb = func; 1486250079Scarl 1487250079Scarl return (0); 1488250079Scarl} 1489250079Scarl 1490250079Scarl/** 1491250079Scarl * ntb_unregister_event_callback() - unregisters the event callback 1492250079Scarl * @ntb: pointer to ntb_softc instance 1493250079Scarl * 1494250079Scarl * This function unregisters the existing callback from transport 1495250079Scarl */ 1496250079Scarlvoid 1497250079Scarlntb_unregister_event_callback(struct ntb_softc *ntb) 1498250079Scarl{ 1499250079Scarl 1500250079Scarl ntb->event_cb = NULL; 1501250079Scarl} 1502250079Scarl 1503289281Scemstatic void 1504289281Scemntb_irq_work(void *arg) 1505289281Scem{ 1506289281Scem struct ntb_db_cb *db_cb = arg; 1507289281Scem struct ntb_softc *ntb; 1508289281Scem int rc; 1509289281Scem 1510289281Scem rc = db_cb->callback(db_cb->data, db_cb->db_num); 1511289281Scem /* Poll if forward progress was made. */ 1512289281Scem if (rc != 0) { 1513289281Scem callout_reset(&db_cb->irq_work, 0, ntb_irq_work, db_cb); 1514289281Scem return; 1515289281Scem } 1516289281Scem 1517289281Scem /* Unmask interrupt if no progress was made. */ 1518289281Scem ntb = db_cb->ntb; 1519289281Scem unmask_ldb_interrupt(ntb, db_cb->db_num); 1520289281Scem} 1521289281Scem 1522250079Scarl/** 1523250079Scarl * ntb_register_db_callback() - register a callback for doorbell interrupt 1524250079Scarl * @ntb: pointer to ntb_softc instance 1525250079Scarl * @idx: doorbell index to register callback, zero based 1526289266Scem * @data: pointer to be returned to caller with every callback 1527250079Scarl * @func: callback function to register 1528250079Scarl * 1529250079Scarl * This function registers a callback function for the doorbell interrupt 1530250079Scarl * on the primary side. The function will unmask the doorbell as well to 1531250079Scarl * allow interrupt. 1532250079Scarl * 1533289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1534250079Scarl */ 1535250079Scarlint 1536250079Scarlntb_register_db_callback(struct ntb_softc *ntb, unsigned int idx, void *data, 1537250079Scarl ntb_db_callback func) 1538250079Scarl{ 1539289343Scem struct ntb_db_cb *db_cb = &ntb->db_cb[idx]; 1540250079Scarl 1541289396Scem if (idx >= ntb->max_cbs || db_cb->callback != NULL || db_cb->reserved) { 1542250079Scarl device_printf(ntb->device, "Invalid Index.\n"); 1543250079Scarl return (EINVAL); 1544250079Scarl } 1545250079Scarl 1546289343Scem db_cb->callback = func; 1547289343Scem db_cb->data = data; 1548289343Scem callout_init(&db_cb->irq_work, 1); 1549250079Scarl 1550289281Scem unmask_ldb_interrupt(ntb, idx); 1551250079Scarl 1552250079Scarl return (0); 1553250079Scarl} 1554250079Scarl 1555250079Scarl/** 1556250079Scarl * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt 1557250079Scarl * @ntb: pointer to ntb_softc instance 1558250079Scarl * @idx: doorbell index to register callback, zero based 1559250079Scarl * 1560250079Scarl * This function unregisters a callback function for the doorbell interrupt 1561250079Scarl * on the primary side. The function will also mask the said doorbell. 1562250079Scarl */ 1563250079Scarlvoid 1564250079Scarlntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx) 1565250079Scarl{ 1566250079Scarl 1567289396Scem if (idx >= ntb->max_cbs || ntb->db_cb[idx].callback == NULL) 1568250079Scarl return; 1569250079Scarl 1570289281Scem mask_ldb_interrupt(ntb, idx); 1571250079Scarl 1572289281Scem callout_drain(&ntb->db_cb[idx].irq_work); 1573250079Scarl ntb->db_cb[idx].callback = NULL; 1574250079Scarl} 1575250079Scarl 1576250079Scarl/** 1577250079Scarl * ntb_find_transport() - find the transport pointer 1578250079Scarl * @transport: pointer to pci device 1579250079Scarl * 1580250079Scarl * Given the pci device pointer, return the transport pointer passed in when 1581250079Scarl * the transport attached when it was inited. 1582250079Scarl * 1583250079Scarl * RETURNS: pointer to transport. 1584250079Scarl */ 1585250079Scarlvoid * 1586250079Scarlntb_find_transport(struct ntb_softc *ntb) 1587250079Scarl{ 1588250079Scarl 1589250079Scarl return (ntb->ntb_transport); 1590250079Scarl} 1591250079Scarl 1592250079Scarl/** 1593250079Scarl * ntb_register_transport() - Register NTB transport with NTB HW driver 1594250079Scarl * @transport: transport identifier 1595250079Scarl * 1596250079Scarl * This function allows a transport to reserve the hardware driver for 1597250079Scarl * NTB usage. 1598250079Scarl * 1599250079Scarl * RETURNS: pointer to ntb_softc, NULL on error. 1600250079Scarl */ 1601250079Scarlstruct ntb_softc * 1602250079Scarlntb_register_transport(struct ntb_softc *ntb, void *transport) 1603250079Scarl{ 1604250079Scarl 1605250079Scarl /* 1606250079Scarl * TODO: when we have more than one transport, we will need to rewrite 1607250079Scarl * this to prevent race conditions 1608250079Scarl */ 1609250079Scarl if (ntb->ntb_transport != NULL) 1610250079Scarl return (NULL); 1611250079Scarl 1612250079Scarl ntb->ntb_transport = transport; 1613250079Scarl return (ntb); 1614250079Scarl} 1615250079Scarl 1616250079Scarl/** 1617250079Scarl * ntb_unregister_transport() - Unregister the transport with the NTB HW driver 1618250079Scarl * @ntb - ntb_softc of the transport to be freed 1619250079Scarl * 1620250079Scarl * This function unregisters the transport from the HW driver and performs any 1621250079Scarl * necessary cleanups. 1622250079Scarl */ 1623250079Scarlvoid 1624250079Scarlntb_unregister_transport(struct ntb_softc *ntb) 1625250079Scarl{ 1626289396Scem uint8_t i; 1627250079Scarl 1628250079Scarl if (ntb->ntb_transport == NULL) 1629250079Scarl return; 1630250079Scarl 1631289396Scem for (i = 0; i < ntb->max_cbs; i++) 1632250079Scarl ntb_unregister_db_callback(ntb, i); 1633250079Scarl 1634250079Scarl ntb_unregister_event_callback(ntb); 1635250079Scarl ntb->ntb_transport = NULL; 1636250079Scarl} 1637250079Scarl 1638250079Scarl/** 1639250079Scarl * ntb_get_max_spads() - get the total scratch regs usable 1640250079Scarl * @ntb: pointer to ntb_softc instance 1641250079Scarl * 1642250079Scarl * This function returns the max 32bit scratchpad registers usable by the 1643250079Scarl * upper layer. 1644250079Scarl * 1645250079Scarl * RETURNS: total number of scratch pad registers available 1646250079Scarl */ 1647289208Scemuint8_t 1648250079Scarlntb_get_max_spads(struct ntb_softc *ntb) 1649250079Scarl{ 1650250079Scarl 1651250079Scarl return (ntb->limits.max_spads); 1652250079Scarl} 1653250079Scarl 1654289396Scemuint8_t 1655289396Scemntb_get_max_cbs(struct ntb_softc *ntb) 1656289396Scem{ 1657289396Scem 1658289396Scem return (ntb->max_cbs); 1659289396Scem} 1660289396Scem 1661289396Scemuint8_t 1662289396Scemntb_get_max_mw(struct ntb_softc *ntb) 1663289396Scem{ 1664289396Scem 1665289396Scem return (ntb->limits.max_mw); 1666289396Scem} 1667289396Scem 1668250079Scarl/** 1669250079Scarl * ntb_write_local_spad() - write to the secondary scratchpad register 1670250079Scarl * @ntb: pointer to ntb_softc instance 1671250079Scarl * @idx: index to the scratchpad register, 0 based 1672250079Scarl * @val: the data value to put into the register 1673250079Scarl * 1674250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad 1675250079Scarl * register. The register resides on the secondary (external) side. 1676250079Scarl * 1677289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1678250079Scarl */ 1679250079Scarlint 1680250079Scarlntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) 1681250079Scarl{ 1682250079Scarl 1683250079Scarl if (idx >= ntb->limits.max_spads) 1684250079Scarl return (EINVAL); 1685250079Scarl 1686255278Scarl ntb_reg_write(4, ntb->reg_ofs.spad_local + idx * 4, val); 1687250079Scarl 1688250079Scarl return (0); 1689250079Scarl} 1690250079Scarl 1691250079Scarl/** 1692250079Scarl * ntb_read_local_spad() - read from the primary scratchpad register 1693250079Scarl * @ntb: pointer to ntb_softc instance 1694250079Scarl * @idx: index to scratchpad register, 0 based 1695250079Scarl * @val: pointer to 32bit integer for storing the register value 1696250079Scarl * 1697250079Scarl * This function allows reading of the 32bit scratchpad register on 1698250079Scarl * the primary (internal) side. 1699250079Scarl * 1700289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1701250079Scarl */ 1702250079Scarlint 1703250079Scarlntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) 1704250079Scarl{ 1705250079Scarl 1706250079Scarl if (idx >= ntb->limits.max_spads) 1707250079Scarl return (EINVAL); 1708250079Scarl 1709255278Scarl *val = ntb_reg_read(4, ntb->reg_ofs.spad_local + idx * 4); 1710250079Scarl 1711250079Scarl return (0); 1712250079Scarl} 1713250079Scarl 1714250079Scarl/** 1715250079Scarl * ntb_write_remote_spad() - write to the secondary scratchpad register 1716250079Scarl * @ntb: pointer to ntb_softc instance 1717250079Scarl * @idx: index to the scratchpad register, 0 based 1718250079Scarl * @val: the data value to put into the register 1719250079Scarl * 1720250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad 1721250079Scarl * register. The register resides on the secondary (external) side. 1722250079Scarl * 1723289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1724250079Scarl */ 1725250079Scarlint 1726250079Scarlntb_write_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) 1727250079Scarl{ 1728250079Scarl 1729250079Scarl if (idx >= ntb->limits.max_spads) 1730250079Scarl return (EINVAL); 1731250079Scarl 1732289538Scem if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) 1733255279Scarl ntb_mw_write(4, XEON_SHADOW_SPAD_OFFSET + idx * 4, val); 1734255279Scarl else 1735255279Scarl ntb_reg_write(4, ntb->reg_ofs.spad_remote + idx * 4, val); 1736250079Scarl 1737250079Scarl return (0); 1738250079Scarl} 1739250079Scarl 1740250079Scarl/** 1741250079Scarl * ntb_read_remote_spad() - read from the primary scratchpad register 1742250079Scarl * @ntb: pointer to ntb_softc instance 1743250079Scarl * @idx: index to scratchpad register, 0 based 1744250079Scarl * @val: pointer to 32bit integer for storing the register value 1745250079Scarl * 1746250079Scarl * This function allows reading of the 32bit scratchpad register on 1747250079Scarl * the primary (internal) side. 1748250079Scarl * 1749289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1750250079Scarl */ 1751250079Scarlint 1752250079Scarlntb_read_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) 1753250079Scarl{ 1754250079Scarl 1755250079Scarl if (idx >= ntb->limits.max_spads) 1756250079Scarl return (EINVAL); 1757250079Scarl 1758289538Scem if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) 1759255279Scarl *val = ntb_mw_read(4, XEON_SHADOW_SPAD_OFFSET + idx * 4); 1760255279Scarl else 1761255279Scarl *val = ntb_reg_read(4, ntb->reg_ofs.spad_remote + idx * 4); 1762250079Scarl 1763250079Scarl return (0); 1764250079Scarl} 1765250079Scarl 1766250079Scarl/** 1767250079Scarl * ntb_get_mw_vbase() - get virtual addr for the NTB memory window 1768250079Scarl * @ntb: pointer to ntb_softc instance 1769250079Scarl * @mw: memory window number 1770250079Scarl * 1771250079Scarl * This function provides the base virtual address of the memory window 1772250079Scarl * specified. 1773250079Scarl * 1774250079Scarl * RETURNS: pointer to virtual address, or NULL on error. 1775250079Scarl */ 1776250079Scarlvoid * 1777250079Scarlntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw) 1778250079Scarl{ 1779250079Scarl 1780289396Scem if (mw >= ntb_get_max_mw(ntb)) 1781250079Scarl return (NULL); 1782250079Scarl 1783250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].vbase); 1784250079Scarl} 1785250079Scarl 1786250079Scarlvm_paddr_t 1787250079Scarlntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw) 1788250079Scarl{ 1789250079Scarl 1790289396Scem if (mw >= ntb_get_max_mw(ntb)) 1791250079Scarl return (0); 1792250079Scarl 1793250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].pbase); 1794250079Scarl} 1795250079Scarl 1796250079Scarl/** 1797250079Scarl * ntb_get_mw_size() - return size of NTB memory window 1798250079Scarl * @ntb: pointer to ntb_softc instance 1799250079Scarl * @mw: memory window number 1800250079Scarl * 1801250079Scarl * This function provides the physical size of the memory window specified 1802250079Scarl * 1803250079Scarl * RETURNS: the size of the memory window or zero on error 1804250079Scarl */ 1805250079Scarlu_long 1806250079Scarlntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw) 1807250079Scarl{ 1808250079Scarl 1809289396Scem if (mw >= ntb_get_max_mw(ntb)) 1810250079Scarl return (0); 1811250079Scarl 1812250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].size); 1813250079Scarl} 1814250079Scarl 1815250079Scarl/** 1816250079Scarl * ntb_set_mw_addr - set the memory window address 1817250079Scarl * @ntb: pointer to ntb_softc instance 1818250079Scarl * @mw: memory window number 1819250079Scarl * @addr: base address for data 1820250079Scarl * 1821250079Scarl * This function sets the base physical address of the memory window. This 1822250079Scarl * memory address is where data from the remote system will be transfered into 1823250079Scarl * or out of depending on how the transport is configured. 1824250079Scarl */ 1825250079Scarlvoid 1826250079Scarlntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr) 1827250079Scarl{ 1828250079Scarl 1829289396Scem if (mw >= ntb_get_max_mw(ntb)) 1830250079Scarl return; 1831250079Scarl 1832250079Scarl switch (NTB_MW_TO_BAR(mw)) { 1833250079Scarl case NTB_B2B_BAR_1: 1834289255Scem ntb_reg_write(8, ntb->reg_ofs.bar2_xlat, addr); 1835250079Scarl break; 1836250079Scarl case NTB_B2B_BAR_2: 1837289397Scem if (HAS_FEATURE(NTB_SPLIT_BAR)) 1838289397Scem ntb_reg_write(4, ntb->reg_ofs.bar4_xlat, addr); 1839289397Scem else 1840289397Scem ntb_reg_write(8, ntb->reg_ofs.bar4_xlat, addr); 1841250079Scarl break; 1842289397Scem case NTB_B2B_BAR_3: 1843289397Scem ntb_reg_write(4, ntb->reg_ofs.bar5_xlat, addr); 1844289397Scem break; 1845250079Scarl } 1846250079Scarl} 1847250079Scarl 1848250079Scarl/** 1849289255Scem * ntb_ring_doorbell() - Set the doorbell on the secondary/external side 1850250079Scarl * @ntb: pointer to ntb_softc instance 1851250079Scarl * @db: doorbell to ring 1852250079Scarl * 1853250079Scarl * This function allows triggering of a doorbell on the secondary/external 1854250079Scarl * side that will initiate an interrupt on the remote host 1855250079Scarl */ 1856250079Scarlvoid 1857289255Scemntb_ring_doorbell(struct ntb_softc *ntb, unsigned int db) 1858250079Scarl{ 1859289347Scem uint64_t bit; 1860250079Scarl 1861250079Scarl if (ntb->type == NTB_SOC) 1862289347Scem bit = 1 << db; 1863289347Scem else 1864289347Scem bit = ((1 << ntb->bits_per_vector) - 1) << 1865289347Scem (db * ntb->bits_per_vector); 1866289347Scem 1867289538Scem if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) { 1868289347Scem ntb_mw_write(2, XEON_SHADOW_PDOORBELL_OFFSET, bit); 1869289347Scem return; 1870289209Scem } 1871289347Scem 1872289347Scem db_iowrite(ntb, ntb->reg_ofs.rdb, bit); 1873250079Scarl} 1874250079Scarl 1875250079Scarl/** 1876250079Scarl * ntb_query_link_status() - return the hardware link status 1877250079Scarl * @ndev: pointer to ntb_device instance 1878250079Scarl * 1879250079Scarl * Returns true if the hardware is connected to the remote system 1880250079Scarl * 1881250079Scarl * RETURNS: true or false based on the hardware link state 1882250079Scarl */ 1883250079Scarlbool 1884250079Scarlntb_query_link_status(struct ntb_softc *ntb) 1885250079Scarl{ 1886250079Scarl 1887250079Scarl return (ntb->link_status == NTB_LINK_UP); 1888250079Scarl} 1889250079Scarl 1890255272Scarlstatic void 1891255272Scarlsave_bar_parameters(struct ntb_pci_bar_info *bar) 1892250079Scarl{ 1893255272Scarl 1894289209Scem bar->pci_bus_tag = rman_get_bustag(bar->pci_resource); 1895289209Scem bar->pci_bus_handle = rman_get_bushandle(bar->pci_resource); 1896289209Scem bar->pbase = rman_get_start(bar->pci_resource); 1897289209Scem bar->size = rman_get_size(bar->pci_resource); 1898289209Scem bar->vbase = rman_get_virtual(bar->pci_resource); 1899250079Scarl} 1900255268Scarl 1901289209Scemdevice_t 1902289209Scemntb_get_device(struct ntb_softc *ntb) 1903255268Scarl{ 1904255268Scarl 1905255268Scarl return (ntb->device); 1906255268Scarl} 1907289208Scem 1908289208Scem/* Export HW-specific errata information. */ 1909289208Scembool 1910289208Scemntb_has_feature(struct ntb_softc *ntb, uint64_t feature) 1911289208Scem{ 1912289208Scem 1913289208Scem return (HAS_FEATURE(feature)); 1914289208Scem} 1915