ntb_hw_intel.c revision 255274
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 255274 2013-09-05 23:00:59Z carl $"); 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> 38250079Scarl#include <vm/vm.h> 39250079Scarl#include <vm/pmap.h> 40250079Scarl#include <machine/bus.h> 41250079Scarl#include <machine/pmap.h> 42250079Scarl#include <machine/resource.h> 43250079Scarl#include <dev/pci/pcireg.h> 44250079Scarl#include <dev/pci/pcivar.h> 45250079Scarl 46250079Scarl#include "ntb_regs.h" 47250079Scarl#include "ntb_hw.h" 48250079Scarl 49250079Scarl/* 50250079Scarl * The Non-Transparent Bridge (NTB) is a device on some Intel processors that 51250079Scarl * allows you to connect two systems using a PCI-e link. 52250079Scarl * 53250079Scarl * This module contains the hardware abstraction layer for the NTB. It allows 54250079Scarl * you to send and recieve interrupts, map the memory windows and send and 55250079Scarl * receive messages in the scratch-pad registers. 56250079Scarl * 57250079Scarl * NOTE: Much of the code in this module is shared with Linux. Any patches may 58250079Scarl * be picked up and redistributed in Linux with a dual GPL/BSD license. 59250079Scarl */ 60250079Scarl 61250079Scarl#define NTB_CONFIG_BAR 0 62250079Scarl#define NTB_B2B_BAR_1 1 63250079Scarl#define NTB_B2B_BAR_2 2 64250079Scarl#define NTB_MAX_BARS 3 65250079Scarl#define NTB_MW_TO_BAR(mw) ((mw) + 1) 66250079Scarl 67250079Scarl#define MAX_MSIX_INTERRUPTS MAX(XEON_MAX_DB_BITS, SOC_MAX_DB_BITS) 68250079Scarl 69250079Scarl#define NTB_HB_TIMEOUT 1 /* second */ 70250079Scarl#define SOC_LINK_RECOVERY_TIME 500 71250079Scarl 72250079Scarl#define DEVICE2SOFTC(dev) ((struct ntb_softc *) device_get_softc(dev)) 73250079Scarl 74250079Scarlenum ntb_device_type { 75250079Scarl NTB_XEON, 76250079Scarl NTB_SOC 77250079Scarl}; 78250079Scarl 79255274Scarl/* Device features and workarounds */ 80255274Scarl#define HAS_FEATURE(feature) \ 81255274Scarl ((ntb->features & (feature)) != 0) 82255274Scarl 83255274Scarl#define NTB_BAR_SIZE_4K (1 << 0) 84255274Scarl#define NTB_REGS_THRU_MW (1 << 1) 85255274Scarl 86250079Scarlstruct ntb_hw_info { 87250079Scarl uint32_t device_id; 88255274Scarl const char *desc; 89250079Scarl enum ntb_device_type type; 90255274Scarl uint64_t features; 91250079Scarl}; 92250079Scarl 93250079Scarlstruct ntb_pci_bar_info { 94250079Scarl bus_space_tag_t pci_bus_tag; 95250079Scarl bus_space_handle_t pci_bus_handle; 96250079Scarl int pci_resource_id; 97250079Scarl struct resource *pci_resource; 98250079Scarl vm_paddr_t pbase; 99250079Scarl void *vbase; 100250079Scarl u_long size; 101250079Scarl}; 102250079Scarl 103250079Scarlstruct ntb_int_info { 104250079Scarl struct resource *res; 105250079Scarl int rid; 106250079Scarl void *tag; 107250079Scarl}; 108250079Scarl 109250079Scarlstruct ntb_db_cb { 110250079Scarl ntb_db_callback callback; 111250079Scarl unsigned int db_num; 112250079Scarl void *data; 113250079Scarl struct ntb_softc *ntb; 114250079Scarl}; 115250079Scarl 116250079Scarlstruct ntb_softc { 117250079Scarl device_t device; 118250079Scarl enum ntb_device_type type; 119255274Scarl uint64_t features; 120250079Scarl 121250079Scarl struct ntb_pci_bar_info bar_info[NTB_MAX_BARS]; 122250079Scarl struct ntb_int_info int_info[MAX_MSIX_INTERRUPTS]; 123250079Scarl uint32_t allocated_interrupts; 124250079Scarl 125250079Scarl struct callout heartbeat_timer; 126250079Scarl struct callout lr_timer; 127250079Scarl 128250079Scarl void *ntb_transport; 129250079Scarl ntb_event_callback event_cb; 130250079Scarl struct ntb_db_cb *db_cb; 131250079Scarl 132250079Scarl struct { 133250079Scarl uint32_t max_spads; 134250079Scarl uint32_t max_db_bits; 135250079Scarl uint32_t msix_cnt; 136250079Scarl } limits; 137250079Scarl struct { 138250079Scarl uint32_t pdb; 139250079Scarl uint32_t pdb_mask; 140250079Scarl uint32_t sdb; 141250079Scarl uint32_t sbar2_xlat; 142250079Scarl uint32_t sbar4_xlat; 143250079Scarl uint32_t spad_remote; 144250079Scarl uint32_t spad_local; 145250079Scarl uint32_t lnk_cntl; 146250079Scarl uint32_t lnk_stat; 147250079Scarl uint32_t spci_cmd; 148250079Scarl } reg_ofs; 149250079Scarl uint8_t conn_type; 150250079Scarl uint8_t dev_type; 151250079Scarl uint8_t bits_per_vector; 152250079Scarl uint8_t link_status; 153250079Scarl uint8_t link_width; 154250079Scarl uint8_t link_speed; 155250079Scarl}; 156250079Scarl 157250079Scarl#define ntb_reg_read(SIZE, offset) \ 158250079Scarl bus_space_read_ ## SIZE (ntb->bar_info[NTB_CONFIG_BAR].pci_bus_tag, \ 159250079Scarl ntb->bar_info[NTB_CONFIG_BAR].pci_bus_handle, (offset)) 160250079Scarl#define ntb_reg_write(SIZE, offset, val) \ 161250079Scarl bus_space_write_ ## SIZE (ntb->bar_info[NTB_CONFIG_BAR].pci_bus_tag, \ 162250079Scarl ntb->bar_info[NTB_CONFIG_BAR].pci_bus_handle, (offset), (val)) 163250079Scarl 164250079Scarl#define ntb_read_1(offset) ntb_reg_read(1, (offset)) 165250079Scarl#define ntb_read_2(offset) ntb_reg_read(2, (offset)) 166250079Scarl#define ntb_read_4(offset) ntb_reg_read(4, (offset)) 167250079Scarl#define ntb_read_8(offset) ntb_reg_read(8, (offset)) 168250079Scarl#define ntb_write_1(offset, val) ntb_reg_write(1, (offset), (val)) 169250079Scarl#define ntb_write_2(offset, val) ntb_reg_write(2, (offset), (val)) 170250079Scarl#define ntb_write_4(offset, val) ntb_reg_write(4, (offset), (val)) 171250079Scarl#define ntb_write_8(offset, val) ntb_reg_write(8, (offset), (val)) 172250079Scarl 173255272Scarltypedef int (*bar_map_strategy)(struct ntb_softc *ntb, 174255272Scarl struct ntb_pci_bar_info *bar); 175255272Scarl 176250079Scarlstatic int ntb_probe(device_t device); 177250079Scarlstatic int ntb_attach(device_t device); 178250079Scarlstatic int ntb_detach(device_t device); 179255272Scarlstatic int ntb_map_pci_bars(struct ntb_softc *ntb); 180255272Scarlstatic int map_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, 181255272Scarl struct ntb_pci_bar_info *bar); 182255272Scarlstatic int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar); 183255272Scarlstatic int map_memory_window_bar(struct ntb_softc *ntb, 184255272Scarl struct ntb_pci_bar_info *bar); 185250079Scarlstatic void ntb_unmap_pci_bar(struct ntb_softc *ntb); 186250079Scarlstatic int ntb_setup_interrupts(struct ntb_softc *ntb); 187250079Scarlstatic void ntb_teardown_interrupts(struct ntb_softc *ntb); 188250079Scarlstatic void handle_soc_irq(void *arg); 189250079Scarlstatic void handle_xeon_irq(void *arg); 190250079Scarlstatic void handle_xeon_event_irq(void *arg); 191250079Scarlstatic void ntb_handle_legacy_interrupt(void *arg); 192250079Scarlstatic int ntb_create_callbacks(struct ntb_softc *ntb, int num_vectors); 193250079Scarlstatic void ntb_free_callbacks(struct ntb_softc *ntb); 194250079Scarlstatic struct ntb_hw_info *ntb_get_device_info(uint32_t device_id); 195250079Scarlstatic int ntb_initialize_hw(struct ntb_softc *ntb); 196250079Scarlstatic int ntb_setup_xeon(struct ntb_softc *ntb); 197250079Scarlstatic int ntb_setup_soc(struct ntb_softc *ntb); 198250079Scarlstatic void ntb_handle_heartbeat(void *arg); 199250079Scarlstatic void ntb_handle_link_event(struct ntb_softc *ntb, int link_state); 200250079Scarlstatic void recover_soc_link(void *arg); 201250079Scarlstatic int ntb_check_link_status(struct ntb_softc *ntb); 202255274Scarlstatic void save_bar_parameters(struct ntb_pci_bar_info *bar); 203250079Scarl 204250079Scarlstatic struct ntb_hw_info pci_ids[] = { 205255274Scarl { 0x3C0D8086, "Xeon E5/Core i7 Non-Transparent Bridge B2B", NTB_XEON, 206255274Scarl NTB_REGS_THRU_MW }, 207255274Scarl { 0x0C4E8086, "Atom Processor S1200 NTB Primary B2B", NTB_SOC, 0 }, 208255274Scarl { 0x0E0D8086, "Xeon E5 V2 Non-Transparent Bridge B2B", NTB_XEON, 209255274Scarl NTB_REGS_THRU_MW | NTB_BAR_SIZE_4K }, 210255274Scarl { 0x00000000, NULL, NTB_SOC, 0 } 211250079Scarl}; 212250079Scarl 213250079Scarl/* 214250079Scarl * OS <-> Driver interface structures 215250079Scarl */ 216250079ScarlMALLOC_DEFINE(M_NTB, "ntb_hw", "ntb_hw driver memory allocations"); 217250079Scarl 218250079Scarlstatic device_method_t ntb_pci_methods[] = { 219250079Scarl /* Device interface */ 220250079Scarl DEVMETHOD(device_probe, ntb_probe), 221250079Scarl DEVMETHOD(device_attach, ntb_attach), 222250079Scarl DEVMETHOD(device_detach, ntb_detach), 223250079Scarl DEVMETHOD_END 224250079Scarl}; 225250079Scarl 226250079Scarlstatic driver_t ntb_pci_driver = { 227250079Scarl "ntb_hw", 228250079Scarl ntb_pci_methods, 229250079Scarl sizeof(struct ntb_softc), 230250079Scarl}; 231250079Scarl 232250079Scarlstatic devclass_t ntb_devclass; 233250079ScarlDRIVER_MODULE(ntb_hw, pci, ntb_pci_driver, ntb_devclass, NULL, NULL); 234250079ScarlMODULE_VERSION(ntb_hw, 1); 235250079Scarl 236250079Scarl/* 237250079Scarl * OS <-> Driver linkage functions 238250079Scarl */ 239250079Scarlstatic int 240250079Scarlntb_probe(device_t device) 241250079Scarl{ 242250079Scarl struct ntb_hw_info *p = ntb_get_device_info(pci_get_devid(device)); 243250079Scarl 244250079Scarl if (p != NULL) { 245250079Scarl device_set_desc(device, p->desc); 246250079Scarl return (0); 247250079Scarl } else 248250079Scarl return (ENXIO); 249250079Scarl} 250250079Scarl 251250079Scarl#define DETACH_ON_ERROR(func) \ 252250079Scarl error = func; \ 253250079Scarl if (error < 0) { \ 254250079Scarl ntb_detach(device); \ 255250079Scarl return (error); \ 256250079Scarl } 257250079Scarl 258250079Scarlstatic int 259250079Scarlntb_attach(device_t device) 260250079Scarl{ 261250079Scarl struct ntb_softc *ntb = DEVICE2SOFTC(device); 262250079Scarl struct ntb_hw_info *p = ntb_get_device_info(pci_get_devid(device)); 263250079Scarl int error; 264250079Scarl 265250079Scarl ntb->device = device; 266250079Scarl ntb->type = p->type; 267255274Scarl ntb->features = p->features; 268250079Scarl 269250079Scarl /* Heartbeat timer for NTB_SOC since there is no link interrupt */ 270250079Scarl callout_init(&ntb->heartbeat_timer, CALLOUT_MPSAFE); 271250079Scarl callout_init(&ntb->lr_timer, CALLOUT_MPSAFE); 272250079Scarl 273255272Scarl DETACH_ON_ERROR(ntb_map_pci_bars(ntb)); 274250079Scarl DETACH_ON_ERROR(ntb_initialize_hw(ntb)); 275250079Scarl DETACH_ON_ERROR(ntb_setup_interrupts(ntb)); 276250079Scarl 277250079Scarl pci_enable_busmaster(ntb->device); 278250079Scarl 279250079Scarl return (error); 280250079Scarl} 281250079Scarl 282250079Scarlstatic int 283250079Scarlntb_detach(device_t device) 284250079Scarl{ 285250079Scarl struct ntb_softc *ntb = DEVICE2SOFTC(device); 286250079Scarl 287250079Scarl callout_drain(&ntb->heartbeat_timer); 288250079Scarl callout_drain(&ntb->lr_timer); 289250079Scarl ntb_teardown_interrupts(ntb); 290250079Scarl ntb_unmap_pci_bar(ntb); 291250079Scarl 292250079Scarl return (0); 293250079Scarl} 294250079Scarl 295250079Scarlstatic int 296255272Scarlntb_map_pci_bars(struct ntb_softc *ntb) 297250079Scarl{ 298255272Scarl int rc; 299250079Scarl 300250079Scarl ntb->bar_info[NTB_CONFIG_BAR].pci_resource_id = PCIR_BAR(0); 301255272Scarl rc = map_pci_bar(ntb, map_mmr_bar, &ntb->bar_info[NTB_CONFIG_BAR]); 302255272Scarl if (rc != 0) 303255272Scarl return rc; 304255272Scarl 305250079Scarl ntb->bar_info[NTB_B2B_BAR_1].pci_resource_id = PCIR_BAR(2); 306255272Scarl rc = map_pci_bar(ntb, map_memory_window_bar, 307255272Scarl &ntb->bar_info[NTB_B2B_BAR_1]); 308255272Scarl if (rc != 0) 309255272Scarl return rc; 310255272Scarl 311250079Scarl ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4); 312255272Scarl rc = map_pci_bar(ntb, map_memory_window_bar, 313255272Scarl &ntb->bar_info[NTB_B2B_BAR_2]); 314255272Scarl if (rc != 0) 315255272Scarl return rc; 316255274Scarl 317255272Scarl return (0); 318255272Scarl} 319250079Scarl 320255272Scarlstatic int 321255272Scarlmap_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, 322255272Scarl struct ntb_pci_bar_info *bar) 323255272Scarl{ 324255272Scarl int rc; 325255272Scarl 326255272Scarl rc = strategy(ntb, bar); 327255272Scarl if (rc != 0) { 328255272Scarl device_printf(ntb->device, 329255272Scarl "unable to allocate pci resource\n"); 330255272Scarl } else { 331255272Scarl device_printf(ntb->device, 332255272Scarl "Bar size = %lx, v %p, p %p\n", 333255272Scarl bar->size, bar->vbase, 334255272Scarl (void *)(bar->pbase)); 335255272Scarl } 336255272Scarl return (rc); 337255272Scarl} 338255272Scarl 339255272Scarlstatic int 340255272Scarlmap_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) 341255272Scarl{ 342255272Scarl 343255272Scarl bar->pci_resource = bus_alloc_resource(ntb->device, SYS_RES_MEMORY, 344255272Scarl &bar->pci_resource_id, 0, ~0, 1, RF_ACTIVE); 345255272Scarl 346255272Scarl if (bar->pci_resource == NULL) 347255272Scarl return (ENXIO); 348255272Scarl else { 349255272Scarl save_bar_parameters(bar); 350255272Scarl return (0); 351255272Scarl } 352255272Scarl} 353255272Scarl 354255272Scarlstatic int 355255272Scarlmap_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) 356255272Scarl{ 357255272Scarl int rc; 358255272Scarl 359255272Scarl bar->pci_resource = bus_alloc_resource(ntb->device, 360255272Scarl SYS_RES_MEMORY, &bar->pci_resource_id, 0, ~0, 1, 361250079Scarl RF_ACTIVE); 362250079Scarl 363255272Scarl if (bar->pci_resource == NULL) 364255272Scarl return (ENXIO); 365255272Scarl else { 366255272Scarl save_bar_parameters(bar); 367255272Scarl /* Mark bar region as write combining to improve performance. */ 368255272Scarl rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size, 369255272Scarl VM_MEMATTR_WRITE_COMBINING); 370255272Scarl if (rc != 0) { 371255272Scarl device_printf(ntb->device, "unable to mark bar as" 372255272Scarl " WRITE_COMBINING\n"); 373255272Scarl return (rc); 374250079Scarl } 375250079Scarl } 376250079Scarl return (0); 377250079Scarl} 378250079Scarl 379250079Scarlstatic void 380250079Scarlntb_unmap_pci_bar(struct ntb_softc *ntb) 381250079Scarl{ 382250079Scarl struct ntb_pci_bar_info *current_bar; 383250079Scarl int i; 384250079Scarl 385250079Scarl for (i = 0; i< NTB_MAX_BARS; i++) { 386250079Scarl current_bar = &ntb->bar_info[i]; 387250079Scarl if (current_bar->pci_resource != NULL) 388250079Scarl bus_release_resource(ntb->device, SYS_RES_MEMORY, 389250079Scarl current_bar->pci_resource_id, 390250079Scarl current_bar->pci_resource); 391250079Scarl } 392250079Scarl} 393250079Scarl 394250079Scarlstatic int 395250079Scarlntb_setup_interrupts(struct ntb_softc *ntb) 396250079Scarl{ 397250079Scarl void (*interrupt_handler)(void *); 398250079Scarl void *int_arg; 399250079Scarl bool use_msix = 0; 400250079Scarl uint32_t num_vectors; 401250079Scarl int i; 402250079Scarl 403250079Scarl ntb->allocated_interrupts = 0; 404250079Scarl /* 405250079Scarl * On SOC, disable all interrupts. On XEON, disable all but Link 406250079Scarl * Interrupt. The rest will be unmasked as callbacks are registered. 407250079Scarl */ 408250079Scarl if (ntb->type == NTB_SOC) 409250079Scarl ntb_write_8(ntb->reg_ofs.pdb_mask, ~0); 410250079Scarl else 411250079Scarl ntb_write_2(ntb->reg_ofs.pdb_mask, 412250079Scarl ~(1 << ntb->limits.max_db_bits)); 413250079Scarl 414250079Scarl num_vectors = MIN(pci_msix_count(ntb->device), 415250079Scarl ntb->limits.max_db_bits); 416250079Scarl if (num_vectors >= 1) { 417250079Scarl pci_alloc_msix(ntb->device, &num_vectors); 418250079Scarl if (num_vectors >= 4) 419250079Scarl use_msix = TRUE; 420250079Scarl } 421250079Scarl 422250079Scarl ntb_create_callbacks(ntb, num_vectors); 423250079Scarl if (use_msix == TRUE) { 424250079Scarl for (i = 0; i < num_vectors; i++) { 425250079Scarl ntb->int_info[i].rid = i + 1; 426250079Scarl ntb->int_info[i].res = bus_alloc_resource_any( 427250079Scarl ntb->device, SYS_RES_IRQ, &ntb->int_info[i].rid, 428250079Scarl RF_ACTIVE); 429250079Scarl if (ntb->int_info[i].res == NULL) { 430250079Scarl device_printf(ntb->device, 431250079Scarl "bus_alloc_resource failed\n"); 432250079Scarl return (-1); 433250079Scarl } 434250079Scarl ntb->int_info[i].tag = NULL; 435250079Scarl ntb->allocated_interrupts++; 436250079Scarl if (ntb->type == NTB_SOC) { 437250079Scarl interrupt_handler = handle_soc_irq; 438250079Scarl int_arg = &ntb->db_cb[i]; 439250079Scarl } else { 440250079Scarl if (i == num_vectors - 1) { 441250079Scarl interrupt_handler = handle_xeon_event_irq; 442250079Scarl int_arg = ntb; 443250079Scarl } else { 444250079Scarl interrupt_handler = 445250079Scarl handle_xeon_irq; 446250079Scarl int_arg = &ntb->db_cb[i]; 447250079Scarl } 448250079Scarl } 449250079Scarl if (bus_setup_intr(ntb->device, ntb->int_info[i].res, 450250079Scarl INTR_MPSAFE | INTR_TYPE_MISC, NULL, 451250079Scarl interrupt_handler, int_arg, 452250079Scarl &ntb->int_info[i].tag) != 0) { 453250079Scarl device_printf(ntb->device, 454250079Scarl "bus_setup_intr failed\n"); 455250079Scarl return (ENXIO); 456250079Scarl } 457250079Scarl } 458250079Scarl } 459250079Scarl else { 460250079Scarl ntb->int_info[0].rid = 0; 461250079Scarl ntb->int_info[0].res = bus_alloc_resource_any(ntb->device, SYS_RES_IRQ, 462250079Scarl &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE); 463250079Scarl interrupt_handler = ntb_handle_legacy_interrupt; 464250079Scarl if (ntb->int_info[0].res == NULL) { 465250079Scarl device_printf(ntb->device, 466250079Scarl "bus_alloc_resource failed\n"); 467250079Scarl return (-1); 468250079Scarl } 469250079Scarl ntb->int_info[0].tag = NULL; 470250079Scarl ntb->allocated_interrupts = 1; 471250079Scarl 472250079Scarl if (bus_setup_intr(ntb->device, ntb->int_info[0].res, 473250079Scarl INTR_MPSAFE | INTR_TYPE_MISC, NULL, 474250079Scarl interrupt_handler, ntb, &ntb->int_info[0].tag) != 0) { 475250079Scarl 476250079Scarl device_printf(ntb->device, "bus_setup_intr failed\n"); 477250079Scarl return (ENXIO); 478250079Scarl } 479250079Scarl } 480250079Scarl 481250079Scarl return (0); 482250079Scarl} 483250079Scarl 484250079Scarlstatic void 485250079Scarlntb_teardown_interrupts(struct ntb_softc *ntb) 486250079Scarl{ 487250079Scarl struct ntb_int_info *current_int; 488250079Scarl int i; 489250079Scarl 490250079Scarl for (i=0; i<ntb->allocated_interrupts; i++) { 491250079Scarl current_int = &ntb->int_info[i]; 492250079Scarl if (current_int->tag != NULL) 493250079Scarl bus_teardown_intr(ntb->device, current_int->res, 494250079Scarl current_int->tag); 495250079Scarl 496250079Scarl if (current_int->res != NULL) 497250079Scarl bus_release_resource(ntb->device, SYS_RES_IRQ, 498250079Scarl rman_get_rid(current_int->res), current_int->res); 499250079Scarl } 500250079Scarl 501250079Scarl ntb_free_callbacks(ntb); 502250079Scarl pci_release_msi(ntb->device); 503250079Scarl} 504250079Scarl 505250079Scarlstatic void 506250079Scarlhandle_soc_irq(void *arg) 507250079Scarl{ 508250079Scarl struct ntb_db_cb *db_cb = arg; 509250079Scarl struct ntb_softc *ntb = db_cb->ntb; 510250079Scarl 511250079Scarl ntb_write_8(ntb->reg_ofs.pdb, (uint64_t) 1 << db_cb->db_num); 512250079Scarl 513250079Scarl if (db_cb->callback != NULL) 514250079Scarl db_cb->callback(db_cb->data, db_cb->db_num); 515250079Scarl} 516250079Scarl 517250079Scarlstatic void 518250079Scarlhandle_xeon_irq(void *arg) 519250079Scarl{ 520250079Scarl struct ntb_db_cb *db_cb = arg; 521250079Scarl struct ntb_softc *ntb = db_cb->ntb; 522250079Scarl 523250079Scarl /* 524250079Scarl * On Xeon, there are 16 bits in the interrupt register 525250079Scarl * but only 4 vectors. So, 5 bits are assigned to the first 3 526250079Scarl * vectors, with the 4th having a single bit for link 527250079Scarl * interrupts. 528250079Scarl */ 529250079Scarl ntb_write_2(ntb->reg_ofs.pdb, 530250079Scarl ((1 << ntb->bits_per_vector) - 1) << 531250079Scarl (db_cb->db_num * ntb->bits_per_vector)); 532250079Scarl 533250079Scarl if (db_cb->callback != NULL) 534250079Scarl db_cb->callback(db_cb->data, db_cb->db_num); 535250079Scarl} 536250079Scarl 537250079Scarl/* Since we do not have a HW doorbell in SOC, this is only used in JF/JT */ 538250079Scarlstatic void 539250079Scarlhandle_xeon_event_irq(void *arg) 540250079Scarl{ 541250079Scarl struct ntb_softc *ntb = arg; 542250079Scarl int rc; 543250079Scarl 544250079Scarl rc = ntb_check_link_status(ntb); 545250079Scarl if (rc != 0) 546250079Scarl device_printf(ntb->device, "Error determining link status\n"); 547250079Scarl 548250079Scarl /* bit 15 is always the link bit */ 549250079Scarl ntb_write_2(ntb->reg_ofs.pdb, 1 << ntb->limits.max_db_bits); 550250079Scarl} 551250079Scarl 552250079Scarlstatic void 553250079Scarlntb_handle_legacy_interrupt(void *arg) 554250079Scarl{ 555250079Scarl struct ntb_softc *ntb = arg; 556250079Scarl unsigned int i = 0; 557250079Scarl uint64_t pdb64; 558250079Scarl uint16_t pdb16; 559250079Scarl 560250079Scarl if (ntb->type == NTB_SOC) { 561250079Scarl pdb64 = ntb_read_8(ntb->reg_ofs.pdb); 562250079Scarl 563250079Scarl while (pdb64) { 564250079Scarl i = ffs(pdb64); 565250079Scarl pdb64 &= pdb64 - 1; 566250079Scarl handle_soc_irq(&ntb->db_cb[i]); 567250079Scarl } 568250079Scarl } else { 569250079Scarl pdb16 = ntb_read_2(ntb->reg_ofs.pdb); 570250079Scarl 571250079Scarl if ((pdb16 & XEON_DB_HW_LINK) != 0) { 572250079Scarl handle_xeon_event_irq(ntb); 573250079Scarl pdb16 &= ~XEON_DB_HW_LINK; 574250079Scarl } 575250079Scarl 576250079Scarl while (pdb16 != 0) { 577250079Scarl i = ffs(pdb16); 578250079Scarl pdb16 &= pdb16 - 1; 579250079Scarl handle_xeon_irq(&ntb->db_cb[i]); 580250079Scarl } 581250079Scarl } 582250079Scarl 583250079Scarl} 584250079Scarl 585250079Scarlstatic int 586250079Scarlntb_create_callbacks(struct ntb_softc *ntb, int num_vectors) 587250079Scarl{ 588250079Scarl int i; 589250079Scarl 590250079Scarl ntb->db_cb = malloc(num_vectors * sizeof(struct ntb_db_cb), M_NTB, 591250079Scarl M_ZERO | M_WAITOK); 592250079Scarl for (i = 0; i < num_vectors; i++) { 593250079Scarl ntb->db_cb[i].db_num = i; 594250079Scarl ntb->db_cb[i].ntb = ntb; 595250079Scarl } 596250079Scarl 597250079Scarl return (0); 598250079Scarl} 599250079Scarl 600250079Scarlstatic void 601250079Scarlntb_free_callbacks(struct ntb_softc *ntb) 602250079Scarl{ 603250079Scarl int i; 604250079Scarl 605250079Scarl for (i = 0; i < ntb->limits.max_db_bits; i++) 606250079Scarl ntb_unregister_db_callback(ntb, i); 607250079Scarl 608250079Scarl free(ntb->db_cb, M_NTB); 609250079Scarl} 610250079Scarl 611250079Scarlstatic struct ntb_hw_info * 612250079Scarlntb_get_device_info(uint32_t device_id) 613250079Scarl{ 614250079Scarl struct ntb_hw_info *ep = pci_ids; 615250079Scarl 616250079Scarl while (ep->device_id) { 617250079Scarl if (ep->device_id == device_id) 618250079Scarl return (ep); 619250079Scarl ++ep; 620250079Scarl } 621250079Scarl return (NULL); 622250079Scarl} 623250079Scarl 624250079Scarlstatic int 625250079Scarlntb_initialize_hw(struct ntb_softc *ntb) 626250079Scarl{ 627250079Scarl 628250079Scarl if (ntb->type == NTB_SOC) 629250079Scarl return (ntb_setup_soc(ntb)); 630250079Scarl else 631250079Scarl return (ntb_setup_xeon(ntb)); 632250079Scarl} 633250079Scarl 634250079Scarlstatic int 635250079Scarlntb_setup_xeon(struct ntb_softc *ntb) 636250079Scarl{ 637250079Scarl uint8_t val, connection_type; 638250079Scarl 639250079Scarl val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1); 640250079Scarl 641250079Scarl connection_type = val & XEON_PPD_CONN_TYPE; 642250079Scarl switch (connection_type) { 643250079Scarl case NTB_CONN_B2B: 644250079Scarl ntb->conn_type = NTB_CONN_B2B; 645250079Scarl break; 646250079Scarl case NTB_CONN_CLASSIC: 647250079Scarl case NTB_CONN_RP: 648250079Scarl default: 649250079Scarl device_printf(ntb->device, "Connection type %d not supported\n", 650250079Scarl connection_type); 651250079Scarl return (ENXIO); 652250079Scarl } 653250079Scarl 654250079Scarl if ((val & XEON_PPD_DEV_TYPE) != 0) 655250079Scarl ntb->dev_type = NTB_DEV_DSD; 656250079Scarl else 657250079Scarl ntb->dev_type = NTB_DEV_USD; 658250079Scarl 659250079Scarl ntb->reg_ofs.pdb = XEON_PDOORBELL_OFFSET; 660250079Scarl ntb->reg_ofs.pdb_mask = XEON_PDBMSK_OFFSET; 661250079Scarl ntb->reg_ofs.sbar2_xlat = XEON_SBAR2XLAT_OFFSET; 662250079Scarl ntb->reg_ofs.sbar4_xlat = XEON_SBAR4XLAT_OFFSET; 663250079Scarl ntb->reg_ofs.lnk_cntl = XEON_NTBCNTL_OFFSET; 664250079Scarl ntb->reg_ofs.lnk_stat = XEON_LINK_STATUS_OFFSET; 665250079Scarl ntb->reg_ofs.spad_local = XEON_SPAD_OFFSET; 666250079Scarl ntb->reg_ofs.spci_cmd = XEON_PCICMD_OFFSET; 667250079Scarl 668250079Scarl if (ntb->conn_type == NTB_CONN_B2B) { 669250079Scarl ntb->reg_ofs.sdb = XEON_B2B_DOORBELL_OFFSET; 670250079Scarl ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET; 671250079Scarl ntb->limits.max_spads = XEON_MAX_SPADS; 672250079Scarl } else { 673250079Scarl ntb->reg_ofs.sdb = XEON_SDOORBELL_OFFSET; 674250079Scarl ntb->reg_ofs.spad_remote = XEON_SPAD_OFFSET; 675250079Scarl ntb->limits.max_spads = XEON_MAX_COMPAT_SPADS; 676250079Scarl } 677250079Scarl 678250079Scarl ntb->limits.max_db_bits = XEON_MAX_DB_BITS; 679250079Scarl ntb->limits.msix_cnt = XEON_MSIX_CNT; 680250079Scarl ntb->bits_per_vector = XEON_DB_BITS_PER_VEC; 681250079Scarl 682250079Scarl /* Enable Bus Master and Memory Space on the secondary side */ 683250079Scarl ntb_write_2(ntb->reg_ofs.spci_cmd, 684250079Scarl PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 685255269Scarl 686255269Scarl /* Enable link training */ 687255269Scarl ntb_write_4(ntb->reg_ofs.lnk_cntl, 688255269Scarl NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP); 689250079Scarl 690250079Scarl return (0); 691250079Scarl} 692250079Scarl 693250079Scarlstatic int 694250079Scarlntb_setup_soc(struct ntb_softc *ntb) 695250079Scarl{ 696250079Scarl uint32_t val, connection_type; 697250079Scarl 698250079Scarl val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4); 699250079Scarl 700250079Scarl connection_type = (val & SOC_PPD_CONN_TYPE) >> 8; 701250079Scarl switch (connection_type) { 702250079Scarl case NTB_CONN_B2B: 703250079Scarl ntb->conn_type = NTB_CONN_B2B; 704250079Scarl break; 705250079Scarl case NTB_CONN_RP: 706250079Scarl default: 707250079Scarl device_printf(ntb->device, "Connection type %d not supported\n", 708250079Scarl connection_type); 709250079Scarl return (ENXIO); 710250079Scarl } 711250079Scarl 712250079Scarl if ((val & SOC_PPD_DEV_TYPE) != 0) 713250079Scarl ntb->dev_type = NTB_DEV_DSD; 714250079Scarl else 715250079Scarl ntb->dev_type = NTB_DEV_USD; 716250079Scarl 717250079Scarl /* Initiate PCI-E link training */ 718250079Scarl pci_write_config(ntb->device, NTB_PPD_OFFSET, val | SOC_PPD_INIT_LINK, 719250079Scarl 4); 720250079Scarl 721250079Scarl ntb->reg_ofs.pdb = SOC_PDOORBELL_OFFSET; 722250079Scarl ntb->reg_ofs.pdb_mask = SOC_PDBMSK_OFFSET; 723250079Scarl ntb->reg_ofs.sbar2_xlat = SOC_SBAR2XLAT_OFFSET; 724250079Scarl ntb->reg_ofs.sbar4_xlat = SOC_SBAR4XLAT_OFFSET; 725250079Scarl ntb->reg_ofs.lnk_cntl = SOC_NTBCNTL_OFFSET; 726250079Scarl ntb->reg_ofs.lnk_stat = SOC_LINK_STATUS_OFFSET; 727250079Scarl ntb->reg_ofs.spad_local = SOC_SPAD_OFFSET; 728250079Scarl ntb->reg_ofs.spci_cmd = SOC_PCICMD_OFFSET; 729250079Scarl 730250079Scarl if (ntb->conn_type == NTB_CONN_B2B) { 731250079Scarl ntb->reg_ofs.sdb = SOC_B2B_DOORBELL_OFFSET; 732250079Scarl ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET; 733250079Scarl ntb->limits.max_spads = SOC_MAX_SPADS; 734250079Scarl } else { 735250079Scarl ntb->reg_ofs.sdb = SOC_PDOORBELL_OFFSET; 736250079Scarl ntb->reg_ofs.spad_remote = SOC_SPAD_OFFSET; 737250079Scarl ntb->limits.max_spads = SOC_MAX_COMPAT_SPADS; 738250079Scarl } 739250079Scarl 740250079Scarl ntb->limits.max_db_bits = SOC_MAX_DB_BITS; 741250079Scarl ntb->limits.msix_cnt = SOC_MSIX_CNT; 742250079Scarl ntb->bits_per_vector = SOC_DB_BITS_PER_VEC; 743250079Scarl 744250079Scarl /* 745250079Scarl * FIXME - MSI-X bug on early SOC HW, remove once internal issue is 746250079Scarl * resolved. Mask transaction layer internal parity errors. 747250079Scarl */ 748250079Scarl pci_write_config(ntb->device, 0xFC, 0x4, 4); 749250079Scarl 750250079Scarl /* 751250079Scarl * Some BIOSes aren't filling out the XLAT offsets. 752250079Scarl * Check and correct the issue. 753250079Scarl */ 754250079Scarl if (ntb->dev_type == NTB_DEV_USD) { 755250079Scarl if (ntb_read_8(SOC_PBAR2XLAT_OFFSET) == 0) 756250079Scarl ntb_write_8(SOC_PBAR2XLAT_OFFSET, 757250079Scarl SOC_PBAR2XLAT_USD_ADDR); 758250079Scarl 759250079Scarl if (ntb_read_8(SOC_PBAR4XLAT_OFFSET) == 0) 760250079Scarl ntb_write_8(SOC_PBAR4XLAT_OFFSET, 761250079Scarl SOC_PBAR4XLAT_USD_ADDR); 762250079Scarl 763250079Scarl if (ntb_read_8(SOC_MBAR23_OFFSET) == 0xC) 764250079Scarl ntb_write_8(SOC_MBAR23_OFFSET, SOC_MBAR23_USD_ADDR); 765250079Scarl 766250079Scarl if (ntb_read_8(SOC_MBAR45_OFFSET) == 0xC) 767250079Scarl ntb_write_8(SOC_MBAR45_OFFSET, SOC_MBAR45_USD_ADDR); 768250079Scarl } else { 769250079Scarl if (ntb_read_8(SOC_PBAR2XLAT_OFFSET) == 0) 770250079Scarl ntb_write_8(SOC_PBAR2XLAT_OFFSET, 771250079Scarl SOC_PBAR2XLAT_DSD_ADDR); 772250079Scarl 773250079Scarl if (ntb_read_8(SOC_PBAR4XLAT_OFFSET) == 0) 774250079Scarl ntb_write_8(SOC_PBAR4XLAT_OFFSET, 775250079Scarl SOC_PBAR4XLAT_DSD_ADDR); 776250079Scarl 777250079Scarl if (ntb_read_8(SOC_MBAR23_OFFSET) == 0xC) 778250079Scarl ntb_write_8(SOC_MBAR23_OFFSET, SOC_MBAR23_DSD_ADDR); 779250079Scarl 780250079Scarl if (ntb_read_8(SOC_MBAR45_OFFSET) == 0xC) 781250079Scarl ntb_write_8(SOC_MBAR45_OFFSET, SOC_MBAR45_DSD_ADDR); 782250079Scarl } 783250079Scarl 784250079Scarl /* Enable Bus Master and Memory Space on the secondary side */ 785250079Scarl ntb_write_2(ntb->reg_ofs.spci_cmd, 786250079Scarl PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 787250079Scarl callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb); 788250079Scarl 789250079Scarl return (0); 790250079Scarl} 791250079Scarl 792250079Scarl/* SOC doesn't have link status interrupt, poll on that platform */ 793250079Scarlstatic void 794250079Scarlntb_handle_heartbeat(void *arg) 795250079Scarl{ 796250079Scarl struct ntb_softc *ntb = arg; 797250079Scarl uint32_t status32; 798250079Scarl int rc = ntb_check_link_status(ntb); 799250079Scarl 800250079Scarl if (rc != 0) 801250079Scarl device_printf(ntb->device, 802250079Scarl "Error determining link status\n"); 803250079Scarl /* Check to see if a link error is the cause of the link down */ 804250079Scarl if (ntb->link_status == NTB_LINK_DOWN) { 805250079Scarl status32 = ntb_read_4(SOC_LTSSMSTATEJMP_OFFSET); 806250079Scarl if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) { 807250079Scarl callout_reset(&ntb->lr_timer, 0, recover_soc_link, 808250079Scarl ntb); 809250079Scarl return; 810250079Scarl } 811250079Scarl } 812250079Scarl 813250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 814250079Scarl ntb_handle_heartbeat, ntb); 815250079Scarl} 816250079Scarl 817250079Scarlstatic void 818250079Scarlsoc_perform_link_restart(struct ntb_softc *ntb) 819250079Scarl{ 820250079Scarl uint32_t status; 821250079Scarl 822250079Scarl /* Driver resets the NTB ModPhy lanes - magic! */ 823250079Scarl ntb_write_1(SOC_MODPHY_PCSREG6, 0xe0); 824250079Scarl ntb_write_1(SOC_MODPHY_PCSREG4, 0x40); 825250079Scarl ntb_write_1(SOC_MODPHY_PCSREG4, 0x60); 826250079Scarl ntb_write_1(SOC_MODPHY_PCSREG6, 0x60); 827250079Scarl 828250079Scarl /* Driver waits 100ms to allow the NTB ModPhy to settle */ 829250079Scarl pause("ModPhy", hz / 10); 830250079Scarl 831250079Scarl /* Clear AER Errors, write to clear */ 832250079Scarl status = ntb_read_4(SOC_ERRCORSTS_OFFSET); 833250079Scarl status &= PCIM_AER_COR_REPLAY_ROLLOVER; 834250079Scarl ntb_write_4(SOC_ERRCORSTS_OFFSET, status); 835250079Scarl 836250079Scarl /* Clear unexpected electrical idle event in LTSSM, write to clear */ 837250079Scarl status = ntb_read_4(SOC_LTSSMERRSTS0_OFFSET); 838250079Scarl status |= SOC_LTSSMERRSTS0_UNEXPECTEDEI; 839250079Scarl ntb_write_4(SOC_LTSSMERRSTS0_OFFSET, status); 840250079Scarl 841250079Scarl /* Clear DeSkew Buffer error, write to clear */ 842250079Scarl status = ntb_read_4(SOC_DESKEWSTS_OFFSET); 843250079Scarl status |= SOC_DESKEWSTS_DBERR; 844250079Scarl ntb_write_4(SOC_DESKEWSTS_OFFSET, status); 845250079Scarl 846250079Scarl status = ntb_read_4(SOC_IBSTERRRCRVSTS0_OFFSET); 847250079Scarl status &= SOC_IBIST_ERR_OFLOW; 848250079Scarl ntb_write_4(SOC_IBSTERRRCRVSTS0_OFFSET, status); 849250079Scarl 850250079Scarl /* Releases the NTB state machine to allow the link to retrain */ 851250079Scarl status = ntb_read_4(SOC_LTSSMSTATEJMP_OFFSET); 852250079Scarl status &= ~SOC_LTSSMSTATEJMP_FORCEDETECT; 853250079Scarl ntb_write_4(SOC_LTSSMSTATEJMP_OFFSET, status); 854250079Scarl} 855250079Scarl 856250079Scarlstatic void 857250079Scarlntb_handle_link_event(struct ntb_softc *ntb, int link_state) 858250079Scarl{ 859250079Scarl enum ntb_hw_event event; 860250079Scarl uint16_t status; 861250079Scarl 862250079Scarl if (ntb->link_status == link_state) 863250079Scarl return; 864250079Scarl 865250079Scarl if (link_state == NTB_LINK_UP) { 866250079Scarl device_printf(ntb->device, "Link Up\n"); 867250079Scarl ntb->link_status = NTB_LINK_UP; 868250079Scarl event = NTB_EVENT_HW_LINK_UP; 869250079Scarl 870250079Scarl if (ntb->type == NTB_SOC) 871250079Scarl status = ntb_read_2(ntb->reg_ofs.lnk_stat); 872250079Scarl else 873250079Scarl status = pci_read_config(ntb->device, 874250079Scarl XEON_LINK_STATUS_OFFSET, 2); 875250079Scarl ntb->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; 876250079Scarl ntb->link_speed = (status & NTB_LINK_SPEED_MASK); 877250079Scarl device_printf(ntb->device, "Link Width %d, Link Speed %d\n", 878250079Scarl ntb->link_width, ntb->link_speed); 879250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 880250079Scarl ntb_handle_heartbeat, ntb); 881250079Scarl } else { 882250079Scarl device_printf(ntb->device, "Link Down\n"); 883250079Scarl ntb->link_status = NTB_LINK_DOWN; 884250079Scarl event = NTB_EVENT_HW_LINK_DOWN; 885250079Scarl /* Don't modify link width/speed, we need it in link recovery */ 886250079Scarl } 887250079Scarl 888250079Scarl /* notify the upper layer if we have an event change */ 889250079Scarl if (ntb->event_cb != NULL) 890250079Scarl ntb->event_cb(ntb->ntb_transport, event); 891250079Scarl} 892250079Scarl 893250079Scarlstatic void 894250079Scarlrecover_soc_link(void *arg) 895250079Scarl{ 896250079Scarl struct ntb_softc *ntb = arg; 897250079Scarl uint8_t speed, width; 898250079Scarl uint32_t status32; 899250079Scarl uint16_t status16; 900250079Scarl 901250079Scarl soc_perform_link_restart(ntb); 902250079Scarl pause("Link", SOC_LINK_RECOVERY_TIME * hz / 1000); 903250079Scarl 904250079Scarl status32 = ntb_read_4(SOC_LTSSMSTATEJMP_OFFSET); 905250079Scarl if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) 906250079Scarl goto retry; 907250079Scarl 908250079Scarl status32 = ntb_read_4(SOC_IBSTERRRCRVSTS0_OFFSET); 909250079Scarl if ((status32 & SOC_IBIST_ERR_OFLOW) != 0) 910250079Scarl goto retry; 911250079Scarl 912250079Scarl status16 = ntb_read_2(ntb->reg_ofs.lnk_stat); 913250079Scarl width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; 914250079Scarl speed = (status16 & NTB_LINK_SPEED_MASK); 915250079Scarl if (ntb->link_width != width || ntb->link_speed != speed) 916250079Scarl goto retry; 917250079Scarl 918250079Scarl callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, 919250079Scarl ntb_handle_heartbeat, ntb); 920250079Scarl return; 921250079Scarl 922250079Scarlretry: 923250079Scarl callout_reset(&ntb->lr_timer, NTB_HB_TIMEOUT * hz, recover_soc_link, 924250079Scarl ntb); 925250079Scarl} 926250079Scarl 927250079Scarlstatic int 928250079Scarlntb_check_link_status(struct ntb_softc *ntb) 929250079Scarl{ 930250079Scarl int link_state; 931250079Scarl uint32_t ntb_cntl; 932250079Scarl uint16_t status; 933250079Scarl 934250079Scarl if (ntb->type == NTB_SOC) { 935250079Scarl ntb_cntl = ntb_read_4(ntb->reg_ofs.lnk_cntl); 936250079Scarl if ((ntb_cntl & SOC_CNTL_LINK_DOWN) != 0) 937250079Scarl link_state = NTB_LINK_DOWN; 938250079Scarl else 939250079Scarl link_state = NTB_LINK_UP; 940250079Scarl } else { 941250079Scarl status = pci_read_config(ntb->device, XEON_LINK_STATUS_OFFSET, 942250079Scarl 2); 943250079Scarl 944250079Scarl if ((status & NTB_LINK_STATUS_ACTIVE) != 0) 945250079Scarl link_state = NTB_LINK_UP; 946250079Scarl else 947250079Scarl link_state = NTB_LINK_DOWN; 948250079Scarl } 949250079Scarl 950250079Scarl ntb_handle_link_event(ntb, link_state); 951250079Scarl 952250079Scarl return (0); 953250079Scarl} 954250079Scarl 955250079Scarl/** 956250079Scarl * ntb_register_event_callback() - register event callback 957250079Scarl * @ntb: pointer to ntb_softc instance 958250079Scarl * @func: callback function to register 959250079Scarl * 960250079Scarl * This function registers a callback for any HW driver events such as link 961250079Scarl * up/down, power management notices and etc. 962250079Scarl * 963250079Scarl * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 964250079Scarl */ 965250079Scarlint 966250079Scarlntb_register_event_callback(struct ntb_softc *ntb, ntb_event_callback func) 967250079Scarl{ 968250079Scarl 969250079Scarl if (ntb->event_cb != NULL) 970250079Scarl return (EINVAL); 971250079Scarl 972250079Scarl ntb->event_cb = func; 973250079Scarl 974250079Scarl return (0); 975250079Scarl} 976250079Scarl 977250079Scarl/** 978250079Scarl * ntb_unregister_event_callback() - unregisters the event callback 979250079Scarl * @ntb: pointer to ntb_softc instance 980250079Scarl * 981250079Scarl * This function unregisters the existing callback from transport 982250079Scarl */ 983250079Scarlvoid 984250079Scarlntb_unregister_event_callback(struct ntb_softc *ntb) 985250079Scarl{ 986250079Scarl 987250079Scarl ntb->event_cb = NULL; 988250079Scarl} 989250079Scarl 990250079Scarl/** 991250079Scarl * ntb_register_db_callback() - register a callback for doorbell interrupt 992250079Scarl * @ntb: pointer to ntb_softc instance 993250079Scarl * @idx: doorbell index to register callback, zero based 994250079Scarl * @func: callback function to register 995250079Scarl * 996250079Scarl * This function registers a callback function for the doorbell interrupt 997250079Scarl * on the primary side. The function will unmask the doorbell as well to 998250079Scarl * allow interrupt. 999250079Scarl * 1000250079Scarl * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 1001250079Scarl */ 1002250079Scarlint 1003250079Scarlntb_register_db_callback(struct ntb_softc *ntb, unsigned int idx, void *data, 1004250079Scarl ntb_db_callback func) 1005250079Scarl{ 1006250079Scarl uint16_t mask; 1007250079Scarl 1008250079Scarl if (idx >= ntb->allocated_interrupts || ntb->db_cb[idx].callback) { 1009250079Scarl device_printf(ntb->device, "Invalid Index.\n"); 1010250079Scarl return (EINVAL); 1011250079Scarl } 1012250079Scarl 1013250079Scarl ntb->db_cb[idx].callback = func; 1014250079Scarl ntb->db_cb[idx].data = data; 1015250079Scarl 1016250079Scarl /* unmask interrupt */ 1017250079Scarl mask = ntb_read_2(ntb->reg_ofs.pdb_mask); 1018250079Scarl mask &= ~(1 << (idx * ntb->bits_per_vector)); 1019250079Scarl ntb_write_2(ntb->reg_ofs.pdb_mask, mask); 1020250079Scarl 1021250079Scarl return (0); 1022250079Scarl} 1023250079Scarl 1024250079Scarl/** 1025250079Scarl * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt 1026250079Scarl * @ntb: pointer to ntb_softc instance 1027250079Scarl * @idx: doorbell index to register callback, zero based 1028250079Scarl * 1029250079Scarl * This function unregisters a callback function for the doorbell interrupt 1030250079Scarl * on the primary side. The function will also mask the said doorbell. 1031250079Scarl */ 1032250079Scarlvoid 1033250079Scarlntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx) 1034250079Scarl{ 1035250079Scarl unsigned long mask; 1036250079Scarl 1037250079Scarl if (idx >= ntb->allocated_interrupts || !ntb->db_cb[idx].callback) 1038250079Scarl return; 1039250079Scarl 1040250079Scarl mask = ntb_read_2(ntb->reg_ofs.pdb_mask); 1041250079Scarl mask |= 1 << (idx * ntb->bits_per_vector); 1042250079Scarl ntb_write_2(ntb->reg_ofs.pdb_mask, mask); 1043250079Scarl 1044250079Scarl ntb->db_cb[idx].callback = NULL; 1045250079Scarl} 1046250079Scarl 1047250079Scarl/** 1048250079Scarl * ntb_find_transport() - find the transport pointer 1049250079Scarl * @transport: pointer to pci device 1050250079Scarl * 1051250079Scarl * Given the pci device pointer, return the transport pointer passed in when 1052250079Scarl * the transport attached when it was inited. 1053250079Scarl * 1054250079Scarl * RETURNS: pointer to transport. 1055250079Scarl */ 1056250079Scarlvoid * 1057250079Scarlntb_find_transport(struct ntb_softc *ntb) 1058250079Scarl{ 1059250079Scarl 1060250079Scarl return (ntb->ntb_transport); 1061250079Scarl} 1062250079Scarl 1063250079Scarl/** 1064250079Scarl * ntb_register_transport() - Register NTB transport with NTB HW driver 1065250079Scarl * @transport: transport identifier 1066250079Scarl * 1067250079Scarl * This function allows a transport to reserve the hardware driver for 1068250079Scarl * NTB usage. 1069250079Scarl * 1070250079Scarl * RETURNS: pointer to ntb_softc, NULL on error. 1071250079Scarl */ 1072250079Scarlstruct ntb_softc * 1073250079Scarlntb_register_transport(struct ntb_softc *ntb, void *transport) 1074250079Scarl{ 1075250079Scarl 1076250079Scarl /* 1077250079Scarl * TODO: when we have more than one transport, we will need to rewrite 1078250079Scarl * this to prevent race conditions 1079250079Scarl */ 1080250079Scarl if (ntb->ntb_transport != NULL) 1081250079Scarl return (NULL); 1082250079Scarl 1083250079Scarl ntb->ntb_transport = transport; 1084250079Scarl return (ntb); 1085250079Scarl} 1086250079Scarl 1087250079Scarl/** 1088250079Scarl * ntb_unregister_transport() - Unregister the transport with the NTB HW driver 1089250079Scarl * @ntb - ntb_softc of the transport to be freed 1090250079Scarl * 1091250079Scarl * This function unregisters the transport from the HW driver and performs any 1092250079Scarl * necessary cleanups. 1093250079Scarl */ 1094250079Scarlvoid 1095250079Scarlntb_unregister_transport(struct ntb_softc *ntb) 1096250079Scarl{ 1097250079Scarl int i; 1098250079Scarl 1099250079Scarl if (ntb->ntb_transport == NULL) 1100250079Scarl return; 1101250079Scarl 1102250079Scarl for (i = 0; i < ntb->allocated_interrupts; i++) 1103250079Scarl ntb_unregister_db_callback(ntb, i); 1104250079Scarl 1105250079Scarl ntb_unregister_event_callback(ntb); 1106250079Scarl ntb->ntb_transport = NULL; 1107250079Scarl} 1108250079Scarl 1109250079Scarl/** 1110250079Scarl * ntb_get_max_spads() - get the total scratch regs usable 1111250079Scarl * @ntb: pointer to ntb_softc instance 1112250079Scarl * 1113250079Scarl * This function returns the max 32bit scratchpad registers usable by the 1114250079Scarl * upper layer. 1115250079Scarl * 1116250079Scarl * RETURNS: total number of scratch pad registers available 1117250079Scarl */ 1118250079Scarlint 1119250079Scarlntb_get_max_spads(struct ntb_softc *ntb) 1120250079Scarl{ 1121250079Scarl 1122250079Scarl return (ntb->limits.max_spads); 1123250079Scarl} 1124250079Scarl 1125250079Scarl/** 1126250079Scarl * ntb_write_local_spad() - write to the secondary scratchpad register 1127250079Scarl * @ntb: pointer to ntb_softc instance 1128250079Scarl * @idx: index to the scratchpad register, 0 based 1129250079Scarl * @val: the data value to put into the register 1130250079Scarl * 1131250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad 1132250079Scarl * register. The register resides on the secondary (external) side. 1133250079Scarl * 1134250079Scarl * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 1135250079Scarl */ 1136250079Scarlint 1137250079Scarlntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) 1138250079Scarl{ 1139250079Scarl 1140250079Scarl if (idx >= ntb->limits.max_spads) 1141250079Scarl return (EINVAL); 1142250079Scarl 1143250079Scarl ntb_write_4(ntb->reg_ofs.spad_local + idx * 4, val); 1144250079Scarl 1145250079Scarl return (0); 1146250079Scarl} 1147250079Scarl 1148250079Scarl/** 1149250079Scarl * ntb_read_local_spad() - read from the primary scratchpad register 1150250079Scarl * @ntb: pointer to ntb_softc instance 1151250079Scarl * @idx: index to scratchpad register, 0 based 1152250079Scarl * @val: pointer to 32bit integer for storing the register value 1153250079Scarl * 1154250079Scarl * This function allows reading of the 32bit scratchpad register on 1155250079Scarl * the primary (internal) side. 1156250079Scarl * 1157250079Scarl * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 1158250079Scarl */ 1159250079Scarlint 1160250079Scarlntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) 1161250079Scarl{ 1162250079Scarl 1163250079Scarl if (idx >= ntb->limits.max_spads) 1164250079Scarl return (EINVAL); 1165250079Scarl 1166250079Scarl *val = ntb_read_4(ntb->reg_ofs.spad_local + idx * 4); 1167250079Scarl 1168250079Scarl return (0); 1169250079Scarl} 1170250079Scarl 1171250079Scarl/** 1172250079Scarl * ntb_write_remote_spad() - write to the secondary scratchpad register 1173250079Scarl * @ntb: pointer to ntb_softc instance 1174250079Scarl * @idx: index to the scratchpad register, 0 based 1175250079Scarl * @val: the data value to put into the register 1176250079Scarl * 1177250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad 1178250079Scarl * register. The register resides on the secondary (external) side. 1179250079Scarl * 1180250079Scarl * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 1181250079Scarl */ 1182250079Scarlint 1183250079Scarlntb_write_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) 1184250079Scarl{ 1185250079Scarl 1186250079Scarl if (idx >= ntb->limits.max_spads) 1187250079Scarl return (EINVAL); 1188250079Scarl 1189250079Scarl ntb_write_4(ntb->reg_ofs.spad_remote + idx * 4, val); 1190250079Scarl 1191250079Scarl return (0); 1192250079Scarl} 1193250079Scarl 1194250079Scarl/** 1195250079Scarl * ntb_read_remote_spad() - read from the primary scratchpad register 1196250079Scarl * @ntb: pointer to ntb_softc instance 1197250079Scarl * @idx: index to scratchpad register, 0 based 1198250079Scarl * @val: pointer to 32bit integer for storing the register value 1199250079Scarl * 1200250079Scarl * This function allows reading of the 32bit scratchpad register on 1201250079Scarl * the primary (internal) side. 1202250079Scarl * 1203250079Scarl * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 1204250079Scarl */ 1205250079Scarlint 1206250079Scarlntb_read_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) 1207250079Scarl{ 1208250079Scarl 1209250079Scarl if (idx >= ntb->limits.max_spads) 1210250079Scarl return (EINVAL); 1211250079Scarl 1212250079Scarl *val = ntb_read_4(ntb->reg_ofs.spad_remote + idx * 4); 1213250079Scarl 1214250079Scarl return (0); 1215250079Scarl} 1216250079Scarl 1217250079Scarl/** 1218250079Scarl * ntb_get_mw_vbase() - get virtual addr for the NTB memory window 1219250079Scarl * @ntb: pointer to ntb_softc instance 1220250079Scarl * @mw: memory window number 1221250079Scarl * 1222250079Scarl * This function provides the base virtual address of the memory window 1223250079Scarl * specified. 1224250079Scarl * 1225250079Scarl * RETURNS: pointer to virtual address, or NULL on error. 1226250079Scarl */ 1227250079Scarlvoid * 1228250079Scarlntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw) 1229250079Scarl{ 1230250079Scarl 1231250079Scarl if (mw >= NTB_NUM_MW) 1232250079Scarl return (NULL); 1233250079Scarl 1234250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].vbase); 1235250079Scarl} 1236250079Scarl 1237250079Scarlvm_paddr_t 1238250079Scarlntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw) 1239250079Scarl{ 1240250079Scarl 1241250079Scarl if (mw >= NTB_NUM_MW) 1242250079Scarl return (0); 1243250079Scarl 1244250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].pbase); 1245250079Scarl} 1246250079Scarl 1247250079Scarl/** 1248250079Scarl * ntb_get_mw_size() - return size of NTB memory window 1249250079Scarl * @ntb: pointer to ntb_softc instance 1250250079Scarl * @mw: memory window number 1251250079Scarl * 1252250079Scarl * This function provides the physical size of the memory window specified 1253250079Scarl * 1254250079Scarl * RETURNS: the size of the memory window or zero on error 1255250079Scarl */ 1256250079Scarlu_long 1257250079Scarlntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw) 1258250079Scarl{ 1259250079Scarl 1260250079Scarl if (mw >= NTB_NUM_MW) 1261250079Scarl return (0); 1262250079Scarl 1263250079Scarl return (ntb->bar_info[NTB_MW_TO_BAR(mw)].size); 1264250079Scarl} 1265250079Scarl 1266250079Scarl/** 1267250079Scarl * ntb_set_mw_addr - set the memory window address 1268250079Scarl * @ntb: pointer to ntb_softc instance 1269250079Scarl * @mw: memory window number 1270250079Scarl * @addr: base address for data 1271250079Scarl * 1272250079Scarl * This function sets the base physical address of the memory window. This 1273250079Scarl * memory address is where data from the remote system will be transfered into 1274250079Scarl * or out of depending on how the transport is configured. 1275250079Scarl */ 1276250079Scarlvoid 1277250079Scarlntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr) 1278250079Scarl{ 1279250079Scarl 1280250079Scarl if (mw >= NTB_NUM_MW) 1281250079Scarl return; 1282250079Scarl 1283250079Scarl switch (NTB_MW_TO_BAR(mw)) { 1284250079Scarl case NTB_B2B_BAR_1: 1285250079Scarl ntb_write_8(ntb->reg_ofs.sbar2_xlat, addr); 1286250079Scarl break; 1287250079Scarl case NTB_B2B_BAR_2: 1288250079Scarl ntb_write_8(ntb->reg_ofs.sbar4_xlat, addr); 1289250079Scarl break; 1290250079Scarl } 1291250079Scarl} 1292250079Scarl 1293250079Scarl/** 1294250079Scarl * ntb_ring_sdb() - Set the doorbell on the secondary/external side 1295250079Scarl * @ntb: pointer to ntb_softc instance 1296250079Scarl * @db: doorbell to ring 1297250079Scarl * 1298250079Scarl * This function allows triggering of a doorbell on the secondary/external 1299250079Scarl * side that will initiate an interrupt on the remote host 1300250079Scarl * 1301250079Scarl * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 1302250079Scarl */ 1303250079Scarlvoid 1304250079Scarlntb_ring_sdb(struct ntb_softc *ntb, unsigned int db) 1305250079Scarl{ 1306250079Scarl 1307250079Scarl if (ntb->type == NTB_SOC) 1308250079Scarl ntb_write_8(ntb->reg_ofs.sdb, (uint64_t) 1 << db); 1309250079Scarl else 1310250079Scarl ntb_write_2(ntb->reg_ofs.sdb, 1311250079Scarl ((1 << ntb->bits_per_vector) - 1) << 1312250079Scarl (db * ntb->bits_per_vector)); 1313250079Scarl} 1314250079Scarl 1315250079Scarl/** 1316250079Scarl * ntb_query_link_status() - return the hardware link status 1317250079Scarl * @ndev: pointer to ntb_device instance 1318250079Scarl * 1319250079Scarl * Returns true if the hardware is connected to the remote system 1320250079Scarl * 1321250079Scarl * RETURNS: true or false based on the hardware link state 1322250079Scarl */ 1323250079Scarlbool 1324250079Scarlntb_query_link_status(struct ntb_softc *ntb) 1325250079Scarl{ 1326250079Scarl 1327250079Scarl return (ntb->link_status == NTB_LINK_UP); 1328250079Scarl} 1329250079Scarl 1330255272Scarlstatic void 1331255272Scarlsave_bar_parameters(struct ntb_pci_bar_info *bar) 1332250079Scarl{ 1333255272Scarl bar->pci_bus_tag = 1334255272Scarl rman_get_bustag(bar->pci_resource); 1335255272Scarl bar->pci_bus_handle = 1336255272Scarl rman_get_bushandle(bar->pci_resource); 1337255272Scarl bar->pbase = 1338255272Scarl rman_get_start(bar->pci_resource); 1339255272Scarl bar->size = 1340255272Scarl rman_get_size(bar->pci_resource); 1341255272Scarl bar->vbase = 1342255272Scarl rman_get_virtual(bar->pci_resource); 1343255272Scarl 1344250079Scarl} 1345255268Scarl 1346255268Scarldevice_t ntb_get_device(struct ntb_softc *ntb) 1347255268Scarl{ 1348255268Scarl 1349255268Scarl return (ntb->device); 1350255268Scarl} 1351