1bf21cd93STycho Nightingale /*- 24c87aefeSPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 34c87aefeSPatrick Mooney * 4bf21cd93STycho Nightingale * Copyright (c) 2011 NetApp, Inc. 5bf21cd93STycho Nightingale * All rights reserved. 6bf21cd93STycho Nightingale * 7bf21cd93STycho Nightingale * Redistribution and use in source and binary forms, with or without 8bf21cd93STycho Nightingale * modification, are permitted provided that the following conditions 9bf21cd93STycho Nightingale * are met: 10bf21cd93STycho Nightingale * 1. Redistributions of source code must retain the above copyright 11bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer. 12bf21cd93STycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright 13bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer in the 14bf21cd93STycho Nightingale * documentation and/or other materials provided with the distribution. 15bf21cd93STycho Nightingale * 16bf21cd93STycho Nightingale * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17bf21cd93STycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18bf21cd93STycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19bf21cd93STycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20bf21cd93STycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21bf21cd93STycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22bf21cd93STycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23bf21cd93STycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24bf21cd93STycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25bf21cd93STycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26bf21cd93STycho Nightingale * SUCH DAMAGE. 27bf21cd93STycho Nightingale * 284c87aefeSPatrick Mooney * $FreeBSD$ 29bf21cd93STycho Nightingale */ 30b22a70abSPatrick Mooney /* 31b22a70abSPatrick Mooney * Copyright 2018 Joyent, Inc. 32b22a70abSPatrick Mooney */ 33bf21cd93STycho Nightingale 34bf21cd93STycho Nightingale #ifndef _PCI_EMUL_H_ 35bf21cd93STycho Nightingale #define _PCI_EMUL_H_ 36bf21cd93STycho Nightingale 37bf21cd93STycho Nightingale #include <sys/types.h> 38bf21cd93STycho Nightingale #include <sys/queue.h> 39bf21cd93STycho Nightingale #include <sys/kernel.h> 402b948146SAndy Fiddaman #include <sys/nv.h> 41bf21cd93STycho Nightingale #include <sys/_pthreadtypes.h> 42bf21cd93STycho Nightingale 43bf21cd93STycho Nightingale #include <dev/pci/pcireg.h> 44bf21cd93STycho Nightingale 45bf21cd93STycho Nightingale #include <assert.h> 46bf21cd93STycho Nightingale 47bf21cd93STycho Nightingale #define PCI_BARMAX PCIR_MAX_BAR_0 /* BAR registers in a Type 0 header */ 48*d7b72f7bSAndy Fiddaman #define PCI_BARMAX_WITH_ROM (PCI_BARMAX + 1) 49*d7b72f7bSAndy Fiddaman #define PCI_ROM_IDX (PCI_BARMAX + 1) 50bf21cd93STycho Nightingale 51bf21cd93STycho Nightingale struct vmctx; 52bf21cd93STycho Nightingale struct pci_devinst; 53bf21cd93STycho Nightingale struct memory_region; 54bf21cd93STycho Nightingale 55bf21cd93STycho Nightingale struct pci_devemu { 56bf21cd93STycho Nightingale char *pe_emu; /* Name of device emulation */ 57bf21cd93STycho Nightingale 58bf21cd93STycho Nightingale /* instance creation */ 59bf21cd93STycho Nightingale int (*pe_init)(struct vmctx *, struct pci_devinst *, 602b948146SAndy Fiddaman nvlist_t *); 612b948146SAndy Fiddaman int (*pe_legacy_config)(nvlist_t *, const char *); 622b948146SAndy Fiddaman const char *pe_alias; 63bf21cd93STycho Nightingale 64bf21cd93STycho Nightingale /* ACPI DSDT enumeration */ 65bf21cd93STycho Nightingale void (*pe_write_dsdt)(struct pci_devinst *); 66bf21cd93STycho Nightingale 67bf21cd93STycho Nightingale /* config space read/write callbacks */ 68bf21cd93STycho Nightingale int (*pe_cfgwrite)(struct vmctx *ctx, int vcpu, 69bf21cd93STycho Nightingale struct pci_devinst *pi, int offset, 70bf21cd93STycho Nightingale int bytes, uint32_t val); 71bf21cd93STycho Nightingale int (*pe_cfgread)(struct vmctx *ctx, int vcpu, 72bf21cd93STycho Nightingale struct pci_devinst *pi, int offset, 73bf21cd93STycho Nightingale int bytes, uint32_t *retval); 74bf21cd93STycho Nightingale 75bf21cd93STycho Nightingale /* BAR read/write callbacks */ 76bf21cd93STycho Nightingale void (*pe_barwrite)(struct vmctx *ctx, int vcpu, 77bf21cd93STycho Nightingale struct pci_devinst *pi, int baridx, 78bf21cd93STycho Nightingale uint64_t offset, int size, uint64_t value); 79bf21cd93STycho Nightingale uint64_t (*pe_barread)(struct vmctx *ctx, int vcpu, 80bf21cd93STycho Nightingale struct pci_devinst *pi, int baridx, 81bf21cd93STycho Nightingale uint64_t offset, int size); 82b22a70abSPatrick Mooney 832b948146SAndy Fiddaman void (*pe_baraddr)(struct vmctx *ctx, struct pci_devinst *pi, 842b948146SAndy Fiddaman int baridx, int enabled, uint64_t address); 85b22a70abSPatrick Mooney #ifndef __FreeBSD__ 86b22a70abSPatrick Mooney void (*pe_lintrupdate)(struct pci_devinst *pi); 87b22a70abSPatrick Mooney #endif /* __FreeBSD__ */ 88bf21cd93STycho Nightingale }; 892b948146SAndy Fiddaman 90bf21cd93STycho Nightingale #define PCI_EMUL_SET(x) DATA_SET(pci_devemu_set, x); 91bf21cd93STycho Nightingale 92bf21cd93STycho Nightingale enum pcibar_type { 93bf21cd93STycho Nightingale PCIBAR_NONE, 94bf21cd93STycho Nightingale PCIBAR_IO, 95bf21cd93STycho Nightingale PCIBAR_MEM32, 96bf21cd93STycho Nightingale PCIBAR_MEM64, 97*d7b72f7bSAndy Fiddaman PCIBAR_MEMHI64, 98*d7b72f7bSAndy Fiddaman PCIBAR_ROM, 99bf21cd93STycho Nightingale }; 100bf21cd93STycho Nightingale 101bf21cd93STycho Nightingale struct pcibar { 102bf21cd93STycho Nightingale enum pcibar_type type; /* io or memory */ 103bf21cd93STycho Nightingale uint64_t size; 104bf21cd93STycho Nightingale uint64_t addr; 1056dc98349SAndy Fiddaman uint8_t lobits; 106bf21cd93STycho Nightingale }; 107bf21cd93STycho Nightingale 108bf21cd93STycho Nightingale #define PI_NAMESZ 40 109bf21cd93STycho Nightingale 110bf21cd93STycho Nightingale struct msix_table_entry { 111bf21cd93STycho Nightingale uint64_t addr; 112bf21cd93STycho Nightingale uint32_t msg_data; 113bf21cd93STycho Nightingale uint32_t vector_control; 114bf21cd93STycho Nightingale } __packed; 115bf21cd93STycho Nightingale 1166dc98349SAndy Fiddaman /* 117bf21cd93STycho Nightingale * In case the structure is modified to hold extra information, use a define 118bf21cd93STycho Nightingale * for the size that should be emulated. 119bf21cd93STycho Nightingale */ 120bf21cd93STycho Nightingale #define MSIX_TABLE_ENTRY_SIZE 16 121bf21cd93STycho Nightingale #define MAX_MSIX_TABLE_ENTRIES 2048 122bf21cd93STycho Nightingale #define PBA_SIZE(msgnum) (roundup2((msgnum), 64) / 8) 123bf21cd93STycho Nightingale 124bf21cd93STycho Nightingale enum lintr_stat { 125bf21cd93STycho Nightingale IDLE, 126bf21cd93STycho Nightingale ASSERTED, 127bf21cd93STycho Nightingale PENDING 128bf21cd93STycho Nightingale }; 129bf21cd93STycho Nightingale 130bf21cd93STycho Nightingale struct pci_devinst { 131bf21cd93STycho Nightingale struct pci_devemu *pi_d; 132bf21cd93STycho Nightingale struct vmctx *pi_vmctx; 133bf21cd93STycho Nightingale uint8_t pi_bus, pi_slot, pi_func; 134bf21cd93STycho Nightingale char pi_name[PI_NAMESZ]; 135bf21cd93STycho Nightingale int pi_bar_getsize; 136bf21cd93STycho Nightingale int pi_prevcap; 137bf21cd93STycho Nightingale int pi_capend; 138bf21cd93STycho Nightingale 139bf21cd93STycho Nightingale struct { 140bf21cd93STycho Nightingale int8_t pin; 141bf21cd93STycho Nightingale enum lintr_stat state; 142bf21cd93STycho Nightingale int pirq_pin; 143bf21cd93STycho Nightingale int ioapic_irq; 144bf21cd93STycho Nightingale pthread_mutex_t lock; 145bf21cd93STycho Nightingale } pi_lintr; 146bf21cd93STycho Nightingale 147bf21cd93STycho Nightingale struct { 148bf21cd93STycho Nightingale int enabled; 149bf21cd93STycho Nightingale uint64_t addr; 150bf21cd93STycho Nightingale uint64_t msg_data; 151bf21cd93STycho Nightingale int maxmsgnum; 152bf21cd93STycho Nightingale } pi_msi; 153bf21cd93STycho Nightingale 154bf21cd93STycho Nightingale struct { 155bf21cd93STycho Nightingale int enabled; 156bf21cd93STycho Nightingale int table_bar; 157bf21cd93STycho Nightingale int pba_bar; 158bf21cd93STycho Nightingale uint32_t table_offset; 159bf21cd93STycho Nightingale int table_count; 160bf21cd93STycho Nightingale uint32_t pba_offset; 161bf21cd93STycho Nightingale int pba_size; 1626dc98349SAndy Fiddaman int function_mask; 163bf21cd93STycho Nightingale struct msix_table_entry *table; /* allocated at runtime */ 1644c87aefeSPatrick Mooney void *pba_page; 1654c87aefeSPatrick Mooney int pba_page_offset; 1666dc98349SAndy Fiddaman uint8_t *mapped_addr; 1676dc98349SAndy Fiddaman size_t mapped_size; 168bf21cd93STycho Nightingale } pi_msix; 169bf21cd93STycho Nightingale 170bf21cd93STycho Nightingale void *pi_arg; /* devemu-private data */ 171bf21cd93STycho Nightingale 172bf21cd93STycho Nightingale u_char pi_cfgdata[PCI_REGMAX + 1]; 173*d7b72f7bSAndy Fiddaman /* ROM is handled like a BAR */ 174*d7b72f7bSAndy Fiddaman struct pcibar pi_bar[PCI_BARMAX_WITH_ROM + 1]; 175*d7b72f7bSAndy Fiddaman uint64_t pi_romoffset; 176bf21cd93STycho Nightingale }; 177bf21cd93STycho Nightingale 178bf21cd93STycho Nightingale struct msicap { 179bf21cd93STycho Nightingale uint8_t capid; 180bf21cd93STycho Nightingale uint8_t nextptr; 181bf21cd93STycho Nightingale uint16_t msgctrl; 182bf21cd93STycho Nightingale uint32_t addrlo; 183bf21cd93STycho Nightingale uint32_t addrhi; 184bf21cd93STycho Nightingale uint16_t msgdata; 185bf21cd93STycho Nightingale } __packed; 1864c87aefeSPatrick Mooney static_assert(sizeof(struct msicap) == 14, "compile-time assertion failed"); 187bf21cd93STycho Nightingale 188bf21cd93STycho Nightingale struct msixcap { 189bf21cd93STycho Nightingale uint8_t capid; 190bf21cd93STycho Nightingale uint8_t nextptr; 191bf21cd93STycho Nightingale uint16_t msgctrl; 192bf21cd93STycho Nightingale uint32_t table_info; /* bar index and offset within it */ 193bf21cd93STycho Nightingale uint32_t pba_info; /* bar index and offset within it */ 194bf21cd93STycho Nightingale } __packed; 1954c87aefeSPatrick Mooney static_assert(sizeof(struct msixcap) == 12, "compile-time assertion failed"); 196bf21cd93STycho Nightingale 197bf21cd93STycho Nightingale struct pciecap { 198bf21cd93STycho Nightingale uint8_t capid; 199bf21cd93STycho Nightingale uint8_t nextptr; 200bf21cd93STycho Nightingale uint16_t pcie_capabilities; 201bf21cd93STycho Nightingale 202bf21cd93STycho Nightingale uint32_t dev_capabilities; /* all devices */ 203bf21cd93STycho Nightingale uint16_t dev_control; 204bf21cd93STycho Nightingale uint16_t dev_status; 205bf21cd93STycho Nightingale 206bf21cd93STycho Nightingale uint32_t link_capabilities; /* devices with links */ 207bf21cd93STycho Nightingale uint16_t link_control; 208bf21cd93STycho Nightingale uint16_t link_status; 209bf21cd93STycho Nightingale 210bf21cd93STycho Nightingale uint32_t slot_capabilities; /* ports with slots */ 211bf21cd93STycho Nightingale uint16_t slot_control; 212bf21cd93STycho Nightingale uint16_t slot_status; 213bf21cd93STycho Nightingale 214bf21cd93STycho Nightingale uint16_t root_control; /* root ports */ 215bf21cd93STycho Nightingale uint16_t root_capabilities; 216bf21cd93STycho Nightingale uint32_t root_status; 217bf21cd93STycho Nightingale 218bf21cd93STycho Nightingale uint32_t dev_capabilities2; /* all devices */ 219bf21cd93STycho Nightingale uint16_t dev_control2; 220bf21cd93STycho Nightingale uint16_t dev_status2; 221bf21cd93STycho Nightingale 222bf21cd93STycho Nightingale uint32_t link_capabilities2; /* devices with links */ 223bf21cd93STycho Nightingale uint16_t link_control2; 224bf21cd93STycho Nightingale uint16_t link_status2; 225bf21cd93STycho Nightingale 226bf21cd93STycho Nightingale uint32_t slot_capabilities2; /* ports with slots */ 227bf21cd93STycho Nightingale uint16_t slot_control2; 228bf21cd93STycho Nightingale uint16_t slot_status2; 229bf21cd93STycho Nightingale } __packed; 2304c87aefeSPatrick Mooney static_assert(sizeof(struct pciecap) == 60, "compile-time assertion failed"); 231bf21cd93STycho Nightingale 232bf21cd93STycho Nightingale typedef void (*pci_lintr_cb)(int b, int s, int pin, int pirq_pin, 233bf21cd93STycho Nightingale int ioapic_irq, void *arg); 234bf21cd93STycho Nightingale 235bf21cd93STycho Nightingale int init_pci(struct vmctx *ctx); 236bf21cd93STycho Nightingale void pci_callback(void); 237bf21cd93STycho Nightingale int pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, 238bf21cd93STycho Nightingale enum pcibar_type type, uint64_t size); 239*d7b72f7bSAndy Fiddaman int pci_emul_alloc_rom(struct pci_devinst *const pdi, const uint64_t size, 240*d7b72f7bSAndy Fiddaman void **const addr); 241bf21cd93STycho Nightingale int pci_emul_add_msicap(struct pci_devinst *pi, int msgnum); 242bf21cd93STycho Nightingale int pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type); 243154972afSPatrick Mooney void pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, 244154972afSPatrick Mooney uint32_t val, uint8_t capoff, int capid); 24584659b24SMichael Zeller void pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old); 246bf21cd93STycho Nightingale void pci_generate_msi(struct pci_devinst *pi, int msgnum); 247bf21cd93STycho Nightingale void pci_generate_msix(struct pci_devinst *pi, int msgnum); 248bf21cd93STycho Nightingale void pci_lintr_assert(struct pci_devinst *pi); 249bf21cd93STycho Nightingale void pci_lintr_deassert(struct pci_devinst *pi); 250bf21cd93STycho Nightingale void pci_lintr_request(struct pci_devinst *pi); 251bf21cd93STycho Nightingale int pci_msi_enabled(struct pci_devinst *pi); 252bf21cd93STycho Nightingale int pci_msix_enabled(struct pci_devinst *pi); 253bf21cd93STycho Nightingale int pci_msix_table_bar(struct pci_devinst *pi); 254bf21cd93STycho Nightingale int pci_msix_pba_bar(struct pci_devinst *pi); 2554c87aefeSPatrick Mooney int pci_msi_maxmsgnum(struct pci_devinst *pi); 2562b948146SAndy Fiddaman int pci_parse_legacy_config(nvlist_t *nvl, const char *opt); 257bf21cd93STycho Nightingale int pci_parse_slot(char *opt); 2584c87aefeSPatrick Mooney void pci_print_supported_devices(); 259bf21cd93STycho Nightingale void pci_populate_msicap(struct msicap *cap, int msgs, int nextptr); 260bf21cd93STycho Nightingale int pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum); 261bf21cd93STycho Nightingale int pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size, 262bf21cd93STycho Nightingale uint64_t value); 263bf21cd93STycho Nightingale uint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size); 264bf21cd93STycho Nightingale int pci_count_lintr(int bus); 265bf21cd93STycho Nightingale void pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg); 266bf21cd93STycho Nightingale void pci_write_dsdt(void); 267bf21cd93STycho Nightingale uint64_t pci_ecfg_base(void); 268bf21cd93STycho Nightingale int pci_bus_configured(int bus); 269bf21cd93STycho Nightingale 2706dc98349SAndy Fiddaman static __inline void 271bf21cd93STycho Nightingale pci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val) 272bf21cd93STycho Nightingale { 273bf21cd93STycho Nightingale assert(offset <= PCI_REGMAX); 274bf21cd93STycho Nightingale *(uint8_t *)(pi->pi_cfgdata + offset) = val; 275bf21cd93STycho Nightingale } 276bf21cd93STycho Nightingale 2776dc98349SAndy Fiddaman static __inline void 278bf21cd93STycho Nightingale pci_set_cfgdata16(struct pci_devinst *pi, int offset, uint16_t val) 279bf21cd93STycho Nightingale { 280bf21cd93STycho Nightingale assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0); 281bf21cd93STycho Nightingale *(uint16_t *)(pi->pi_cfgdata + offset) = val; 282bf21cd93STycho Nightingale } 283bf21cd93STycho Nightingale 2846dc98349SAndy Fiddaman static __inline void 285bf21cd93STycho Nightingale pci_set_cfgdata32(struct pci_devinst *pi, int offset, uint32_t val) 286bf21cd93STycho Nightingale { 287bf21cd93STycho Nightingale assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0); 288bf21cd93STycho Nightingale *(uint32_t *)(pi->pi_cfgdata + offset) = val; 289bf21cd93STycho Nightingale } 290bf21cd93STycho Nightingale 291bf21cd93STycho Nightingale static __inline uint8_t 292bf21cd93STycho Nightingale pci_get_cfgdata8(struct pci_devinst *pi, int offset) 293bf21cd93STycho Nightingale { 294bf21cd93STycho Nightingale assert(offset <= PCI_REGMAX); 295bf21cd93STycho Nightingale return (*(uint8_t *)(pi->pi_cfgdata + offset)); 296bf21cd93STycho Nightingale } 297bf21cd93STycho Nightingale 298bf21cd93STycho Nightingale static __inline uint16_t 299bf21cd93STycho Nightingale pci_get_cfgdata16(struct pci_devinst *pi, int offset) 300bf21cd93STycho Nightingale { 301bf21cd93STycho Nightingale assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0); 302bf21cd93STycho Nightingale return (*(uint16_t *)(pi->pi_cfgdata + offset)); 303bf21cd93STycho Nightingale } 304bf21cd93STycho Nightingale 305bf21cd93STycho Nightingale static __inline uint32_t 306bf21cd93STycho Nightingale pci_get_cfgdata32(struct pci_devinst *pi, int offset) 307bf21cd93STycho Nightingale { 308bf21cd93STycho Nightingale assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0); 309bf21cd93STycho Nightingale return (*(uint32_t *)(pi->pi_cfgdata + offset)); 310bf21cd93STycho Nightingale } 311bf21cd93STycho Nightingale 312bf21cd93STycho Nightingale #endif /* _PCI_EMUL_H_ */ 313