1366f6083SPeter Grehan /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 4366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 5366f6083SPeter Grehan * All rights reserved. 6366f6083SPeter Grehan * 7366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 8366f6083SPeter Grehan * modification, are permitted provided that the following conditions 9366f6083SPeter Grehan * are met: 10366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 12366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 13366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 14366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 15366f6083SPeter Grehan * 16366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26366f6083SPeter Grehan * SUCH DAMAGE. 27366f6083SPeter Grehan */ 28366f6083SPeter Grehan 29366f6083SPeter Grehan #ifndef _PCI_EMUL_H_ 30366f6083SPeter Grehan #define _PCI_EMUL_H_ 31366f6083SPeter Grehan 32366f6083SPeter Grehan #include <sys/types.h> 33366f6083SPeter Grehan #include <sys/queue.h> 34366f6083SPeter Grehan #include <sys/kernel.h> 35621b5090SJohn Baldwin #include <sys/nv.h> 36ffaed739SCorvin Köhne #include <sys/pciio.h> 373cbf3585SJohn Baldwin #include <sys/_pthreadtypes.h> 38366f6083SPeter Grehan 39366f6083SPeter Grehan #include <dev/pci/pcireg.h> 40366f6083SPeter Grehan 41366f6083SPeter Grehan #include <assert.h> 42366f6083SPeter Grehan 43*0efad4acSJessica Clarke #include "pci_irq.h" 44*0efad4acSJessica Clarke 45366f6083SPeter Grehan #define PCI_BARMAX PCIR_MAX_BAR_0 /* BAR registers in a Type 0 header */ 46e47fe318SCorvin Köhne #define PCI_BARMAX_WITH_ROM (PCI_BARMAX + 1) 47e47fe318SCorvin Köhne #define PCI_ROM_IDX (PCI_BARMAX + 1) 48366f6083SPeter Grehan 49366f6083SPeter Grehan struct vmctx; 50366f6083SPeter Grehan struct pci_devinst; 51cd942e0fSPeter Grehan struct memory_region; 52483d953aSJohn Baldwin struct vm_snapshot_meta; 53366f6083SPeter Grehan 54366f6083SPeter Grehan struct pci_devemu { 55d06bf11cSMark Johnston const char *pe_emu; /* Name of device emulation */ 56366f6083SPeter Grehan 57366f6083SPeter Grehan /* instance creation */ 586a284cacSJohn Baldwin int (*pe_init)(struct pci_devinst *, nvlist_t *); 59621b5090SJohn Baldwin int (*pe_legacy_config)(nvlist_t *, const char *); 60621b5090SJohn Baldwin const char *pe_alias; 61366f6083SPeter Grehan 62e6c8bc29SJohn Baldwin /* ACPI DSDT enumeration */ 63e6c8bc29SJohn Baldwin void (*pe_write_dsdt)(struct pci_devinst *); 64e6c8bc29SJohn Baldwin 65366f6083SPeter Grehan /* config space read/write callbacks */ 666a284cacSJohn Baldwin int (*pe_cfgwrite)(struct pci_devinst *pi, int offset, 67366f6083SPeter Grehan int bytes, uint32_t val); 686a284cacSJohn Baldwin int (*pe_cfgread)(struct pci_devinst *pi, int offset, 69366f6083SPeter Grehan int bytes, uint32_t *retval); 70366f6083SPeter Grehan 714d1e669cSPeter Grehan /* BAR read/write callbacks */ 726a284cacSJohn Baldwin void (*pe_barwrite)(struct pci_devinst *pi, int baridx, 734d1e669cSPeter Grehan uint64_t offset, int size, uint64_t value); 746a284cacSJohn Baldwin uint64_t (*pe_barread)(struct pci_devinst *pi, int baridx, 754d1e669cSPeter Grehan uint64_t offset, int size); 76483d953aSJohn Baldwin 776a284cacSJohn Baldwin void (*pe_baraddr)(struct pci_devinst *pi, 78f8a6ec2dSD Scott Phillips int baridx, int enabled, uint64_t address); 79f8a6ec2dSD Scott Phillips 80483d953aSJohn Baldwin /* Save/restore device state */ 81483d953aSJohn Baldwin int (*pe_snapshot)(struct vm_snapshot_meta *meta); 826a284cacSJohn Baldwin int (*pe_pause)(struct pci_devinst *pi); 836a284cacSJohn Baldwin int (*pe_resume)(struct pci_devinst *pi); 84621b5090SJohn Baldwin 85366f6083SPeter Grehan }; 861308a17bSElyes Haouas #define PCI_EMUL_SET(x) DATA_SET(pci_devemu_set, x) 87366f6083SPeter Grehan 88366f6083SPeter Grehan enum pcibar_type { 89366f6083SPeter Grehan PCIBAR_NONE, 90366f6083SPeter Grehan PCIBAR_IO, 91366f6083SPeter Grehan PCIBAR_MEM32, 92366f6083SPeter Grehan PCIBAR_MEM64, 93e47fe318SCorvin Köhne PCIBAR_MEMHI64, 94e47fe318SCorvin Köhne PCIBAR_ROM, 95366f6083SPeter Grehan }; 96366f6083SPeter Grehan 97366f6083SPeter Grehan struct pcibar { 98366f6083SPeter Grehan enum pcibar_type type; /* io or memory */ 99366f6083SPeter Grehan uint64_t size; 100366f6083SPeter Grehan uint64_t addr; 101e87a6f3eSCorvin Köhne uint8_t lobits; 102366f6083SPeter Grehan }; 103366f6083SPeter Grehan 104366f6083SPeter Grehan #define PI_NAMESZ 40 105366f6083SPeter Grehan 106cd942e0fSPeter Grehan struct msix_table_entry { 107cd942e0fSPeter Grehan uint64_t addr; 108cd942e0fSPeter Grehan uint32_t msg_data; 109cd942e0fSPeter Grehan uint32_t vector_control; 110cd942e0fSPeter Grehan } __packed; 111cd942e0fSPeter Grehan 112cd942e0fSPeter Grehan /* 113cd942e0fSPeter Grehan * In case the structure is modified to hold extra information, use a define 114cd942e0fSPeter Grehan * for the size that should be emulated. 115cd942e0fSPeter Grehan */ 116cd942e0fSPeter Grehan #define MSIX_TABLE_ENTRY_SIZE 16 117c9b4e987SNeel Natu #define MAX_MSIX_TABLE_ENTRIES 2048 1187a902ec0SNeel Natu #define PBA_SIZE(msgnum) (roundup2((msgnum), 64) / 8) 119cd942e0fSPeter Grehan 120366f6083SPeter Grehan struct pci_devinst { 121366f6083SPeter Grehan struct pci_devemu *pi_d; 122366f6083SPeter Grehan struct vmctx *pi_vmctx; 123366f6083SPeter Grehan uint8_t pi_bus, pi_slot, pi_func; 124366f6083SPeter Grehan char pi_name[PI_NAMESZ]; 125366f6083SPeter Grehan int pi_bar_getsize; 126a96b8b80SJohn Baldwin int pi_prevcap; 127a96b8b80SJohn Baldwin int pi_capend; 128366f6083SPeter Grehan 129366f6083SPeter Grehan struct { 1303cbf3585SJohn Baldwin int8_t pin; 13155c13f6eSMark Johnston enum { 13255c13f6eSMark Johnston IDLE, 13355c13f6eSMark Johnston ASSERTED, 13455c13f6eSMark Johnston PENDING, 13555c13f6eSMark Johnston } state; 136*0efad4acSJessica Clarke struct pci_irq irq; 1373cbf3585SJohn Baldwin pthread_mutex_t lock; 1383cbf3585SJohn Baldwin } pi_lintr; 1393cbf3585SJohn Baldwin 1403cbf3585SJohn Baldwin struct { 141366f6083SPeter Grehan int enabled; 1424f8be175SNeel Natu uint64_t addr; 1434f8be175SNeel Natu uint64_t msg_data; 1444f8be175SNeel Natu int maxmsgnum; 145366f6083SPeter Grehan } pi_msi; 146366f6083SPeter Grehan 147cd942e0fSPeter Grehan struct { 148cd942e0fSPeter Grehan int enabled; 149cd942e0fSPeter Grehan int table_bar; 150cd942e0fSPeter Grehan int pba_bar; 1517a902ec0SNeel Natu uint32_t table_offset; 152cd942e0fSPeter Grehan int table_count; 1537a902ec0SNeel Natu uint32_t pba_offset; 1547a902ec0SNeel Natu int pba_size; 155c9b4e987SNeel Natu int function_mask; 1562e81a7e8SNeel Natu struct msix_table_entry *table; /* allocated at runtime */ 1577fa23353SMark Johnston uint8_t *mapped_addr; 1587fa23353SMark Johnston size_t mapped_size; 159cd942e0fSPeter Grehan } pi_msix; 160cd942e0fSPeter Grehan 161366f6083SPeter Grehan void *pi_arg; /* devemu-private data */ 162366f6083SPeter Grehan 163366f6083SPeter Grehan u_char pi_cfgdata[PCI_REGMAX + 1]; 164e47fe318SCorvin Köhne /* ROM is handled like a BAR */ 165e47fe318SCorvin Köhne struct pcibar pi_bar[PCI_BARMAX_WITH_ROM + 1]; 166e47fe318SCorvin Köhne uint64_t pi_romoffset; 167366f6083SPeter Grehan }; 168366f6083SPeter Grehan 169366f6083SPeter Grehan struct msicap { 170366f6083SPeter Grehan uint8_t capid; 171366f6083SPeter Grehan uint8_t nextptr; 172366f6083SPeter Grehan uint16_t msgctrl; 173366f6083SPeter Grehan uint32_t addrlo; 174366f6083SPeter Grehan uint32_t addrhi; 175366f6083SPeter Grehan uint16_t msgdata; 176366f6083SPeter Grehan } __packed; 1777e12dfe5SEnji Cooper static_assert(sizeof(struct msicap) == 14, "compile-time assertion failed"); 178366f6083SPeter Grehan 179cd942e0fSPeter Grehan struct msixcap { 180cd942e0fSPeter Grehan uint8_t capid; 181cd942e0fSPeter Grehan uint8_t nextptr; 182cd942e0fSPeter Grehan uint16_t msgctrl; 1832e81a7e8SNeel Natu uint32_t table_info; /* bar index and offset within it */ 1842e81a7e8SNeel Natu uint32_t pba_info; /* bar index and offset within it */ 185cd942e0fSPeter Grehan } __packed; 1867e12dfe5SEnji Cooper static_assert(sizeof(struct msixcap) == 12, "compile-time assertion failed"); 187cd942e0fSPeter Grehan 18874f80b23SNeel Natu struct pciecap { 18974f80b23SNeel Natu uint8_t capid; 19074f80b23SNeel Natu uint8_t nextptr; 19174f80b23SNeel Natu uint16_t pcie_capabilities; 19274f80b23SNeel Natu 19374f80b23SNeel Natu uint32_t dev_capabilities; /* all devices */ 19474f80b23SNeel Natu uint16_t dev_control; 19574f80b23SNeel Natu uint16_t dev_status; 19674f80b23SNeel Natu 19774f80b23SNeel Natu uint32_t link_capabilities; /* devices with links */ 19874f80b23SNeel Natu uint16_t link_control; 19974f80b23SNeel Natu uint16_t link_status; 20074f80b23SNeel Natu 20174f80b23SNeel Natu uint32_t slot_capabilities; /* ports with slots */ 20274f80b23SNeel Natu uint16_t slot_control; 20374f80b23SNeel Natu uint16_t slot_status; 20474f80b23SNeel Natu 20574f80b23SNeel Natu uint16_t root_control; /* root ports */ 20674f80b23SNeel Natu uint16_t root_capabilities; 20774f80b23SNeel Natu uint32_t root_status; 20874f80b23SNeel Natu 20974f80b23SNeel Natu uint32_t dev_capabilities2; /* all devices */ 21074f80b23SNeel Natu uint16_t dev_control2; 21174f80b23SNeel Natu uint16_t dev_status2; 21274f80b23SNeel Natu 21374f80b23SNeel Natu uint32_t link_capabilities2; /* devices with links */ 21474f80b23SNeel Natu uint16_t link_control2; 21574f80b23SNeel Natu uint16_t link_status2; 21674f80b23SNeel Natu 21774f80b23SNeel Natu uint32_t slot_capabilities2; /* ports with slots */ 21874f80b23SNeel Natu uint16_t slot_control2; 21974f80b23SNeel Natu uint16_t slot_status2; 22074f80b23SNeel Natu } __packed; 2217e12dfe5SEnji Cooper static_assert(sizeof(struct pciecap) == 60, "compile-time assertion failed"); 22274f80b23SNeel Natu 223*0efad4acSJessica Clarke typedef void (*pci_lintr_cb)(int b, int s, int pin, struct pci_irq *irq, 224*0efad4acSJessica Clarke void *arg); 22555c13f6eSMark Johnston void pci_lintr_assert(struct pci_devinst *pi); 22655c13f6eSMark Johnston void pci_lintr_deassert(struct pci_devinst *pi); 22755c13f6eSMark Johnston void pci_lintr_request(struct pci_devinst *pi); 22855c13f6eSMark Johnston int pci_count_lintr(int bus); 22955c13f6eSMark Johnston void pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg); 2303cbf3585SJohn Baldwin 231a38e2a64SPeter Grehan int init_pci(struct vmctx *ctx); 2320038ee98SPeter Grehan void pci_callback(void); 233ffaed739SCorvin Köhne uint32_t pci_config_read_reg(const struct pcisel *host_sel, nvlist_t *nvl, 234ffaed739SCorvin Köhne uint32_t reg, uint8_t size, uint32_t def); 2354d1e669cSPeter Grehan int pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, 2360038ee98SPeter Grehan enum pcibar_type type, uint64_t size); 237e47fe318SCorvin Köhne int pci_emul_alloc_rom(struct pci_devinst *const pdi, const uint64_t size, 238e47fe318SCorvin Köhne void **const addr); 2396632a0a4SCorvin Köhne int pci_emul_add_boot_device(struct pci_devinst *const pi, 2406632a0a4SCorvin Köhne const int bootindex); 2410038ee98SPeter Grehan int pci_emul_add_msicap(struct pci_devinst *pi, int msgnum); 24274f80b23SNeel Natu int pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type); 24321368498SPeter Grehan void pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, 24421368498SPeter Grehan uint32_t val, uint8_t capoff, int capid); 24556282675SJohn Baldwin void pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old); 246366f6083SPeter Grehan void pci_generate_msi(struct pci_devinst *pi, int msgnum); 2474d1e669cSPeter Grehan void pci_generate_msix(struct pci_devinst *pi, int msgnum); 248366f6083SPeter Grehan int pci_msi_enabled(struct pci_devinst *pi); 2494d1e669cSPeter Grehan int pci_msix_enabled(struct pci_devinst *pi); 250aa12663fSNeel Natu int pci_msix_table_bar(struct pci_devinst *pi); 251aa12663fSNeel Natu int pci_msix_pba_bar(struct pci_devinst *pi); 2523dd79610SAlexander Motin int pci_msi_maxmsgnum(struct pci_devinst *pi); 253621b5090SJohn Baldwin int pci_parse_legacy_config(nvlist_t *nvl, const char *opt); 254d2bc4816SJohn Baldwin int pci_parse_slot(char *opt); 25575ce327aSMark Johnston void pci_print_supported_devices(void); 256366f6083SPeter Grehan void pci_populate_msicap(struct msicap *cap, int msgs, int nextptr); 257c9b4e987SNeel Natu int pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum); 258c9b4e987SNeel Natu int pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size, 259c9b4e987SNeel Natu uint64_t value); 260c9b4e987SNeel Natu uint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size); 261e6c8bc29SJohn Baldwin void pci_write_dsdt(void); 26212a6eb99SNeel Natu uint64_t pci_ecfg_base(void); 263b100acf2SNeel Natu int pci_bus_configured(int bus); 26455c13f6eSMark Johnston 265483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 266381ef27dSVitaliy Gusev struct pci_devinst *pci_next(const struct pci_devinst *cursor); 267483d953aSJohn Baldwin int pci_snapshot(struct vm_snapshot_meta *meta); 268381ef27dSVitaliy Gusev int pci_pause(struct pci_devinst *pdi); 269381ef27dSVitaliy Gusev int pci_resume(struct pci_devinst *pdi); 270483d953aSJohn Baldwin #endif 271366f6083SPeter Grehan 272366f6083SPeter Grehan static __inline void 273366f6083SPeter Grehan pci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val) 274366f6083SPeter Grehan { 275366f6083SPeter Grehan assert(offset <= PCI_REGMAX); 276366f6083SPeter Grehan *(uint8_t *)(pi->pi_cfgdata + offset) = val; 277366f6083SPeter Grehan } 278366f6083SPeter Grehan 279366f6083SPeter Grehan static __inline void 280366f6083SPeter Grehan pci_set_cfgdata16(struct pci_devinst *pi, int offset, uint16_t val) 281366f6083SPeter Grehan { 282366f6083SPeter Grehan assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0); 283366f6083SPeter Grehan *(uint16_t *)(pi->pi_cfgdata + offset) = val; 284366f6083SPeter Grehan } 285366f6083SPeter Grehan 286366f6083SPeter Grehan static __inline void 287366f6083SPeter Grehan pci_set_cfgdata32(struct pci_devinst *pi, int offset, uint32_t val) 288366f6083SPeter Grehan { 289366f6083SPeter Grehan assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0); 290366f6083SPeter Grehan *(uint32_t *)(pi->pi_cfgdata + offset) = val; 291366f6083SPeter Grehan } 292366f6083SPeter Grehan 293366f6083SPeter Grehan static __inline uint8_t 294366f6083SPeter Grehan pci_get_cfgdata8(struct pci_devinst *pi, int offset) 295366f6083SPeter Grehan { 296366f6083SPeter Grehan assert(offset <= PCI_REGMAX); 297366f6083SPeter Grehan return (*(uint8_t *)(pi->pi_cfgdata + offset)); 298366f6083SPeter Grehan } 299366f6083SPeter Grehan 300366f6083SPeter Grehan static __inline uint16_t 301366f6083SPeter Grehan pci_get_cfgdata16(struct pci_devinst *pi, int offset) 302366f6083SPeter Grehan { 303366f6083SPeter Grehan assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0); 304366f6083SPeter Grehan return (*(uint16_t *)(pi->pi_cfgdata + offset)); 305366f6083SPeter Grehan } 306366f6083SPeter Grehan 307366f6083SPeter Grehan static __inline uint32_t 308366f6083SPeter Grehan pci_get_cfgdata32(struct pci_devinst *pi, int offset) 309366f6083SPeter Grehan { 310366f6083SPeter Grehan assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0); 311366f6083SPeter Grehan return (*(uint32_t *)(pi->pi_cfgdata + offset)); 312366f6083SPeter Grehan } 313366f6083SPeter Grehan 314366f6083SPeter Grehan #endif /* _PCI_EMUL_H_ */ 315