ntb_hw_intel.c revision 289257
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 289257 2015-10-13 19:45:29Z 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 { 136289255Scem uint32_t ldb; 137289255Scem uint32_t ldb_mask; 138289255Scem uint32_t rdb; 139289255Scem uint32_t bar2_xlat; 140289255Scem uint32_t bar4_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 155289234Scem#ifdef __i386__ 156289234Scemstatic __inline uint64_t 157289234Scembus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle, 158289234Scem bus_size_t offset) 159289234Scem{ 160289234Scem 161289234Scem return (bus_space_read_4(tag, handle, offset) | 162289234Scem ((uint64_t)bus_space_read_4(tag, handle, offset + 4)) << 32); 163289234Scem} 164289234Scem 165289234Scemstatic __inline void 166289234Scembus_space_write_8(bus_space_tag_t tag, bus_space_handle_t handle, 167289234Scem bus_size_t offset, uint64_t val) 168289234Scem{ 169289234Scem 170289234Scem bus_space_write_4(tag, handle, offset, val); 171289234Scem bus_space_write_4(tag, handle, offset + 4, val >> 32); 172289234Scem} 173289234Scem#endif 174289234Scem 175255279Scarl#define ntb_bar_read(SIZE, bar, offset) \ 176255279Scarl bus_space_read_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \ 177255279Scarl ntb->bar_info[(bar)].pci_bus_handle, (offset)) 178255279Scarl#define ntb_bar_write(SIZE, bar, offset, val) \ 179255279Scarl bus_space_write_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \ 180255279Scarl ntb->bar_info[(bar)].pci_bus_handle, (offset), (val)) 181255279Scarl#define ntb_reg_read(SIZE, offset) ntb_bar_read(SIZE, NTB_CONFIG_BAR, offset) 182250079Scarl#define ntb_reg_write(SIZE, offset, val) \ 183255279Scarl ntb_bar_write(SIZE, NTB_CONFIG_BAR, offset, val) 184255279Scarl#define ntb_mw_read(SIZE, offset) ntb_bar_read(SIZE, NTB_B2B_BAR_2, offset) 185255279Scarl#define ntb_mw_write(SIZE, offset, val) \ 186255279Scarl ntb_bar_write(SIZE, NTB_B2B_BAR_2, offset, val) 187250079Scarl 188255272Scarltypedef int (*bar_map_strategy)(struct ntb_softc *ntb, 189255272Scarl struct ntb_pci_bar_info *bar); 190255272Scarl 191250079Scarlstatic int ntb_probe(device_t device); 192250079Scarlstatic int ntb_attach(device_t device); 193250079Scarlstatic int ntb_detach(device_t device); 194255272Scarlstatic int ntb_map_pci_bars(struct ntb_softc *ntb); 195255272Scarlstatic int map_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, 196255272Scarl struct ntb_pci_bar_info *bar); 197255272Scarlstatic int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar); 198255272Scarlstatic int map_memory_window_bar(struct ntb_softc *ntb, 199255272Scarl struct ntb_pci_bar_info *bar); 200250079Scarlstatic void ntb_unmap_pci_bar(struct ntb_softc *ntb); 201250079Scarlstatic int ntb_setup_interrupts(struct ntb_softc *ntb); 202250079Scarlstatic void ntb_teardown_interrupts(struct ntb_softc *ntb); 203250079Scarlstatic void handle_soc_irq(void *arg); 204250079Scarlstatic void handle_xeon_irq(void *arg); 205250079Scarlstatic void handle_xeon_event_irq(void *arg); 206250079Scarlstatic void ntb_handle_legacy_interrupt(void *arg); 207250079Scarlstatic int ntb_create_callbacks(struct ntb_softc *ntb, int num_vectors); 208250079Scarlstatic void ntb_free_callbacks(struct ntb_softc *ntb); 209250079Scarlstatic struct ntb_hw_info *ntb_get_device_info(uint32_t device_id); 210250079Scarlstatic int ntb_initialize_hw(struct ntb_softc *ntb); 211250079Scarlstatic int ntb_setup_xeon(struct ntb_softc *ntb); 212250079Scarlstatic int ntb_setup_soc(struct ntb_softc *ntb); 213255279Scarlstatic void configure_soc_secondary_side_bars(struct ntb_softc *ntb); 214255279Scarlstatic void configure_xeon_secondary_side_bars(struct ntb_softc *ntb); 215250079Scarlstatic void ntb_handle_heartbeat(void *arg); 216250079Scarlstatic void ntb_handle_link_event(struct ntb_softc *ntb, int link_state); 217250079Scarlstatic void recover_soc_link(void *arg); 218250079Scarlstatic int ntb_check_link_status(struct ntb_softc *ntb); 219255274Scarlstatic void save_bar_parameters(struct ntb_pci_bar_info *bar); 220250079Scarl 221250079Scarlstatic struct ntb_hw_info pci_ids[] = { 222255274Scarl { 0x0C4E8086, "Atom Processor S1200 NTB Primary B2B", NTB_SOC, 0 }, 223289233Scem 224289233Scem /* XXX: PS/SS IDs left out until they are supported. */ 225289233Scem { 0x37258086, "JSF Xeon C35xx/C55xx Non-Transparent Bridge B2B", 226289233Scem NTB_XEON, NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 }, 227289233Scem { 0x3C0D8086, "SNB Xeon E5/Core i7 Non-Transparent Bridge B2B", 228289233Scem NTB_XEON, NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 }, 229289233Scem { 0x0E0D8086, "IVT Xeon E5 V2 Non-Transparent Bridge B2B", NTB_XEON, 230289233Scem NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 | NTB_SB01BASE_LOCKUP 231289233Scem | NTB_BAR_SIZE_4K }, 232289233Scem { 0x2F0D8086, "HSX Xeon E5 V3 Non-Transparent Bridge B2B", NTB_XEON, 233289233Scem NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 | NTB_SB01BASE_LOCKUP 234289233Scem }, 235289233Scem { 0x6F0D8086, "BDX Xeon E5 V4 Non-Transparent Bridge B2B", NTB_XEON, 236289233Scem NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 | NTB_SB01BASE_LOCKUP 237289233Scem }, 238289233Scem 239255274Scarl { 0x00000000, NULL, NTB_SOC, 0 } 240250079Scarl}; 241250079Scarl 242250079Scarl/* 243250079Scarl * OS <-> Driver interface structures 244250079Scarl */ 245250079ScarlMALLOC_DEFINE(M_NTB, "ntb_hw", "ntb_hw driver memory allocations"); 246250079Scarl 247250079Scarlstatic device_method_t ntb_pci_methods[] = { 248250079Scarl /* Device interface */ 249250079Scarl DEVMETHOD(device_probe, ntb_probe), 250250079Scarl DEVMETHOD(device_attach, ntb_attach), 251250079Scarl DEVMETHOD(device_detach, ntb_detach), 252250079Scarl DEVMETHOD_END 253250079Scarl}; 254250079Scarl 255250079Scarlstatic driver_t ntb_pci_driver = { 256250079Scarl "ntb_hw", 257250079Scarl ntb_pci_methods, 258250079Scarl sizeof(struct ntb_softc), 259250079Scarl}; 260250079Scarl 261250079Scarlstatic devclass_t ntb_devclass; 262250079ScarlDRIVER_MODULE(ntb_hw, pci, ntb_pci_driver, ntb_devclass, NULL, NULL); 263250079ScarlMODULE_VERSION(ntb_hw, 1); 264250079Scarl 265289207ScemSYSCTL_NODE(_hw, OID_AUTO, ntb, CTLFLAG_RW, 0, "NTB sysctls"); 266289207Scem 267250079Scarl/* 268250079Scarl * OS <-> Driver linkage functions 269250079Scarl */ 270250079Scarlstatic int 271250079Scarlntb_probe(device_t device) 272250079Scarl{ 273289209Scem struct ntb_hw_info *p; 274250079Scarl 275289209Scem p = ntb_get_device_info(pci_get_devid(device)); 276289209Scem if (p == NULL) 277250079Scarl return (ENXIO); 278289209Scem 279289209Scem device_set_desc(device, p->desc); 280289209Scem return (0); 281250079Scarl} 282250079Scarl 283250079Scarlstatic int 284250079Scarlntb_attach(device_t device) 285250079Scarl{ 286289209Scem struct ntb_softc *ntb; 287289209Scem struct ntb_hw_info *p; 288250079Scarl int error; 289250079Scarl 290289209Scem ntb = DEVICE2SOFTC(device); 291289209Scem p = ntb_get_device_info(pci_get_devid(device)); 292289209Scem 293250079Scarl ntb->device = device; 294250079Scarl ntb->type = p->type; 295255274Scarl ntb->features = p->features; 296250079Scarl 297250079Scarl /* Heartbeat timer for NTB_SOC since there is no link interrupt */ 298283291Sjkim callout_init(&ntb->heartbeat_timer, 1); 299283291Sjkim callout_init(&ntb->lr_timer, 1); 300250079Scarl 301289209Scem error = ntb_map_pci_bars(ntb); 302289209Scem if (error) 303289209Scem goto out; 304289209Scem error = ntb_initialize_hw(ntb); 305289209Scem if (error) 306289209Scem goto out; 307289209Scem error = ntb_setup_interrupts(ntb); 308289209Scem if (error) 309289209Scem goto out; 310250079Scarl 311250079Scarl pci_enable_busmaster(ntb->device); 312250079Scarl 313289209Scemout: 314289209Scem if (error != 0) 315289209Scem ntb_detach(device); 316250079Scarl return (error); 317250079Scarl} 318250079Scarl 319250079Scarlstatic int 320250079Scarlntb_detach(device_t device) 321250079Scarl{ 322289209Scem struct ntb_softc *ntb; 323250079Scarl 324289209Scem ntb = DEVICE2SOFTC(device); 325250079Scarl callout_drain(&ntb->heartbeat_timer); 326250079Scarl callout_drain(&ntb->lr_timer); 327250079Scarl ntb_teardown_interrupts(ntb); 328250079Scarl ntb_unmap_pci_bar(ntb); 329250079Scarl 330250079Scarl return (0); 331250079Scarl} 332250079Scarl 333250079Scarlstatic int 334255272Scarlntb_map_pci_bars(struct ntb_softc *ntb) 335250079Scarl{ 336255272Scarl int rc; 337250079Scarl 338250079Scarl ntb->bar_info[NTB_CONFIG_BAR].pci_resource_id = PCIR_BAR(0); 339255272Scarl rc = map_pci_bar(ntb, map_mmr_bar, &ntb->bar_info[NTB_CONFIG_BAR]); 340255272Scarl if (rc != 0) 341289209Scem return (rc); 342255272Scarl 343289209Scem ntb->bar_info[NTB_B2B_BAR_1].pci_resource_id = PCIR_BAR(2); 344255272Scarl rc = map_pci_bar(ntb, map_memory_window_bar, 345255272Scarl &ntb->bar_info[NTB_B2B_BAR_1]); 346255272Scarl if (rc != 0) 347289209Scem return (rc); 348255272Scarl 349289209Scem ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4); 350255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 351255279Scarl rc = map_pci_bar(ntb, map_mmr_bar, 352255279Scarl &ntb->bar_info[NTB_B2B_BAR_2]); 353255279Scarl else 354255279Scarl rc = map_pci_bar(ntb, map_memory_window_bar, 355255279Scarl &ntb->bar_info[NTB_B2B_BAR_2]); 356289209Scem return (rc); 357255272Scarl} 358250079Scarl 359255272Scarlstatic int 360255272Scarlmap_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, 361255272Scarl struct ntb_pci_bar_info *bar) 362255272Scarl{ 363255272Scarl int rc; 364255272Scarl 365255272Scarl rc = strategy(ntb, bar); 366289209Scem if (rc != 0) 367255272Scarl device_printf(ntb->device, 368255272Scarl "unable to allocate pci resource\n"); 369289209Scem else 370255279Scarl device_printf(ntb->device, 371255272Scarl "Bar size = %lx, v %p, p %p\n", 372289209Scem bar->size, bar->vbase, (void *)(bar->pbase)); 373255272Scarl return (rc); 374255272Scarl} 375255272Scarl 376255272Scarlstatic int 377255272Scarlmap_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) 378255272Scarl{ 379255272Scarl 380255275Scarl bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, 381289209Scem &bar->pci_resource_id, RF_ACTIVE); 382255272Scarl if (bar->pci_resource == NULL) 383255272Scarl return (ENXIO); 384289209Scem 385289209Scem save_bar_parameters(bar); 386289209Scem return (0); 387255272Scarl} 388255272Scarl 389255272Scarlstatic int 390255272Scarlmap_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) 391255272Scarl{ 392255272Scarl int rc; 393255276Scarl uint8_t bar_size_bits = 0; 394255272Scarl 395289209Scem bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, 396289209Scem &bar->pci_resource_id, RF_ACTIVE); 397250079Scarl 398255272Scarl if (bar->pci_resource == NULL) 399255272Scarl return (ENXIO); 400255276Scarl 401289209Scem save_bar_parameters(bar); 402289209Scem /* 403289209Scem * Ivytown NTB BAR sizes are misreported by the hardware due to a 404289209Scem * hardware issue. To work around this, query the size it should be 405289209Scem * configured to by the device and modify the resource to correspond to 406289209Scem * this new size. The BIOS on systems with this problem is required to 407289209Scem * provide enough address space to allow the driver to make this change 408289209Scem * safely. 409289209Scem * 410289209Scem * Ideally I could have just specified the size when I allocated the 411289209Scem * resource like: 412289209Scem * bus_alloc_resource(ntb->device, 413289209Scem * SYS_RES_MEMORY, &bar->pci_resource_id, 0ul, ~0ul, 414289209Scem * 1ul << bar_size_bits, RF_ACTIVE); 415289209Scem * but the PCI driver does not honor the size in this call, so we have 416289209Scem * to modify it after the fact. 417289209Scem */ 418289209Scem if (HAS_FEATURE(NTB_BAR_SIZE_4K)) { 419289209Scem if (bar->pci_resource_id == PCIR_BAR(2)) 420289209Scem bar_size_bits = pci_read_config(ntb->device, 421289209Scem XEON_PBAR23SZ_OFFSET, 1); 422289209Scem else 423289209Scem bar_size_bits = pci_read_config(ntb->device, 424289209Scem XEON_PBAR45SZ_OFFSET, 1); 425289209Scem 426289209Scem rc = bus_adjust_resource(ntb->device, SYS_RES_MEMORY, 427289209Scem bar->pci_resource, bar->pbase, 428289209Scem bar->pbase + (1ul << bar_size_bits) - 1); 429255272Scarl if (rc != 0) { 430289209Scem device_printf(ntb->device, 431289209Scem "unable to resize bar\n"); 432255272Scarl return (rc); 433250079Scarl } 434289209Scem 435289209Scem save_bar_parameters(bar); 436250079Scarl } 437289209Scem 438289209Scem /* Mark bar region as write combining to improve performance. */ 439289209Scem rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size, 440289209Scem VM_MEMATTR_WRITE_COMBINING); 441289209Scem if (rc != 0) { 442289209Scem device_printf(ntb->device, 443289209Scem "unable to mark bar as WRITE_COMBINING\n"); 444289209Scem return (rc); 445289209Scem } 446250079Scarl return (0); 447250079Scarl} 448250079Scarl 449250079Scarlstatic void 450250079Scarlntb_unmap_pci_bar(struct ntb_softc *ntb) 451250079Scarl{ 452250079Scarl struct ntb_pci_bar_info *current_bar; 453250079Scarl int i; 454250079Scarl 455250079Scarl for (i = 0; i< NTB_MAX_BARS; i++) { 456250079Scarl current_bar = &ntb->bar_info[i]; 457250079Scarl if (current_bar->pci_resource != NULL) 458250079Scarl bus_release_resource(ntb->device, SYS_RES_MEMORY, 459250079Scarl current_bar->pci_resource_id, 460250079Scarl current_bar->pci_resource); 461250079Scarl } 462250079Scarl} 463250079Scarl 464250079Scarlstatic int 465250079Scarlntb_setup_interrupts(struct ntb_softc *ntb) 466250079Scarl{ 467250079Scarl void (*interrupt_handler)(void *); 468250079Scarl void *int_arg; 469289209Scem bool use_msix = false; 470250079Scarl uint32_t num_vectors; 471250079Scarl int i; 472250079Scarl 473250079Scarl ntb->allocated_interrupts = 0; 474250079Scarl /* 475250079Scarl * On SOC, disable all interrupts. On XEON, disable all but Link 476250079Scarl * Interrupt. The rest will be unmasked as callbacks are registered. 477250079Scarl */ 478250079Scarl if (ntb->type == NTB_SOC) 479289255Scem ntb_reg_write(8, ntb->reg_ofs.ldb_mask, ~0); 480250079Scarl else 481289255Scem ntb_reg_write(2, ntb->reg_ofs.ldb_mask, 482250079Scarl ~(1 << ntb->limits.max_db_bits)); 483250079Scarl 484250079Scarl num_vectors = MIN(pci_msix_count(ntb->device), 485250079Scarl ntb->limits.max_db_bits); 486250079Scarl if (num_vectors >= 1) { 487250079Scarl pci_alloc_msix(ntb->device, &num_vectors); 488250079Scarl if (num_vectors >= 4) 489289209Scem use_msix = true; 490250079Scarl } 491250079Scarl 492250079Scarl ntb_create_callbacks(ntb, num_vectors); 493289209Scem if (use_msix == true) { 494250079Scarl for (i = 0; i < num_vectors; i++) { 495250079Scarl ntb->int_info[i].rid = i + 1; 496250079Scarl ntb->int_info[i].res = bus_alloc_resource_any( 497250079Scarl ntb->device, SYS_RES_IRQ, &ntb->int_info[i].rid, 498250079Scarl RF_ACTIVE); 499250079Scarl if (ntb->int_info[i].res == NULL) { 500250079Scarl device_printf(ntb->device, 501250079Scarl "bus_alloc_resource failed\n"); 502289209Scem return (ENOMEM); 503250079Scarl } 504250079Scarl ntb->int_info[i].tag = NULL; 505250079Scarl ntb->allocated_interrupts++; 506250079Scarl if (ntb->type == NTB_SOC) { 507250079Scarl interrupt_handler = handle_soc_irq; 508250079Scarl int_arg = &ntb->db_cb[i]; 509250079Scarl } else { 510250079Scarl if (i == num_vectors - 1) { 511255279Scarl interrupt_handler = 512255279Scarl handle_xeon_event_irq; 513250079Scarl int_arg = ntb; 514250079Scarl } else { 515250079Scarl interrupt_handler = 516250079Scarl handle_xeon_irq; 517250079Scarl int_arg = &ntb->db_cb[i]; 518250079Scarl } 519250079Scarl } 520250079Scarl if (bus_setup_intr(ntb->device, ntb->int_info[i].res, 521250079Scarl INTR_MPSAFE | INTR_TYPE_MISC, NULL, 522250079Scarl interrupt_handler, int_arg, 523250079Scarl &ntb->int_info[i].tag) != 0) { 524250079Scarl device_printf(ntb->device, 525250079Scarl "bus_setup_intr failed\n"); 526250079Scarl return (ENXIO); 527250079Scarl } 528250079Scarl } 529289209Scem } else { 530250079Scarl ntb->int_info[0].rid = 0; 531255279Scarl ntb->int_info[0].res = bus_alloc_resource_any(ntb->device, 532255279Scarl SYS_RES_IRQ, &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE); 533250079Scarl interrupt_handler = ntb_handle_legacy_interrupt; 534250079Scarl if (ntb->int_info[0].res == NULL) { 535250079Scarl device_printf(ntb->device, 536250079Scarl "bus_alloc_resource failed\n"); 537289209Scem return (ENOMEM); 538250079Scarl } 539250079Scarl ntb->int_info[0].tag = NULL; 540250079Scarl ntb->allocated_interrupts = 1; 541250079Scarl 542250079Scarl if (bus_setup_intr(ntb->device, ntb->int_info[0].res, 543250079Scarl INTR_MPSAFE | INTR_TYPE_MISC, NULL, 544250079Scarl interrupt_handler, ntb, &ntb->int_info[0].tag) != 0) { 545250079Scarl 546250079Scarl device_printf(ntb->device, "bus_setup_intr failed\n"); 547250079Scarl return (ENXIO); 548250079Scarl } 549250079Scarl } 550250079Scarl 551250079Scarl return (0); 552250079Scarl} 553250079Scarl 554250079Scarlstatic void 555250079Scarlntb_teardown_interrupts(struct ntb_softc *ntb) 556250079Scarl{ 557250079Scarl struct ntb_int_info *current_int; 558250079Scarl int i; 559250079Scarl 560289209Scem for (i = 0; i < ntb->allocated_interrupts; i++) { 561250079Scarl current_int = &ntb->int_info[i]; 562250079Scarl if (current_int->tag != NULL) 563250079Scarl bus_teardown_intr(ntb->device, current_int->res, 564250079Scarl current_int->tag); 565250079Scarl 566250079Scarl if (current_int->res != NULL) 567250079Scarl bus_release_resource(ntb->device, SYS_RES_IRQ, 568250079Scarl rman_get_rid(current_int->res), current_int->res); 569250079Scarl } 570250079Scarl 571250079Scarl ntb_free_callbacks(ntb); 572250079Scarl pci_release_msi(ntb->device); 573250079Scarl} 574250079Scarl 575250079Scarlstatic void 576250079Scarlhandle_soc_irq(void *arg) 577250079Scarl{ 578250079Scarl struct ntb_db_cb *db_cb = arg; 579250079Scarl struct ntb_softc *ntb = db_cb->ntb; 580250079Scarl 581289255Scem ntb_reg_write(8, ntb->reg_ofs.ldb, (uint64_t) 1 << db_cb->db_num); 582250079Scarl 583250079Scarl if (db_cb->callback != NULL) 584250079Scarl db_cb->callback(db_cb->data, db_cb->db_num); 585250079Scarl} 586250079Scarl 587250079Scarlstatic void 588250079Scarlhandle_xeon_irq(void *arg) 589250079Scarl{ 590250079Scarl struct ntb_db_cb *db_cb = arg; 591250079Scarl struct ntb_softc *ntb = db_cb->ntb; 592250079Scarl 593250079Scarl /* 594250079Scarl * On Xeon, there are 16 bits in the interrupt register 595250079Scarl * but only 4 vectors. So, 5 bits are assigned to the first 3 596250079Scarl * vectors, with the 4th having a single bit for link 597250079Scarl * interrupts. 598250079Scarl */ 599289255Scem ntb_reg_write(2, ntb->reg_ofs.ldb, 600250079Scarl ((1 << ntb->bits_per_vector) - 1) << 601250079Scarl (db_cb->db_num * ntb->bits_per_vector)); 602250079Scarl 603250079Scarl if (db_cb->callback != NULL) 604250079Scarl db_cb->callback(db_cb->data, db_cb->db_num); 605250079Scarl} 606250079Scarl 607250079Scarl/* Since we do not have a HW doorbell in SOC, this is only used in JF/JT */ 608250079Scarlstatic void 609250079Scarlhandle_xeon_event_irq(void *arg) 610250079Scarl{ 611250079Scarl struct ntb_softc *ntb = arg; 612250079Scarl int rc; 613250079Scarl 614250079Scarl rc = ntb_check_link_status(ntb); 615250079Scarl if (rc != 0) 616250079Scarl device_printf(ntb->device, "Error determining link status\n"); 617250079Scarl 618250079Scarl /* bit 15 is always the link bit */ 619289255Scem ntb_reg_write(2, ntb->reg_ofs.ldb, 1 << ntb->limits.max_db_bits); 620250079Scarl} 621250079Scarl 622250079Scarlstatic void 623250079Scarlntb_handle_legacy_interrupt(void *arg) 624250079Scarl{ 625250079Scarl struct ntb_softc *ntb = arg; 626250079Scarl unsigned int i = 0; 627289255Scem uint64_t ldb64; 628289255Scem uint16_t ldb16; 629250079Scarl 630250079Scarl if (ntb->type == NTB_SOC) { 631289255Scem ldb64 = ntb_reg_read(8, ntb->reg_ofs.ldb); 632250079Scarl 633289255Scem while (ldb64) { 634289255Scem i = ffs(ldb64); 635289255Scem ldb64 &= ldb64 - 1; 636250079Scarl handle_soc_irq(&ntb->db_cb[i]); 637250079Scarl } 638250079Scarl } else { 639289255Scem ldb16 = ntb_reg_read(2, ntb->reg_ofs.ldb); 640250079Scarl 641289255Scem if ((ldb16 & XEON_DB_HW_LINK) != 0) { 642250079Scarl handle_xeon_event_irq(ntb); 643289255Scem ldb16 &= ~XEON_DB_HW_LINK; 644250079Scarl } 645250079Scarl 646289255Scem while (ldb16 != 0) { 647289255Scem i = ffs(ldb16); 648289255Scem ldb16 &= ldb16 - 1; 649250079Scarl handle_xeon_irq(&ntb->db_cb[i]); 650250079Scarl } 651250079Scarl } 652250079Scarl 653250079Scarl} 654250079Scarl 655250079Scarlstatic int 656250079Scarlntb_create_callbacks(struct ntb_softc *ntb, int num_vectors) 657250079Scarl{ 658250079Scarl int i; 659250079Scarl 660289209Scem ntb->db_cb = malloc(num_vectors * sizeof(*ntb->db_cb), M_NTB, 661250079Scarl M_ZERO | M_WAITOK); 662250079Scarl for (i = 0; i < num_vectors; i++) { 663250079Scarl ntb->db_cb[i].db_num = i; 664250079Scarl ntb->db_cb[i].ntb = ntb; 665250079Scarl } 666250079Scarl 667250079Scarl return (0); 668250079Scarl} 669250079Scarl 670250079Scarlstatic void 671250079Scarlntb_free_callbacks(struct ntb_softc *ntb) 672250079Scarl{ 673250079Scarl int i; 674250079Scarl 675250079Scarl for (i = 0; i < ntb->limits.max_db_bits; i++) 676250079Scarl ntb_unregister_db_callback(ntb, i); 677250079Scarl 678250079Scarl free(ntb->db_cb, M_NTB); 679250079Scarl} 680250079Scarl 681250079Scarlstatic struct ntb_hw_info * 682250079Scarlntb_get_device_info(uint32_t device_id) 683250079Scarl{ 684250079Scarl struct ntb_hw_info *ep = pci_ids; 685250079Scarl 686250079Scarl while (ep->device_id) { 687250079Scarl if (ep->device_id == device_id) 688250079Scarl return (ep); 689250079Scarl ++ep; 690250079Scarl } 691250079Scarl return (NULL); 692250079Scarl} 693250079Scarl 694250079Scarlstatic int 695250079Scarlntb_initialize_hw(struct ntb_softc *ntb) 696250079Scarl{ 697250079Scarl 698250079Scarl if (ntb->type == NTB_SOC) 699250079Scarl return (ntb_setup_soc(ntb)); 700250079Scarl else 701250079Scarl return (ntb_setup_xeon(ntb)); 702250079Scarl} 703250079Scarl 704250079Scarlstatic int 705250079Scarlntb_setup_xeon(struct ntb_softc *ntb) 706250079Scarl{ 707250079Scarl uint8_t val, connection_type; 708250079Scarl 709250079Scarl val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1); 710250079Scarl 711250079Scarl connection_type = val & XEON_PPD_CONN_TYPE; 712289257Scem 713289257Scem if ((val & XEON_PPD_DEV_TYPE) != 0) 714289257Scem ntb->dev_type = NTB_DEV_USD; 715289257Scem else 716289257Scem ntb->dev_type = NTB_DEV_DSD; 717289257Scem 718289257Scem ntb->reg_ofs.ldb = XEON_PDOORBELL_OFFSET; 719289257Scem ntb->reg_ofs.ldb_mask = XEON_PDBMSK_OFFSET; 720289257Scem ntb->reg_ofs.spad_local = XEON_SPAD_OFFSET; 721289257Scem ntb->reg_ofs.bar2_xlat = XEON_SBAR2XLAT_OFFSET; 722289257Scem ntb->reg_ofs.bar4_xlat = XEON_SBAR4XLAT_OFFSET; 723289257Scem 724250079Scarl switch (connection_type) { 725250079Scarl case NTB_CONN_B2B: 726250079Scarl ntb->conn_type = NTB_CONN_B2B; 727289257Scem 728289257Scem /* 729289257Scem * reg_ofs.rdb and reg_ofs.spad_remote are effectively ignored 730289257Scem * with the NTB_REGS_THRU_MW errata mode enabled. (See 731289257Scem * ntb_ring_doorbell() and ntb_read/write_remote_spad().) 732289257Scem */ 733289257Scem ntb->reg_ofs.rdb = XEON_B2B_DOORBELL_OFFSET; 734289257Scem ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET; 735289257Scem 736289257Scem ntb->limits.max_spads = XEON_MAX_SPADS; 737250079Scarl break; 738289257Scem 739250079Scarl case NTB_CONN_RP: 740289257Scem /* 741289257Scem * Every Xeon today needs NTB_REGS_THRU_MW, so punt on RP for 742289257Scem * now. 743289257Scem */ 744289257Scem KASSERT(HAS_FEATURE(NTB_REGS_THRU_MW), 745289257Scem ("Xeon without MW errata unimplemented")); 746289257Scem device_printf(ntb->device, 747289257Scem "NTB-RP disabled to due hardware errata.\n"); 748289257Scem return (ENXIO); 749289257Scem 750289257Scem case NTB_CONN_TRANSPARENT: 751250079Scarl default: 752250079Scarl device_printf(ntb->device, "Connection type %d not supported\n", 753250079Scarl connection_type); 754250079Scarl return (ENXIO); 755250079Scarl } 756250079Scarl 757289208Scem /* 758289208Scem * There is a Xeon hardware errata related to writes to SDOORBELL or 759289208Scem * B2BDOORBELL in conjunction with inbound access to NTB MMIO space, 760289208Scem * which may hang the system. To workaround this use the second memory 761289208Scem * window to access the interrupt and scratch pad registers on the 762289208Scem * remote system. 763289208Scem */ 764289208Scem if (HAS_FEATURE(NTB_REGS_THRU_MW)) 765289208Scem /* 766289208Scem * Set the Limit register to 4k, the minimum size, to prevent 767289208Scem * an illegal access. 768289208Scem */ 769289208Scem ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 770289208Scem ntb_get_mw_size(ntb, 1) + 0x1000); 771289208Scem else 772289208Scem /* 773289208Scem * Disable the limit register, just in case it is set to 774289208Scem * something silly. 775289208Scem */ 776289208Scem ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0); 777289208Scem 778289208Scem 779289257Scem ntb->reg_ofs.lnk_cntl = XEON_NTBCNTL_OFFSET; 780289257Scem ntb->reg_ofs.lnk_stat = XEON_LINK_STATUS_OFFSET; 781289257Scem ntb->reg_ofs.spci_cmd = XEON_PCICMD_OFFSET; 782250079Scarl 783289255Scem ntb->limits.max_db_bits = XEON_MAX_DB_BITS; 784250079Scarl ntb->limits.msix_cnt = XEON_MSIX_CNT; 785250079Scarl ntb->bits_per_vector = XEON_DB_BITS_PER_VEC; 786250079Scarl 787255279Scarl configure_xeon_secondary_side_bars(ntb); 788289209Scem 789250079Scarl /* Enable Bus Master and Memory Space on the secondary side */ 790289257Scem if (ntb->conn_type == NTB_CONN_B2B) 791289257Scem ntb_reg_write(2, ntb->reg_ofs.spci_cmd, 792289257Scem PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 793255279Scarl 794255269Scarl /* Enable link training */ 795255278Scarl ntb_reg_write(4, ntb->reg_ofs.lnk_cntl, 796255269Scarl NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP); 797250079Scarl 798250079Scarl return (0); 799250079Scarl} 800250079Scarl 801250079Scarlstatic int 802250079Scarlntb_setup_soc(struct ntb_softc *ntb) 803250079Scarl{ 804250079Scarl uint32_t val, connection_type; 805250079Scarl 806250079Scarl val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4); 807250079Scarl 808250079Scarl connection_type = (val & SOC_PPD_CONN_TYPE) >> 8; 809250079Scarl switch (connection_type) { 810250079Scarl case NTB_CONN_B2B: 811250079Scarl ntb->conn_type = NTB_CONN_B2B; 812250079Scarl break; 813250079Scarl case NTB_CONN_RP: 814250079Scarl default: 815250079Scarl device_printf(ntb->device, "Connection type %d not supported\n", 816250079Scarl connection_type); 817250079Scarl return (ENXIO); 818250079Scarl } 819250079Scarl 820250079Scarl if ((val & SOC_PPD_DEV_TYPE) != 0) 821250079Scarl ntb->dev_type = NTB_DEV_DSD; 822250079Scarl else 823250079Scarl ntb->dev_type = NTB_DEV_USD; 824250079Scarl 825250079Scarl /* Initiate PCI-E link training */ 826250079Scarl pci_write_config(ntb->device, NTB_PPD_OFFSET, val | SOC_PPD_INIT_LINK, 827250079Scarl 4); 828250079Scarl 829289255Scem ntb->reg_ofs.ldb = SOC_PDOORBELL_OFFSET; 830289255Scem ntb->reg_ofs.ldb_mask = SOC_PDBMSK_OFFSET; 831289255Scem ntb->reg_ofs.bar2_xlat = SOC_SBAR2XLAT_OFFSET; 832289255Scem ntb->reg_ofs.bar4_xlat = SOC_SBAR4XLAT_OFFSET; 833250079Scarl ntb->reg_ofs.lnk_cntl = SOC_NTBCNTL_OFFSET; 834250079Scarl ntb->reg_ofs.lnk_stat = SOC_LINK_STATUS_OFFSET; 835250079Scarl ntb->reg_ofs.spad_local = SOC_SPAD_OFFSET; 836250079Scarl ntb->reg_ofs.spci_cmd = SOC_PCICMD_OFFSET; 837250079Scarl 838250079Scarl if (ntb->conn_type == NTB_CONN_B2B) { 839289255Scem ntb->reg_ofs.rdb = SOC_B2B_DOORBELL_OFFSET; 840250079Scarl ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET; 841250079Scarl ntb->limits.max_spads = SOC_MAX_SPADS; 842250079Scarl } else { 843289255Scem ntb->reg_ofs.rdb = SOC_PDOORBELL_OFFSET; 844250079Scarl ntb->reg_ofs.spad_remote = SOC_SPAD_OFFSET; 845250079Scarl ntb->limits.max_spads = SOC_MAX_COMPAT_SPADS; 846250079Scarl } 847250079Scarl 848289255Scem ntb->limits.max_db_bits = SOC_MAX_DB_BITS; 849250079Scarl ntb->limits.msix_cnt = SOC_MSIX_CNT; 850250079Scarl ntb->bits_per_vector = SOC_DB_BITS_PER_VEC; 851250079Scarl 852250079Scarl /* 853250079Scarl * FIXME - MSI-X bug on early SOC HW, remove once internal issue is 854250079Scarl * resolved. Mask transaction layer internal parity errors. 855250079Scarl */ 856250079Scarl pci_write_config(ntb->device, 0xFC, 0x4, 4); 857250079Scarl 858255279Scarl configure_soc_secondary_side_bars(ntb); 859250079Scarl 860250079Scarl /* Enable Bus Master and Memory Space on the secondary side */ 861255278Scarl ntb_reg_write(2, ntb->reg_ofs.spci_cmd, 862250079Scarl PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 863289209Scem 864250079Scarl callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb); 865250079Scarl 866250079Scarl return (0); 867250079Scarl} 868250079Scarl 869255279Scarlstatic void 870255279Scarlconfigure_soc_secondary_side_bars(struct ntb_softc *ntb) 871255279Scarl{ 872255279Scarl 873255279Scarl if (ntb->dev_type == NTB_DEV_USD) { 874255279Scarl ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR); 875255279Scarl ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, PBAR4XLAT_USD_ADDR); 876255279Scarl ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_USD_ADDR); 877255279Scarl ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR45_USD_ADDR); 878255279Scarl } else { 879255279Scarl ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR); 880255279Scarl ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, PBAR4XLAT_DSD_ADDR); 881255279Scarl ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_DSD_ADDR); 882255279Scarl ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR45_DSD_ADDR); 883255279Scarl } 884255279Scarl} 885255279Scarl 886255279Scarlstatic void 887255279Scarlconfigure_xeon_secondary_side_bars(struct ntb_softc *ntb) 888255279Scarl{ 889255279Scarl 890255279Scarl if (ntb->dev_type == NTB_DEV_USD) { 891255279Scarl ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR); 892255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 893255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 894255279Scarl MBAR01_DSD_ADDR); 895289208Scem else { 896255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 897255279Scarl PBAR4XLAT_USD_ADDR); 898289208Scem /* 899289208Scem * B2B_XLAT_OFFSET is a 64-bit register but can only be 900289208Scem * written 32 bits at a time. 901289208Scem */ 902289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, 903289208Scem MBAR01_DSD_ADDR & 0xffffffff); 904289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, 905289208Scem MBAR01_DSD_ADDR >> 32); 906289208Scem } 907255279Scarl ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_USD_ADDR); 908255279Scarl ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_USD_ADDR); 909255279Scarl ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_USD_ADDR); 910255279Scarl } else { 911255279Scarl ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR); 912255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 913255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 914255279Scarl MBAR01_USD_ADDR); 915289208Scem else { 916255279Scarl ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, 917255279Scarl PBAR4XLAT_DSD_ADDR); 918289208Scem /* 919289208Scem * B2B_XLAT_OFFSET is a 64-bit register but can only be 920289208Scem * written 32 bits at a time. 921289208Scem */ 922289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, 923289208Scem MBAR01_USD_ADDR & 0xffffffff); 924289208Scem ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, 925289208Scem MBAR01_USD_ADDR >> 32); 926289208Scem } 927255279Scarl ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_DSD_ADDR); 928255279Scarl ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_DSD_ADDR); 929255279Scarl ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_DSD_ADDR); 930255279Scarl } 931255279Scarl} 932255279Scarl 933255281Scarl/* SOC does not have link status interrupt, poll on that platform */ 934250079Scarlstatic void 935250079Scarlntb_handle_heartbeat(void *arg) 936250079Scarl{ 937250079Scarl struct ntb_softc *ntb = arg; 938250079Scarl uint32_t status32; 939289209Scem int rc; 940250079Scarl 941289209Scem rc = ntb_check_link_status(ntb); 942250079Scarl if (rc != 0) 943250079Scarl device_printf(ntb->device, 944250079Scarl "Error determining link status\n"); 945289232Scem 946250079Scarl /* Check to see if a link error is the cause of the link down */ 947250079Scarl if (ntb->link_status == NTB_LINK_DOWN) { 948255278Scarl status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 949250079Scarl if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) { 950250079Scarl callout_reset(&ntb->lr_timer, 0, recover_soc_link, 951250079Scarl ntb); 952250079Scarl return; 953250079Scarl } 954250079Scarl } 955250079Scarl 956250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 957250079Scarl ntb_handle_heartbeat, ntb); 958250079Scarl} 959250079Scarl 960250079Scarlstatic void 961250079Scarlsoc_perform_link_restart(struct ntb_softc *ntb) 962250079Scarl{ 963250079Scarl uint32_t status; 964250079Scarl 965250079Scarl /* Driver resets the NTB ModPhy lanes - magic! */ 966255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0xe0); 967255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x40); 968255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x60); 969255278Scarl ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0x60); 970250079Scarl 971250079Scarl /* Driver waits 100ms to allow the NTB ModPhy to settle */ 972250079Scarl pause("ModPhy", hz / 10); 973250079Scarl 974250079Scarl /* Clear AER Errors, write to clear */ 975255278Scarl status = ntb_reg_read(4, SOC_ERRCORSTS_OFFSET); 976250079Scarl status &= PCIM_AER_COR_REPLAY_ROLLOVER; 977255278Scarl ntb_reg_write(4, SOC_ERRCORSTS_OFFSET, status); 978250079Scarl 979250079Scarl /* Clear unexpected electrical idle event in LTSSM, write to clear */ 980255278Scarl status = ntb_reg_read(4, SOC_LTSSMERRSTS0_OFFSET); 981250079Scarl status |= SOC_LTSSMERRSTS0_UNEXPECTEDEI; 982255278Scarl ntb_reg_write(4, SOC_LTSSMERRSTS0_OFFSET, status); 983250079Scarl 984250079Scarl /* Clear DeSkew Buffer error, write to clear */ 985255278Scarl status = ntb_reg_read(4, SOC_DESKEWSTS_OFFSET); 986250079Scarl status |= SOC_DESKEWSTS_DBERR; 987255278Scarl ntb_reg_write(4, SOC_DESKEWSTS_OFFSET, status); 988250079Scarl 989255278Scarl status = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET); 990250079Scarl status &= SOC_IBIST_ERR_OFLOW; 991255278Scarl ntb_reg_write(4, SOC_IBSTERRRCRVSTS0_OFFSET, status); 992250079Scarl 993250079Scarl /* Releases the NTB state machine to allow the link to retrain */ 994255278Scarl status = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 995250079Scarl status &= ~SOC_LTSSMSTATEJMP_FORCEDETECT; 996255278Scarl ntb_reg_write(4, SOC_LTSSMSTATEJMP_OFFSET, status); 997250079Scarl} 998250079Scarl 999250079Scarlstatic void 1000250079Scarlntb_handle_link_event(struct ntb_softc *ntb, int link_state) 1001250079Scarl{ 1002250079Scarl enum ntb_hw_event event; 1003250079Scarl uint16_t status; 1004250079Scarl 1005250079Scarl if (ntb->link_status == link_state) 1006250079Scarl return; 1007250079Scarl 1008250079Scarl if (link_state == NTB_LINK_UP) { 1009250079Scarl device_printf(ntb->device, "Link Up\n"); 1010250079Scarl ntb->link_status = NTB_LINK_UP; 1011250079Scarl event = NTB_EVENT_HW_LINK_UP; 1012250079Scarl 1013289257Scem if (ntb->type == NTB_SOC || 1014289257Scem ntb->conn_type == NTB_CONN_TRANSPARENT) 1015255278Scarl status = ntb_reg_read(2, ntb->reg_ofs.lnk_stat); 1016250079Scarl else 1017250079Scarl status = pci_read_config(ntb->device, 1018250079Scarl XEON_LINK_STATUS_OFFSET, 2); 1019250079Scarl ntb->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; 1020250079Scarl ntb->link_speed = (status & NTB_LINK_SPEED_MASK); 1021250079Scarl device_printf(ntb->device, "Link Width %d, Link Speed %d\n", 1022250079Scarl ntb->link_width, ntb->link_speed); 1023250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 1024250079Scarl ntb_handle_heartbeat, ntb); 1025250079Scarl } else { 1026250079Scarl device_printf(ntb->device, "Link Down\n"); 1027250079Scarl ntb->link_status = NTB_LINK_DOWN; 1028250079Scarl event = NTB_EVENT_HW_LINK_DOWN; 1029255281Scarl /* Do not modify link width/speed, we need it in link recovery */ 1030250079Scarl } 1031250079Scarl 1032250079Scarl /* notify the upper layer if we have an event change */ 1033250079Scarl if (ntb->event_cb != NULL) 1034250079Scarl ntb->event_cb(ntb->ntb_transport, event); 1035250079Scarl} 1036250079Scarl 1037250079Scarlstatic void 1038250079Scarlrecover_soc_link(void *arg) 1039250079Scarl{ 1040250079Scarl struct ntb_softc *ntb = arg; 1041250079Scarl uint8_t speed, width; 1042250079Scarl uint32_t status32; 1043250079Scarl uint16_t status16; 1044250079Scarl 1045250079Scarl soc_perform_link_restart(ntb); 1046250079Scarl 1047289232Scem /* 1048289232Scem * There is a potential race between the 2 NTB devices recovering at 1049289232Scem * the same time. If the times are the same, the link will not recover 1050289232Scem * and the driver will be stuck in this loop forever. Add a random 1051289232Scem * interval to the recovery time to prevent this race. 1052289232Scem */ 1053289232Scem status32 = arc4random() % SOC_LINK_RECOVERY_TIME; 1054289232Scem pause("Link", (SOC_LINK_RECOVERY_TIME + status32) * hz / 1000); 1055289232Scem 1056255278Scarl status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); 1057250079Scarl if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) 1058250079Scarl goto retry; 1059250079Scarl 1060255278Scarl status32 = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET); 1061250079Scarl if ((status32 & SOC_IBIST_ERR_OFLOW) != 0) 1062250079Scarl goto retry; 1063250079Scarl 1064289232Scem status32 = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); 1065289232Scem if ((status32 & SOC_CNTL_LINK_DOWN) != 0) 1066289232Scem goto out; 1067289232Scem 1068255278Scarl status16 = ntb_reg_read(2, ntb->reg_ofs.lnk_stat); 1069250079Scarl width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; 1070250079Scarl speed = (status16 & NTB_LINK_SPEED_MASK); 1071250079Scarl if (ntb->link_width != width || ntb->link_speed != speed) 1072250079Scarl goto retry; 1073250079Scarl 1074289232Scemout: 1075250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 1076250079Scarl ntb_handle_heartbeat, ntb); 1077250079Scarl return; 1078250079Scarl 1079250079Scarlretry: 1080250079Scarl callout_reset(&ntb->lr_timer, NTB_HB_TIMEOUT * hz, recover_soc_link, 1081250079Scarl ntb); 1082250079Scarl} 1083250079Scarl 1084250079Scarlstatic int 1085250079Scarlntb_check_link_status(struct ntb_softc *ntb) 1086250079Scarl{ 1087250079Scarl int link_state; 1088250079Scarl uint32_t ntb_cntl; 1089250079Scarl uint16_t status; 1090250079Scarl 1091250079Scarl if (ntb->type == NTB_SOC) { 1092255278Scarl ntb_cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); 1093250079Scarl if ((ntb_cntl & SOC_CNTL_LINK_DOWN) != 0) 1094250079Scarl link_state = NTB_LINK_DOWN; 1095250079Scarl else 1096250079Scarl link_state = NTB_LINK_UP; 1097250079Scarl } else { 1098250079Scarl status = pci_read_config(ntb->device, XEON_LINK_STATUS_OFFSET, 1099250079Scarl 2); 1100250079Scarl 1101250079Scarl if ((status & NTB_LINK_STATUS_ACTIVE) != 0) 1102250079Scarl link_state = NTB_LINK_UP; 1103250079Scarl else 1104250079Scarl link_state = NTB_LINK_DOWN; 1105250079Scarl } 1106250079Scarl 1107250079Scarl ntb_handle_link_event(ntb, link_state); 1108250079Scarl 1109250079Scarl return (0); 1110250079Scarl} 1111250079Scarl 1112250079Scarl/** 1113250079Scarl * ntb_register_event_callback() - register event callback 1114250079Scarl * @ntb: pointer to ntb_softc instance 1115250079Scarl * @func: callback function to register 1116250079Scarl * 1117250079Scarl * This function registers a callback for any HW driver events such as link 1118250079Scarl * up/down, power management notices and etc. 1119250079Scarl * 1120289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1121250079Scarl */ 1122250079Scarlint 1123250079Scarlntb_register_event_callback(struct ntb_softc *ntb, ntb_event_callback func) 1124250079Scarl{ 1125250079Scarl 1126250079Scarl if (ntb->event_cb != NULL) 1127250079Scarl return (EINVAL); 1128250079Scarl 1129250079Scarl ntb->event_cb = func; 1130250079Scarl 1131250079Scarl return (0); 1132250079Scarl} 1133250079Scarl 1134250079Scarl/** 1135250079Scarl * ntb_unregister_event_callback() - unregisters the event callback 1136250079Scarl * @ntb: pointer to ntb_softc instance 1137250079Scarl * 1138250079Scarl * This function unregisters the existing callback from transport 1139250079Scarl */ 1140250079Scarlvoid 1141250079Scarlntb_unregister_event_callback(struct ntb_softc *ntb) 1142250079Scarl{ 1143250079Scarl 1144250079Scarl ntb->event_cb = NULL; 1145250079Scarl} 1146250079Scarl 1147250079Scarl/** 1148250079Scarl * ntb_register_db_callback() - register a callback for doorbell interrupt 1149250079Scarl * @ntb: pointer to ntb_softc instance 1150250079Scarl * @idx: doorbell index to register callback, zero based 1151250079Scarl * @func: callback function to register 1152250079Scarl * 1153250079Scarl * This function registers a callback function for the doorbell interrupt 1154250079Scarl * on the primary side. The function will unmask the doorbell as well to 1155250079Scarl * allow interrupt. 1156250079Scarl * 1157289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1158250079Scarl */ 1159250079Scarlint 1160250079Scarlntb_register_db_callback(struct ntb_softc *ntb, unsigned int idx, void *data, 1161250079Scarl ntb_db_callback func) 1162250079Scarl{ 1163250079Scarl uint16_t mask; 1164250079Scarl 1165250079Scarl if (idx >= ntb->allocated_interrupts || ntb->db_cb[idx].callback) { 1166250079Scarl device_printf(ntb->device, "Invalid Index.\n"); 1167250079Scarl return (EINVAL); 1168250079Scarl } 1169250079Scarl 1170250079Scarl ntb->db_cb[idx].callback = func; 1171250079Scarl ntb->db_cb[idx].data = data; 1172250079Scarl 1173250079Scarl /* unmask interrupt */ 1174289255Scem mask = ntb_reg_read(2, ntb->reg_ofs.ldb_mask); 1175250079Scarl mask &= ~(1 << (idx * ntb->bits_per_vector)); 1176289255Scem ntb_reg_write(2, ntb->reg_ofs.ldb_mask, mask); 1177250079Scarl 1178250079Scarl return (0); 1179250079Scarl} 1180250079Scarl 1181250079Scarl/** 1182250079Scarl * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt 1183250079Scarl * @ntb: pointer to ntb_softc instance 1184250079Scarl * @idx: doorbell index to register callback, zero based 1185250079Scarl * 1186250079Scarl * This function unregisters a callback function for the doorbell interrupt 1187250079Scarl * on the primary side. The function will also mask the said doorbell. 1188250079Scarl */ 1189250079Scarlvoid 1190250079Scarlntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx) 1191250079Scarl{ 1192250079Scarl unsigned long mask; 1193250079Scarl 1194250079Scarl if (idx >= ntb->allocated_interrupts || !ntb->db_cb[idx].callback) 1195250079Scarl return; 1196250079Scarl 1197289255Scem mask = ntb_reg_read(2, ntb->reg_ofs.ldb_mask); 1198250079Scarl mask |= 1 << (idx * ntb->bits_per_vector); 1199289255Scem ntb_reg_write(2, ntb->reg_ofs.ldb_mask, mask); 1200250079Scarl 1201250079Scarl ntb->db_cb[idx].callback = NULL; 1202250079Scarl} 1203250079Scarl 1204250079Scarl/** 1205250079Scarl * ntb_find_transport() - find the transport pointer 1206250079Scarl * @transport: pointer to pci device 1207250079Scarl * 1208250079Scarl * Given the pci device pointer, return the transport pointer passed in when 1209250079Scarl * the transport attached when it was inited. 1210250079Scarl * 1211250079Scarl * RETURNS: pointer to transport. 1212250079Scarl */ 1213250079Scarlvoid * 1214250079Scarlntb_find_transport(struct ntb_softc *ntb) 1215250079Scarl{ 1216250079Scarl 1217250079Scarl return (ntb->ntb_transport); 1218250079Scarl} 1219250079Scarl 1220250079Scarl/** 1221250079Scarl * ntb_register_transport() - Register NTB transport with NTB HW driver 1222250079Scarl * @transport: transport identifier 1223250079Scarl * 1224250079Scarl * This function allows a transport to reserve the hardware driver for 1225250079Scarl * NTB usage. 1226250079Scarl * 1227250079Scarl * RETURNS: pointer to ntb_softc, NULL on error. 1228250079Scarl */ 1229250079Scarlstruct ntb_softc * 1230250079Scarlntb_register_transport(struct ntb_softc *ntb, void *transport) 1231250079Scarl{ 1232250079Scarl 1233250079Scarl /* 1234250079Scarl * TODO: when we have more than one transport, we will need to rewrite 1235250079Scarl * this to prevent race conditions 1236250079Scarl */ 1237250079Scarl if (ntb->ntb_transport != NULL) 1238250079Scarl return (NULL); 1239250079Scarl 1240250079Scarl ntb->ntb_transport = transport; 1241250079Scarl return (ntb); 1242250079Scarl} 1243250079Scarl 1244250079Scarl/** 1245250079Scarl * ntb_unregister_transport() - Unregister the transport with the NTB HW driver 1246250079Scarl * @ntb - ntb_softc of the transport to be freed 1247250079Scarl * 1248250079Scarl * This function unregisters the transport from the HW driver and performs any 1249250079Scarl * necessary cleanups. 1250250079Scarl */ 1251250079Scarlvoid 1252250079Scarlntb_unregister_transport(struct ntb_softc *ntb) 1253250079Scarl{ 1254250079Scarl int i; 1255250079Scarl 1256250079Scarl if (ntb->ntb_transport == NULL) 1257250079Scarl return; 1258250079Scarl 1259250079Scarl for (i = 0; i < ntb->allocated_interrupts; i++) 1260250079Scarl ntb_unregister_db_callback(ntb, i); 1261250079Scarl 1262250079Scarl ntb_unregister_event_callback(ntb); 1263250079Scarl ntb->ntb_transport = NULL; 1264250079Scarl} 1265250079Scarl 1266250079Scarl/** 1267250079Scarl * ntb_get_max_spads() - get the total scratch regs usable 1268250079Scarl * @ntb: pointer to ntb_softc instance 1269250079Scarl * 1270250079Scarl * This function returns the max 32bit scratchpad registers usable by the 1271250079Scarl * upper layer. 1272250079Scarl * 1273250079Scarl * RETURNS: total number of scratch pad registers available 1274250079Scarl */ 1275289208Scemuint8_t 1276250079Scarlntb_get_max_spads(struct ntb_softc *ntb) 1277250079Scarl{ 1278250079Scarl 1279250079Scarl return (ntb->limits.max_spads); 1280250079Scarl} 1281250079Scarl 1282250079Scarl/** 1283250079Scarl * ntb_write_local_spad() - write to the secondary scratchpad register 1284250079Scarl * @ntb: pointer to ntb_softc instance 1285250079Scarl * @idx: index to the scratchpad register, 0 based 1286250079Scarl * @val: the data value to put into the register 1287250079Scarl * 1288250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad 1289250079Scarl * register. The register resides on the secondary (external) side. 1290250079Scarl * 1291289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1292250079Scarl */ 1293250079Scarlint 1294250079Scarlntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) 1295250079Scarl{ 1296250079Scarl 1297250079Scarl if (idx >= ntb->limits.max_spads) 1298250079Scarl return (EINVAL); 1299250079Scarl 1300255278Scarl ntb_reg_write(4, ntb->reg_ofs.spad_local + idx * 4, val); 1301250079Scarl 1302250079Scarl return (0); 1303250079Scarl} 1304250079Scarl 1305250079Scarl/** 1306250079Scarl * ntb_read_local_spad() - read from the primary scratchpad register 1307250079Scarl * @ntb: pointer to ntb_softc instance 1308250079Scarl * @idx: index to scratchpad register, 0 based 1309250079Scarl * @val: pointer to 32bit integer for storing the register value 1310250079Scarl * 1311250079Scarl * This function allows reading of the 32bit scratchpad register on 1312250079Scarl * the primary (internal) side. 1313250079Scarl * 1314289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1315250079Scarl */ 1316250079Scarlint 1317250079Scarlntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) 1318250079Scarl{ 1319250079Scarl 1320250079Scarl if (idx >= ntb->limits.max_spads) 1321250079Scarl return (EINVAL); 1322250079Scarl 1323255278Scarl *val = ntb_reg_read(4, ntb->reg_ofs.spad_local + idx * 4); 1324250079Scarl 1325250079Scarl return (0); 1326250079Scarl} 1327250079Scarl 1328250079Scarl/** 1329250079Scarl * ntb_write_remote_spad() - write to the secondary scratchpad register 1330250079Scarl * @ntb: pointer to ntb_softc instance 1331250079Scarl * @idx: index to the scratchpad register, 0 based 1332250079Scarl * @val: the data value to put into the register 1333250079Scarl * 1334250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad 1335250079Scarl * register. The register resides on the secondary (external) side. 1336250079Scarl * 1337289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1338250079Scarl */ 1339250079Scarlint 1340250079Scarlntb_write_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) 1341250079Scarl{ 1342250079Scarl 1343250079Scarl if (idx >= ntb->limits.max_spads) 1344250079Scarl return (EINVAL); 1345250079Scarl 1346255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 1347255279Scarl ntb_mw_write(4, XEON_SHADOW_SPAD_OFFSET + idx * 4, val); 1348255279Scarl else 1349255279Scarl ntb_reg_write(4, ntb->reg_ofs.spad_remote + idx * 4, val); 1350250079Scarl 1351250079Scarl return (0); 1352250079Scarl} 1353250079Scarl 1354250079Scarl/** 1355250079Scarl * ntb_read_remote_spad() - read from the primary scratchpad register 1356250079Scarl * @ntb: pointer to ntb_softc instance 1357250079Scarl * @idx: index to scratchpad register, 0 based 1358250079Scarl * @val: pointer to 32bit integer for storing the register value 1359250079Scarl * 1360250079Scarl * This function allows reading of the 32bit scratchpad register on 1361250079Scarl * the primary (internal) side. 1362250079Scarl * 1363289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1364250079Scarl */ 1365250079Scarlint 1366250079Scarlntb_read_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) 1367250079Scarl{ 1368250079Scarl 1369250079Scarl if (idx >= ntb->limits.max_spads) 1370250079Scarl return (EINVAL); 1371250079Scarl 1372255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 1373255279Scarl *val = ntb_mw_read(4, XEON_SHADOW_SPAD_OFFSET + idx * 4); 1374255279Scarl else 1375255279Scarl *val = ntb_reg_read(4, ntb->reg_ofs.spad_remote + idx * 4); 1376250079Scarl 1377250079Scarl return (0); 1378250079Scarl} 1379250079Scarl 1380250079Scarl/** 1381250079Scarl * ntb_get_mw_vbase() - get virtual addr for the NTB memory window 1382250079Scarl * @ntb: pointer to ntb_softc instance 1383250079Scarl * @mw: memory window number 1384250079Scarl * 1385250079Scarl * This function provides the base virtual address of the memory window 1386250079Scarl * specified. 1387250079Scarl * 1388250079Scarl * RETURNS: pointer to virtual address, or NULL on error. 1389250079Scarl */ 1390250079Scarlvoid * 1391250079Scarlntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw) 1392250079Scarl{ 1393250079Scarl 1394250079Scarl if (mw >= NTB_NUM_MW) 1395250079Scarl return (NULL); 1396250079Scarl 1397250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].vbase); 1398250079Scarl} 1399250079Scarl 1400250079Scarlvm_paddr_t 1401250079Scarlntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw) 1402250079Scarl{ 1403250079Scarl 1404250079Scarl if (mw >= NTB_NUM_MW) 1405250079Scarl return (0); 1406250079Scarl 1407250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].pbase); 1408250079Scarl} 1409250079Scarl 1410250079Scarl/** 1411250079Scarl * ntb_get_mw_size() - return size of NTB memory window 1412250079Scarl * @ntb: pointer to ntb_softc instance 1413250079Scarl * @mw: memory window number 1414250079Scarl * 1415250079Scarl * This function provides the physical size of the memory window specified 1416250079Scarl * 1417250079Scarl * RETURNS: the size of the memory window or zero on error 1418250079Scarl */ 1419250079Scarlu_long 1420250079Scarlntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw) 1421250079Scarl{ 1422250079Scarl 1423250079Scarl if (mw >= NTB_NUM_MW) 1424250079Scarl return (0); 1425250079Scarl 1426250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].size); 1427250079Scarl} 1428250079Scarl 1429250079Scarl/** 1430250079Scarl * ntb_set_mw_addr - set the memory window address 1431250079Scarl * @ntb: pointer to ntb_softc instance 1432250079Scarl * @mw: memory window number 1433250079Scarl * @addr: base address for data 1434250079Scarl * 1435250079Scarl * This function sets the base physical address of the memory window. This 1436250079Scarl * memory address is where data from the remote system will be transfered into 1437250079Scarl * or out of depending on how the transport is configured. 1438250079Scarl */ 1439250079Scarlvoid 1440250079Scarlntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr) 1441250079Scarl{ 1442250079Scarl 1443250079Scarl if (mw >= NTB_NUM_MW) 1444250079Scarl return; 1445250079Scarl 1446250079Scarl switch (NTB_MW_TO_BAR(mw)) { 1447250079Scarl case NTB_B2B_BAR_1: 1448289255Scem ntb_reg_write(8, ntb->reg_ofs.bar2_xlat, addr); 1449250079Scarl break; 1450250079Scarl case NTB_B2B_BAR_2: 1451289255Scem ntb_reg_write(8, ntb->reg_ofs.bar4_xlat, addr); 1452250079Scarl break; 1453250079Scarl } 1454250079Scarl} 1455250079Scarl 1456250079Scarl/** 1457289255Scem * ntb_ring_doorbell() - Set the doorbell on the secondary/external side 1458250079Scarl * @ntb: pointer to ntb_softc instance 1459250079Scarl * @db: doorbell to ring 1460250079Scarl * 1461250079Scarl * This function allows triggering of a doorbell on the secondary/external 1462250079Scarl * side that will initiate an interrupt on the remote host 1463250079Scarl * 1464289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success. 1465250079Scarl */ 1466250079Scarlvoid 1467289255Scemntb_ring_doorbell(struct ntb_softc *ntb, unsigned int db) 1468250079Scarl{ 1469250079Scarl 1470250079Scarl if (ntb->type == NTB_SOC) 1471289255Scem ntb_reg_write(8, ntb->reg_ofs.rdb, (uint64_t) 1 << db); 1472289209Scem else { 1473255279Scarl if (HAS_FEATURE(NTB_REGS_THRU_MW)) 1474255279Scarl ntb_mw_write(2, XEON_SHADOW_PDOORBELL_OFFSET, 1475255279Scarl ((1 << ntb->bits_per_vector) - 1) << 1476255279Scarl (db * ntb->bits_per_vector)); 1477255279Scarl else 1478289255Scem ntb_reg_write(2, ntb->reg_ofs.rdb, 1479255279Scarl ((1 << ntb->bits_per_vector) - 1) << 1480255279Scarl (db * ntb->bits_per_vector)); 1481289209Scem } 1482250079Scarl} 1483250079Scarl 1484250079Scarl/** 1485250079Scarl * ntb_query_link_status() - return the hardware link status 1486250079Scarl * @ndev: pointer to ntb_device instance 1487250079Scarl * 1488250079Scarl * Returns true if the hardware is connected to the remote system 1489250079Scarl * 1490250079Scarl * RETURNS: true or false based on the hardware link state 1491250079Scarl */ 1492250079Scarlbool 1493250079Scarlntb_query_link_status(struct ntb_softc *ntb) 1494250079Scarl{ 1495250079Scarl 1496250079Scarl return (ntb->link_status == NTB_LINK_UP); 1497250079Scarl} 1498250079Scarl 1499255272Scarlstatic void 1500255272Scarlsave_bar_parameters(struct ntb_pci_bar_info *bar) 1501250079Scarl{ 1502255272Scarl 1503289209Scem bar->pci_bus_tag = rman_get_bustag(bar->pci_resource); 1504289209Scem bar->pci_bus_handle = rman_get_bushandle(bar->pci_resource); 1505289209Scem bar->pbase = rman_get_start(bar->pci_resource); 1506289209Scem bar->size = rman_get_size(bar->pci_resource); 1507289209Scem bar->vbase = rman_get_virtual(bar->pci_resource); 1508250079Scarl} 1509255268Scarl 1510289209Scemdevice_t 1511289209Scemntb_get_device(struct ntb_softc *ntb) 1512255268Scarl{ 1513255268Scarl 1514255268Scarl return (ntb->device); 1515255268Scarl} 1516289208Scem 1517289208Scem/* Export HW-specific errata information. */ 1518289208Scembool 1519289208Scemntb_has_feature(struct ntb_softc *ntb, uint64_t feature) 1520289208Scem{ 1521289208Scem 1522289208Scem return (HAS_FEATURE(feature)); 1523289208Scem} 1524