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> 40bf21cd93STycho Nightingale #include <sys/_pthreadtypes.h> 41bf21cd93STycho Nightingale 42bf21cd93STycho Nightingale #include <dev/pci/pcireg.h> 43bf21cd93STycho Nightingale 44bf21cd93STycho Nightingale #include <assert.h> 45bf21cd93STycho Nightingale 46bf21cd93STycho Nightingale #define PCI_BARMAX PCIR_MAX_BAR_0 /* BAR registers in a Type 0 header */ 47bf21cd93STycho Nightingale 48bf21cd93STycho Nightingale struct vmctx; 49bf21cd93STycho Nightingale struct pci_devinst; 50bf21cd93STycho Nightingale struct memory_region; 51bf21cd93STycho Nightingale 52bf21cd93STycho Nightingale struct pci_devemu { 53bf21cd93STycho Nightingale char *pe_emu; /* Name of device emulation */ 54bf21cd93STycho Nightingale 55bf21cd93STycho Nightingale /* instance creation */ 56bf21cd93STycho Nightingale int (*pe_init)(struct vmctx *, struct pci_devinst *, 57bf21cd93STycho Nightingale char *opts); 58bf21cd93STycho Nightingale 59bf21cd93STycho Nightingale /* ACPI DSDT enumeration */ 60bf21cd93STycho Nightingale void (*pe_write_dsdt)(struct pci_devinst *); 61bf21cd93STycho Nightingale 62bf21cd93STycho Nightingale /* config space read/write callbacks */ 63bf21cd93STycho Nightingale int (*pe_cfgwrite)(struct vmctx *ctx, int vcpu, 64bf21cd93STycho Nightingale struct pci_devinst *pi, int offset, 65bf21cd93STycho Nightingale int bytes, uint32_t val); 66bf21cd93STycho Nightingale int (*pe_cfgread)(struct vmctx *ctx, int vcpu, 67bf21cd93STycho Nightingale struct pci_devinst *pi, int offset, 68bf21cd93STycho Nightingale int bytes, uint32_t *retval); 69bf21cd93STycho Nightingale 70bf21cd93STycho Nightingale /* BAR read/write callbacks */ 71bf21cd93STycho Nightingale void (*pe_barwrite)(struct vmctx *ctx, int vcpu, 72bf21cd93STycho Nightingale struct pci_devinst *pi, int baridx, 73bf21cd93STycho Nightingale uint64_t offset, int size, uint64_t value); 74bf21cd93STycho Nightingale uint64_t (*pe_barread)(struct vmctx *ctx, int vcpu, 75bf21cd93STycho Nightingale struct pci_devinst *pi, int baridx, 76bf21cd93STycho Nightingale uint64_t offset, int size); 77b22a70abSPatrick Mooney 78b22a70abSPatrick Mooney #ifndef __FreeBSD__ 79b22a70abSPatrick Mooney void (*pe_lintrupdate)(struct pci_devinst *pi); 80b22a70abSPatrick Mooney #endif /* __FreeBSD__ */ 81bf21cd93STycho Nightingale }; 82bf21cd93STycho Nightingale #define PCI_EMUL_SET(x) DATA_SET(pci_devemu_set, x); 83bf21cd93STycho Nightingale 84bf21cd93STycho Nightingale enum pcibar_type { 85bf21cd93STycho Nightingale PCIBAR_NONE, 86bf21cd93STycho Nightingale PCIBAR_IO, 87bf21cd93STycho Nightingale PCIBAR_MEM32, 88bf21cd93STycho Nightingale PCIBAR_MEM64, 89bf21cd93STycho Nightingale PCIBAR_MEMHI64 90bf21cd93STycho Nightingale }; 91bf21cd93STycho Nightingale 92bf21cd93STycho Nightingale struct pcibar { 93bf21cd93STycho Nightingale enum pcibar_type type; /* io or memory */ 94bf21cd93STycho Nightingale uint64_t size; 95bf21cd93STycho Nightingale uint64_t addr; 96bf21cd93STycho Nightingale }; 97bf21cd93STycho Nightingale 98bf21cd93STycho Nightingale #define PI_NAMESZ 40 99bf21cd93STycho Nightingale 100bf21cd93STycho Nightingale struct msix_table_entry { 101bf21cd93STycho Nightingale uint64_t addr; 102bf21cd93STycho Nightingale uint32_t msg_data; 103bf21cd93STycho Nightingale uint32_t vector_control; 104bf21cd93STycho Nightingale } __packed; 105bf21cd93STycho Nightingale 106bf21cd93STycho Nightingale /* 107bf21cd93STycho Nightingale * In case the structure is modified to hold extra information, use a define 108bf21cd93STycho Nightingale * for the size that should be emulated. 109bf21cd93STycho Nightingale */ 110bf21cd93STycho Nightingale #define MSIX_TABLE_ENTRY_SIZE 16 111bf21cd93STycho Nightingale #define MAX_MSIX_TABLE_ENTRIES 2048 112bf21cd93STycho Nightingale #define PBA_SIZE(msgnum) (roundup2((msgnum), 64) / 8) 113bf21cd93STycho Nightingale 114bf21cd93STycho Nightingale enum lintr_stat { 115bf21cd93STycho Nightingale IDLE, 116bf21cd93STycho Nightingale ASSERTED, 117bf21cd93STycho Nightingale PENDING 118bf21cd93STycho Nightingale }; 119bf21cd93STycho Nightingale 120bf21cd93STycho Nightingale struct pci_devinst { 121bf21cd93STycho Nightingale struct pci_devemu *pi_d; 122bf21cd93STycho Nightingale struct vmctx *pi_vmctx; 123bf21cd93STycho Nightingale uint8_t pi_bus, pi_slot, pi_func; 124bf21cd93STycho Nightingale char pi_name[PI_NAMESZ]; 125bf21cd93STycho Nightingale int pi_bar_getsize; 126bf21cd93STycho Nightingale int pi_prevcap; 127bf21cd93STycho Nightingale int pi_capend; 128bf21cd93STycho Nightingale 129bf21cd93STycho Nightingale struct { 130bf21cd93STycho Nightingale int8_t pin; 131bf21cd93STycho Nightingale enum lintr_stat state; 132bf21cd93STycho Nightingale int pirq_pin; 133bf21cd93STycho Nightingale int ioapic_irq; 134bf21cd93STycho Nightingale pthread_mutex_t lock; 135bf21cd93STycho Nightingale } pi_lintr; 136bf21cd93STycho Nightingale 137bf21cd93STycho Nightingale struct { 138bf21cd93STycho Nightingale int enabled; 139bf21cd93STycho Nightingale uint64_t addr; 140bf21cd93STycho Nightingale uint64_t msg_data; 141bf21cd93STycho Nightingale int maxmsgnum; 142bf21cd93STycho Nightingale } pi_msi; 143bf21cd93STycho Nightingale 144bf21cd93STycho Nightingale struct { 145bf21cd93STycho Nightingale int enabled; 146bf21cd93STycho Nightingale int table_bar; 147bf21cd93STycho Nightingale int pba_bar; 148bf21cd93STycho Nightingale uint32_t table_offset; 149bf21cd93STycho Nightingale int table_count; 150bf21cd93STycho Nightingale uint32_t pba_offset; 151bf21cd93STycho Nightingale int pba_size; 152bf21cd93STycho Nightingale int function_mask; 153bf21cd93STycho Nightingale struct msix_table_entry *table; /* allocated at runtime */ 1544c87aefeSPatrick Mooney void *pba_page; 1554c87aefeSPatrick Mooney int pba_page_offset; 156bf21cd93STycho Nightingale } pi_msix; 157bf21cd93STycho Nightingale 158bf21cd93STycho Nightingale void *pi_arg; /* devemu-private data */ 159bf21cd93STycho Nightingale 160bf21cd93STycho Nightingale u_char pi_cfgdata[PCI_REGMAX + 1]; 161bf21cd93STycho Nightingale struct pcibar pi_bar[PCI_BARMAX + 1]; 162bf21cd93STycho Nightingale }; 163bf21cd93STycho Nightingale 164bf21cd93STycho Nightingale struct msicap { 165bf21cd93STycho Nightingale uint8_t capid; 166bf21cd93STycho Nightingale uint8_t nextptr; 167bf21cd93STycho Nightingale uint16_t msgctrl; 168bf21cd93STycho Nightingale uint32_t addrlo; 169bf21cd93STycho Nightingale uint32_t addrhi; 170bf21cd93STycho Nightingale uint16_t msgdata; 171bf21cd93STycho Nightingale } __packed; 1724c87aefeSPatrick Mooney static_assert(sizeof(struct msicap) == 14, "compile-time assertion failed"); 173bf21cd93STycho Nightingale 174bf21cd93STycho Nightingale struct msixcap { 175bf21cd93STycho Nightingale uint8_t capid; 176bf21cd93STycho Nightingale uint8_t nextptr; 177bf21cd93STycho Nightingale uint16_t msgctrl; 178bf21cd93STycho Nightingale uint32_t table_info; /* bar index and offset within it */ 179bf21cd93STycho Nightingale uint32_t pba_info; /* bar index and offset within it */ 180bf21cd93STycho Nightingale } __packed; 1814c87aefeSPatrick Mooney static_assert(sizeof(struct msixcap) == 12, "compile-time assertion failed"); 182bf21cd93STycho Nightingale 183bf21cd93STycho Nightingale struct pciecap { 184bf21cd93STycho Nightingale uint8_t capid; 185bf21cd93STycho Nightingale uint8_t nextptr; 186bf21cd93STycho Nightingale uint16_t pcie_capabilities; 187bf21cd93STycho Nightingale 188bf21cd93STycho Nightingale uint32_t dev_capabilities; /* all devices */ 189bf21cd93STycho Nightingale uint16_t dev_control; 190bf21cd93STycho Nightingale uint16_t dev_status; 191bf21cd93STycho Nightingale 192bf21cd93STycho Nightingale uint32_t link_capabilities; /* devices with links */ 193bf21cd93STycho Nightingale uint16_t link_control; 194bf21cd93STycho Nightingale uint16_t link_status; 195bf21cd93STycho Nightingale 196bf21cd93STycho Nightingale uint32_t slot_capabilities; /* ports with slots */ 197bf21cd93STycho Nightingale uint16_t slot_control; 198bf21cd93STycho Nightingale uint16_t slot_status; 199bf21cd93STycho Nightingale 200bf21cd93STycho Nightingale uint16_t root_control; /* root ports */ 201bf21cd93STycho Nightingale uint16_t root_capabilities; 202bf21cd93STycho Nightingale uint32_t root_status; 203bf21cd93STycho Nightingale 204bf21cd93STycho Nightingale uint32_t dev_capabilities2; /* all devices */ 205bf21cd93STycho Nightingale uint16_t dev_control2; 206bf21cd93STycho Nightingale uint16_t dev_status2; 207bf21cd93STycho Nightingale 208bf21cd93STycho Nightingale uint32_t link_capabilities2; /* devices with links */ 209bf21cd93STycho Nightingale uint16_t link_control2; 210bf21cd93STycho Nightingale uint16_t link_status2; 211bf21cd93STycho Nightingale 212bf21cd93STycho Nightingale uint32_t slot_capabilities2; /* ports with slots */ 213bf21cd93STycho Nightingale uint16_t slot_control2; 214bf21cd93STycho Nightingale uint16_t slot_status2; 215bf21cd93STycho Nightingale } __packed; 2164c87aefeSPatrick Mooney static_assert(sizeof(struct pciecap) == 60, "compile-time assertion failed"); 217bf21cd93STycho Nightingale 218bf21cd93STycho Nightingale typedef void (*pci_lintr_cb)(int b, int s, int pin, int pirq_pin, 219bf21cd93STycho Nightingale int ioapic_irq, void *arg); 220bf21cd93STycho Nightingale 221bf21cd93STycho Nightingale int init_pci(struct vmctx *ctx); 222bf21cd93STycho Nightingale void msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset, 223bf21cd93STycho Nightingale int bytes, uint32_t val); 224bf21cd93STycho Nightingale void msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset, 225bf21cd93STycho Nightingale int bytes, uint32_t val); 226bf21cd93STycho Nightingale void pci_callback(void); 227bf21cd93STycho Nightingale int pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, 228bf21cd93STycho Nightingale enum pcibar_type type, uint64_t size); 229bf21cd93STycho Nightingale int pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, 230bf21cd93STycho Nightingale uint64_t hostbase, enum pcibar_type type, uint64_t size); 231bf21cd93STycho Nightingale int pci_emul_add_msicap(struct pci_devinst *pi, int msgnum); 232bf21cd93STycho Nightingale int pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type); 233*84659b24SMichael Zeller void pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old); 234bf21cd93STycho Nightingale void pci_generate_msi(struct pci_devinst *pi, int msgnum); 235bf21cd93STycho Nightingale void pci_generate_msix(struct pci_devinst *pi, int msgnum); 236bf21cd93STycho Nightingale void pci_lintr_assert(struct pci_devinst *pi); 237bf21cd93STycho Nightingale void pci_lintr_deassert(struct pci_devinst *pi); 238bf21cd93STycho Nightingale void pci_lintr_request(struct pci_devinst *pi); 239bf21cd93STycho Nightingale int pci_msi_enabled(struct pci_devinst *pi); 240bf21cd93STycho Nightingale int pci_msix_enabled(struct pci_devinst *pi); 241bf21cd93STycho Nightingale int pci_msix_table_bar(struct pci_devinst *pi); 242bf21cd93STycho Nightingale int pci_msix_pba_bar(struct pci_devinst *pi); 2434c87aefeSPatrick Mooney int pci_msi_maxmsgnum(struct pci_devinst *pi); 244bf21cd93STycho Nightingale int pci_parse_slot(char *opt); 2454c87aefeSPatrick Mooney void pci_print_supported_devices(); 246bf21cd93STycho Nightingale void pci_populate_msicap(struct msicap *cap, int msgs, int nextptr); 247bf21cd93STycho Nightingale int pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum); 248bf21cd93STycho Nightingale int pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size, 249bf21cd93STycho Nightingale uint64_t value); 250bf21cd93STycho Nightingale uint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size); 251bf21cd93STycho Nightingale int pci_count_lintr(int bus); 252bf21cd93STycho Nightingale void pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg); 253bf21cd93STycho Nightingale void pci_write_dsdt(void); 254bf21cd93STycho Nightingale uint64_t pci_ecfg_base(void); 255bf21cd93STycho Nightingale int pci_bus_configured(int bus); 256bf21cd93STycho Nightingale 257bf21cd93STycho Nightingale static __inline void 258bf21cd93STycho Nightingale pci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val) 259bf21cd93STycho Nightingale { 260bf21cd93STycho Nightingale assert(offset <= PCI_REGMAX); 261bf21cd93STycho Nightingale *(uint8_t *)(pi->pi_cfgdata + offset) = val; 262bf21cd93STycho Nightingale } 263bf21cd93STycho Nightingale 264bf21cd93STycho Nightingale static __inline void 265bf21cd93STycho Nightingale pci_set_cfgdata16(struct pci_devinst *pi, int offset, uint16_t val) 266bf21cd93STycho Nightingale { 267bf21cd93STycho Nightingale assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0); 268bf21cd93STycho Nightingale *(uint16_t *)(pi->pi_cfgdata + offset) = val; 269bf21cd93STycho Nightingale } 270bf21cd93STycho Nightingale 271bf21cd93STycho Nightingale static __inline void 272bf21cd93STycho Nightingale pci_set_cfgdata32(struct pci_devinst *pi, int offset, uint32_t val) 273bf21cd93STycho Nightingale { 274bf21cd93STycho Nightingale assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0); 275bf21cd93STycho Nightingale *(uint32_t *)(pi->pi_cfgdata + offset) = val; 276bf21cd93STycho Nightingale } 277bf21cd93STycho Nightingale 278bf21cd93STycho Nightingale static __inline uint8_t 279bf21cd93STycho Nightingale pci_get_cfgdata8(struct pci_devinst *pi, int offset) 280bf21cd93STycho Nightingale { 281bf21cd93STycho Nightingale assert(offset <= PCI_REGMAX); 282bf21cd93STycho Nightingale return (*(uint8_t *)(pi->pi_cfgdata + offset)); 283bf21cd93STycho Nightingale } 284bf21cd93STycho Nightingale 285bf21cd93STycho Nightingale static __inline uint16_t 286bf21cd93STycho Nightingale pci_get_cfgdata16(struct pci_devinst *pi, int offset) 287bf21cd93STycho Nightingale { 288bf21cd93STycho Nightingale assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0); 289bf21cd93STycho Nightingale return (*(uint16_t *)(pi->pi_cfgdata + offset)); 290bf21cd93STycho Nightingale } 291bf21cd93STycho Nightingale 292bf21cd93STycho Nightingale static __inline uint32_t 293bf21cd93STycho Nightingale pci_get_cfgdata32(struct pci_devinst *pi, int offset) 294bf21cd93STycho Nightingale { 295bf21cd93STycho Nightingale assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0); 296bf21cd93STycho Nightingale return (*(uint32_t *)(pi->pi_cfgdata + offset)); 297bf21cd93STycho Nightingale } 298bf21cd93STycho Nightingale 299bf21cd93STycho Nightingale #endif /* _PCI_EMUL_H_ */ 300