ntb_hw_intel.c revision 289232
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 289232 2015-10-13 17:20:47Z 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 65250079Scarl#define NTB_MAX_BARS 3 66250079Scarl#define NTB_MW_TO_BAR(mw) ((mw) + 1) 67250079Scarl 68250079Scarl#define MAX_MSIX_INTERRUPTS MAX(XEON_MAX_DB_BITS, SOC_MAX_DB_BITS) 69250079Scarl 70250079Scarl#define NTB_HB_TIMEOUT 1 /* second */ 71250079Scarl#define SOC_LINK_RECOVERY_TIME 500 72250079Scarl 73250079Scarl#define DEVICE2SOFTC(dev) ((struct ntb_softc *) device_get_softc(dev)) 74250079Scarl 75250079Scarlenum ntb_device_type { 76250079Scarl NTB_XEON, 77250079Scarl NTB_SOC 78250079Scarl}; 79250079Scarl 80255274Scarl/* Device features and workarounds */ 81255274Scarl#define HAS_FEATURE(feature) \ 82255274Scarl ((ntb->features & (feature)) != 0) 83255274Scarl 84250079Scarlstruct ntb_hw_info { 85250079Scarl uint32_t device_id; 86255274Scarl const char *desc; 87250079Scarl enum ntb_device_type type; 88255274Scarl uint64_t features; 89250079Scarl}; 90250079Scarl 91250079Scarlstruct ntb_pci_bar_info { 92250079Scarl bus_space_tag_t pci_bus_tag; 93250079Scarl bus_space_handle_t pci_bus_handle; 94250079Scarl int pci_resource_id; 95250079Scarl struct resource *pci_resource; 96250079Scarl vm_paddr_t pbase; 97250079Scarl void *vbase; 98250079Scarl u_long size; 99250079Scarl}; 100250079Scarl 101250079Scarlstruct ntb_int_info { 102250079Scarl struct resource *res; 103250079Scarl int rid; 104250079Scarl void *tag; 105250079Scarl}; 106250079Scarl 107250079Scarlstruct ntb_db_cb { 108250079Scarl ntb_db_callback callback; 109250079Scarl unsigned int db_num; 110250079Scarl void *data; 111250079Scarl struct ntb_softc *ntb; 112250079Scarl}; 113250079Scarl 114250079Scarlstruct ntb_softc { 115250079Scarl device_t device; 116250079Scarl enum ntb_device_type type; 117255274Scarl uint64_t features; 118250079Scarl 119250079Scarl struct ntb_pci_bar_info bar_info[NTB_MAX_BARS]; 120250079Scarl struct ntb_int_info int_info[MAX_MSIX_INTERRUPTS]; 121250079Scarl uint32_t allocated_interrupts; 122250079Scarl 123250079Scarl struct callout heartbeat_timer; 124250079Scarl struct callout lr_timer; 125250079Scarl 126250079Scarl void *ntb_transport; 127250079Scarl ntb_event_callback event_cb; 128250079Scarl struct ntb_db_cb *db_cb; 129250079Scarl 130250079Scarl struct { 131289208Scem uint8_t max_spads; 132289208Scem uint8_t max_db_bits; 133289208Scem uint8_t msix_cnt; 134250079Scarl } limits; 135250079Scarl struct { 136250079Scarl uint32_t pdb; 137250079Scarl uint32_t pdb_mask; 138250079Scarl uint32_t sdb; 139250079Scarl uint32_t sbar2_xlat; 140250079Scarl uint32_t sbar4_xlat; 141250079Scarl uint32_t spad_remote; 142250079Scarl uint32_t spad_local; 143250079Scarl uint32_t lnk_cntl; 144250079Scarl uint32_t lnk_stat; 145250079Scarl uint32_t spci_cmd; 146250079Scarl } reg_ofs; 147250079Scarl uint8_t conn_type; 148250079Scarl uint8_t dev_type; 149250079Scarl uint8_t bits_per_vector; 150250079Scarl uint8_t link_status; 151250079Scarl uint8_t link_width; 152250079Scarl uint8_t link_speed; 153250079Scarl}; 154250079Scarl 155255279Scarl#define ntb_bar_read(SIZE, bar, offset) \ 156255279Scarl bus_space_read_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \ 157255279Scarl ntb->bar_info[(bar)].pci_bus_handle, (offset)) 158255279Scarl#define ntb_bar_write(SIZE, bar, offset, val) \ 159255279Scarl bus_space_write_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \ 160255279Scarl ntb->bar_info[(bar)].pci_bus_handle, (offset), (val)) 161255279Scarl#define ntb_reg_read(SIZE, offset) ntb_bar_read(SIZE, NTB_CONFIG_BAR, offset) 162250079Scarl#define ntb_reg_write(SIZE, offset, val) \ 163255279Scarl ntb_bar_write(SIZE, NTB_CONFIG_BAR, offset, val) 164255279Scarl#define ntb_mw_read(SIZE, offset) ntb_bar_read(SIZE, NTB_B2B_BAR_2, offset) 165255279Scarl#define ntb_mw_write(SIZE, offset, val) \ 166255279Scarl ntb_bar_write(SIZE, NTB_B2B_BAR_2, offset, val) 167250079Scarl 168255272Scarltypedef int (*bar_map_strategy)(struct ntb_softc *ntb, 169255272Scarl struct ntb_pci_bar_info *bar); 170255272Scarl 171250079Scarlstatic int ntb_probe(device_t device); 172250079Scarlstatic int ntb_attach(device_t device); 173250079Scarlstatic int ntb_detach(device_t device); 174255272Scarlstatic int ntb_map_pci_bars(struct ntb_softc *ntb); 175255272Scarlstatic int map_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, 176255272Scarl struct ntb_pci_bar_info *bar); 177255272Scarlstatic int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar); 178255272Scarlstatic int map_memory_window_bar(struct ntb_softc *ntb, 179255272Scarl struct ntb_pci_bar_info *bar); 180250079Scarlstatic void ntb_unmap_pci_bar(struct ntb_softc *ntb); 181250079Scarlstatic int ntb_setup_interrupts(struct ntb_softc *ntb); 182250079Scarlstatic void ntb_teardown_interrupts(struct ntb_softc *ntb); 183250079Scarlstatic void handle_soc_irq(void *arg); 184250079Scarlstatic void handle_xeon_irq(void *arg); 185250079Scarlstatic void handle_xeon_event_irq(void *arg); 186250079Scarlstatic void ntb_handle_legacy_interrupt(void *arg); 187250079Scarlstatic int ntb_create_callbacks(struct ntb_softc *ntb, int num_vectors); 188250079Scarlstatic void ntb_free_callbacks(struct ntb_softc *ntb); 189250079Scarlstatic struct ntb_hw_info *ntb_get_device_info(uint32_t device_id); 190250079Scarlstatic int ntb_initialize_hw(struct ntb_softc *ntb); 191250079Scarlstatic int ntb_setup_xeon(struct ntb_softc *ntb); 192250079Scarlstatic int ntb_setup_soc(struct ntb_softc *ntb); 193255279Scarlstatic void configure_soc_secondary_side_bars(struct ntb_softc *ntb); 194255279Scarlstatic void configure_xeon_secondary_side_bars(struct ntb_softc *ntb); 195250079Scarlstatic void ntb_handle_heartbeat(void *arg); 196250079Scarlstatic void ntb_handle_link_event(struct ntb_softc *ntb, int link_state); 197250079Scarlstatic void recover_soc_link(void *arg); 198250079Scarlstatic int ntb_check_link_status(struct ntb_softc *ntb); 199255274Scarlstatic void save_bar_parameters(struct ntb_pci_bar_info *bar); 200250079Scarl 201250079Scarlstatic struct ntb_hw_info pci_ids[] = { 202255274Scarl { 0x3C0D8086, "Xeon E5/Core i7 Non-Transparent Bridge B2B", NTB_XEON, 203255274Scarl NTB_REGS_THRU_MW }, 204255274Scarl { 0x0C4E8086, "Atom Processor S1200 NTB Primary B2B", NTB_SOC, 0 }, 205255274Scarl { 0x0E0D8086, "Xeon E5 V2 Non-Transparent Bridge B2B", NTB_XEON, 206255274Scarl NTB_REGS_THRU_MW | NTB_BAR_SIZE_4K }, 207255274Scarl { 0x00000000, NULL, NTB_SOC, 0 } 208250079Scarl}; 209250079Scarl 210250079Scarl/* 211250079Scarl * OS <-> Driver interface structures 212250079Scarl */ 213250079ScarlMALLOC_DEFINE(M_NTB, "ntb_hw", "ntb_hw driver memory allocations"); 214250079Scarl 215250079Scarlstatic device_method_t ntb_pci_methods[] = { 216250079Scarl /* Device interface */ 217250079Scarl DEVMETHOD(device_probe, ntb_probe), 218250079Scarl DEVMETHOD(device_attach, ntb_attach), 219250079Scarl DEVMETHOD(device_detach, ntb_detach), 220250079Scarl DEVMETHOD_END 221250079Scarl}; 222250079Scarl 223250079Scarlstatic driver_t ntb_pci_driver = { 224250079Scarl "ntb_hw", 225250079Scarl ntb_pci_methods, 226250079Scarl sizeof(struct ntb_softc), 227250079Scarl}; 228250079Scarl 229250079Scarlstatic devclass_t ntb_devclass; 230250079ScarlDRIVER_MODULE(ntb_hw, pci, ntb_pci_driver, ntb_devclass, NULL, NULL); 231250079ScarlMODULE_VERSION(ntb_hw, 1); 232250079Scarl 233289207ScemSYSCTL_NODE(_hw, OID_AUTO, ntb, CTLFLAG_RW, 0, "NTB sysctls"); 234289207Scem 235250079Scarl/* 236250079Scarl * OS <-> Driver linkage functions 237250079Scarl */ 238250079Scarlstatic int 239250079Scarlntb_probe(device_t device) 240250079Scarl{ 241289209Scem struct ntb_hw_info *p; 242250079Scarl 243289209Scem p = ntb_get_device_info(pci_get_devid(device)); 244289209Scem if (p == NULL) 245250079Scarl return (ENXIO); 246289209Scem 247289209Scem device_set_desc(device, p->desc); 248289209Scem return (0); 249250079Scarl} 250250079Scarl 251250079Scarlstatic int 252250079Scarlntb_attach(device_t device) 253250079Scarl{ 254289209Scem struct ntb_softc *ntb; 255289209Scem struct ntb_hw_info *p; 256250079Scarl int error; 257250079Scarl 258289209Scem ntb = DEVICE2SOFTC(device); 259289209Scem p = ntb_get_device_info(pci_get_devid(device)); 260289209Scem 261250079Scarl ntb->device = device; 262250079Scarl ntb->type = p->type; 263255274Scarl ntb->features = p->features; 264250079Scarl 265250079Scarl /* Heartbeat timer for NTB_SOC since there is no link interrupt */ 266283291Sjkim callout_init(&ntb->heartbeat_timer, 1); 267283291Sjkim callout_init(&ntb->lr_timer, 1); 268250079Scarl 269289209Scem error = ntb_map_pci_bars(ntb); 270289209Scem if (error) 271289209Scem goto out; 272289209Scem error = ntb_initialize_hw(ntb); 273289209Scem if (error) 274289209Scem goto out; 275289209Scem error = ntb_setup_interrupts(ntb); 276289209Scem if (error) 277289209Scem goto out; 278250079Scarl 279250079Scarl pci_enable_busmaster(ntb->device); 280250079Scarl 281289209Scemout: 282289209Scem if (error != 0) 283289209Scem ntb_detach(device); 284250079Scarl return (error); 285250079Scarl} 286250079Scarl 287250079Scarlstatic int 288250079Scarlntb_detach(device_t device) 289250079Scarl{ 290289209Scem struct ntb_softc *ntb; 291250079Scarl 292289209Scem ntb = DEVICE2SOFTC(device); 293250079Scarl callout_drain(&ntb->heartbeat_timer); 294250079Scarl callout_drain(&ntb->lr_timer); 295250079Scarl ntb_teardown_interrupts(ntb); 296250079Scarl ntb_unmap_pci_bar(ntb); 297250079Scarl 298250079Scarl return (0); 299250079Scarl} 300250079Scarl 301250079Scarlstatic int 302255272Scarlntb_map_pci_bars(struct ntb_softc *ntb) 303250079Scarl{ 304255272Scarl int rc; 305250079Scarl 306250079Scarl ntb->bar_info[NTB_CONFIG_BAR].pci_resource_id = PCIR_BAR(0); 307255272Scarl rc = map_pci_bar(ntb, map_mmr_bar, &ntb->bar_info[NTB_CONFIG_BAR]); 308255272Scarl if (rc != 0) 309289209Scem return (rc); 310255272Scarl 311289209Scem ntb->bar_info[NTB_B2B_BAR_1].pci_resource_id = PCIR_BAR(2); 312255272Scarl rc = map_pci_bar(ntb, map_memory_window_bar, 313255272Scarl &ntb->bar_info[NTB_B2B_BAR_1]); 314255272Scarl if (rc != 0) 315289209Scem return (rc); 316255272Scarl 317289209Scem ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4); 318255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 319255279Scarl rc = map_pci_bar(ntb, map_mmr_bar, 320255279Scarl &ntb->bar_info[NTB_B2B_BAR_2]); 321255279Scarl else 322255279Scarl rc = map_pci_bar(ntb, map_memory_window_bar, 323255279Scarl &ntb->bar_info[NTB_B2B_BAR_2]); 324289209Scem return (rc); 325255272Scarl} 326250079Scarl 327255272Scarlstatic int 328255272Scarlmap_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, 329255272Scarl struct ntb_pci_bar_info *bar) 330255272Scarl{ 331255272Scarl int rc; 332255272Scarl 333255272Scarl rc = strategy(ntb, bar); 334289209Scem if (rc != 0) 335255272Scarl device_printf(ntb->device, 336255272Scarl "unable to allocate pci resource\n"); 337289209Scem else 338255279Scarl device_printf(ntb->device, 339255272Scarl "Bar size = %lx, v %p, p %p\n", 340289209Scem bar->size, bar->vbase, (void *)(bar->pbase)); 341255272Scarl return (rc); 342255272Scarl} 343255272Scarl 344255272Scarlstatic int 345255272Scarlmap_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) 346255272Scarl{ 347255272Scarl 348255275Scarl bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, 349289209Scem &bar->pci_resource_id, RF_ACTIVE); 350255272Scarl if (bar->pci_resource == NULL) 351255272Scarl return (ENXIO); 352289209Scem 353289209Scem save_bar_parameters(bar); 354289209Scem return (0); 355255272Scarl} 356255272Scarl 357255272Scarlstatic int 358255272Scarlmap_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) 359255272Scarl{ 360255272Scarl int rc; 361255276Scarl uint8_t bar_size_bits = 0; 362255272Scarl 363289209Scem bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, 364289209Scem &bar->pci_resource_id, RF_ACTIVE); 365250079Scarl 366255272Scarl if (bar->pci_resource == NULL) 367255272Scarl return (ENXIO); 368255276Scarl 369289209Scem save_bar_parameters(bar); 370289209Scem /* 371289209Scem * Ivytown NTB BAR sizes are misreported by the hardware due to a 372289209Scem * hardware issue. To work around this, query the size it should be 373289209Scem * configured to by the device and modify the resource to correspond to 374289209Scem * this new size. The BIOS on systems with this problem is required to 375289209Scem * provide enough address space to allow the driver to make this change 376289209Scem * safely. 377289209Scem * 378289209Scem * Ideally I could have just specified the size when I allocated the 379289209Scem * resource like: 380289209Scem * bus_alloc_resource(ntb->device, 381289209Scem * SYS_RES_MEMORY, &bar->pci_resource_id, 0ul, ~0ul, 382289209Scem * 1ul << bar_size_bits, RF_ACTIVE); 383289209Scem * but the PCI driver does not honor the size in this call, so we have 384289209Scem * to modify it after the fact. 385289209Scem */ 386289209Scem if (HAS_FEATURE(NTB_BAR_SIZE_4K)) { 387289209Scem if (bar->pci_resource_id == PCIR_BAR(2)) 388289209Scem bar_size_bits = pci_read_config(ntb->device, 389289209Scem XEON_PBAR23SZ_OFFSET, 1); 390289209Scem else 391289209Scem bar_size_bits = pci_read_config(ntb->device, 392289209Scem XEON_PBAR45SZ_OFFSET, 1); 393289209Scem 394289209Scem rc = bus_adjust_resource(ntb->device, SYS_RES_MEMORY, 395289209Scem bar->pci_resource, bar->pbase, 396289209Scem bar->pbase + (1ul << bar_size_bits) - 1); 397255272Scarl if (rc != 0) { 398289209Scem device_printf(ntb->device, 399289209Scem "unable to resize bar\n"); 400255272Scarl return (rc); 401250079Scarl } 402289209Scem 403289209Scem save_bar_parameters(bar); 404250079Scarl } 405289209Scem 406289209Scem /* Mark bar region as write combining to improve performance. */ 407289209Scem rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size, 408289209Scem VM_MEMATTR_WRITE_COMBINING); 409289209Scem if (rc != 0) { 410289209Scem device_printf(ntb->device, 411289209Scem "unable to mark bar as WRITE_COMBINING\n"); 412289209Scem return (rc); 413289209Scem } 414250079Scarl return (0); 415250079Scarl} 416250079Scarl 417250079Scarlstatic void 418250079Scarlntb_unmap_pci_bar(struct ntb_softc *ntb) 419250079Scarl{ 420250079Scarl struct ntb_pci_bar_info *current_bar; 421250079Scarl int i; 422250079Scarl 423250079Scarl for (i = 0; i< NTB_MAX_BARS; i++) { 424250079Scarl current_bar = &ntb->bar_info[i]; 425250079Scarl if (current_bar->pci_resource != NULL) 426250079Scarl bus_release_resource(ntb->device, SYS_RES_MEMORY, 427250079Scarl current_bar->pci_resource_id, 428250079Scarl current_bar->pci_resource); 429250079Scarl } 430250079Scarl} 431250079Scarl 432250079Scarlstatic int 433250079Scarlntb_setup_interrupts(struct ntb_softc *ntb) 434250079Scarl{ 435250079Scarl void (*interrupt_handler)(void *); 436250079Scarl void *int_arg; 437289209Scem bool use_msix = false; 438250079Scarl uint32_t num_vectors; 439250079Scarl int i; 440250079Scarl 441250079Scarl ntb->allocated_interrupts = 0; 442250079Scarl /* 443250079Scarl * On SOC, disable all interrupts. On XEON, disable all but Link 444250079Scarl * Interrupt. The rest will be unmasked as callbacks are registered. 445250079Scarl */ 446250079Scarl if (ntb->type == NTB_SOC) 447255278Scarl ntb_reg_write(8, ntb->reg_ofs.pdb_mask, ~0); 448250079Scarl else 449255278Scarl ntb_reg_write(2, ntb->reg_ofs.pdb_mask, 450250079Scarl ~(1 << ntb->limits.max_db_bits)); 451250079Scarl 452250079Scarl num_vectors = MIN(pci_msix_count(ntb->device), 453250079Scarl ntb->limits.max_db_bits); 454250079Scarl if (num_vectors >= 1) { 455250079Scarl pci_alloc_msix(ntb->device, &num_vectors); 456250079Scarl if (num_vectors >= 4) 457289209Scem use_msix = true; 458250079Scarl } 459250079Scarl 460250079Scarl ntb_create_callbacks(ntb, num_vectors); 461289209Scem if (use_msix == true) { 462250079Scarl for (i = 0; i < num_vectors; i++) { 463250079Scarl ntb->int_info[i].rid = i + 1; 464250079Scarl ntb->int_info[i].res = bus_alloc_resource_any( 465250079Scarl ntb->device, SYS_RES_IRQ, &ntb->int_info[i].rid, 466250079Scarl RF_ACTIVE); 467250079Scarl if (ntb->int_info[i].res == NULL) { 468250079Scarl device_printf(ntb->device, 469250079Scarl "bus_alloc_resource failed\n"); 470289209Scem return (ENOMEM); 471250079Scarl } 472250079Scarl ntb->int_info[i].tag = NULL; 473250079Scarl ntb->allocated_interrupts++; 474250079Scarl if (ntb->type == NTB_SOC) { 475250079Scarl interrupt_handler = handle_soc_irq; 476250079Scarl int_arg = &ntb->db_cb[i]; 477250079Scarl } else { 478250079Scarl if (i == num_vectors - 1) { 479255279Scarl interrupt_handler = 480255279Scarl handle_xeon_event_irq; 481250079Scarl int_arg = ntb; 482250079Scarl } else { 483250079Scarl interrupt_handler = 484250079Scarl handle_xeon_irq; 485250079Scarl int_arg = &ntb->db_cb[i]; 486250079Scarl } 487250079Scarl } 488250079Scarl if (bus_setup_intr(ntb->device, ntb->int_info[i].res, 489250079Scarl INTR_MPSAFE | INTR_TYPE_MISC, NULL, 490250079Scarl interrupt_handler, int_arg, 491250079Scarl &ntb->int_info[i].tag) != 0) { 492250079Scarl device_printf(ntb->device, 493250079Scarl "bus_setup_intr failed\n"); 494250079Scarl return (ENXIO); 495250079Scarl } 496250079Scarl } 497289209Scem } else { 498250079Scarl ntb->int_info[0].rid = 0; 499255279Scarl ntb->int_info[0].res = bus_alloc_resource_any(ntb->device, 500255279Scarl SYS_RES_IRQ, &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE); 501250079Scarl interrupt_handler = ntb_handle_legacy_interrupt; 502250079Scarl if (ntb->int_info[0].res == NULL) { 503250079Scarl device_printf(ntb->device, 504250079Scarl "bus_alloc_resource failed\n"); 505289209Scem return (ENOMEM); 506250079Scarl } 507250079Scarl ntb->int_info[0].tag = NULL; 508250079Scarl ntb->allocated_interrupts = 1; 509250079Scarl 510250079Scarl if (bus_setup_intr(ntb->device, ntb->int_info[0].res, 511250079Scarl INTR_MPSAFE | INTR_TYPE_MISC, NULL, 512250079Scarl interrupt_handler, ntb, &ntb->int_info[0].tag) != 0) { 513250079Scarl 514250079Scarl device_printf(ntb->device, "bus_setup_intr failed\n"); 515250079Scarl return (ENXIO); 516250079Scarl } 517250079Scarl } 518250079Scarl 519250079Scarl return (0); 520250079Scarl} 521250079Scarl 522250079Scarlstatic void 523250079Scarlntb_teardown_interrupts(struct ntb_softc *ntb) 524250079Scarl{ 525250079Scarl struct ntb_int_info *current_int; 526250079Scarl int i; 527250079Scarl 528289209Scem for (i = 0; i < ntb->allocated_interrupts; i++) { 529250079Scarl current_int = &ntb->int_info[i]; 530250079Scarl if (current_int->tag != NULL) 531250079Scarl bus_teardown_intr(ntb->device, current_int->res, 532250079Scarl current_int->tag); 533250079Scarl 534250079Scarl if (current_int->res != NULL) 535250079Scarl bus_release_resource(ntb->device, SYS_RES_IRQ, 536250079Scarl rman_get_rid(current_int->res), current_int->res); 537250079Scarl } 538250079Scarl 539250079Scarl ntb_free_callbacks(ntb); 540250079Scarl pci_release_msi(ntb->device); 541250079Scarl} 542250079Scarl 543250079Scarlstatic void 544250079Scarlhandle_soc_irq(void *arg) 545250079Scarl{ 546250079Scarl struct ntb_db_cb *db_cb = arg; 547250079Scarl struct ntb_softc *ntb = db_cb->ntb; 548250079Scarl 549255278Scarl ntb_reg_write(8, ntb->reg_ofs.pdb, (uint64_t) 1 << db_cb->db_num); 550250079Scarl 551250079Scarl if (db_cb->callback != NULL) 552250079Scarl db_cb->callback(db_cb->data, db_cb->db_num); 553250079Scarl} 554250079Scarl 555250079Scarlstatic void 556250079Scarlhandle_xeon_irq(void *arg) 557250079Scarl{ 558250079Scarl struct ntb_db_cb *db_cb = arg; 559250079Scarl struct ntb_softc *ntb = db_cb->ntb; 560250079Scarl 561250079Scarl /* 562250079Scarl * On Xeon, there are 16 bits in the interrupt register 563250079Scarl * but only 4 vectors. So, 5 bits are assigned to the first 3 564250079Scarl * vectors, with the 4th having a single bit for link 565250079Scarl * interrupts. 566250079Scarl */ 567255278Scarl ntb_reg_write(2, ntb->reg_ofs.pdb, 568250079Scarl ((1 << ntb->bits_per_vector) - 1) << 569250079Scarl (db_cb->db_num * ntb->bits_per_vector)); 570250079Scarl 571250079Scarl if (db_cb->callback != NULL) 572250079Scarl db_cb->callback(db_cb->data, db_cb->db_num); 573250079Scarl} 574250079Scarl 575250079Scarl/* Since we do not have a HW doorbell in SOC, this is only used in JF/JT */ 576250079Scarlstatic void 577250079Scarlhandle_xeon_event_irq(void *arg) 578250079Scarl{ 579250079Scarl struct ntb_softc *ntb = arg; 580250079Scarl int rc; 581250079Scarl 582250079Scarl rc = ntb_check_link_status(ntb); 583250079Scarl if (rc != 0) 584250079Scarl device_printf(ntb->device, "Error determining link status\n"); 585250079Scarl 586250079Scarl /* bit 15 is always the link bit */ 587255278Scarl ntb_reg_write(2, ntb->reg_ofs.pdb, 1 << ntb->limits.max_db_bits); 588250079Scarl} 589250079Scarl 590250079Scarlstatic void 591250079Scarlntb_handle_legacy_interrupt(void *arg) 592250079Scarl{ 593250079Scarl struct ntb_softc *ntb = arg; 594250079Scarl unsigned int i = 0; 595250079Scarl uint64_t pdb64; 596250079Scarl uint16_t pdb16; 597250079Scarl 598250079Scarl if (ntb->type == NTB_SOC) { 599255278Scarl pdb64 = ntb_reg_read(8, ntb->reg_ofs.pdb); 600250079Scarl 601250079Scarl while (pdb64) { 602250079Scarl i = ffs(pdb64); 603250079Scarl pdb64 &= pdb64 - 1; 604250079Scarl handle_soc_irq(&ntb->db_cb[i]); 605250079Scarl } 606250079Scarl } else { 607255278Scarl pdb16 = ntb_reg_read(2, ntb->reg_ofs.pdb); 608250079Scarl 609250079Scarl if ((pdb16 & XEON_DB_HW_LINK) != 0) { 610250079Scarl handle_xeon_event_irq(ntb); 611250079Scarl pdb16 &= ~XEON_DB_HW_LINK; 612250079Scarl } 613250079Scarl 614250079Scarl while (pdb16 != 0) { 615250079Scarl i = ffs(pdb16); 616250079Scarl pdb16 &= pdb16 - 1; 617250079Scarl handle_xeon_irq(&ntb->db_cb[i]); 618250079Scarl } 619250079Scarl } 620250079Scarl 621250079Scarl} 622250079Scarl 623250079Scarlstatic int 624250079Scarlntb_create_callbacks(struct ntb_softc *ntb, int num_vectors) 625250079Scarl{ 626250079Scarl int i; 627250079Scarl 628289209Scem ntb->db_cb = malloc(num_vectors * sizeof(*ntb->db_cb), M_NTB, 629250079Scarl M_ZERO | M_WAITOK); 630250079Scarl for (i = 0; i < num_vectors; i++) { 631250079Scarl ntb->db_cb[i].db_num = i; 632250079Scarl ntb->db_cb[i].ntb = ntb; 633250079Scarl } 634250079Scarl 635250079Scarl return (0); 636250079Scarl} 637250079Scarl 638250079Scarlstatic void 639250079Scarlntb_free_callbacks(struct ntb_softc *ntb) 640250079Scarl{ 641250079Scarl int i; 642250079Scarl 643250079Scarl for (i = 0; i < ntb->limits.max_db_bits; i++) 644250079Scarl ntb_unregister_db_callback(ntb, i); 645250079Scarl 646250079Scarl free(ntb->db_cb, M_NTB); 647250079Scarl} 648250079Scarl 649250079Scarlstatic struct ntb_hw_info * 650250079Scarlntb_get_device_info(uint32_t device_id) 651250079Scarl{ 652250079Scarl struct ntb_hw_info *ep = pci_ids; 653250079Scarl 654250079Scarl while (ep->device_id) { 655250079Scarl if (ep->device_id == device_id) 656250079Scarl return (ep); 657250079Scarl ++ep; 658250079Scarl } 659250079Scarl return (NULL); 660250079Scarl} 661250079Scarl 662250079Scarlstatic int 663250079Scarlntb_initialize_hw(struct ntb_softc *ntb) 664250079Scarl{ 665250079Scarl 666250079Scarl if (ntb->type == NTB_SOC) 667250079Scarl return (ntb_setup_soc(ntb)); 668250079Scarl else 669250079Scarl return (ntb_setup_xeon(ntb)); 670250079Scarl} 671250079Scarl 672250079Scarlstatic int 673250079Scarlntb_setup_xeon(struct ntb_softc *ntb) 674250079Scarl{ 675250079Scarl uint8_t val, connection_type; 676250079Scarl 677250079Scarl val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1); 678250079Scarl 679250079Scarl connection_type = val & XEON_PPD_CONN_TYPE; 680250079Scarl switch (connection_type) { 681250079Scarl case NTB_CONN_B2B: 682250079Scarl ntb->conn_type = NTB_CONN_B2B; 683250079Scarl break; 684250079Scarl case NTB_CONN_CLASSIC: 685250079Scarl case NTB_CONN_RP: 686250079Scarl default: 687250079Scarl device_printf(ntb->device, "Connection type %d not supported\n", 688250079Scarl connection_type); 689250079Scarl return (ENXIO); 690250079Scarl } 691250079Scarl 692250079Scarl if ((val & XEON_PPD_DEV_TYPE) != 0) 693289206Scem ntb->dev_type = NTB_DEV_USD; 694289206Scem else 695250079Scarl ntb->dev_type = NTB_DEV_DSD; 696250079Scarl 697250079Scarl ntb->reg_ofs.pdb = XEON_PDOORBELL_OFFSET; 698250079Scarl ntb->reg_ofs.pdb_mask = XEON_PDBMSK_OFFSET; 699250079Scarl ntb->reg_ofs.sbar2_xlat = XEON_SBAR2XLAT_OFFSET; 700250079Scarl ntb->reg_ofs.sbar4_xlat = XEON_SBAR4XLAT_OFFSET; 701250079Scarl ntb->reg_ofs.lnk_cntl = XEON_NTBCNTL_OFFSET; 702250079Scarl ntb->reg_ofs.lnk_stat = XEON_LINK_STATUS_OFFSET; 703250079Scarl ntb->reg_ofs.spad_local = XEON_SPAD_OFFSET; 704250079Scarl ntb->reg_ofs.spci_cmd = XEON_PCICMD_OFFSET; 705250079Scarl 706289208Scem /* 707289208Scem * There is a Xeon hardware errata related to writes to SDOORBELL or 708289208Scem * B2BDOORBELL in conjunction with inbound access to NTB MMIO space, 709289208Scem * which may hang the system. To workaround this use the second memory 710289208Scem * window to access the interrupt and scratch pad registers on the 711289208Scem * remote system. 712289208Scem */ 713289208Scem if (HAS_FEATURE(NTB_REGS_THRU_MW)) 714289208Scem /* 715289208Scem * Set the Limit register to 4k, the minimum size, to prevent 716289208Scem * an illegal access. 717289208Scem */ 718289208Scem ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 719289208Scem ntb_get_mw_size(ntb, 1) + 0x1000); 720289208Scem else 721289208Scem /* 722289208Scem * Disable the limit register, just in case it is set to 723289208Scem * something silly. 724289208Scem */ 725289208Scem ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0); 726289208Scem 727289208Scem 728250079Scarl if (ntb->conn_type == NTB_CONN_B2B) { 729250079Scarl ntb->reg_ofs.sdb = XEON_B2B_DOORBELL_OFFSET; 730250079Scarl ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET; 731250079Scarl ntb->limits.max_spads = XEON_MAX_SPADS; 732250079Scarl } else { 733250079Scarl ntb->reg_ofs.sdb = XEON_SDOORBELL_OFFSET; 734250079Scarl ntb->reg_ofs.spad_remote = XEON_SPAD_OFFSET; 735250079Scarl ntb->limits.max_spads = XEON_MAX_COMPAT_SPADS; 736250079Scarl } 737250079Scarl 738250079Scarl ntb->limits.max_db_bits = XEON_MAX_DB_BITS; 739250079Scarl ntb->limits.msix_cnt = XEON_MSIX_CNT; 740250079Scarl ntb->bits_per_vector = XEON_DB_BITS_PER_VEC; 741250079Scarl 742255279Scarl configure_xeon_secondary_side_bars(ntb); 743289209Scem 744250079Scarl /* Enable Bus Master and Memory Space on the secondary side */ 745255278Scarl ntb_reg_write(2, ntb->reg_ofs.spci_cmd, 746250079Scarl PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 747255279Scarl 748255269Scarl /* Enable link training */ 749255278Scarl ntb_reg_write(4, ntb->reg_ofs.lnk_cntl, 750255269Scarl NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP); 751250079Scarl 752250079Scarl return (0); 753250079Scarl} 754250079Scarl 755250079Scarlstatic int 756250079Scarlntb_setup_soc(struct ntb_softc *ntb) 757250079Scarl{ 758250079Scarl uint32_t val, connection_type; 759250079Scarl 760250079Scarl val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4); 761250079Scarl 762250079Scarl connection_type = (val & SOC_PPD_CONN_TYPE) >> 8; 763250079Scarl switch (connection_type) { 764250079Scarl case NTB_CONN_B2B: 765250079Scarl ntb->conn_type = NTB_CONN_B2B; 766250079Scarl break; 767250079Scarl case NTB_CONN_RP: 768250079Scarl default: 769250079Scarl device_printf(ntb->device, "Connection type %d not supported\n", 770250079Scarl connection_type); 771250079Scarl return (ENXIO); 772250079Scarl } 773250079Scarl 774250079Scarl if ((val & SOC_PPD_DEV_TYPE) != 0) 775250079Scarl ntb->dev_type = NTB_DEV_DSD; 776250079Scarl else 777250079Scarl ntb->dev_type = NTB_DEV_USD; 778250079Scarl 779250079Scarl /* Initiate PCI-E link training */ 780250079Scarl pci_write_config(ntb->device, NTB_PPD_OFFSET, val | SOC_PPD_INIT_LINK, 781250079Scarl 4); 782250079Scarl 783250079Scarl ntb->reg_ofs.pdb = SOC_PDOORBELL_OFFSET; 784250079Scarl ntb->reg_ofs.pdb_mask = SOC_PDBMSK_OFFSET; 785250079Scarl ntb->reg_ofs.sbar2_xlat = SOC_SBAR2XLAT_OFFSET; 786250079Scarl ntb->reg_ofs.sbar4_xlat = SOC_SBAR4XLAT_OFFSET; 787250079Scarl ntb->reg_ofs.lnk_cntl = SOC_NTBCNTL_OFFSET; 788250079Scarl ntb->reg_ofs.lnk_stat = SOC_LINK_STATUS_OFFSET; 789250079Scarl ntb->reg_ofs.spad_local = SOC_SPAD_OFFSET; 790250079Scarl ntb->reg_ofs.spci_cmd = SOC_PCICMD_OFFSET; 791250079Scarl 792250079Scarl if (ntb->conn_type == NTB_CONN_B2B) { 793250079Scarl ntb->reg_ofs.sdb = SOC_B2B_DOORBELL_OFFSET; 794250079Scarl ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET; 795250079Scarl ntb->limits.max_spads = SOC_MAX_SPADS; 796250079Scarl } else { 797250079Scarl ntb->reg_ofs.sdb = SOC_PDOORBELL_OFFSET; 798250079Scarl ntb->reg_ofs.spad_remote = SOC_SPAD_OFFSET; 799250079Scarl ntb->limits.max_spads = SOC_MAX_COMPAT_SPADS; 800250079Scarl } 801250079Scarl 802250079Scarl ntb->limits.max_db_bits = SOC_MAX_DB_BITS; 803250079Scarl ntb->limits.msix_cnt = SOC_MSIX_CNT; 804250079Scarl ntb->bits_per_vector = SOC_DB_BITS_PER_VEC; 805250079Scarl 806250079Scarl /* 807250079Scarl * FIXME - MSI-X bug on early SOC HW, remove once internal issue is 808250079Scarl * resolved. Mask transaction layer internal parity errors. 809250079Scarl */ 810250079Scarl pci_write_config(ntb->device, 0xFC, 0x4, 4); 811250079Scarl 812255279Scarl configure_soc_secondary_side_bars(ntb); 813250079Scarl 814250079Scarl /* Enable Bus Master and Memory Space on the secondary side */ 815255278Scarl ntb_reg_write(2, ntb->reg_ofs.spci_cmd, 816250079Scarl PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 817289209Scem 818250079Scarl callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb); 819250079Scarl 820250079Scarl return (0); 821250079Scarl} 822250079Scarl 823255279Scarlstatic void 824255279Scarlconfigure_soc_secondary_side_bars(struct ntb_softc *ntb) 825255279Scarl{ 826255279Scarl 827255279Scarl if (ntb->dev_type == NTB_DEV_USD) { 828255279Scarl ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR); 829255279Scarl ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, PBAR4XLAT_USD_ADDR); 830255279Scarl ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_USD_ADDR); 831255279Scarl ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR45_USD_ADDR); 832255279Scarl } else { 833255279Scarl ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR); 834255279Scarl ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, PBAR4XLAT_DSD_ADDR); 835255279Scarl ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_DSD_ADDR); 836255279Scarl ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR45_DSD_ADDR); 837255279Scarl } 838255279Scarl} 839255279Scarl 840255279Scarlstatic void 841255279Scarlconfigure_xeon_secondary_side_bars(struct ntb_softc *ntb) 842255279Scarl{ 843255279Scarl 844255279Scarl if (ntb->dev_type == NTB_DEV_USD) { 845255279Scarl ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR); 846255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 847255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 848255279Scarl MBAR01_DSD_ADDR); 849289208Scem else { 850255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 851255279Scarl PBAR4XLAT_USD_ADDR); 852289208Scem /* 853289208Scem * B2B_XLAT_OFFSET is a 64-bit register but can only be 854289208Scem * written 32 bits at a time. 855289208Scem */ 856289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, 857289208Scem MBAR01_DSD_ADDR & 0xffffffff); 858289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, 859289208Scem MBAR01_DSD_ADDR >> 32); 860289208Scem } 861255279Scarl ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_USD_ADDR); 862255279Scarl ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_USD_ADDR); 863255279Scarl ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_USD_ADDR); 864255279Scarl } else { 865255279Scarl ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR); 866255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 867255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 868255279Scarl MBAR01_USD_ADDR); 869289208Scem else { 870255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 871255279Scarl PBAR4XLAT_DSD_ADDR); 872289208Scem /* 873289208Scem * B2B_XLAT_OFFSET is a 64-bit register but can only be 874289208Scem * written 32 bits at a time. 875289208Scem */ 876289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, 877289208Scem MBAR01_USD_ADDR & 0xffffffff); 878289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, 879289208Scem MBAR01_USD_ADDR >> 32); 880289208Scem } 881255279Scarl ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_DSD_ADDR); 882255279Scarl ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_DSD_ADDR); 883255279Scarl ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_DSD_ADDR); 884255279Scarl } 885255279Scarl} 886255279Scarl 887255281Scarl/* SOC does not have link status interrupt, poll on that platform */ 888250079Scarlstatic void 889250079Scarlntb_handle_heartbeat(void *arg) 890250079Scarl{ 891250079Scarl struct ntb_softc *ntb = arg; 892250079Scarl uint32_t status32; 893289209Scem int rc; 894250079Scarl 895289209Scem rc = ntb_check_link_status(ntb); 896250079Scarl if (rc != 0) 897250079Scarl device_printf(ntb->device, 898250079Scarl "Error determining link status\n"); 899289232Scem 900250079Scarl /* Check to see if a link error is the cause of the link down */ 901250079Scarl if (ntb->link_status == NTB_LINK_DOWN) { 902255278Scarl status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 903250079Scarl if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) { 904250079Scarl callout_reset(&ntb->lr_timer, 0, recover_soc_link, 905250079Scarl ntb); 906250079Scarl return; 907250079Scarl } 908250079Scarl } 909250079Scarl 910250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 911250079Scarl ntb_handle_heartbeat, ntb); 912250079Scarl} 913250079Scarl 914250079Scarlstatic void 915250079Scarlsoc_perform_link_restart(struct ntb_softc *ntb) 916250079Scarl{ 917250079Scarl uint32_t status; 918250079Scarl 919250079Scarl /* Driver resets the NTB ModPhy lanes - magic! */ 920255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0xe0); 921255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x40); 922255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x60); 923255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0x60); 924250079Scarl 925250079Scarl /* Driver waits 100ms to allow the NTB ModPhy to settle */ 926250079Scarl pause("ModPhy", hz / 10); 927250079Scarl 928250079Scarl /* Clear AER Errors, write to clear */ 929255278Scarl status = ntb_reg_read(4, SOC_ERRCORSTS_OFFSET); 930250079Scarl status &= PCIM_AER_COR_REPLAY_ROLLOVER; 931255278Scarl ntb_reg_write(4, SOC_ERRCORSTS_OFFSET, status); 932250079Scarl 933250079Scarl /* Clear unexpected electrical idle event in LTSSM, write to clear */ 934255278Scarl status = ntb_reg_read(4, SOC_LTSSMERRSTS0_OFFSET); 935250079Scarl status |= SOC_LTSSMERRSTS0_UNEXPECTEDEI; 936255278Scarl ntb_reg_write(4, SOC_LTSSMERRSTS0_OFFSET, status); 937250079Scarl 938250079Scarl /* Clear DeSkew Buffer error, write to clear */ 939255278Scarl status = ntb_reg_read(4, SOC_DESKEWSTS_OFFSET); 940250079Scarl status |= SOC_DESKEWSTS_DBERR; 941255278Scarl ntb_reg_write(4, SOC_DESKEWSTS_OFFSET, status); 942250079Scarl 943255278Scarl status = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET); 944250079Scarl status &= SOC_IBIST_ERR_OFLOW; 945255278Scarl ntb_reg_write(4, SOC_IBSTERRRCRVSTS0_OFFSET, status); 946250079Scarl 947250079Scarl /* Releases the NTB state machine to allow the link to retrain */ 948255278Scarl status = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 949250079Scarl status &= ~SOC_LTSSMSTATEJMP_FORCEDETECT; 950255278Scarl ntb_reg_write(4, SOC_LTSSMSTATEJMP_OFFSET, status); 951250079Scarl} 952250079Scarl 953250079Scarlstatic void 954250079Scarlntb_handle_link_event(struct ntb_softc *ntb, int link_state) 955250079Scarl{ 956250079Scarl enum ntb_hw_event event; 957250079Scarl uint16_t status; 958250079Scarl 959250079Scarl if (ntb->link_status == link_state) 960250079Scarl return; 961250079Scarl 962250079Scarl if (link_state == NTB_LINK_UP) { 963250079Scarl device_printf(ntb->device, "Link Up\n"); 964250079Scarl ntb->link_status = NTB_LINK_UP; 965250079Scarl event = NTB_EVENT_HW_LINK_UP; 966250079Scarl 967250079Scarl if (ntb->type == NTB_SOC) 968255278Scarl status = ntb_reg_read(2, ntb->reg_ofs.lnk_stat); 969250079Scarl else 970250079Scarl status = pci_read_config(ntb->device, 971250079Scarl XEON_LINK_STATUS_OFFSET, 2); 972250079Scarl ntb->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; 973250079Scarl ntb->link_speed = (status & NTB_LINK_SPEED_MASK); 974250079Scarl device_printf(ntb->device, "Link Width %d, Link Speed %d\n", 975250079Scarl ntb->link_width, ntb->link_speed); 976250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 977250079Scarl ntb_handle_heartbeat, ntb); 978250079Scarl } else { 979250079Scarl device_printf(ntb->device, "Link Down\n"); 980250079Scarl ntb->link_status = NTB_LINK_DOWN; 981250079Scarl event = NTB_EVENT_HW_LINK_DOWN; 982255281Scarl /* Do not modify link width/speed, we need it in link recovery */ 983250079Scarl } 984250079Scarl 985250079Scarl /* notify the upper layer if we have an event change */ 986250079Scarl if (ntb->event_cb != NULL) 987250079Scarl ntb->event_cb(ntb->ntb_transport, event); 988250079Scarl} 989250079Scarl 990250079Scarlstatic void 991250079Scarlrecover_soc_link(void *arg) 992250079Scarl{ 993250079Scarl struct ntb_softc *ntb = arg; 994250079Scarl uint8_t speed, width; 995250079Scarl uint32_t status32; 996250079Scarl uint16_t status16; 997250079Scarl 998250079Scarl soc_perform_link_restart(ntb); 999250079Scarl 1000289232Scem /* 1001289232Scem * There is a potential race between the 2 NTB devices recovering at 1002289232Scem * the same time. If the times are the same, the link will not recover 1003289232Scem * and the driver will be stuck in this loop forever. Add a random 1004289232Scem * interval to the recovery time to prevent this race. 1005289232Scem */ 1006289232Scem status32 = arc4random() % SOC_LINK_RECOVERY_TIME; 1007289232Scem pause("Link", (SOC_LINK_RECOVERY_TIME + status32) * hz / 1000); 1008289232Scem 1009255278Scarl status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 1010250079Scarl if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) 1011250079Scarl goto retry; 1012250079Scarl 1013255278Scarl status32 = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET); 1014250079Scarl if ((status32 & SOC_IBIST_ERR_OFLOW) != 0) 1015250079Scarl goto retry; 1016250079Scarl 1017289232Scem status32 = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); 1018289232Scem if ((status32 & SOC_CNTL_LINK_DOWN) != 0) 1019289232Scem goto out; 1020289232Scem 1021255278Scarl status16 = ntb_reg_read(2, ntb->reg_ofs.lnk_stat); 1022250079Scarl width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; 1023250079Scarl speed = (status16 & NTB_LINK_SPEED_MASK); 1024250079Scarl if (ntb->link_width != width || ntb->link_speed != speed) 1025250079Scarl goto retry; 1026250079Scarl 1027289232Scemout: 1028250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 1029250079Scarl ntb_handle_heartbeat, ntb); 1030250079Scarl return; 1031250079Scarl 1032250079Scarlretry: 1033250079Scarl callout_reset(&ntb->lr_timer, NTB_HB_TIMEOUT * hz, recover_soc_link, 1034250079Scarl ntb); 1035250079Scarl} 1036250079Scarl 1037250079Scarlstatic int 1038250079Scarlntb_check_link_status(struct ntb_softc *ntb) 1039250079Scarl{ 1040250079Scarl int link_state; 1041250079Scarl uint32_t ntb_cntl; 1042250079Scarl uint16_t status; 1043250079Scarl 1044250079Scarl if (ntb->type == NTB_SOC) { 1045255278Scarl ntb_cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); 1046250079Scarl if ((ntb_cntl & SOC_CNTL_LINK_DOWN) != 0) 1047250079Scarl link_state = NTB_LINK_DOWN; 1048250079Scarl else 1049250079Scarl link_state = NTB_LINK_UP; 1050250079Scarl } else { 1051250079Scarl status = pci_read_config(ntb->device, XEON_LINK_STATUS_OFFSET, 1052250079Scarl 2); 1053250079Scarl 1054250079Scarl if ((status & NTB_LINK_STATUS_ACTIVE) != 0) 1055250079Scarl link_state = NTB_LINK_UP; 1056250079Scarl else 1057250079Scarl link_state = NTB_LINK_DOWN; 1058250079Scarl } 1059250079Scarl 1060250079Scarl ntb_handle_link_event(ntb, link_state); 1061250079Scarl 1062250079Scarl return (0); 1063250079Scarl} 1064250079Scarl 1065250079Scarl/** 1066250079Scarl * ntb_register_event_callback() - register event callback 1067250079Scarl * @ntb: pointer to ntb_softc instance 1068250079Scarl * @func: callback function to register 1069250079Scarl * 1070250079Scarl * This function registers a callback for any HW driver events such as link 1071250079Scarl * up/down, power management notices and etc. 1072250079Scarl * 1073289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1074250079Scarl */ 1075250079Scarlint 1076250079Scarlntb_register_event_callback(struct ntb_softc *ntb, ntb_event_callback func) 1077250079Scarl{ 1078250079Scarl 1079250079Scarl if (ntb->event_cb != NULL) 1080250079Scarl return (EINVAL); 1081250079Scarl 1082250079Scarl ntb->event_cb = func; 1083250079Scarl 1084250079Scarl return (0); 1085250079Scarl} 1086250079Scarl 1087250079Scarl/** 1088250079Scarl * ntb_unregister_event_callback() - unregisters the event callback 1089250079Scarl * @ntb: pointer to ntb_softc instance 1090250079Scarl * 1091250079Scarl * This function unregisters the existing callback from transport 1092250079Scarl */ 1093250079Scarlvoid 1094250079Scarlntb_unregister_event_callback(struct ntb_softc *ntb) 1095250079Scarl{ 1096250079Scarl 1097250079Scarl ntb->event_cb = NULL; 1098250079Scarl} 1099250079Scarl 1100250079Scarl/** 1101250079Scarl * ntb_register_db_callback() - register a callback for doorbell interrupt 1102250079Scarl * @ntb: pointer to ntb_softc instance 1103250079Scarl * @idx: doorbell index to register callback, zero based 1104250079Scarl * @func: callback function to register 1105250079Scarl * 1106250079Scarl * This function registers a callback function for the doorbell interrupt 1107250079Scarl * on the primary side. The function will unmask the doorbell as well to 1108250079Scarl * allow interrupt. 1109250079Scarl * 1110289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1111250079Scarl */ 1112250079Scarlint 1113250079Scarlntb_register_db_callback(struct ntb_softc *ntb, unsigned int idx, void *data, 1114250079Scarl ntb_db_callback func) 1115250079Scarl{ 1116250079Scarl uint16_t mask; 1117250079Scarl 1118250079Scarl if (idx >= ntb->allocated_interrupts || ntb->db_cb[idx].callback) { 1119250079Scarl device_printf(ntb->device, "Invalid Index.\n"); 1120250079Scarl return (EINVAL); 1121250079Scarl } 1122250079Scarl 1123250079Scarl ntb->db_cb[idx].callback = func; 1124250079Scarl ntb->db_cb[idx].data = data; 1125250079Scarl 1126250079Scarl /* unmask interrupt */ 1127255278Scarl mask = ntb_reg_read(2, ntb->reg_ofs.pdb_mask); 1128250079Scarl mask &= ~(1 << (idx * ntb->bits_per_vector)); 1129255278Scarl ntb_reg_write(2, ntb->reg_ofs.pdb_mask, mask); 1130250079Scarl 1131250079Scarl return (0); 1132250079Scarl} 1133250079Scarl 1134250079Scarl/** 1135250079Scarl * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt 1136250079Scarl * @ntb: pointer to ntb_softc instance 1137250079Scarl * @idx: doorbell index to register callback, zero based 1138250079Scarl * 1139250079Scarl * This function unregisters a callback function for the doorbell interrupt 1140250079Scarl * on the primary side. The function will also mask the said doorbell. 1141250079Scarl */ 1142250079Scarlvoid 1143250079Scarlntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx) 1144250079Scarl{ 1145250079Scarl unsigned long mask; 1146250079Scarl 1147250079Scarl if (idx >= ntb->allocated_interrupts || !ntb->db_cb[idx].callback) 1148250079Scarl return; 1149250079Scarl 1150255278Scarl mask = ntb_reg_read(2, ntb->reg_ofs.pdb_mask); 1151250079Scarl mask |= 1 << (idx * ntb->bits_per_vector); 1152255278Scarl ntb_reg_write(2, ntb->reg_ofs.pdb_mask, mask); 1153250079Scarl 1154250079Scarl ntb->db_cb[idx].callback = NULL; 1155250079Scarl} 1156250079Scarl 1157250079Scarl/** 1158250079Scarl * ntb_find_transport() - find the transport pointer 1159250079Scarl * @transport: pointer to pci device 1160250079Scarl * 1161250079Scarl * Given the pci device pointer, return the transport pointer passed in when 1162250079Scarl * the transport attached when it was inited. 1163250079Scarl * 1164250079Scarl * RETURNS: pointer to transport. 1165250079Scarl */ 1166250079Scarlvoid * 1167250079Scarlntb_find_transport(struct ntb_softc *ntb) 1168250079Scarl{ 1169250079Scarl 1170250079Scarl return (ntb->ntb_transport); 1171250079Scarl} 1172250079Scarl 1173250079Scarl/** 1174250079Scarl * ntb_register_transport() - Register NTB transport with NTB HW driver 1175250079Scarl * @transport: transport identifier 1176250079Scarl * 1177250079Scarl * This function allows a transport to reserve the hardware driver for 1178250079Scarl * NTB usage. 1179250079Scarl * 1180250079Scarl * RETURNS: pointer to ntb_softc, NULL on error. 1181250079Scarl */ 1182250079Scarlstruct ntb_softc * 1183250079Scarlntb_register_transport(struct ntb_softc *ntb, void *transport) 1184250079Scarl{ 1185250079Scarl 1186250079Scarl /* 1187250079Scarl * TODO: when we have more than one transport, we will need to rewrite 1188250079Scarl * this to prevent race conditions 1189250079Scarl */ 1190250079Scarl if (ntb->ntb_transport != NULL) 1191250079Scarl return (NULL); 1192250079Scarl 1193250079Scarl ntb->ntb_transport = transport; 1194250079Scarl return (ntb); 1195250079Scarl} 1196250079Scarl 1197250079Scarl/** 1198250079Scarl * ntb_unregister_transport() - Unregister the transport with the NTB HW driver 1199250079Scarl * @ntb - ntb_softc of the transport to be freed 1200250079Scarl * 1201250079Scarl * This function unregisters the transport from the HW driver and performs any 1202250079Scarl * necessary cleanups. 1203250079Scarl */ 1204250079Scarlvoid 1205250079Scarlntb_unregister_transport(struct ntb_softc *ntb) 1206250079Scarl{ 1207250079Scarl int i; 1208250079Scarl 1209250079Scarl if (ntb->ntb_transport == NULL) 1210250079Scarl return; 1211250079Scarl 1212250079Scarl for (i = 0; i < ntb->allocated_interrupts; i++) 1213250079Scarl ntb_unregister_db_callback(ntb, i); 1214250079Scarl 1215250079Scarl ntb_unregister_event_callback(ntb); 1216250079Scarl ntb->ntb_transport = NULL; 1217250079Scarl} 1218250079Scarl 1219250079Scarl/** 1220250079Scarl * ntb_get_max_spads() - get the total scratch regs usable 1221250079Scarl * @ntb: pointer to ntb_softc instance 1222250079Scarl * 1223250079Scarl * This function returns the max 32bit scratchpad registers usable by the 1224250079Scarl * upper layer. 1225250079Scarl * 1226250079Scarl * RETURNS: total number of scratch pad registers available 1227250079Scarl */ 1228289208Scemuint8_t 1229250079Scarlntb_get_max_spads(struct ntb_softc *ntb) 1230250079Scarl{ 1231250079Scarl 1232250079Scarl return (ntb->limits.max_spads); 1233250079Scarl} 1234250079Scarl 1235250079Scarl/** 1236250079Scarl * ntb_write_local_spad() - write to the secondary scratchpad register 1237250079Scarl * @ntb: pointer to ntb_softc instance 1238250079Scarl * @idx: index to the scratchpad register, 0 based 1239250079Scarl * @val: the data value to put into the register 1240250079Scarl * 1241250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad 1242250079Scarl * register. The register resides on the secondary (external) side. 1243250079Scarl * 1244289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1245250079Scarl */ 1246250079Scarlint 1247250079Scarlntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) 1248250079Scarl{ 1249250079Scarl 1250250079Scarl if (idx >= ntb->limits.max_spads) 1251250079Scarl return (EINVAL); 1252250079Scarl 1253255278Scarl ntb_reg_write(4, ntb->reg_ofs.spad_local + idx * 4, val); 1254250079Scarl 1255250079Scarl return (0); 1256250079Scarl} 1257250079Scarl 1258250079Scarl/** 1259250079Scarl * ntb_read_local_spad() - read from the primary scratchpad register 1260250079Scarl * @ntb: pointer to ntb_softc instance 1261250079Scarl * @idx: index to scratchpad register, 0 based 1262250079Scarl * @val: pointer to 32bit integer for storing the register value 1263250079Scarl * 1264250079Scarl * This function allows reading of the 32bit scratchpad register on 1265250079Scarl * the primary (internal) side. 1266250079Scarl * 1267289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1268250079Scarl */ 1269250079Scarlint 1270250079Scarlntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) 1271250079Scarl{ 1272250079Scarl 1273250079Scarl if (idx >= ntb->limits.max_spads) 1274250079Scarl return (EINVAL); 1275250079Scarl 1276255278Scarl *val = ntb_reg_read(4, ntb->reg_ofs.spad_local + idx * 4); 1277250079Scarl 1278250079Scarl return (0); 1279250079Scarl} 1280250079Scarl 1281250079Scarl/** 1282250079Scarl * ntb_write_remote_spad() - write to the secondary scratchpad register 1283250079Scarl * @ntb: pointer to ntb_softc instance 1284250079Scarl * @idx: index to the scratchpad register, 0 based 1285250079Scarl * @val: the data value to put into the register 1286250079Scarl * 1287250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad 1288250079Scarl * register. The register resides on the secondary (external) side. 1289250079Scarl * 1290289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1291250079Scarl */ 1292250079Scarlint 1293250079Scarlntb_write_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) 1294250079Scarl{ 1295250079Scarl 1296250079Scarl if (idx >= ntb->limits.max_spads) 1297250079Scarl return (EINVAL); 1298250079Scarl 1299255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 1300255279Scarl ntb_mw_write(4, XEON_SHADOW_SPAD_OFFSET + idx * 4, val); 1301255279Scarl else 1302255279Scarl ntb_reg_write(4, ntb->reg_ofs.spad_remote + idx * 4, val); 1303250079Scarl 1304250079Scarl return (0); 1305250079Scarl} 1306250079Scarl 1307250079Scarl/** 1308250079Scarl * ntb_read_remote_spad() - read from the primary scratchpad register 1309250079Scarl * @ntb: pointer to ntb_softc instance 1310250079Scarl * @idx: index to scratchpad register, 0 based 1311250079Scarl * @val: pointer to 32bit integer for storing the register value 1312250079Scarl * 1313250079Scarl * This function allows reading of the 32bit scratchpad register on 1314250079Scarl * the primary (internal) side. 1315250079Scarl * 1316289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1317250079Scarl */ 1318250079Scarlint 1319250079Scarlntb_read_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) 1320250079Scarl{ 1321250079Scarl 1322250079Scarl if (idx >= ntb->limits.max_spads) 1323250079Scarl return (EINVAL); 1324250079Scarl 1325255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 1326255279Scarl *val = ntb_mw_read(4, XEON_SHADOW_SPAD_OFFSET + idx * 4); 1327255279Scarl else 1328255279Scarl *val = ntb_reg_read(4, ntb->reg_ofs.spad_remote + idx * 4); 1329250079Scarl 1330250079Scarl return (0); 1331250079Scarl} 1332250079Scarl 1333250079Scarl/** 1334250079Scarl * ntb_get_mw_vbase() - get virtual addr for the NTB memory window 1335250079Scarl * @ntb: pointer to ntb_softc instance 1336250079Scarl * @mw: memory window number 1337250079Scarl * 1338250079Scarl * This function provides the base virtual address of the memory window 1339250079Scarl * specified. 1340250079Scarl * 1341250079Scarl * RETURNS: pointer to virtual address, or NULL on error. 1342250079Scarl */ 1343250079Scarlvoid * 1344250079Scarlntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw) 1345250079Scarl{ 1346250079Scarl 1347250079Scarl if (mw >= NTB_NUM_MW) 1348250079Scarl return (NULL); 1349250079Scarl 1350250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].vbase); 1351250079Scarl} 1352250079Scarl 1353250079Scarlvm_paddr_t 1354250079Scarlntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw) 1355250079Scarl{ 1356250079Scarl 1357250079Scarl if (mw >= NTB_NUM_MW) 1358250079Scarl return (0); 1359250079Scarl 1360250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].pbase); 1361250079Scarl} 1362250079Scarl 1363250079Scarl/** 1364250079Scarl * ntb_get_mw_size() - return size of NTB memory window 1365250079Scarl * @ntb: pointer to ntb_softc instance 1366250079Scarl * @mw: memory window number 1367250079Scarl * 1368250079Scarl * This function provides the physical size of the memory window specified 1369250079Scarl * 1370250079Scarl * RETURNS: the size of the memory window or zero on error 1371250079Scarl */ 1372250079Scarlu_long 1373250079Scarlntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw) 1374250079Scarl{ 1375250079Scarl 1376250079Scarl if (mw >= NTB_NUM_MW) 1377250079Scarl return (0); 1378250079Scarl 1379250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].size); 1380250079Scarl} 1381250079Scarl 1382250079Scarl/** 1383250079Scarl * ntb_set_mw_addr - set the memory window address 1384250079Scarl * @ntb: pointer to ntb_softc instance 1385250079Scarl * @mw: memory window number 1386250079Scarl * @addr: base address for data 1387250079Scarl * 1388250079Scarl * This function sets the base physical address of the memory window. This 1389250079Scarl * memory address is where data from the remote system will be transfered into 1390250079Scarl * or out of depending on how the transport is configured. 1391250079Scarl */ 1392250079Scarlvoid 1393250079Scarlntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr) 1394250079Scarl{ 1395250079Scarl 1396250079Scarl if (mw >= NTB_NUM_MW) 1397250079Scarl return; 1398250079Scarl 1399250079Scarl switch (NTB_MW_TO_BAR(mw)) { 1400250079Scarl case NTB_B2B_BAR_1: 1401255278Scarl ntb_reg_write(8, ntb->reg_ofs.sbar2_xlat, addr); 1402250079Scarl break; 1403250079Scarl case NTB_B2B_BAR_2: 1404255278Scarl ntb_reg_write(8, ntb->reg_ofs.sbar4_xlat, addr); 1405250079Scarl break; 1406250079Scarl } 1407250079Scarl} 1408250079Scarl 1409250079Scarl/** 1410250079Scarl * ntb_ring_sdb() - Set the doorbell on the secondary/external side 1411250079Scarl * @ntb: pointer to ntb_softc instance 1412250079Scarl * @db: doorbell to ring 1413250079Scarl * 1414250079Scarl * This function allows triggering of a doorbell on the secondary/external 1415250079Scarl * side that will initiate an interrupt on the remote host 1416250079Scarl * 1417289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1418250079Scarl */ 1419250079Scarlvoid 1420250079Scarlntb_ring_sdb(struct ntb_softc *ntb, unsigned int db) 1421250079Scarl{ 1422250079Scarl 1423250079Scarl if (ntb->type == NTB_SOC) 1424255278Scarl ntb_reg_write(8, ntb->reg_ofs.sdb, (uint64_t) 1 << db); 1425289209Scem else { 1426255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 1427255279Scarl ntb_mw_write(2, XEON_SHADOW_PDOORBELL_OFFSET, 1428255279Scarl ((1 << ntb->bits_per_vector) - 1) << 1429255279Scarl (db * ntb->bits_per_vector)); 1430255279Scarl else 1431255279Scarl ntb_reg_write(2, ntb->reg_ofs.sdb, 1432255279Scarl ((1 << ntb->bits_per_vector) - 1) << 1433255279Scarl (db * ntb->bits_per_vector)); 1434289209Scem } 1435250079Scarl} 1436250079Scarl 1437250079Scarl/** 1438250079Scarl * ntb_query_link_status() - return the hardware link status 1439250079Scarl * @ndev: pointer to ntb_device instance 1440250079Scarl * 1441250079Scarl * Returns true if the hardware is connected to the remote system 1442250079Scarl * 1443250079Scarl * RETURNS: true or false based on the hardware link state 1444250079Scarl */ 1445250079Scarlbool 1446250079Scarlntb_query_link_status(struct ntb_softc *ntb) 1447250079Scarl{ 1448250079Scarl 1449250079Scarl return (ntb->link_status == NTB_LINK_UP); 1450250079Scarl} 1451250079Scarl 1452255272Scarlstatic void 1453255272Scarlsave_bar_parameters(struct ntb_pci_bar_info *bar) 1454250079Scarl{ 1455255272Scarl 1456289209Scem bar->pci_bus_tag = rman_get_bustag(bar->pci_resource); 1457289209Scem bar->pci_bus_handle = rman_get_bushandle(bar->pci_resource); 1458289209Scem bar->pbase = rman_get_start(bar->pci_resource); 1459289209Scem bar->size = rman_get_size(bar->pci_resource); 1460289209Scem bar->vbase = rman_get_virtual(bar->pci_resource); 1461250079Scarl} 1462255268Scarl 1463289209Scemdevice_t 1464289209Scemntb_get_device(struct ntb_softc *ntb) 1465255268Scarl{ 1466255268Scarl 1467255268Scarl return (ntb->device); 1468255268Scarl} 1469289208Scem 1470289208Scem/* Export HW-specific errata information. */ 1471289208Scembool 1472289208Scemntb_has_feature(struct ntb_softc *ntb, uint64_t feature) 1473289208Scem{ 1474289208Scem 1475289208Scem return (HAS_FEATURE(feature)); 1476289208Scem} 1477