1366f6083SPeter Grehan /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 29366f6083SPeter Grehan */ 30366f6083SPeter Grehan 31366f6083SPeter Grehan #include <sys/cdefs.h> 32366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 33366f6083SPeter Grehan 34366f6083SPeter Grehan #include <sys/param.h> 35366f6083SPeter Grehan #include <sys/linker_set.h> 36366f6083SPeter Grehan 37366f6083SPeter Grehan #include <ctype.h> 387e12dfe5SEnji Cooper #include <errno.h> 393cbf3585SJohn Baldwin #include <pthread.h> 40366f6083SPeter Grehan #include <stdio.h> 41366f6083SPeter Grehan #include <stdlib.h> 42366f6083SPeter Grehan #include <string.h> 43366f6083SPeter Grehan #include <strings.h> 44366f6083SPeter Grehan #include <assert.h> 45028d9311SNeel Natu #include <stdbool.h> 46366f6083SPeter Grehan 47366f6083SPeter Grehan #include <machine/vmm.h> 48366f6083SPeter Grehan #include <vmmapi.h> 49366f6083SPeter Grehan 50e6c8bc29SJohn Baldwin #include "acpi.h" 51e285ef8dSPeter Grehan #include "bhyverun.h" 52366f6083SPeter Grehan #include "inout.h" 533cbf3585SJohn Baldwin #include "ioapic.h" 544d1e669cSPeter Grehan #include "mem.h" 55366f6083SPeter Grehan #include "pci_emul.h" 56b3e9732aSJohn Baldwin #include "pci_irq.h" 57e6c8bc29SJohn Baldwin #include "pci_lpc.h" 58366f6083SPeter Grehan 59366f6083SPeter Grehan #define CONF1_ADDR_PORT 0x0cf8 60366f6083SPeter Grehan #define CONF1_DATA_PORT 0x0cfc 61366f6083SPeter Grehan 6275543036SPeter Grehan #define CONF1_ENABLE 0x80000000ul 6375543036SPeter Grehan 64d84882caSNeel Natu #define MAXBUSES (PCI_BUSMAX + 1) 6599d65389SNeel Natu #define MAXSLOTS (PCI_SLOTMAX + 1) 6699d65389SNeel Natu #define MAXFUNCS (PCI_FUNCMAX + 1) 67366f6083SPeter Grehan 683cbf3585SJohn Baldwin struct funcinfo { 693cbf3585SJohn Baldwin char *fi_name; 703cbf3585SJohn Baldwin char *fi_param; 713cbf3585SJohn Baldwin struct pci_devinst *fi_devi; 723cbf3585SJohn Baldwin }; 733cbf3585SJohn Baldwin 743cbf3585SJohn Baldwin struct intxinfo { 753cbf3585SJohn Baldwin int ii_count; 76b3e9732aSJohn Baldwin int ii_pirq_pin; 773cbf3585SJohn Baldwin int ii_ioapic_irq; 783cbf3585SJohn Baldwin }; 793cbf3585SJohn Baldwin 803cbf3585SJohn Baldwin struct slotinfo { 813cbf3585SJohn Baldwin struct intxinfo si_intpins[4]; 823cbf3585SJohn Baldwin struct funcinfo si_funcs[MAXFUNCS]; 83d84882caSNeel Natu }; 84d84882caSNeel Natu 85d84882caSNeel Natu struct businfo { 86d84882caSNeel Natu uint16_t iobase, iolimit; /* I/O window */ 87d84882caSNeel Natu uint32_t membase32, memlimit32; /* mmio window below 4GB */ 88d84882caSNeel Natu uint64_t membase64, memlimit64; /* mmio window above 4GB */ 89d84882caSNeel Natu struct slotinfo slotinfo[MAXSLOTS]; 90d84882caSNeel Natu }; 91d84882caSNeel Natu 92d84882caSNeel Natu static struct businfo *pci_businfo[MAXBUSES]; 93366f6083SPeter Grehan 94366f6083SPeter Grehan SET_DECLARE(pci_devemu_set, struct pci_devemu); 95366f6083SPeter Grehan 96366f6083SPeter Grehan static uint64_t pci_emul_iobase; 97366f6083SPeter Grehan static uint64_t pci_emul_membase32; 98366f6083SPeter Grehan static uint64_t pci_emul_membase64; 99366f6083SPeter Grehan 100366f6083SPeter Grehan #define PCI_EMUL_IOBASE 0x2000 101366f6083SPeter Grehan #define PCI_EMUL_IOLIMIT 0x10000 102366f6083SPeter Grehan 10312a6eb99SNeel Natu #define PCI_EMUL_ECFG_BASE 0xE0000000 /* 3.5GB */ 10412a6eb99SNeel Natu #define PCI_EMUL_ECFG_SIZE (MAXBUSES * 1024 * 1024) /* 1MB per bus */ 10512a6eb99SNeel Natu SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE); 10612a6eb99SNeel Natu 10712a6eb99SNeel Natu #define PCI_EMUL_MEMLIMIT32 PCI_EMUL_ECFG_BASE 108366f6083SPeter Grehan 109366f6083SPeter Grehan #define PCI_EMUL_MEMBASE64 0xD000000000UL 110366f6083SPeter Grehan #define PCI_EMUL_MEMLIMIT64 0xFD00000000UL 111366f6083SPeter Grehan 112b05c77ffSNeel Natu static struct pci_devemu *pci_emul_finddev(char *name); 113b3e9732aSJohn Baldwin static void pci_lintr_route(struct pci_devinst *pi); 1143cbf3585SJohn Baldwin static void pci_lintr_update(struct pci_devinst *pi); 11512a6eb99SNeel Natu static void pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, 11612a6eb99SNeel Natu int func, int coff, int bytes, uint32_t *val); 117366f6083SPeter Grehan 11854335630SNeel Natu static __inline void 11954335630SNeel Natu CFGWRITE(struct pci_devinst *pi, int coff, uint32_t val, int bytes) 12054335630SNeel Natu { 12154335630SNeel Natu 12254335630SNeel Natu if (bytes == 1) 12354335630SNeel Natu pci_set_cfgdata8(pi, coff, val); 12454335630SNeel Natu else if (bytes == 2) 12554335630SNeel Natu pci_set_cfgdata16(pi, coff, val); 12654335630SNeel Natu else 12754335630SNeel Natu pci_set_cfgdata32(pi, coff, val); 12854335630SNeel Natu } 12954335630SNeel Natu 13054335630SNeel Natu static __inline uint32_t 13154335630SNeel Natu CFGREAD(struct pci_devinst *pi, int coff, int bytes) 13254335630SNeel Natu { 13354335630SNeel Natu 13454335630SNeel Natu if (bytes == 1) 13554335630SNeel Natu return (pci_get_cfgdata8(pi, coff)); 13654335630SNeel Natu else if (bytes == 2) 13754335630SNeel Natu return (pci_get_cfgdata16(pi, coff)); 13854335630SNeel Natu else 13954335630SNeel Natu return (pci_get_cfgdata32(pi, coff)); 14054335630SNeel Natu } 14154335630SNeel Natu 142366f6083SPeter Grehan /* 143366f6083SPeter Grehan * I/O access 144366f6083SPeter Grehan */ 145366f6083SPeter Grehan 146366f6083SPeter Grehan /* 147366f6083SPeter Grehan * Slot options are in the form: 148366f6083SPeter Grehan * 149d84882caSNeel Natu * <bus>:<slot>:<func>,<emul>[,<config>] 15099d65389SNeel Natu * <slot>[:<func>],<emul>[,<config>] 151366f6083SPeter Grehan * 152366f6083SPeter Grehan * slot is 0..31 15399d65389SNeel Natu * func is 0..7 154366f6083SPeter Grehan * emul is a string describing the type of PCI device e.g. virtio-net 155366f6083SPeter Grehan * config is an optional string, depending on the device, that can be 156366f6083SPeter Grehan * used for configuration. 157366f6083SPeter Grehan * Examples are: 158366f6083SPeter Grehan * 1,virtio-net,tap0 15999d65389SNeel Natu * 3:0,dummy 160366f6083SPeter Grehan */ 161366f6083SPeter Grehan static void 162366f6083SPeter Grehan pci_parse_slot_usage(char *aopt) 163366f6083SPeter Grehan { 164b05c77ffSNeel Natu 165b05c77ffSNeel Natu fprintf(stderr, "Invalid PCI slot info field \"%s\"\n", aopt); 166366f6083SPeter Grehan } 167366f6083SPeter Grehan 168b05c77ffSNeel Natu int 169d2bc4816SJohn Baldwin pci_parse_slot(char *opt) 170366f6083SPeter Grehan { 171d84882caSNeel Natu struct businfo *bi; 172d84882caSNeel Natu struct slotinfo *si; 173d84882caSNeel Natu char *emul, *config, *str, *cp; 174d84882caSNeel Natu int error, bnum, snum, fnum; 175366f6083SPeter Grehan 176b05c77ffSNeel Natu error = -1; 177d84882caSNeel Natu str = strdup(opt); 17899d65389SNeel Natu 179d84882caSNeel Natu emul = config = NULL; 180d84882caSNeel Natu if ((cp = strchr(str, ',')) != NULL) { 181d84882caSNeel Natu *cp = '\0'; 182d84882caSNeel Natu emul = cp + 1; 183d84882caSNeel Natu if ((cp = strchr(emul, ',')) != NULL) { 184d84882caSNeel Natu *cp = '\0'; 185d84882caSNeel Natu config = cp + 1; 18699d65389SNeel Natu } 187d84882caSNeel Natu } else { 188b05c77ffSNeel Natu pci_parse_slot_usage(opt); 189b05c77ffSNeel Natu goto done; 190366f6083SPeter Grehan } 191366f6083SPeter Grehan 192d84882caSNeel Natu /* <bus>:<slot>:<func> */ 193d84882caSNeel Natu if (sscanf(str, "%d:%d:%d", &bnum, &snum, &fnum) != 3) { 194d84882caSNeel Natu bnum = 0; 195d84882caSNeel Natu /* <slot>:<func> */ 196d84882caSNeel Natu if (sscanf(str, "%d:%d", &snum, &fnum) != 2) { 197d84882caSNeel Natu fnum = 0; 198d84882caSNeel Natu /* <slot> */ 199d84882caSNeel Natu if (sscanf(str, "%d", &snum) != 1) { 200d84882caSNeel Natu snum = -1; 201d84882caSNeel Natu } 202d84882caSNeel Natu } 203d84882caSNeel Natu } 204b05c77ffSNeel Natu 205d84882caSNeel Natu if (bnum < 0 || bnum >= MAXBUSES || snum < 0 || snum >= MAXSLOTS || 206d84882caSNeel Natu fnum < 0 || fnum >= MAXFUNCS) { 207b05c77ffSNeel Natu pci_parse_slot_usage(opt); 208b05c77ffSNeel Natu goto done; 209b05c77ffSNeel Natu } 210b05c77ffSNeel Natu 211d84882caSNeel Natu if (pci_businfo[bnum] == NULL) 212d84882caSNeel Natu pci_businfo[bnum] = calloc(1, sizeof(struct businfo)); 213d84882caSNeel Natu 214d84882caSNeel Natu bi = pci_businfo[bnum]; 215d84882caSNeel Natu si = &bi->slotinfo[snum]; 216d84882caSNeel Natu 217d84882caSNeel Natu if (si->si_funcs[fnum].fi_name != NULL) { 218b05c77ffSNeel Natu fprintf(stderr, "pci slot %d:%d already occupied!\n", 219b05c77ffSNeel Natu snum, fnum); 220b05c77ffSNeel Natu goto done; 221b05c77ffSNeel Natu } 222b05c77ffSNeel Natu 223b05c77ffSNeel Natu if (pci_emul_finddev(emul) == NULL) { 224b05c77ffSNeel Natu fprintf(stderr, "pci slot %d:%d: unknown device \"%s\"\n", 225b05c77ffSNeel Natu snum, fnum, emul); 226b05c77ffSNeel Natu goto done; 227b05c77ffSNeel Natu } 228b05c77ffSNeel Natu 229b05c77ffSNeel Natu error = 0; 230d84882caSNeel Natu si->si_funcs[fnum].fi_name = emul; 231d84882caSNeel Natu si->si_funcs[fnum].fi_param = config; 232b05c77ffSNeel Natu 233b05c77ffSNeel Natu done: 23492046bf1SMarcelo Araujo if (error) 235d84882caSNeel Natu free(str); 236b05c77ffSNeel Natu 237b05c77ffSNeel Natu return (error); 238366f6083SPeter Grehan } 239366f6083SPeter Grehan 240657d2158SMarcelo Araujo void 241657d2158SMarcelo Araujo pci_print_supported_devices() 242657d2158SMarcelo Araujo { 243657d2158SMarcelo Araujo struct pci_devemu **pdpp, *pdp; 244657d2158SMarcelo Araujo 245657d2158SMarcelo Araujo SET_FOREACH(pdpp, pci_devemu_set) { 246657d2158SMarcelo Araujo pdp = *pdpp; 247657d2158SMarcelo Araujo printf("%s\n", pdp->pe_emu); 248657d2158SMarcelo Araujo } 249657d2158SMarcelo Araujo } 250657d2158SMarcelo Araujo 251366f6083SPeter Grehan static int 252c9b4e987SNeel Natu pci_valid_pba_offset(struct pci_devinst *pi, uint64_t offset) 253c9b4e987SNeel Natu { 254c9b4e987SNeel Natu 255c9b4e987SNeel Natu if (offset < pi->pi_msix.pba_offset) 256c9b4e987SNeel Natu return (0); 257c9b4e987SNeel Natu 258c9b4e987SNeel Natu if (offset >= pi->pi_msix.pba_offset + pi->pi_msix.pba_size) { 259c9b4e987SNeel Natu return (0); 260c9b4e987SNeel Natu } 261c9b4e987SNeel Natu 262c9b4e987SNeel Natu return (1); 263c9b4e987SNeel Natu } 264c9b4e987SNeel Natu 265c9b4e987SNeel Natu int 266c9b4e987SNeel Natu pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size, 267c9b4e987SNeel Natu uint64_t value) 268c9b4e987SNeel Natu { 269c9b4e987SNeel Natu int msix_entry_offset; 270c9b4e987SNeel Natu int tab_index; 271c9b4e987SNeel Natu char *dest; 272c9b4e987SNeel Natu 273c9b4e987SNeel Natu /* support only 4 or 8 byte writes */ 274c9b4e987SNeel Natu if (size != 4 && size != 8) 275c9b4e987SNeel Natu return (-1); 276c9b4e987SNeel Natu 277c9b4e987SNeel Natu /* 278c9b4e987SNeel Natu * Return if table index is beyond what device supports 279c9b4e987SNeel Natu */ 280c9b4e987SNeel Natu tab_index = offset / MSIX_TABLE_ENTRY_SIZE; 281c9b4e987SNeel Natu if (tab_index >= pi->pi_msix.table_count) 282c9b4e987SNeel Natu return (-1); 283c9b4e987SNeel Natu 284c9b4e987SNeel Natu msix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; 285c9b4e987SNeel Natu 286c9b4e987SNeel Natu /* support only aligned writes */ 287c9b4e987SNeel Natu if ((msix_entry_offset % size) != 0) 288c9b4e987SNeel Natu return (-1); 289c9b4e987SNeel Natu 290c9b4e987SNeel Natu dest = (char *)(pi->pi_msix.table + tab_index); 291c9b4e987SNeel Natu dest += msix_entry_offset; 292c9b4e987SNeel Natu 293c9b4e987SNeel Natu if (size == 4) 294c9b4e987SNeel Natu *((uint32_t *)dest) = value; 295c9b4e987SNeel Natu else 296c9b4e987SNeel Natu *((uint64_t *)dest) = value; 297c9b4e987SNeel Natu 298c9b4e987SNeel Natu return (0); 299c9b4e987SNeel Natu } 300c9b4e987SNeel Natu 301c9b4e987SNeel Natu uint64_t 302c9b4e987SNeel Natu pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size) 303c9b4e987SNeel Natu { 304c9b4e987SNeel Natu char *dest; 305c9b4e987SNeel Natu int msix_entry_offset; 306c9b4e987SNeel Natu int tab_index; 307c9b4e987SNeel Natu uint64_t retval = ~0; 308c9b4e987SNeel Natu 3096a52209fSNeel Natu /* 3106a52209fSNeel Natu * The PCI standard only allows 4 and 8 byte accesses to the MSI-X 311463a577bSEitan Adler * table but we also allow 1 byte access to accommodate reads from 3126a52209fSNeel Natu * ddb. 3136a52209fSNeel Natu */ 3146a52209fSNeel Natu if (size != 1 && size != 4 && size != 8) 315c9b4e987SNeel Natu return (retval); 316c9b4e987SNeel Natu 317c9b4e987SNeel Natu msix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; 318c9b4e987SNeel Natu 319c9b4e987SNeel Natu /* support only aligned reads */ 320c9b4e987SNeel Natu if ((msix_entry_offset % size) != 0) { 321c9b4e987SNeel Natu return (retval); 322c9b4e987SNeel Natu } 323c9b4e987SNeel Natu 324c9b4e987SNeel Natu tab_index = offset / MSIX_TABLE_ENTRY_SIZE; 325c9b4e987SNeel Natu 326c9b4e987SNeel Natu if (tab_index < pi->pi_msix.table_count) { 327c9b4e987SNeel Natu /* valid MSI-X Table access */ 328c9b4e987SNeel Natu dest = (char *)(pi->pi_msix.table + tab_index); 329c9b4e987SNeel Natu dest += msix_entry_offset; 330c9b4e987SNeel Natu 3316a52209fSNeel Natu if (size == 1) 3326a52209fSNeel Natu retval = *((uint8_t *)dest); 3336a52209fSNeel Natu else if (size == 4) 334c9b4e987SNeel Natu retval = *((uint32_t *)dest); 335c9b4e987SNeel Natu else 336c9b4e987SNeel Natu retval = *((uint64_t *)dest); 337c9b4e987SNeel Natu } else if (pci_valid_pba_offset(pi, offset)) { 338c9b4e987SNeel Natu /* return 0 for PBA access */ 339c9b4e987SNeel Natu retval = 0; 340c9b4e987SNeel Natu } 341c9b4e987SNeel Natu 342c9b4e987SNeel Natu return (retval); 343c9b4e987SNeel Natu } 344c9b4e987SNeel Natu 345aa12663fSNeel Natu int 346aa12663fSNeel Natu pci_msix_table_bar(struct pci_devinst *pi) 347aa12663fSNeel Natu { 348aa12663fSNeel Natu 349aa12663fSNeel Natu if (pi->pi_msix.table != NULL) 350aa12663fSNeel Natu return (pi->pi_msix.table_bar); 351aa12663fSNeel Natu else 352aa12663fSNeel Natu return (-1); 353aa12663fSNeel Natu } 354aa12663fSNeel Natu 355aa12663fSNeel Natu int 356aa12663fSNeel Natu pci_msix_pba_bar(struct pci_devinst *pi) 357aa12663fSNeel Natu { 358aa12663fSNeel Natu 359aa12663fSNeel Natu if (pi->pi_msix.table != NULL) 360aa12663fSNeel Natu return (pi->pi_msix.pba_bar); 361aa12663fSNeel Natu else 362aa12663fSNeel Natu return (-1); 363aa12663fSNeel Natu } 364aa12663fSNeel Natu 365c9b4e987SNeel Natu static int 3664d1e669cSPeter Grehan pci_emul_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 367366f6083SPeter Grehan uint32_t *eax, void *arg) 368366f6083SPeter Grehan { 369366f6083SPeter Grehan struct pci_devinst *pdi = arg; 370366f6083SPeter Grehan struct pci_devemu *pe = pdi->pi_d; 3714d1e669cSPeter Grehan uint64_t offset; 3724d1e669cSPeter Grehan int i; 373366f6083SPeter Grehan 374366f6083SPeter Grehan for (i = 0; i <= PCI_BARMAX; i++) { 375366f6083SPeter Grehan if (pdi->pi_bar[i].type == PCIBAR_IO && 376366f6083SPeter Grehan port >= pdi->pi_bar[i].addr && 377c9b4e987SNeel Natu port + bytes <= pdi->pi_bar[i].addr + pdi->pi_bar[i].size) { 378366f6083SPeter Grehan offset = port - pdi->pi_bar[i].addr; 379366f6083SPeter Grehan if (in) 3804d1e669cSPeter Grehan *eax = (*pe->pe_barread)(ctx, vcpu, pdi, i, 3814d1e669cSPeter Grehan offset, bytes); 382366f6083SPeter Grehan else 3834d1e669cSPeter Grehan (*pe->pe_barwrite)(ctx, vcpu, pdi, i, offset, 3844d1e669cSPeter Grehan bytes, *eax); 385366f6083SPeter Grehan return (0); 386366f6083SPeter Grehan } 387366f6083SPeter Grehan } 388366f6083SPeter Grehan return (-1); 389366f6083SPeter Grehan } 390366f6083SPeter Grehan 391366f6083SPeter Grehan static int 3924d1e669cSPeter Grehan pci_emul_mem_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr, 3934d1e669cSPeter Grehan int size, uint64_t *val, void *arg1, long arg2) 3944d1e669cSPeter Grehan { 3954d1e669cSPeter Grehan struct pci_devinst *pdi = arg1; 3964d1e669cSPeter Grehan struct pci_devemu *pe = pdi->pi_d; 3974d1e669cSPeter Grehan uint64_t offset; 3984d1e669cSPeter Grehan int bidx = (int) arg2; 3994d1e669cSPeter Grehan 4004d1e669cSPeter Grehan assert(bidx <= PCI_BARMAX); 4014d1e669cSPeter Grehan assert(pdi->pi_bar[bidx].type == PCIBAR_MEM32 || 4024d1e669cSPeter Grehan pdi->pi_bar[bidx].type == PCIBAR_MEM64); 4034d1e669cSPeter Grehan assert(addr >= pdi->pi_bar[bidx].addr && 4044d1e669cSPeter Grehan addr + size <= pdi->pi_bar[bidx].addr + pdi->pi_bar[bidx].size); 4054d1e669cSPeter Grehan 4064d1e669cSPeter Grehan offset = addr - pdi->pi_bar[bidx].addr; 4074d1e669cSPeter Grehan 408b6ae8b05STycho Nightingale if (dir == MEM_F_WRITE) { 40967b6ffaaSTycho Nightingale if (size == 8) { 410b6ae8b05STycho Nightingale (*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset, 411b6ae8b05STycho Nightingale 4, *val & 0xffffffff); 412b6ae8b05STycho Nightingale (*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset + 4, 413b6ae8b05STycho Nightingale 4, *val >> 32); 414b6ae8b05STycho Nightingale } else { 415b6ae8b05STycho Nightingale (*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset, 416b6ae8b05STycho Nightingale size, *val); 417b6ae8b05STycho Nightingale } 418b6ae8b05STycho Nightingale } else { 41967b6ffaaSTycho Nightingale if (size == 8) { 420b6ae8b05STycho Nightingale *val = (*pe->pe_barread)(ctx, vcpu, pdi, bidx, 421b6ae8b05STycho Nightingale offset, 4); 422b6ae8b05STycho Nightingale *val |= (*pe->pe_barread)(ctx, vcpu, pdi, bidx, 423b6ae8b05STycho Nightingale offset + 4, 4) << 32; 424b6ae8b05STycho Nightingale } else { 425b6ae8b05STycho Nightingale *val = (*pe->pe_barread)(ctx, vcpu, pdi, bidx, 426b6ae8b05STycho Nightingale offset, size); 427b6ae8b05STycho Nightingale } 428b6ae8b05STycho Nightingale } 4294d1e669cSPeter Grehan 4304d1e669cSPeter Grehan return (0); 4314d1e669cSPeter Grehan } 4324d1e669cSPeter Grehan 4334d1e669cSPeter Grehan 4344d1e669cSPeter Grehan static int 435366f6083SPeter Grehan pci_emul_alloc_resource(uint64_t *baseptr, uint64_t limit, uint64_t size, 436366f6083SPeter Grehan uint64_t *addr) 437366f6083SPeter Grehan { 438366f6083SPeter Grehan uint64_t base; 439366f6083SPeter Grehan 440366f6083SPeter Grehan assert((size & (size - 1)) == 0); /* must be a power of 2 */ 441366f6083SPeter Grehan 442366f6083SPeter Grehan base = roundup2(*baseptr, size); 443366f6083SPeter Grehan 444366f6083SPeter Grehan if (base + size <= limit) { 445366f6083SPeter Grehan *addr = base; 446366f6083SPeter Grehan *baseptr = base + size; 447366f6083SPeter Grehan return (0); 448366f6083SPeter Grehan } else 449366f6083SPeter Grehan return (-1); 450366f6083SPeter Grehan } 451366f6083SPeter Grehan 452366f6083SPeter Grehan int 4534d1e669cSPeter Grehan pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type, 4544d1e669cSPeter Grehan uint64_t size) 4554d1e669cSPeter Grehan { 4564d1e669cSPeter Grehan 4574d1e669cSPeter Grehan return (pci_emul_alloc_pbar(pdi, idx, 0, type, size)); 4584d1e669cSPeter Grehan } 4594d1e669cSPeter Grehan 460028d9311SNeel Natu /* 461028d9311SNeel Natu * Register (or unregister) the MMIO or I/O region associated with the BAR 462028d9311SNeel Natu * register 'idx' of an emulated pci device. 463028d9311SNeel Natu */ 464028d9311SNeel Natu static void 465028d9311SNeel Natu modify_bar_registration(struct pci_devinst *pi, int idx, int registration) 466028d9311SNeel Natu { 467028d9311SNeel Natu int error; 468028d9311SNeel Natu struct inout_port iop; 469028d9311SNeel Natu struct mem_range mr; 470028d9311SNeel Natu 471028d9311SNeel Natu switch (pi->pi_bar[idx].type) { 472028d9311SNeel Natu case PCIBAR_IO: 473028d9311SNeel Natu bzero(&iop, sizeof(struct inout_port)); 474028d9311SNeel Natu iop.name = pi->pi_name; 475028d9311SNeel Natu iop.port = pi->pi_bar[idx].addr; 476028d9311SNeel Natu iop.size = pi->pi_bar[idx].size; 477028d9311SNeel Natu if (registration) { 478028d9311SNeel Natu iop.flags = IOPORT_F_INOUT; 479028d9311SNeel Natu iop.handler = pci_emul_io_handler; 480028d9311SNeel Natu iop.arg = pi; 481028d9311SNeel Natu error = register_inout(&iop); 482028d9311SNeel Natu } else 483028d9311SNeel Natu error = unregister_inout(&iop); 484028d9311SNeel Natu break; 485028d9311SNeel Natu case PCIBAR_MEM32: 486028d9311SNeel Natu case PCIBAR_MEM64: 487028d9311SNeel Natu bzero(&mr, sizeof(struct mem_range)); 488028d9311SNeel Natu mr.name = pi->pi_name; 489028d9311SNeel Natu mr.base = pi->pi_bar[idx].addr; 490028d9311SNeel Natu mr.size = pi->pi_bar[idx].size; 491028d9311SNeel Natu if (registration) { 492028d9311SNeel Natu mr.flags = MEM_F_RW; 493028d9311SNeel Natu mr.handler = pci_emul_mem_handler; 494028d9311SNeel Natu mr.arg1 = pi; 495028d9311SNeel Natu mr.arg2 = idx; 496028d9311SNeel Natu error = register_mem(&mr); 497028d9311SNeel Natu } else 498028d9311SNeel Natu error = unregister_mem(&mr); 499028d9311SNeel Natu break; 500028d9311SNeel Natu default: 501028d9311SNeel Natu error = EINVAL; 502028d9311SNeel Natu break; 503028d9311SNeel Natu } 504028d9311SNeel Natu assert(error == 0); 505028d9311SNeel Natu } 506028d9311SNeel Natu 507028d9311SNeel Natu static void 508028d9311SNeel Natu unregister_bar(struct pci_devinst *pi, int idx) 509028d9311SNeel Natu { 510028d9311SNeel Natu 511028d9311SNeel Natu modify_bar_registration(pi, idx, 0); 512028d9311SNeel Natu } 513028d9311SNeel Natu 514028d9311SNeel Natu static void 515028d9311SNeel Natu register_bar(struct pci_devinst *pi, int idx) 516028d9311SNeel Natu { 517028d9311SNeel Natu 518028d9311SNeel Natu modify_bar_registration(pi, idx, 1); 519028d9311SNeel Natu } 520028d9311SNeel Natu 521028d9311SNeel Natu /* Are we decoding i/o port accesses for the emulated pci device? */ 522028d9311SNeel Natu static int 523028d9311SNeel Natu porten(struct pci_devinst *pi) 524028d9311SNeel Natu { 525028d9311SNeel Natu uint16_t cmd; 526028d9311SNeel Natu 527028d9311SNeel Natu cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); 528028d9311SNeel Natu 529028d9311SNeel Natu return (cmd & PCIM_CMD_PORTEN); 530028d9311SNeel Natu } 531028d9311SNeel Natu 532028d9311SNeel Natu /* Are we decoding memory accesses for the emulated pci device? */ 533028d9311SNeel Natu static int 534028d9311SNeel Natu memen(struct pci_devinst *pi) 535028d9311SNeel Natu { 536028d9311SNeel Natu uint16_t cmd; 537028d9311SNeel Natu 538028d9311SNeel Natu cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); 539028d9311SNeel Natu 540028d9311SNeel Natu return (cmd & PCIM_CMD_MEMEN); 541028d9311SNeel Natu } 542028d9311SNeel Natu 543028d9311SNeel Natu /* 544028d9311SNeel Natu * Update the MMIO or I/O address that is decoded by the BAR register. 545028d9311SNeel Natu * 546028d9311SNeel Natu * If the pci device has enabled the address space decoding then intercept 547028d9311SNeel Natu * the address range decoded by the BAR register. 548028d9311SNeel Natu */ 549028d9311SNeel Natu static void 550028d9311SNeel Natu update_bar_address(struct pci_devinst *pi, uint64_t addr, int idx, int type) 551028d9311SNeel Natu { 552028d9311SNeel Natu int decode; 553028d9311SNeel Natu 554028d9311SNeel Natu if (pi->pi_bar[idx].type == PCIBAR_IO) 555028d9311SNeel Natu decode = porten(pi); 556028d9311SNeel Natu else 557028d9311SNeel Natu decode = memen(pi); 558028d9311SNeel Natu 559028d9311SNeel Natu if (decode) 560028d9311SNeel Natu unregister_bar(pi, idx); 561028d9311SNeel Natu 562028d9311SNeel Natu switch (type) { 563028d9311SNeel Natu case PCIBAR_IO: 564028d9311SNeel Natu case PCIBAR_MEM32: 565028d9311SNeel Natu pi->pi_bar[idx].addr = addr; 566028d9311SNeel Natu break; 567028d9311SNeel Natu case PCIBAR_MEM64: 568028d9311SNeel Natu pi->pi_bar[idx].addr &= ~0xffffffffUL; 569028d9311SNeel Natu pi->pi_bar[idx].addr |= addr; 570028d9311SNeel Natu break; 571028d9311SNeel Natu case PCIBAR_MEMHI64: 572028d9311SNeel Natu pi->pi_bar[idx].addr &= 0xffffffff; 573028d9311SNeel Natu pi->pi_bar[idx].addr |= addr; 574028d9311SNeel Natu break; 575028d9311SNeel Natu default: 576028d9311SNeel Natu assert(0); 577028d9311SNeel Natu } 578028d9311SNeel Natu 579028d9311SNeel Natu if (decode) 580028d9311SNeel Natu register_bar(pi, idx); 581028d9311SNeel Natu } 582028d9311SNeel Natu 5834d1e669cSPeter Grehan int 5844d1e669cSPeter Grehan pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase, 585366f6083SPeter Grehan enum pcibar_type type, uint64_t size) 586366f6083SPeter Grehan { 587028d9311SNeel Natu int error; 588366f6083SPeter Grehan uint64_t *baseptr, limit, addr, mask, lobits, bar; 5892729c9bbSJohn Baldwin uint16_t cmd, enbit; 590366f6083SPeter Grehan 591366f6083SPeter Grehan assert(idx >= 0 && idx <= PCI_BARMAX); 592366f6083SPeter Grehan 593366f6083SPeter Grehan if ((size & (size - 1)) != 0) 594366f6083SPeter Grehan size = 1UL << flsl(size); /* round up to a power of 2 */ 595366f6083SPeter Grehan 596028d9311SNeel Natu /* Enforce minimum BAR sizes required by the PCI standard */ 597028d9311SNeel Natu if (type == PCIBAR_IO) { 598028d9311SNeel Natu if (size < 4) 599028d9311SNeel Natu size = 4; 600028d9311SNeel Natu } else { 601028d9311SNeel Natu if (size < 16) 602028d9311SNeel Natu size = 16; 603028d9311SNeel Natu } 604028d9311SNeel Natu 605366f6083SPeter Grehan switch (type) { 606366f6083SPeter Grehan case PCIBAR_NONE: 607366f6083SPeter Grehan baseptr = NULL; 6082729c9bbSJohn Baldwin addr = mask = lobits = enbit = 0; 609366f6083SPeter Grehan break; 610366f6083SPeter Grehan case PCIBAR_IO: 611366f6083SPeter Grehan baseptr = &pci_emul_iobase; 612366f6083SPeter Grehan limit = PCI_EMUL_IOLIMIT; 613366f6083SPeter Grehan mask = PCIM_BAR_IO_BASE; 614366f6083SPeter Grehan lobits = PCIM_BAR_IO_SPACE; 6152729c9bbSJohn Baldwin enbit = PCIM_CMD_PORTEN; 616366f6083SPeter Grehan break; 617366f6083SPeter Grehan case PCIBAR_MEM64: 618366f6083SPeter Grehan /* 619366f6083SPeter Grehan * XXX 620366f6083SPeter Grehan * Some drivers do not work well if the 64-bit BAR is allocated 621366f6083SPeter Grehan * above 4GB. Allow for this by allocating small requests under 622366f6083SPeter Grehan * 4GB unless then allocation size is larger than some arbitrary 623366f6083SPeter Grehan * number (32MB currently). 624366f6083SPeter Grehan */ 625366f6083SPeter Grehan if (size > 32 * 1024 * 1024) { 626366f6083SPeter Grehan /* 627366f6083SPeter Grehan * XXX special case for device requiring peer-peer DMA 628366f6083SPeter Grehan */ 629366f6083SPeter Grehan if (size == 0x100000000UL) 630366f6083SPeter Grehan baseptr = &hostbase; 631366f6083SPeter Grehan else 632366f6083SPeter Grehan baseptr = &pci_emul_membase64; 633366f6083SPeter Grehan limit = PCI_EMUL_MEMLIMIT64; 634366f6083SPeter Grehan mask = PCIM_BAR_MEM_BASE; 635366f6083SPeter Grehan lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 | 636366f6083SPeter Grehan PCIM_BAR_MEM_PREFETCH; 637366f6083SPeter Grehan break; 63825d4944eSNeel Natu } else { 63925d4944eSNeel Natu baseptr = &pci_emul_membase32; 64025d4944eSNeel Natu limit = PCI_EMUL_MEMLIMIT32; 64125d4944eSNeel Natu mask = PCIM_BAR_MEM_BASE; 64225d4944eSNeel Natu lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64; 643366f6083SPeter Grehan } 6442729c9bbSJohn Baldwin enbit = PCIM_CMD_MEMEN; 64525d4944eSNeel Natu break; 646366f6083SPeter Grehan case PCIBAR_MEM32: 647366f6083SPeter Grehan baseptr = &pci_emul_membase32; 648366f6083SPeter Grehan limit = PCI_EMUL_MEMLIMIT32; 649366f6083SPeter Grehan mask = PCIM_BAR_MEM_BASE; 650366f6083SPeter Grehan lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32; 6512729c9bbSJohn Baldwin enbit = PCIM_CMD_MEMEN; 652366f6083SPeter Grehan break; 653366f6083SPeter Grehan default: 654366f6083SPeter Grehan printf("pci_emul_alloc_base: invalid bar type %d\n", type); 655366f6083SPeter Grehan assert(0); 656366f6083SPeter Grehan } 657366f6083SPeter Grehan 658366f6083SPeter Grehan if (baseptr != NULL) { 659366f6083SPeter Grehan error = pci_emul_alloc_resource(baseptr, limit, size, &addr); 660366f6083SPeter Grehan if (error != 0) 661366f6083SPeter Grehan return (error); 662366f6083SPeter Grehan } 663366f6083SPeter Grehan 664366f6083SPeter Grehan pdi->pi_bar[idx].type = type; 665366f6083SPeter Grehan pdi->pi_bar[idx].addr = addr; 666366f6083SPeter Grehan pdi->pi_bar[idx].size = size; 667366f6083SPeter Grehan 668366f6083SPeter Grehan /* Initialize the BAR register in config space */ 669366f6083SPeter Grehan bar = (addr & mask) | lobits; 670366f6083SPeter Grehan pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar); 671366f6083SPeter Grehan 672366f6083SPeter Grehan if (type == PCIBAR_MEM64) { 673366f6083SPeter Grehan assert(idx + 1 <= PCI_BARMAX); 674366f6083SPeter Grehan pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64; 675366f6083SPeter Grehan pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32); 676366f6083SPeter Grehan } 677366f6083SPeter Grehan 6782729c9bbSJohn Baldwin cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND); 6792729c9bbSJohn Baldwin if ((cmd & enbit) != enbit) 6802729c9bbSJohn Baldwin pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit); 681028d9311SNeel Natu register_bar(pdi, idx); 682366f6083SPeter Grehan 683366f6083SPeter Grehan return (0); 684366f6083SPeter Grehan } 685366f6083SPeter Grehan 686366f6083SPeter Grehan #define CAP_START_OFFSET 0x40 687366f6083SPeter Grehan static int 688366f6083SPeter Grehan pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen) 689366f6083SPeter Grehan { 690a96b8b80SJohn Baldwin int i, capoff, reallen; 691366f6083SPeter Grehan uint16_t sts; 692366f6083SPeter Grehan 693a96b8b80SJohn Baldwin assert(caplen > 0); 694366f6083SPeter Grehan 695366f6083SPeter Grehan reallen = roundup2(caplen, 4); /* dword aligned */ 696366f6083SPeter Grehan 697366f6083SPeter Grehan sts = pci_get_cfgdata16(pi, PCIR_STATUS); 698a96b8b80SJohn Baldwin if ((sts & PCIM_STATUS_CAPPRESENT) == 0) 699366f6083SPeter Grehan capoff = CAP_START_OFFSET; 700a96b8b80SJohn Baldwin else 701a96b8b80SJohn Baldwin capoff = pi->pi_capend + 1; 702366f6083SPeter Grehan 703366f6083SPeter Grehan /* Check if we have enough space */ 704a96b8b80SJohn Baldwin if (capoff + reallen > PCI_REGMAX + 1) 705366f6083SPeter Grehan return (-1); 706366f6083SPeter Grehan 707a96b8b80SJohn Baldwin /* Set the previous capability pointer */ 708a96b8b80SJohn Baldwin if ((sts & PCIM_STATUS_CAPPRESENT) == 0) { 709a96b8b80SJohn Baldwin pci_set_cfgdata8(pi, PCIR_CAP_PTR, capoff); 710a96b8b80SJohn Baldwin pci_set_cfgdata16(pi, PCIR_STATUS, sts|PCIM_STATUS_CAPPRESENT); 711a96b8b80SJohn Baldwin } else 712a96b8b80SJohn Baldwin pci_set_cfgdata8(pi, pi->pi_prevcap + 1, capoff); 713a96b8b80SJohn Baldwin 714366f6083SPeter Grehan /* Copy the capability */ 715366f6083SPeter Grehan for (i = 0; i < caplen; i++) 716366f6083SPeter Grehan pci_set_cfgdata8(pi, capoff + i, capdata[i]); 717366f6083SPeter Grehan 718366f6083SPeter Grehan /* Set the next capability pointer */ 719a96b8b80SJohn Baldwin pci_set_cfgdata8(pi, capoff + 1, 0); 720366f6083SPeter Grehan 721a96b8b80SJohn Baldwin pi->pi_prevcap = capoff; 722a96b8b80SJohn Baldwin pi->pi_capend = capoff + reallen - 1; 723366f6083SPeter Grehan return (0); 724366f6083SPeter Grehan } 725366f6083SPeter Grehan 726366f6083SPeter Grehan static struct pci_devemu * 727366f6083SPeter Grehan pci_emul_finddev(char *name) 728366f6083SPeter Grehan { 729366f6083SPeter Grehan struct pci_devemu **pdpp, *pdp; 730366f6083SPeter Grehan 731366f6083SPeter Grehan SET_FOREACH(pdpp, pci_devemu_set) { 732366f6083SPeter Grehan pdp = *pdpp; 733366f6083SPeter Grehan if (!strcmp(pdp->pe_emu, name)) { 734366f6083SPeter Grehan return (pdp); 735366f6083SPeter Grehan } 736366f6083SPeter Grehan } 737366f6083SPeter Grehan 738366f6083SPeter Grehan return (NULL); 739366f6083SPeter Grehan } 740366f6083SPeter Grehan 741a38e2a64SPeter Grehan static int 742d84882caSNeel Natu pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int bus, int slot, 743d84882caSNeel Natu int func, struct funcinfo *fi) 744366f6083SPeter Grehan { 745366f6083SPeter Grehan struct pci_devinst *pdi; 746a38e2a64SPeter Grehan int err; 747a38e2a64SPeter Grehan 748994f858aSXin LI pdi = calloc(1, sizeof(struct pci_devinst)); 749366f6083SPeter Grehan 750366f6083SPeter Grehan pdi->pi_vmctx = ctx; 751d84882caSNeel Natu pdi->pi_bus = bus; 752366f6083SPeter Grehan pdi->pi_slot = slot; 75399d65389SNeel Natu pdi->pi_func = func; 7543cbf3585SJohn Baldwin pthread_mutex_init(&pdi->pi_lintr.lock, NULL); 7553cbf3585SJohn Baldwin pdi->pi_lintr.pin = 0; 7563cbf3585SJohn Baldwin pdi->pi_lintr.state = IDLE; 757b3e9732aSJohn Baldwin pdi->pi_lintr.pirq_pin = 0; 7583cbf3585SJohn Baldwin pdi->pi_lintr.ioapic_irq = 0; 759366f6083SPeter Grehan pdi->pi_d = pde; 760366f6083SPeter Grehan snprintf(pdi->pi_name, PI_NAMESZ, "%s-pci-%d", pde->pe_emu, slot); 761366f6083SPeter Grehan 762366f6083SPeter Grehan /* Disable legacy interrupts */ 763366f6083SPeter Grehan pci_set_cfgdata8(pdi, PCIR_INTLINE, 255); 764366f6083SPeter Grehan pci_set_cfgdata8(pdi, PCIR_INTPIN, 0); 765366f6083SPeter Grehan 7662729c9bbSJohn Baldwin pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN); 767366f6083SPeter Grehan 768d84882caSNeel Natu err = (*pde->pe_init)(ctx, pdi, fi->fi_param); 769d84882caSNeel Natu if (err == 0) 770d84882caSNeel Natu fi->fi_devi = pdi; 771d84882caSNeel Natu else 772366f6083SPeter Grehan free(pdi); 773a38e2a64SPeter Grehan 774a38e2a64SPeter Grehan return (err); 775366f6083SPeter Grehan } 776366f6083SPeter Grehan 777366f6083SPeter Grehan void 778366f6083SPeter Grehan pci_populate_msicap(struct msicap *msicap, int msgnum, int nextptr) 779366f6083SPeter Grehan { 780366f6083SPeter Grehan int mmc; 781366f6083SPeter Grehan 782366f6083SPeter Grehan /* Number of msi messages must be a power of 2 between 1 and 32 */ 783366f6083SPeter Grehan assert((msgnum & (msgnum - 1)) == 0 && msgnum >= 1 && msgnum <= 32); 784366f6083SPeter Grehan mmc = ffs(msgnum) - 1; 785366f6083SPeter Grehan 786366f6083SPeter Grehan bzero(msicap, sizeof(struct msicap)); 787366f6083SPeter Grehan msicap->capid = PCIY_MSI; 788366f6083SPeter Grehan msicap->nextptr = nextptr; 789366f6083SPeter Grehan msicap->msgctrl = PCIM_MSICTRL_64BIT | (mmc << 1); 790366f6083SPeter Grehan } 791366f6083SPeter Grehan 792366f6083SPeter Grehan int 793366f6083SPeter Grehan pci_emul_add_msicap(struct pci_devinst *pi, int msgnum) 794366f6083SPeter Grehan { 795366f6083SPeter Grehan struct msicap msicap; 796366f6083SPeter Grehan 797366f6083SPeter Grehan pci_populate_msicap(&msicap, msgnum, 0); 798366f6083SPeter Grehan 799366f6083SPeter Grehan return (pci_emul_add_capability(pi, (u_char *)&msicap, sizeof(msicap))); 800366f6083SPeter Grehan } 801366f6083SPeter Grehan 802c9b4e987SNeel Natu static void 803c9b4e987SNeel Natu pci_populate_msixcap(struct msixcap *msixcap, int msgnum, int barnum, 804a96b8b80SJohn Baldwin uint32_t msix_tab_size) 805c9b4e987SNeel Natu { 806c9b4e987SNeel Natu 807c9b4e987SNeel Natu assert(msix_tab_size % 4096 == 0); 808c9b4e987SNeel Natu 809c9b4e987SNeel Natu bzero(msixcap, sizeof(struct msixcap)); 810c9b4e987SNeel Natu msixcap->capid = PCIY_MSIX; 811c9b4e987SNeel Natu 812c9b4e987SNeel Natu /* 813c9b4e987SNeel Natu * Message Control Register, all fields set to 814c9b4e987SNeel Natu * zero except for the Table Size. 815c9b4e987SNeel Natu * Note: Table size N is encoded as N-1 816c9b4e987SNeel Natu */ 817c9b4e987SNeel Natu msixcap->msgctrl = msgnum - 1; 818c9b4e987SNeel Natu 819c9b4e987SNeel Natu /* 820c9b4e987SNeel Natu * MSI-X BAR setup: 821c9b4e987SNeel Natu * - MSI-X table start at offset 0 822c9b4e987SNeel Natu * - PBA table starts at a 4K aligned offset after the MSI-X table 823c9b4e987SNeel Natu */ 824c9b4e987SNeel Natu msixcap->table_info = barnum & PCIM_MSIX_BIR_MASK; 825c9b4e987SNeel Natu msixcap->pba_info = msix_tab_size | (barnum & PCIM_MSIX_BIR_MASK); 826c9b4e987SNeel Natu } 827c9b4e987SNeel Natu 828c9b4e987SNeel Natu static void 829c9b4e987SNeel Natu pci_msix_table_init(struct pci_devinst *pi, int table_entries) 830c9b4e987SNeel Natu { 831c9b4e987SNeel Natu int i, table_size; 832c9b4e987SNeel Natu 833c9b4e987SNeel Natu assert(table_entries > 0); 834c9b4e987SNeel Natu assert(table_entries <= MAX_MSIX_TABLE_ENTRIES); 835c9b4e987SNeel Natu 836c9b4e987SNeel Natu table_size = table_entries * MSIX_TABLE_ENTRY_SIZE; 837994f858aSXin LI pi->pi_msix.table = calloc(1, table_size); 838c9b4e987SNeel Natu 839c9b4e987SNeel Natu /* set mask bit of vector control register */ 840c9b4e987SNeel Natu for (i = 0; i < table_entries; i++) 841c9b4e987SNeel Natu pi->pi_msix.table[i].vector_control |= PCIM_MSIX_VCTRL_MASK; 842c9b4e987SNeel Natu } 843c9b4e987SNeel Natu 844c9b4e987SNeel Natu int 845c9b4e987SNeel Natu pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum) 846c9b4e987SNeel Natu { 847c9b4e987SNeel Natu uint32_t tab_size; 848c9b4e987SNeel Natu struct msixcap msixcap; 849c9b4e987SNeel Natu 850c9b4e987SNeel Natu assert(msgnum >= 1 && msgnum <= MAX_MSIX_TABLE_ENTRIES); 851c9b4e987SNeel Natu assert(barnum >= 0 && barnum <= PCIR_MAX_BAR_0); 852c9b4e987SNeel Natu 853c9b4e987SNeel Natu tab_size = msgnum * MSIX_TABLE_ENTRY_SIZE; 854c9b4e987SNeel Natu 855c9b4e987SNeel Natu /* Align table size to nearest 4K */ 856c9b4e987SNeel Natu tab_size = roundup2(tab_size, 4096); 857c9b4e987SNeel Natu 858c9b4e987SNeel Natu pi->pi_msix.table_bar = barnum; 859c9b4e987SNeel Natu pi->pi_msix.pba_bar = barnum; 860c9b4e987SNeel Natu pi->pi_msix.table_offset = 0; 861c9b4e987SNeel Natu pi->pi_msix.table_count = msgnum; 862c9b4e987SNeel Natu pi->pi_msix.pba_offset = tab_size; 8637a902ec0SNeel Natu pi->pi_msix.pba_size = PBA_SIZE(msgnum); 864c9b4e987SNeel Natu 865c9b4e987SNeel Natu pci_msix_table_init(pi, msgnum); 866c9b4e987SNeel Natu 867a96b8b80SJohn Baldwin pci_populate_msixcap(&msixcap, msgnum, barnum, tab_size); 868c9b4e987SNeel Natu 869c9b4e987SNeel Natu /* allocate memory for MSI-X Table and PBA */ 870c9b4e987SNeel Natu pci_emul_alloc_bar(pi, barnum, PCIBAR_MEM32, 871c9b4e987SNeel Natu tab_size + pi->pi_msix.pba_size); 872c9b4e987SNeel Natu 873c9b4e987SNeel Natu return (pci_emul_add_capability(pi, (u_char *)&msixcap, 874c9b4e987SNeel Natu sizeof(msixcap))); 875c9b4e987SNeel Natu } 876c9b4e987SNeel Natu 877366f6083SPeter Grehan void 878cd942e0fSPeter Grehan msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset, 879cd942e0fSPeter Grehan int bytes, uint32_t val) 880cd942e0fSPeter Grehan { 881cd942e0fSPeter Grehan uint16_t msgctrl, rwmask; 882d74fdc6aSMarcelo Araujo int off; 883cd942e0fSPeter Grehan 884cd942e0fSPeter Grehan off = offset - capoff; 885cd942e0fSPeter Grehan /* Message Control Register */ 886cd942e0fSPeter Grehan if (off == 2 && bytes == 2) { 887cd942e0fSPeter Grehan rwmask = PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK; 888cd942e0fSPeter Grehan msgctrl = pci_get_cfgdata16(pi, offset); 889cd942e0fSPeter Grehan msgctrl &= ~rwmask; 890cd942e0fSPeter Grehan msgctrl |= val & rwmask; 891cd942e0fSPeter Grehan val = msgctrl; 892cd942e0fSPeter Grehan 893cd942e0fSPeter Grehan pi->pi_msix.enabled = val & PCIM_MSIXCTRL_MSIX_ENABLE; 894c9b4e987SNeel Natu pi->pi_msix.function_mask = val & PCIM_MSIXCTRL_FUNCTION_MASK; 8953cbf3585SJohn Baldwin pci_lintr_update(pi); 896cd942e0fSPeter Grehan } 897cd942e0fSPeter Grehan 898cd942e0fSPeter Grehan CFGWRITE(pi, offset, val, bytes); 899cd942e0fSPeter Grehan } 900cd942e0fSPeter Grehan 901cd942e0fSPeter Grehan void 902366f6083SPeter Grehan msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset, 903366f6083SPeter Grehan int bytes, uint32_t val) 904366f6083SPeter Grehan { 905366f6083SPeter Grehan uint16_t msgctrl, rwmask, msgdata, mme; 906366f6083SPeter Grehan uint32_t addrlo; 907366f6083SPeter Grehan 908366f6083SPeter Grehan /* 909366f6083SPeter Grehan * If guest is writing to the message control register make sure 910366f6083SPeter Grehan * we do not overwrite read-only fields. 911366f6083SPeter Grehan */ 912366f6083SPeter Grehan if ((offset - capoff) == 2 && bytes == 2) { 913366f6083SPeter Grehan rwmask = PCIM_MSICTRL_MME_MASK | PCIM_MSICTRL_MSI_ENABLE; 914366f6083SPeter Grehan msgctrl = pci_get_cfgdata16(pi, offset); 915366f6083SPeter Grehan msgctrl &= ~rwmask; 916366f6083SPeter Grehan msgctrl |= val & rwmask; 917366f6083SPeter Grehan val = msgctrl; 918366f6083SPeter Grehan 919366f6083SPeter Grehan addrlo = pci_get_cfgdata32(pi, capoff + 4); 920366f6083SPeter Grehan if (msgctrl & PCIM_MSICTRL_64BIT) 921366f6083SPeter Grehan msgdata = pci_get_cfgdata16(pi, capoff + 12); 922366f6083SPeter Grehan else 923366f6083SPeter Grehan msgdata = pci_get_cfgdata16(pi, capoff + 8); 924366f6083SPeter Grehan 925366f6083SPeter Grehan mme = msgctrl & PCIM_MSICTRL_MME_MASK; 926366f6083SPeter Grehan pi->pi_msi.enabled = msgctrl & PCIM_MSICTRL_MSI_ENABLE ? 1 : 0; 927366f6083SPeter Grehan if (pi->pi_msi.enabled) { 9284f8be175SNeel Natu pi->pi_msi.addr = addrlo; 9294f8be175SNeel Natu pi->pi_msi.msg_data = msgdata; 9304f8be175SNeel Natu pi->pi_msi.maxmsgnum = 1 << (mme >> 4); 931366f6083SPeter Grehan } else { 9324f8be175SNeel Natu pi->pi_msi.maxmsgnum = 0; 933366f6083SPeter Grehan } 9343cbf3585SJohn Baldwin pci_lintr_update(pi); 935366f6083SPeter Grehan } 936366f6083SPeter Grehan 937366f6083SPeter Grehan CFGWRITE(pi, offset, val, bytes); 938366f6083SPeter Grehan } 939366f6083SPeter Grehan 94074f80b23SNeel Natu void 94174f80b23SNeel Natu pciecap_cfgwrite(struct pci_devinst *pi, int capoff, int offset, 94274f80b23SNeel Natu int bytes, uint32_t val) 94374f80b23SNeel Natu { 94474f80b23SNeel Natu 94574f80b23SNeel Natu /* XXX don't write to the readonly parts */ 94674f80b23SNeel Natu CFGWRITE(pi, offset, val, bytes); 94774f80b23SNeel Natu } 94874f80b23SNeel Natu 94974f80b23SNeel Natu #define PCIECAP_VERSION 0x2 95074f80b23SNeel Natu int 95174f80b23SNeel Natu pci_emul_add_pciecap(struct pci_devinst *pi, int type) 95274f80b23SNeel Natu { 95374f80b23SNeel Natu int err; 95474f80b23SNeel Natu struct pciecap pciecap; 95574f80b23SNeel Natu 95674f80b23SNeel Natu if (type != PCIEM_TYPE_ROOT_PORT) 95774f80b23SNeel Natu return (-1); 95874f80b23SNeel Natu 95974f80b23SNeel Natu bzero(&pciecap, sizeof(pciecap)); 96074f80b23SNeel Natu 96174f80b23SNeel Natu pciecap.capid = PCIY_EXPRESS; 962f0dfbcccSChuck Tuffli pciecap.pcie_capabilities = PCIECAP_VERSION | PCIEM_TYPE_ROOT_PORT; 96374f80b23SNeel Natu pciecap.link_capabilities = 0x411; /* gen1, x1 */ 96474f80b23SNeel Natu pciecap.link_status = 0x11; /* gen1, x1 */ 96574f80b23SNeel Natu 96674f80b23SNeel Natu err = pci_emul_add_capability(pi, (u_char *)&pciecap, sizeof(pciecap)); 96774f80b23SNeel Natu return (err); 96874f80b23SNeel Natu } 96974f80b23SNeel Natu 970366f6083SPeter Grehan /* 971366f6083SPeter Grehan * This function assumes that 'coff' is in the capabilities region of the 972366f6083SPeter Grehan * config space. 973366f6083SPeter Grehan */ 974366f6083SPeter Grehan static void 975366f6083SPeter Grehan pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val) 976366f6083SPeter Grehan { 977366f6083SPeter Grehan int capid; 978366f6083SPeter Grehan uint8_t capoff, nextoff; 979366f6083SPeter Grehan 980366f6083SPeter Grehan /* Do not allow un-aligned writes */ 981366f6083SPeter Grehan if ((offset & (bytes - 1)) != 0) 982366f6083SPeter Grehan return; 983366f6083SPeter Grehan 984366f6083SPeter Grehan /* Find the capability that we want to update */ 985366f6083SPeter Grehan capoff = CAP_START_OFFSET; 986366f6083SPeter Grehan while (1) { 987366f6083SPeter Grehan nextoff = pci_get_cfgdata8(pi, capoff + 1); 988a96b8b80SJohn Baldwin if (nextoff == 0) 989a96b8b80SJohn Baldwin break; 990366f6083SPeter Grehan if (offset >= capoff && offset < nextoff) 991366f6083SPeter Grehan break; 992366f6083SPeter Grehan 993366f6083SPeter Grehan capoff = nextoff; 994366f6083SPeter Grehan } 995366f6083SPeter Grehan assert(offset >= capoff); 996366f6083SPeter Grehan 997366f6083SPeter Grehan /* 9982a8d400aSPeter Grehan * Capability ID and Next Capability Pointer are readonly. 9992a8d400aSPeter Grehan * However, some o/s's do 4-byte writes that include these. 10002a8d400aSPeter Grehan * For this case, trim the write back to 2 bytes and adjust 10012a8d400aSPeter Grehan * the data. 1002366f6083SPeter Grehan */ 10032a8d400aSPeter Grehan if (offset == capoff || offset == capoff + 1) { 10042a8d400aSPeter Grehan if (offset == capoff && bytes == 4) { 10052a8d400aSPeter Grehan bytes = 2; 10062a8d400aSPeter Grehan offset += 2; 10072a8d400aSPeter Grehan val >>= 16; 10082a8d400aSPeter Grehan } else 1009366f6083SPeter Grehan return; 10102a8d400aSPeter Grehan } 1011366f6083SPeter Grehan 1012a96b8b80SJohn Baldwin capid = pci_get_cfgdata8(pi, capoff); 1013366f6083SPeter Grehan switch (capid) { 1014366f6083SPeter Grehan case PCIY_MSI: 1015366f6083SPeter Grehan msicap_cfgwrite(pi, capoff, offset, bytes, val); 1016366f6083SPeter Grehan break; 1017c9b4e987SNeel Natu case PCIY_MSIX: 1018c9b4e987SNeel Natu msixcap_cfgwrite(pi, capoff, offset, bytes, val); 1019c9b4e987SNeel Natu break; 102074f80b23SNeel Natu case PCIY_EXPRESS: 102174f80b23SNeel Natu pciecap_cfgwrite(pi, capoff, offset, bytes, val); 102274f80b23SNeel Natu break; 1023366f6083SPeter Grehan default: 1024366f6083SPeter Grehan break; 1025366f6083SPeter Grehan } 1026366f6083SPeter Grehan } 1027366f6083SPeter Grehan 1028366f6083SPeter Grehan static int 1029366f6083SPeter Grehan pci_emul_iscap(struct pci_devinst *pi, int offset) 1030366f6083SPeter Grehan { 1031366f6083SPeter Grehan uint16_t sts; 1032366f6083SPeter Grehan 1033366f6083SPeter Grehan sts = pci_get_cfgdata16(pi, PCIR_STATUS); 1034366f6083SPeter Grehan if ((sts & PCIM_STATUS_CAPPRESENT) != 0) { 1035a96b8b80SJohn Baldwin if (offset >= CAP_START_OFFSET && offset <= pi->pi_capend) 1036a96b8b80SJohn Baldwin return (1); 1037366f6083SPeter Grehan } 1038a96b8b80SJohn Baldwin return (0); 1039366f6083SPeter Grehan } 1040366f6083SPeter Grehan 10410ab13648SPeter Grehan static int 10420ab13648SPeter Grehan pci_emul_fallback_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr, 10430ab13648SPeter Grehan int size, uint64_t *val, void *arg1, long arg2) 10440ab13648SPeter Grehan { 10450ab13648SPeter Grehan /* 10460ab13648SPeter Grehan * Ignore writes; return 0xff's for reads. The mem read code 10470ab13648SPeter Grehan * will take care of truncating to the correct size. 10480ab13648SPeter Grehan */ 10490ab13648SPeter Grehan if (dir == MEM_F_READ) { 10500ab13648SPeter Grehan *val = 0xffffffffffffffff; 10510ab13648SPeter Grehan } 10520ab13648SPeter Grehan 10530ab13648SPeter Grehan return (0); 10540ab13648SPeter Grehan } 10550ab13648SPeter Grehan 105612a6eb99SNeel Natu static int 105712a6eb99SNeel Natu pci_emul_ecfg_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr, 105812a6eb99SNeel Natu int bytes, uint64_t *val, void *arg1, long arg2) 105912a6eb99SNeel Natu { 106012a6eb99SNeel Natu int bus, slot, func, coff, in; 106112a6eb99SNeel Natu 106212a6eb99SNeel Natu coff = addr & 0xfff; 106312a6eb99SNeel Natu func = (addr >> 12) & 0x7; 106412a6eb99SNeel Natu slot = (addr >> 15) & 0x1f; 106512a6eb99SNeel Natu bus = (addr >> 20) & 0xff; 106612a6eb99SNeel Natu in = (dir == MEM_F_READ); 106712a6eb99SNeel Natu if (in) 106812a6eb99SNeel Natu *val = ~0UL; 106912a6eb99SNeel Natu pci_cfgrw(ctx, vcpu, in, bus, slot, func, coff, bytes, (uint32_t *)val); 107012a6eb99SNeel Natu return (0); 107112a6eb99SNeel Natu } 107212a6eb99SNeel Natu 107312a6eb99SNeel Natu uint64_t 107412a6eb99SNeel Natu pci_ecfg_base(void) 107512a6eb99SNeel Natu { 107612a6eb99SNeel Natu 107712a6eb99SNeel Natu return (PCI_EMUL_ECFG_BASE); 107812a6eb99SNeel Natu } 107912a6eb99SNeel Natu 1080d84882caSNeel Natu #define BUSIO_ROUNDUP 32 1081d84882caSNeel Natu #define BUSMEM_ROUNDUP (1024 * 1024) 1082d84882caSNeel Natu 1083a38e2a64SPeter Grehan int 1084366f6083SPeter Grehan init_pci(struct vmctx *ctx) 1085366f6083SPeter Grehan { 108612a6eb99SNeel Natu struct mem_range mr; 1087366f6083SPeter Grehan struct pci_devemu *pde; 1088d84882caSNeel Natu struct businfo *bi; 1089d84882caSNeel Natu struct slotinfo *si; 10903cbf3585SJohn Baldwin struct funcinfo *fi; 10919f08548dSNeel Natu size_t lowmem; 1092d84882caSNeel Natu int bus, slot, func; 10930ab13648SPeter Grehan int error; 1094366f6083SPeter Grehan 1095366f6083SPeter Grehan pci_emul_iobase = PCI_EMUL_IOBASE; 10969f08548dSNeel Natu pci_emul_membase32 = vm_get_lowmem_limit(ctx); 1097366f6083SPeter Grehan pci_emul_membase64 = PCI_EMUL_MEMBASE64; 1098366f6083SPeter Grehan 1099d84882caSNeel Natu for (bus = 0; bus < MAXBUSES; bus++) { 1100d84882caSNeel Natu if ((bi = pci_businfo[bus]) == NULL) 1101d84882caSNeel Natu continue; 1102d84882caSNeel Natu /* 1103d84882caSNeel Natu * Keep track of the i/o and memory resources allocated to 1104d84882caSNeel Natu * this bus. 1105d84882caSNeel Natu */ 1106d84882caSNeel Natu bi->iobase = pci_emul_iobase; 1107d84882caSNeel Natu bi->membase32 = pci_emul_membase32; 1108d84882caSNeel Natu bi->membase64 = pci_emul_membase64; 1109d84882caSNeel Natu 111099d65389SNeel Natu for (slot = 0; slot < MAXSLOTS; slot++) { 1111d84882caSNeel Natu si = &bi->slotinfo[slot]; 111299d65389SNeel Natu for (func = 0; func < MAXFUNCS; func++) { 1113d84882caSNeel Natu fi = &si->si_funcs[func]; 1114d84882caSNeel Natu if (fi->fi_name == NULL) 1115d84882caSNeel Natu continue; 11163cbf3585SJohn Baldwin pde = pci_emul_finddev(fi->fi_name); 1117b05c77ffSNeel Natu assert(pde != NULL); 1118d84882caSNeel Natu error = pci_emul_init(ctx, pde, bus, slot, 1119d84882caSNeel Natu func, fi); 1120a38e2a64SPeter Grehan if (error) 1121a38e2a64SPeter Grehan return (error); 1122366f6083SPeter Grehan } 1123366f6083SPeter Grehan } 1124d84882caSNeel Natu 1125d84882caSNeel Natu /* 1126d84882caSNeel Natu * Add some slop to the I/O and memory resources decoded by 1127d84882caSNeel Natu * this bus to give a guest some flexibility if it wants to 1128d84882caSNeel Natu * reprogram the BARs. 1129d84882caSNeel Natu */ 1130d84882caSNeel Natu pci_emul_iobase += BUSIO_ROUNDUP; 1131d84882caSNeel Natu pci_emul_iobase = roundup2(pci_emul_iobase, BUSIO_ROUNDUP); 1132d84882caSNeel Natu bi->iolimit = pci_emul_iobase; 1133d84882caSNeel Natu 1134d84882caSNeel Natu pci_emul_membase32 += BUSMEM_ROUNDUP; 1135d84882caSNeel Natu pci_emul_membase32 = roundup2(pci_emul_membase32, 1136d84882caSNeel Natu BUSMEM_ROUNDUP); 1137d84882caSNeel Natu bi->memlimit32 = pci_emul_membase32; 1138d84882caSNeel Natu 1139d84882caSNeel Natu pci_emul_membase64 += BUSMEM_ROUNDUP; 1140d84882caSNeel Natu pci_emul_membase64 = roundup2(pci_emul_membase64, 1141d84882caSNeel Natu BUSMEM_ROUNDUP); 1142d84882caSNeel Natu bi->memlimit64 = pci_emul_membase64; 1143366f6083SPeter Grehan } 11440038ee98SPeter Grehan 11450038ee98SPeter Grehan /* 1146b3e9732aSJohn Baldwin * PCI backends are initialized before routing INTx interrupts 1147b3e9732aSJohn Baldwin * so that LPC devices are able to reserve ISA IRQs before 1148b3e9732aSJohn Baldwin * routing PIRQ pins. 1149b3e9732aSJohn Baldwin */ 1150b3e9732aSJohn Baldwin for (bus = 0; bus < MAXBUSES; bus++) { 1151b3e9732aSJohn Baldwin if ((bi = pci_businfo[bus]) == NULL) 1152b3e9732aSJohn Baldwin continue; 1153b3e9732aSJohn Baldwin 1154b3e9732aSJohn Baldwin for (slot = 0; slot < MAXSLOTS; slot++) { 1155b3e9732aSJohn Baldwin si = &bi->slotinfo[slot]; 1156b3e9732aSJohn Baldwin for (func = 0; func < MAXFUNCS; func++) { 1157b3e9732aSJohn Baldwin fi = &si->si_funcs[func]; 1158b3e9732aSJohn Baldwin if (fi->fi_devi == NULL) 1159b3e9732aSJohn Baldwin continue; 1160b3e9732aSJohn Baldwin pci_lintr_route(fi->fi_devi); 1161b3e9732aSJohn Baldwin } 1162b3e9732aSJohn Baldwin } 1163b3e9732aSJohn Baldwin } 1164b3e9732aSJohn Baldwin lpc_pirq_routed(); 1165b3e9732aSJohn Baldwin 1166b3e9732aSJohn Baldwin /* 11679f08548dSNeel Natu * The guest physical memory map looks like the following: 11689f08548dSNeel Natu * [0, lowmem) guest system memory 11699f08548dSNeel Natu * [lowmem, lowmem_limit) memory hole (may be absent) 117012a6eb99SNeel Natu * [lowmem_limit, 0xE0000000) PCI hole (32-bit BAR allocation) 117112a6eb99SNeel Natu * [0xE0000000, 0xF0000000) PCI extended config window 117212a6eb99SNeel Natu * [0xF0000000, 4GB) LAPIC, IOAPIC, HPET, firmware 11739f08548dSNeel Natu * [4GB, 4GB + highmem) 117412a6eb99SNeel Natu */ 117512a6eb99SNeel Natu 117612a6eb99SNeel Natu /* 11779f08548dSNeel Natu * Accesses to memory addresses that are not allocated to system 11789f08548dSNeel Natu * memory or PCI devices return 0xff's. 11790ab13648SPeter Grehan */ 1180be679db4SNeel Natu lowmem = vm_get_lowmem_size(ctx); 118112a6eb99SNeel Natu bzero(&mr, sizeof(struct mem_range)); 118212a6eb99SNeel Natu mr.name = "PCI hole"; 118312a6eb99SNeel Natu mr.flags = MEM_F_RW | MEM_F_IMMUTABLE; 118412a6eb99SNeel Natu mr.base = lowmem; 118512a6eb99SNeel Natu mr.size = (4ULL * 1024 * 1024 * 1024) - lowmem; 118612a6eb99SNeel Natu mr.handler = pci_emul_fallback_handler; 118712a6eb99SNeel Natu error = register_mem_fallback(&mr); 118812a6eb99SNeel Natu assert(error == 0); 11899f08548dSNeel Natu 119012a6eb99SNeel Natu /* PCI extended config space */ 119112a6eb99SNeel Natu bzero(&mr, sizeof(struct mem_range)); 119212a6eb99SNeel Natu mr.name = "PCI ECFG"; 119312a6eb99SNeel Natu mr.flags = MEM_F_RW | MEM_F_IMMUTABLE; 119412a6eb99SNeel Natu mr.base = PCI_EMUL_ECFG_BASE; 119512a6eb99SNeel Natu mr.size = PCI_EMUL_ECFG_SIZE; 119612a6eb99SNeel Natu mr.handler = pci_emul_ecfg_handler; 119712a6eb99SNeel Natu error = register_mem(&mr); 11980ab13648SPeter Grehan assert(error == 0); 1199a38e2a64SPeter Grehan 1200a38e2a64SPeter Grehan return (0); 1201366f6083SPeter Grehan } 1202366f6083SPeter Grehan 12033cbf3585SJohn Baldwin static void 1204b3e9732aSJohn Baldwin pci_apic_prt_entry(int bus, int slot, int pin, int pirq_pin, int ioapic_irq, 1205b3e9732aSJohn Baldwin void *arg) 12063cbf3585SJohn Baldwin { 12073cbf3585SJohn Baldwin 1208b3e9732aSJohn Baldwin dsdt_line(" Package ()"); 12093cbf3585SJohn Baldwin dsdt_line(" {"); 12103cbf3585SJohn Baldwin dsdt_line(" 0x%X,", slot << 16 | 0xffff); 12113cbf3585SJohn Baldwin dsdt_line(" 0x%02X,", pin - 1); 12123cbf3585SJohn Baldwin dsdt_line(" Zero,"); 12133cbf3585SJohn Baldwin dsdt_line(" 0x%X", ioapic_irq); 1214b3e9732aSJohn Baldwin dsdt_line(" },"); 1215b3e9732aSJohn Baldwin } 1216b3e9732aSJohn Baldwin 1217b3e9732aSJohn Baldwin static void 1218b3e9732aSJohn Baldwin pci_pirq_prt_entry(int bus, int slot, int pin, int pirq_pin, int ioapic_irq, 1219b3e9732aSJohn Baldwin void *arg) 1220b3e9732aSJohn Baldwin { 1221b3e9732aSJohn Baldwin char *name; 1222b3e9732aSJohn Baldwin 1223b3e9732aSJohn Baldwin name = lpc_pirq_name(pirq_pin); 1224b3e9732aSJohn Baldwin if (name == NULL) 1225b3e9732aSJohn Baldwin return; 1226b3e9732aSJohn Baldwin dsdt_line(" Package ()"); 1227b3e9732aSJohn Baldwin dsdt_line(" {"); 1228b3e9732aSJohn Baldwin dsdt_line(" 0x%X,", slot << 16 | 0xffff); 1229b3e9732aSJohn Baldwin dsdt_line(" 0x%02X,", pin - 1); 1230b3e9732aSJohn Baldwin dsdt_line(" %s,", name); 1231b3e9732aSJohn Baldwin dsdt_line(" 0x00"); 1232b3e9732aSJohn Baldwin dsdt_line(" },"); 1233b3e9732aSJohn Baldwin free(name); 12343cbf3585SJohn Baldwin } 12353cbf3585SJohn Baldwin 1236d84882caSNeel Natu /* 1237d84882caSNeel Natu * A bhyve virtual machine has a flat PCI hierarchy with a root port 1238d84882caSNeel Natu * corresponding to each PCI bus. 1239d84882caSNeel Natu */ 1240d84882caSNeel Natu static void 1241d84882caSNeel Natu pci_bus_write_dsdt(int bus) 1242e6c8bc29SJohn Baldwin { 1243d84882caSNeel Natu struct businfo *bi; 1244d84882caSNeel Natu struct slotinfo *si; 1245e6c8bc29SJohn Baldwin struct pci_devinst *pi; 1246b3e9732aSJohn Baldwin int count, func, slot; 1247e6c8bc29SJohn Baldwin 1248d84882caSNeel Natu /* 1249d84882caSNeel Natu * If there are no devices on this 'bus' then just return. 1250d84882caSNeel Natu */ 1251d84882caSNeel Natu if ((bi = pci_businfo[bus]) == NULL) { 1252d84882caSNeel Natu /* 1253d84882caSNeel Natu * Bus 0 is special because it decodes the I/O ports used 1254d84882caSNeel Natu * for PCI config space access even if there are no devices 1255d84882caSNeel Natu * on it. 1256d84882caSNeel Natu */ 1257d84882caSNeel Natu if (bus != 0) 1258d84882caSNeel Natu return; 1259d84882caSNeel Natu } 1260d84882caSNeel Natu 1261d84882caSNeel Natu dsdt_line(" Device (PC%02X)", bus); 1262e6c8bc29SJohn Baldwin dsdt_line(" {"); 1263e6c8bc29SJohn Baldwin dsdt_line(" Name (_HID, EisaId (\"PNP0A03\"))"); 1264e6c8bc29SJohn Baldwin dsdt_line(" Name (_ADR, Zero)"); 1265d84882caSNeel Natu 1266d84882caSNeel Natu dsdt_line(" Method (_BBN, 0, NotSerialized)"); 1267d84882caSNeel Natu dsdt_line(" {"); 1268d84882caSNeel Natu dsdt_line(" Return (0x%08X)", bus); 1269d84882caSNeel Natu dsdt_line(" }"); 1270e6c8bc29SJohn Baldwin dsdt_line(" Name (_CRS, ResourceTemplate ()"); 1271e6c8bc29SJohn Baldwin dsdt_line(" {"); 1272e6c8bc29SJohn Baldwin dsdt_line(" WordBusNumber (ResourceProducer, MinFixed, " 1273e6c8bc29SJohn Baldwin "MaxFixed, PosDecode,"); 1274e6c8bc29SJohn Baldwin dsdt_line(" 0x0000, // Granularity"); 1275d84882caSNeel Natu dsdt_line(" 0x%04X, // Range Minimum", bus); 1276d84882caSNeel Natu dsdt_line(" 0x%04X, // Range Maximum", bus); 1277e6c8bc29SJohn Baldwin dsdt_line(" 0x0000, // Translation Offset"); 1278d84882caSNeel Natu dsdt_line(" 0x0001, // Length"); 1279e6c8bc29SJohn Baldwin dsdt_line(" ,, )"); 1280d84882caSNeel Natu 1281d84882caSNeel Natu if (bus == 0) { 1282e6c8bc29SJohn Baldwin dsdt_indent(3); 1283e6c8bc29SJohn Baldwin dsdt_fixed_ioport(0xCF8, 8); 1284e6c8bc29SJohn Baldwin dsdt_unindent(3); 1285d84882caSNeel Natu 1286e6c8bc29SJohn Baldwin dsdt_line(" WordIO (ResourceProducer, MinFixed, MaxFixed, " 1287e6c8bc29SJohn Baldwin "PosDecode, EntireRange,"); 1288e6c8bc29SJohn Baldwin dsdt_line(" 0x0000, // Granularity"); 1289e6c8bc29SJohn Baldwin dsdt_line(" 0x0000, // Range Minimum"); 1290e6c8bc29SJohn Baldwin dsdt_line(" 0x0CF7, // Range Maximum"); 1291e6c8bc29SJohn Baldwin dsdt_line(" 0x0000, // Translation Offset"); 1292e6c8bc29SJohn Baldwin dsdt_line(" 0x0CF8, // Length"); 1293e6c8bc29SJohn Baldwin dsdt_line(" ,, , TypeStatic)"); 1294d84882caSNeel Natu 1295e6c8bc29SJohn Baldwin dsdt_line(" WordIO (ResourceProducer, MinFixed, MaxFixed, " 1296e6c8bc29SJohn Baldwin "PosDecode, EntireRange,"); 1297e6c8bc29SJohn Baldwin dsdt_line(" 0x0000, // Granularity"); 1298e6c8bc29SJohn Baldwin dsdt_line(" 0x0D00, // Range Minimum"); 1299d84882caSNeel Natu dsdt_line(" 0x%04X, // Range Maximum", 1300d84882caSNeel Natu PCI_EMUL_IOBASE - 1); 1301e6c8bc29SJohn Baldwin dsdt_line(" 0x0000, // Translation Offset"); 1302d84882caSNeel Natu dsdt_line(" 0x%04X, // Length", 1303d84882caSNeel Natu PCI_EMUL_IOBASE - 0x0D00); 1304e6c8bc29SJohn Baldwin dsdt_line(" ,, , TypeStatic)"); 1305d84882caSNeel Natu 1306d84882caSNeel Natu if (bi == NULL) { 1307d84882caSNeel Natu dsdt_line(" })"); 1308d84882caSNeel Natu goto done; 1309d84882caSNeel Natu } 1310d84882caSNeel Natu } 1311d84882caSNeel Natu assert(bi != NULL); 1312d84882caSNeel Natu 1313d84882caSNeel Natu /* i/o window */ 1314d84882caSNeel Natu dsdt_line(" WordIO (ResourceProducer, MinFixed, MaxFixed, " 1315d84882caSNeel Natu "PosDecode, EntireRange,"); 1316d84882caSNeel Natu dsdt_line(" 0x0000, // Granularity"); 1317d84882caSNeel Natu dsdt_line(" 0x%04X, // Range Minimum", bi->iobase); 1318d84882caSNeel Natu dsdt_line(" 0x%04X, // Range Maximum", 1319d84882caSNeel Natu bi->iolimit - 1); 1320d84882caSNeel Natu dsdt_line(" 0x0000, // Translation Offset"); 1321d84882caSNeel Natu dsdt_line(" 0x%04X, // Length", 1322d84882caSNeel Natu bi->iolimit - bi->iobase); 1323d84882caSNeel Natu dsdt_line(" ,, , TypeStatic)"); 1324d84882caSNeel Natu 1325d84882caSNeel Natu /* mmio window (32-bit) */ 1326e6c8bc29SJohn Baldwin dsdt_line(" DWordMemory (ResourceProducer, PosDecode, " 1327e6c8bc29SJohn Baldwin "MinFixed, MaxFixed, NonCacheable, ReadWrite,"); 1328e6c8bc29SJohn Baldwin dsdt_line(" 0x00000000, // Granularity"); 1329d84882caSNeel Natu dsdt_line(" 0x%08X, // Range Minimum\n", bi->membase32); 1330e6c8bc29SJohn Baldwin dsdt_line(" 0x%08X, // Range Maximum\n", 1331d84882caSNeel Natu bi->memlimit32 - 1); 1332e6c8bc29SJohn Baldwin dsdt_line(" 0x00000000, // Translation Offset"); 1333d84882caSNeel Natu dsdt_line(" 0x%08X, // Length\n", 1334d84882caSNeel Natu bi->memlimit32 - bi->membase32); 1335e6c8bc29SJohn Baldwin dsdt_line(" ,, , AddressRangeMemory, TypeStatic)"); 1336d84882caSNeel Natu 1337d84882caSNeel Natu /* mmio window (64-bit) */ 1338e6c8bc29SJohn Baldwin dsdt_line(" QWordMemory (ResourceProducer, PosDecode, " 1339e6c8bc29SJohn Baldwin "MinFixed, MaxFixed, NonCacheable, ReadWrite,"); 1340e6c8bc29SJohn Baldwin dsdt_line(" 0x0000000000000000, // Granularity"); 1341d84882caSNeel Natu dsdt_line(" 0x%016lX, // Range Minimum\n", bi->membase64); 1342e6c8bc29SJohn Baldwin dsdt_line(" 0x%016lX, // Range Maximum\n", 1343d84882caSNeel Natu bi->memlimit64 - 1); 1344e6c8bc29SJohn Baldwin dsdt_line(" 0x0000000000000000, // Translation Offset"); 1345e6c8bc29SJohn Baldwin dsdt_line(" 0x%016lX, // Length\n", 1346d84882caSNeel Natu bi->memlimit64 - bi->membase64); 1347e6c8bc29SJohn Baldwin dsdt_line(" ,, , AddressRangeMemory, TypeStatic)"); 1348e6c8bc29SJohn Baldwin dsdt_line(" })"); 1349d84882caSNeel Natu 1350d84882caSNeel Natu count = pci_count_lintr(bus); 13513cbf3585SJohn Baldwin if (count != 0) { 13523cbf3585SJohn Baldwin dsdt_indent(2); 1353b3e9732aSJohn Baldwin dsdt_line("Name (PPRT, Package ()"); 13543cbf3585SJohn Baldwin dsdt_line("{"); 1355b3e9732aSJohn Baldwin pci_walk_lintr(bus, pci_pirq_prt_entry, NULL); 13563cbf3585SJohn Baldwin dsdt_line("})"); 1357b3e9732aSJohn Baldwin dsdt_line("Name (APRT, Package ()"); 1358b3e9732aSJohn Baldwin dsdt_line("{"); 1359b3e9732aSJohn Baldwin pci_walk_lintr(bus, pci_apic_prt_entry, NULL); 1360b3e9732aSJohn Baldwin dsdt_line("})"); 1361b3e9732aSJohn Baldwin dsdt_line("Method (_PRT, 0, NotSerialized)"); 1362b3e9732aSJohn Baldwin dsdt_line("{"); 1363b3e9732aSJohn Baldwin dsdt_line(" If (PICM)"); 1364b3e9732aSJohn Baldwin dsdt_line(" {"); 1365b3e9732aSJohn Baldwin dsdt_line(" Return (APRT)"); 1366b3e9732aSJohn Baldwin dsdt_line(" }"); 1367b3e9732aSJohn Baldwin dsdt_line(" Else"); 1368b3e9732aSJohn Baldwin dsdt_line(" {"); 1369b3e9732aSJohn Baldwin dsdt_line(" Return (PPRT)"); 1370b3e9732aSJohn Baldwin dsdt_line(" }"); 1371b3e9732aSJohn Baldwin dsdt_line("}"); 13723cbf3585SJohn Baldwin dsdt_unindent(2); 13733cbf3585SJohn Baldwin } 1374e6c8bc29SJohn Baldwin 1375e6c8bc29SJohn Baldwin dsdt_indent(2); 1376e6c8bc29SJohn Baldwin for (slot = 0; slot < MAXSLOTS; slot++) { 1377d84882caSNeel Natu si = &bi->slotinfo[slot]; 1378e6c8bc29SJohn Baldwin for (func = 0; func < MAXFUNCS; func++) { 1379d84882caSNeel Natu pi = si->si_funcs[func].fi_devi; 1380e6c8bc29SJohn Baldwin if (pi != NULL && pi->pi_d->pe_write_dsdt != NULL) 1381e6c8bc29SJohn Baldwin pi->pi_d->pe_write_dsdt(pi); 1382e6c8bc29SJohn Baldwin } 1383e6c8bc29SJohn Baldwin } 1384e6c8bc29SJohn Baldwin dsdt_unindent(2); 1385d84882caSNeel Natu done: 1386e6c8bc29SJohn Baldwin dsdt_line(" }"); 1387e6c8bc29SJohn Baldwin } 1388e6c8bc29SJohn Baldwin 1389d84882caSNeel Natu void 1390d84882caSNeel Natu pci_write_dsdt(void) 1391d84882caSNeel Natu { 1392d84882caSNeel Natu int bus; 1393d84882caSNeel Natu 1394b3e9732aSJohn Baldwin dsdt_indent(1); 1395b3e9732aSJohn Baldwin dsdt_line("Name (PICM, 0x00)"); 1396b3e9732aSJohn Baldwin dsdt_line("Method (_PIC, 1, NotSerialized)"); 1397b3e9732aSJohn Baldwin dsdt_line("{"); 1398b3e9732aSJohn Baldwin dsdt_line(" Store (Arg0, PICM)"); 1399b3e9732aSJohn Baldwin dsdt_line("}"); 1400b3e9732aSJohn Baldwin dsdt_line(""); 1401b3e9732aSJohn Baldwin dsdt_line("Scope (_SB)"); 1402b3e9732aSJohn Baldwin dsdt_line("{"); 1403d84882caSNeel Natu for (bus = 0; bus < MAXBUSES; bus++) 1404d84882caSNeel Natu pci_bus_write_dsdt(bus); 1405b3e9732aSJohn Baldwin dsdt_line("}"); 1406b3e9732aSJohn Baldwin dsdt_unindent(1); 1407d84882caSNeel Natu } 1408d84882caSNeel Natu 1409366f6083SPeter Grehan int 1410b100acf2SNeel Natu pci_bus_configured(int bus) 1411b100acf2SNeel Natu { 1412b100acf2SNeel Natu assert(bus >= 0 && bus < MAXBUSES); 1413b100acf2SNeel Natu return (pci_businfo[bus] != NULL); 1414b100acf2SNeel Natu } 1415b100acf2SNeel Natu 1416b100acf2SNeel Natu int 1417366f6083SPeter Grehan pci_msi_enabled(struct pci_devinst *pi) 1418366f6083SPeter Grehan { 1419366f6083SPeter Grehan return (pi->pi_msi.enabled); 1420366f6083SPeter Grehan } 1421366f6083SPeter Grehan 1422366f6083SPeter Grehan int 14234f8be175SNeel Natu pci_msi_maxmsgnum(struct pci_devinst *pi) 1424366f6083SPeter Grehan { 1425366f6083SPeter Grehan if (pi->pi_msi.enabled) 14264f8be175SNeel Natu return (pi->pi_msi.maxmsgnum); 1427366f6083SPeter Grehan else 1428366f6083SPeter Grehan return (0); 1429366f6083SPeter Grehan } 1430366f6083SPeter Grehan 1431c9b4e987SNeel Natu int 1432c9b4e987SNeel Natu pci_msix_enabled(struct pci_devinst *pi) 1433c9b4e987SNeel Natu { 1434c9b4e987SNeel Natu 1435c9b4e987SNeel Natu return (pi->pi_msix.enabled && !pi->pi_msi.enabled); 1436c9b4e987SNeel Natu } 1437c9b4e987SNeel Natu 1438c9b4e987SNeel Natu void 1439c9b4e987SNeel Natu pci_generate_msix(struct pci_devinst *pi, int index) 1440c9b4e987SNeel Natu { 1441c9b4e987SNeel Natu struct msix_table_entry *mte; 1442c9b4e987SNeel Natu 1443c9b4e987SNeel Natu if (!pci_msix_enabled(pi)) 1444c9b4e987SNeel Natu return; 1445c9b4e987SNeel Natu 1446c9b4e987SNeel Natu if (pi->pi_msix.function_mask) 1447c9b4e987SNeel Natu return; 1448c9b4e987SNeel Natu 1449c9b4e987SNeel Natu if (index >= pi->pi_msix.table_count) 1450c9b4e987SNeel Natu return; 1451c9b4e987SNeel Natu 1452c9b4e987SNeel Natu mte = &pi->pi_msix.table[index]; 1453c9b4e987SNeel Natu if ((mte->vector_control & PCIM_MSIX_VCTRL_MASK) == 0) { 1454c9b4e987SNeel Natu /* XXX Set PBA bit if interrupt is disabled */ 14554f8be175SNeel Natu vm_lapic_msi(pi->pi_vmctx, mte->addr, mte->msg_data); 1456c9b4e987SNeel Natu } 1457c9b4e987SNeel Natu } 1458c9b4e987SNeel Natu 1459366f6083SPeter Grehan void 14604f8be175SNeel Natu pci_generate_msi(struct pci_devinst *pi, int index) 1461366f6083SPeter Grehan { 1462366f6083SPeter Grehan 14634f8be175SNeel Natu if (pci_msi_enabled(pi) && index < pci_msi_maxmsgnum(pi)) { 14644f8be175SNeel Natu vm_lapic_msi(pi->pi_vmctx, pi->pi_msi.addr, 14654f8be175SNeel Natu pi->pi_msi.msg_data + index); 1466366f6083SPeter Grehan } 1467366f6083SPeter Grehan } 1468366f6083SPeter Grehan 14693cbf3585SJohn Baldwin static bool 14703cbf3585SJohn Baldwin pci_lintr_permitted(struct pci_devinst *pi) 14710038ee98SPeter Grehan { 14723cbf3585SJohn Baldwin uint16_t cmd; 14730038ee98SPeter Grehan 14743cbf3585SJohn Baldwin cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); 14753cbf3585SJohn Baldwin return (!(pi->pi_msi.enabled || pi->pi_msix.enabled || 14763cbf3585SJohn Baldwin (cmd & PCIM_CMD_INTxDIS))); 14773cbf3585SJohn Baldwin } 14783cbf3585SJohn Baldwin 1479b3e9732aSJohn Baldwin void 14803cbf3585SJohn Baldwin pci_lintr_request(struct pci_devinst *pi) 14813cbf3585SJohn Baldwin { 1482d84882caSNeel Natu struct businfo *bi; 14833cbf3585SJohn Baldwin struct slotinfo *si; 1484b3e9732aSJohn Baldwin int bestpin, bestcount, pin; 14853cbf3585SJohn Baldwin 1486d84882caSNeel Natu bi = pci_businfo[pi->pi_bus]; 1487d84882caSNeel Natu assert(bi != NULL); 1488d84882caSNeel Natu 14893cbf3585SJohn Baldwin /* 1490b3e9732aSJohn Baldwin * Just allocate a pin from our slot. The pin will be 1491b3e9732aSJohn Baldwin * assigned IRQs later when interrupts are routed. 14923cbf3585SJohn Baldwin */ 1493d84882caSNeel Natu si = &bi->slotinfo[pi->pi_slot]; 14943cbf3585SJohn Baldwin bestpin = 0; 14953cbf3585SJohn Baldwin bestcount = si->si_intpins[0].ii_count; 14963cbf3585SJohn Baldwin for (pin = 1; pin < 4; pin++) { 14973cbf3585SJohn Baldwin if (si->si_intpins[pin].ii_count < bestcount) { 14983cbf3585SJohn Baldwin bestpin = pin; 14993cbf3585SJohn Baldwin bestcount = si->si_intpins[pin].ii_count; 15003cbf3585SJohn Baldwin } 15013cbf3585SJohn Baldwin } 15023cbf3585SJohn Baldwin 15033cbf3585SJohn Baldwin si->si_intpins[bestpin].ii_count++; 15043cbf3585SJohn Baldwin pi->pi_lintr.pin = bestpin + 1; 15053cbf3585SJohn Baldwin pci_set_cfgdata8(pi, PCIR_INTPIN, bestpin + 1); 1506b3e9732aSJohn Baldwin } 1507b3e9732aSJohn Baldwin 1508b3e9732aSJohn Baldwin static void 1509b3e9732aSJohn Baldwin pci_lintr_route(struct pci_devinst *pi) 1510b3e9732aSJohn Baldwin { 1511b3e9732aSJohn Baldwin struct businfo *bi; 1512b3e9732aSJohn Baldwin struct intxinfo *ii; 1513b3e9732aSJohn Baldwin 1514b3e9732aSJohn Baldwin if (pi->pi_lintr.pin == 0) 1515b3e9732aSJohn Baldwin return; 1516b3e9732aSJohn Baldwin 1517b3e9732aSJohn Baldwin bi = pci_businfo[pi->pi_bus]; 1518b3e9732aSJohn Baldwin assert(bi != NULL); 1519b3e9732aSJohn Baldwin ii = &bi->slotinfo[pi->pi_slot].si_intpins[pi->pi_lintr.pin - 1]; 1520b3e9732aSJohn Baldwin 1521b3e9732aSJohn Baldwin /* 1522b3e9732aSJohn Baldwin * Attempt to allocate an I/O APIC pin for this intpin if one 1523b3e9732aSJohn Baldwin * is not yet assigned. 1524b3e9732aSJohn Baldwin */ 1525b3e9732aSJohn Baldwin if (ii->ii_ioapic_irq == 0) 15261b4496d0SAlexander Motin ii->ii_ioapic_irq = ioapic_pci_alloc_irq(pi); 1527b3e9732aSJohn Baldwin assert(ii->ii_ioapic_irq > 0); 1528b3e9732aSJohn Baldwin 1529b3e9732aSJohn Baldwin /* 1530b3e9732aSJohn Baldwin * Attempt to allocate a PIRQ pin for this intpin if one is 1531b3e9732aSJohn Baldwin * not yet assigned. 1532b3e9732aSJohn Baldwin */ 1533b3e9732aSJohn Baldwin if (ii->ii_pirq_pin == 0) 15341b4496d0SAlexander Motin ii->ii_pirq_pin = pirq_alloc_pin(pi); 1535b3e9732aSJohn Baldwin assert(ii->ii_pirq_pin > 0); 1536b3e9732aSJohn Baldwin 1537b3e9732aSJohn Baldwin pi->pi_lintr.ioapic_irq = ii->ii_ioapic_irq; 1538b3e9732aSJohn Baldwin pi->pi_lintr.pirq_pin = ii->ii_pirq_pin; 1539b3e9732aSJohn Baldwin pci_set_cfgdata8(pi, PCIR_INTLINE, pirq_irq(ii->ii_pirq_pin)); 15400038ee98SPeter Grehan } 15410038ee98SPeter Grehan 15420038ee98SPeter Grehan void 15430038ee98SPeter Grehan pci_lintr_assert(struct pci_devinst *pi) 15440038ee98SPeter Grehan { 15450038ee98SPeter Grehan 15463cbf3585SJohn Baldwin assert(pi->pi_lintr.pin > 0); 1547ac7304a7SNeel Natu 15483cbf3585SJohn Baldwin pthread_mutex_lock(&pi->pi_lintr.lock); 15493cbf3585SJohn Baldwin if (pi->pi_lintr.state == IDLE) { 15503cbf3585SJohn Baldwin if (pci_lintr_permitted(pi)) { 15513cbf3585SJohn Baldwin pi->pi_lintr.state = ASSERTED; 1552b3e9732aSJohn Baldwin pci_irq_assert(pi); 15533cbf3585SJohn Baldwin } else 15543cbf3585SJohn Baldwin pi->pi_lintr.state = PENDING; 15550038ee98SPeter Grehan } 15563cbf3585SJohn Baldwin pthread_mutex_unlock(&pi->pi_lintr.lock); 1557ac7304a7SNeel Natu } 15580038ee98SPeter Grehan 15590038ee98SPeter Grehan void 15600038ee98SPeter Grehan pci_lintr_deassert(struct pci_devinst *pi) 15610038ee98SPeter Grehan { 15620038ee98SPeter Grehan 15633cbf3585SJohn Baldwin assert(pi->pi_lintr.pin > 0); 1564ac7304a7SNeel Natu 15653cbf3585SJohn Baldwin pthread_mutex_lock(&pi->pi_lintr.lock); 15663cbf3585SJohn Baldwin if (pi->pi_lintr.state == ASSERTED) { 15673cbf3585SJohn Baldwin pi->pi_lintr.state = IDLE; 1568b3e9732aSJohn Baldwin pci_irq_deassert(pi); 15693cbf3585SJohn Baldwin } else if (pi->pi_lintr.state == PENDING) 15703cbf3585SJohn Baldwin pi->pi_lintr.state = IDLE; 15713cbf3585SJohn Baldwin pthread_mutex_unlock(&pi->pi_lintr.lock); 15723cbf3585SJohn Baldwin } 15733cbf3585SJohn Baldwin 15743cbf3585SJohn Baldwin static void 15753cbf3585SJohn Baldwin pci_lintr_update(struct pci_devinst *pi) 15763cbf3585SJohn Baldwin { 15773cbf3585SJohn Baldwin 15783cbf3585SJohn Baldwin pthread_mutex_lock(&pi->pi_lintr.lock); 15793cbf3585SJohn Baldwin if (pi->pi_lintr.state == ASSERTED && !pci_lintr_permitted(pi)) { 1580b3e9732aSJohn Baldwin pci_irq_deassert(pi); 15813cbf3585SJohn Baldwin pi->pi_lintr.state = PENDING; 15823cbf3585SJohn Baldwin } else if (pi->pi_lintr.state == PENDING && pci_lintr_permitted(pi)) { 15833cbf3585SJohn Baldwin pi->pi_lintr.state = ASSERTED; 1584b3e9732aSJohn Baldwin pci_irq_assert(pi); 15853cbf3585SJohn Baldwin } 15863cbf3585SJohn Baldwin pthread_mutex_unlock(&pi->pi_lintr.lock); 15873cbf3585SJohn Baldwin } 15883cbf3585SJohn Baldwin 15893cbf3585SJohn Baldwin int 1590d84882caSNeel Natu pci_count_lintr(int bus) 15913cbf3585SJohn Baldwin { 15923cbf3585SJohn Baldwin int count, slot, pin; 1593d84882caSNeel Natu struct slotinfo *slotinfo; 15943cbf3585SJohn Baldwin 15953cbf3585SJohn Baldwin count = 0; 1596d84882caSNeel Natu if (pci_businfo[bus] != NULL) { 15973cbf3585SJohn Baldwin for (slot = 0; slot < MAXSLOTS; slot++) { 1598d84882caSNeel Natu slotinfo = &pci_businfo[bus]->slotinfo[slot]; 15993cbf3585SJohn Baldwin for (pin = 0; pin < 4; pin++) { 1600d84882caSNeel Natu if (slotinfo->si_intpins[pin].ii_count != 0) 16013cbf3585SJohn Baldwin count++; 16023cbf3585SJohn Baldwin } 16033cbf3585SJohn Baldwin } 1604d84882caSNeel Natu } 16053cbf3585SJohn Baldwin return (count); 16063cbf3585SJohn Baldwin } 16073cbf3585SJohn Baldwin 16083cbf3585SJohn Baldwin void 1609d84882caSNeel Natu pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg) 16103cbf3585SJohn Baldwin { 1611d84882caSNeel Natu struct businfo *bi; 1612d84882caSNeel Natu struct slotinfo *si; 16133cbf3585SJohn Baldwin struct intxinfo *ii; 16143cbf3585SJohn Baldwin int slot, pin; 16153cbf3585SJohn Baldwin 1616d84882caSNeel Natu if ((bi = pci_businfo[bus]) == NULL) 1617d84882caSNeel Natu return; 1618d84882caSNeel Natu 16193cbf3585SJohn Baldwin for (slot = 0; slot < MAXSLOTS; slot++) { 1620d84882caSNeel Natu si = &bi->slotinfo[slot]; 16213cbf3585SJohn Baldwin for (pin = 0; pin < 4; pin++) { 1622d84882caSNeel Natu ii = &si->si_intpins[pin]; 16233cbf3585SJohn Baldwin if (ii->ii_count != 0) 1624b3e9732aSJohn Baldwin cb(bus, slot, pin + 1, ii->ii_pirq_pin, 1625b3e9732aSJohn Baldwin ii->ii_ioapic_irq, arg); 16263cbf3585SJohn Baldwin } 16270038ee98SPeter Grehan } 1628ac7304a7SNeel Natu } 16290038ee98SPeter Grehan 163099d65389SNeel Natu /* 163199d65389SNeel Natu * Return 1 if the emulated device in 'slot' is a multi-function device. 163299d65389SNeel Natu * Return 0 otherwise. 163399d65389SNeel Natu */ 163499d65389SNeel Natu static int 1635d84882caSNeel Natu pci_emul_is_mfdev(int bus, int slot) 163699d65389SNeel Natu { 1637d84882caSNeel Natu struct businfo *bi; 1638d84882caSNeel Natu struct slotinfo *si; 163999d65389SNeel Natu int f, numfuncs; 16400038ee98SPeter Grehan 164199d65389SNeel Natu numfuncs = 0; 1642d84882caSNeel Natu if ((bi = pci_businfo[bus]) != NULL) { 1643d84882caSNeel Natu si = &bi->slotinfo[slot]; 164499d65389SNeel Natu for (f = 0; f < MAXFUNCS; f++) { 1645d84882caSNeel Natu if (si->si_funcs[f].fi_devi != NULL) { 164699d65389SNeel Natu numfuncs++; 164799d65389SNeel Natu } 164899d65389SNeel Natu } 1649d84882caSNeel Natu } 165099d65389SNeel Natu return (numfuncs > 1); 165199d65389SNeel Natu } 165299d65389SNeel Natu 165399d65389SNeel Natu /* 165499d65389SNeel Natu * Ensure that the PCIM_MFDEV bit is properly set (or unset) depending on 165599d65389SNeel Natu * whether or not is a multi-function being emulated in the pci 'slot'. 165699d65389SNeel Natu */ 165799d65389SNeel Natu static void 1658d84882caSNeel Natu pci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv) 165999d65389SNeel Natu { 166099d65389SNeel Natu int mfdev; 166199d65389SNeel Natu 166299d65389SNeel Natu if (off <= PCIR_HDRTYPE && off + bytes > PCIR_HDRTYPE) { 1663d84882caSNeel Natu mfdev = pci_emul_is_mfdev(bus, slot); 166499d65389SNeel Natu switch (bytes) { 166599d65389SNeel Natu case 1: 166699d65389SNeel Natu case 2: 166799d65389SNeel Natu *rv &= ~PCIM_MFDEV; 166899d65389SNeel Natu if (mfdev) { 166999d65389SNeel Natu *rv |= PCIM_MFDEV; 167099d65389SNeel Natu } 167199d65389SNeel Natu break; 167299d65389SNeel Natu case 4: 167399d65389SNeel Natu *rv &= ~(PCIM_MFDEV << 16); 167499d65389SNeel Natu if (mfdev) { 167599d65389SNeel Natu *rv |= (PCIM_MFDEV << 16); 167699d65389SNeel Natu } 167799d65389SNeel Natu break; 167899d65389SNeel Natu } 167999d65389SNeel Natu } 168099d65389SNeel Natu } 16810038ee98SPeter Grehan 168256282675SJohn Baldwin /* 168356282675SJohn Baldwin * Update device state in response to changes to the PCI command 168456282675SJohn Baldwin * register. 168556282675SJohn Baldwin */ 168656282675SJohn Baldwin void 168756282675SJohn Baldwin pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old) 168856282675SJohn Baldwin { 168956282675SJohn Baldwin int i; 169056282675SJohn Baldwin uint16_t changed, new; 169156282675SJohn Baldwin 169256282675SJohn Baldwin new = pci_get_cfgdata16(pi, PCIR_COMMAND); 169356282675SJohn Baldwin changed = old ^ new; 169456282675SJohn Baldwin 169556282675SJohn Baldwin /* 169656282675SJohn Baldwin * If the MMIO or I/O address space decoding has changed then 169756282675SJohn Baldwin * register/unregister all BARs that decode that address space. 169856282675SJohn Baldwin */ 169956282675SJohn Baldwin for (i = 0; i <= PCI_BARMAX; i++) { 170056282675SJohn Baldwin switch (pi->pi_bar[i].type) { 170156282675SJohn Baldwin case PCIBAR_NONE: 170256282675SJohn Baldwin case PCIBAR_MEMHI64: 170356282675SJohn Baldwin break; 170456282675SJohn Baldwin case PCIBAR_IO: 170556282675SJohn Baldwin /* I/O address space decoding changed? */ 170656282675SJohn Baldwin if (changed & PCIM_CMD_PORTEN) { 170756282675SJohn Baldwin if (new & PCIM_CMD_PORTEN) 170856282675SJohn Baldwin register_bar(pi, i); 170956282675SJohn Baldwin else 171056282675SJohn Baldwin unregister_bar(pi, i); 171156282675SJohn Baldwin } 171256282675SJohn Baldwin break; 171356282675SJohn Baldwin case PCIBAR_MEM32: 171456282675SJohn Baldwin case PCIBAR_MEM64: 171556282675SJohn Baldwin /* MMIO address space decoding changed? */ 171656282675SJohn Baldwin if (changed & PCIM_CMD_MEMEN) { 171756282675SJohn Baldwin if (new & PCIM_CMD_MEMEN) 171856282675SJohn Baldwin register_bar(pi, i); 171956282675SJohn Baldwin else 172056282675SJohn Baldwin unregister_bar(pi, i); 172156282675SJohn Baldwin } 172256282675SJohn Baldwin break; 172356282675SJohn Baldwin default: 172456282675SJohn Baldwin assert(0); 172556282675SJohn Baldwin } 172656282675SJohn Baldwin } 172756282675SJohn Baldwin 172856282675SJohn Baldwin /* 172956282675SJohn Baldwin * If INTx has been unmasked and is pending, assert the 173056282675SJohn Baldwin * interrupt. 173156282675SJohn Baldwin */ 173256282675SJohn Baldwin pci_lintr_update(pi); 173356282675SJohn Baldwin } 173456282675SJohn Baldwin 1735028d9311SNeel Natu static void 173654335630SNeel Natu pci_emul_cmdsts_write(struct pci_devinst *pi, int coff, uint32_t new, int bytes) 1737028d9311SNeel Natu { 173856282675SJohn Baldwin int rshift; 173956282675SJohn Baldwin uint32_t cmd, old, readonly; 174054335630SNeel Natu 174154335630SNeel Natu cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); /* stash old value */ 1742028d9311SNeel Natu 1743028d9311SNeel Natu /* 174454335630SNeel Natu * From PCI Local Bus Specification 3.0 sections 6.2.2 and 6.2.3. 174554335630SNeel Natu * 174654335630SNeel Natu * XXX Bits 8, 11, 12, 13, 14 and 15 in the status register are 174754335630SNeel Natu * 'write 1 to clear'. However these bits are not set to '1' by 174854335630SNeel Natu * any device emulation so it is simpler to treat them as readonly. 1749028d9311SNeel Natu */ 175054335630SNeel Natu rshift = (coff & 0x3) * 8; 175154335630SNeel Natu readonly = 0xFFFFF880 >> rshift; 1752028d9311SNeel Natu 175354335630SNeel Natu old = CFGREAD(pi, coff, bytes); 175454335630SNeel Natu new &= ~readonly; 175554335630SNeel Natu new |= (old & readonly); 175654335630SNeel Natu CFGWRITE(pi, coff, new, bytes); /* update config */ 175754335630SNeel Natu 175856282675SJohn Baldwin pci_emul_cmd_changed(pi, cmd); 1759028d9311SNeel Natu } 1760028d9311SNeel Natu 176112a6eb99SNeel Natu static void 176212a6eb99SNeel Natu pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func, 176312a6eb99SNeel Natu int coff, int bytes, uint32_t *eax) 1764366f6083SPeter Grehan { 1765d84882caSNeel Natu struct businfo *bi; 1766d84882caSNeel Natu struct slotinfo *si; 1767366f6083SPeter Grehan struct pci_devinst *pi; 1768366f6083SPeter Grehan struct pci_devemu *pe; 176912a6eb99SNeel Natu int idx, needcfg; 1770028d9311SNeel Natu uint64_t addr, bar, mask; 1771366f6083SPeter Grehan 177212a6eb99SNeel Natu if ((bi = pci_businfo[bus]) != NULL) { 177312a6eb99SNeel Natu si = &bi->slotinfo[slot]; 177412a6eb99SNeel Natu pi = si->si_funcs[func].fi_devi; 1775d84882caSNeel Natu } else 177690415e0bSNeel Natu pi = NULL; 177790415e0bSNeel Natu 177899d65389SNeel Natu /* 177912a6eb99SNeel Natu * Just return if there is no device at this slot:func or if the 178012a6eb99SNeel Natu * the guest is doing an un-aligned access. 178199d65389SNeel Natu */ 178212a6eb99SNeel Natu if (pi == NULL || (bytes != 1 && bytes != 2 && bytes != 4) || 178312a6eb99SNeel Natu (coff & (bytes - 1)) != 0) { 1784366f6083SPeter Grehan if (in) 1785366f6083SPeter Grehan *eax = 0xffffffff; 178612a6eb99SNeel Natu return; 178712a6eb99SNeel Natu } 178812a6eb99SNeel Natu 178912a6eb99SNeel Natu /* 179012a6eb99SNeel Natu * Ignore all writes beyond the standard config space and return all 179112a6eb99SNeel Natu * ones on reads. 179212a6eb99SNeel Natu */ 179312a6eb99SNeel Natu if (coff >= PCI_REGMAX + 1) { 179412a6eb99SNeel Natu if (in) { 179512a6eb99SNeel Natu *eax = 0xffffffff; 179612a6eb99SNeel Natu /* 179712a6eb99SNeel Natu * Extended capabilities begin at offset 256 in config 179812a6eb99SNeel Natu * space. Absence of extended capabilities is signaled 179912a6eb99SNeel Natu * with all 0s in the extended capability header at 180012a6eb99SNeel Natu * offset 256. 180112a6eb99SNeel Natu */ 180212a6eb99SNeel Natu if (coff <= PCI_REGMAX + 4) 180312a6eb99SNeel Natu *eax = 0x00000000; 180412a6eb99SNeel Natu } 180512a6eb99SNeel Natu return; 1806366f6083SPeter Grehan } 1807366f6083SPeter Grehan 1808366f6083SPeter Grehan pe = pi->pi_d; 1809366f6083SPeter Grehan 1810366f6083SPeter Grehan /* 1811366f6083SPeter Grehan * Config read 1812366f6083SPeter Grehan */ 1813366f6083SPeter Grehan if (in) { 1814366f6083SPeter Grehan /* Let the device emulation override the default handler */ 181599d65389SNeel Natu if (pe->pe_cfgread != NULL) { 181612a6eb99SNeel Natu needcfg = pe->pe_cfgread(ctx, vcpu, pi, coff, bytes, 181712a6eb99SNeel Natu eax); 181899d65389SNeel Natu } else { 181999d65389SNeel Natu needcfg = 1; 182099d65389SNeel Natu } 1821366f6083SPeter Grehan 182254335630SNeel Natu if (needcfg) 182354335630SNeel Natu *eax = CFGREAD(pi, coff, bytes); 182499d65389SNeel Natu 182512a6eb99SNeel Natu pci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax); 1826366f6083SPeter Grehan } else { 1827366f6083SPeter Grehan /* Let the device emulation override the default handler */ 1828366f6083SPeter Grehan if (pe->pe_cfgwrite != NULL && 1829366f6083SPeter Grehan (*pe->pe_cfgwrite)(ctx, vcpu, pi, coff, bytes, *eax) == 0) 183012a6eb99SNeel Natu return; 1831366f6083SPeter Grehan 1832366f6083SPeter Grehan /* 1833366f6083SPeter Grehan * Special handling for write to BAR registers 1834366f6083SPeter Grehan */ 1835366f6083SPeter Grehan if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) { 1836366f6083SPeter Grehan /* 1837366f6083SPeter Grehan * Ignore writes to BAR registers that are not 1838366f6083SPeter Grehan * 4-byte aligned. 1839366f6083SPeter Grehan */ 1840366f6083SPeter Grehan if (bytes != 4 || (coff & 0x3) != 0) 184112a6eb99SNeel Natu return; 1842366f6083SPeter Grehan idx = (coff - PCIR_BAR(0)) / 4; 1843028d9311SNeel Natu mask = ~(pi->pi_bar[idx].size - 1); 1844366f6083SPeter Grehan switch (pi->pi_bar[idx].type) { 1845366f6083SPeter Grehan case PCIBAR_NONE: 1846028d9311SNeel Natu pi->pi_bar[idx].addr = bar = 0; 1847366f6083SPeter Grehan break; 1848366f6083SPeter Grehan case PCIBAR_IO: 1849028d9311SNeel Natu addr = *eax & mask; 1850028d9311SNeel Natu addr &= 0xffff; 1851028d9311SNeel Natu bar = addr | PCIM_BAR_IO_SPACE; 1852028d9311SNeel Natu /* 1853028d9311SNeel Natu * Register the new BAR value for interception 1854028d9311SNeel Natu */ 1855028d9311SNeel Natu if (addr != pi->pi_bar[idx].addr) { 1856028d9311SNeel Natu update_bar_address(pi, addr, idx, 1857028d9311SNeel Natu PCIBAR_IO); 1858028d9311SNeel Natu } 1859366f6083SPeter Grehan break; 1860366f6083SPeter Grehan case PCIBAR_MEM32: 1861028d9311SNeel Natu addr = bar = *eax & mask; 1862366f6083SPeter Grehan bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32; 1863028d9311SNeel Natu if (addr != pi->pi_bar[idx].addr) { 1864028d9311SNeel Natu update_bar_address(pi, addr, idx, 1865028d9311SNeel Natu PCIBAR_MEM32); 1866028d9311SNeel Natu } 1867366f6083SPeter Grehan break; 1868366f6083SPeter Grehan case PCIBAR_MEM64: 1869028d9311SNeel Natu addr = bar = *eax & mask; 1870366f6083SPeter Grehan bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 | 1871366f6083SPeter Grehan PCIM_BAR_MEM_PREFETCH; 1872028d9311SNeel Natu if (addr != (uint32_t)pi->pi_bar[idx].addr) { 1873028d9311SNeel Natu update_bar_address(pi, addr, idx, 1874028d9311SNeel Natu PCIBAR_MEM64); 1875028d9311SNeel Natu } 1876366f6083SPeter Grehan break; 1877366f6083SPeter Grehan case PCIBAR_MEMHI64: 1878366f6083SPeter Grehan mask = ~(pi->pi_bar[idx - 1].size - 1); 1879028d9311SNeel Natu addr = ((uint64_t)*eax << 32) & mask; 1880028d9311SNeel Natu bar = addr >> 32; 1881028d9311SNeel Natu if (bar != pi->pi_bar[idx - 1].addr >> 32) { 1882028d9311SNeel Natu update_bar_address(pi, addr, idx - 1, 1883028d9311SNeel Natu PCIBAR_MEMHI64); 1884028d9311SNeel Natu } 1885366f6083SPeter Grehan break; 1886366f6083SPeter Grehan default: 1887366f6083SPeter Grehan assert(0); 1888366f6083SPeter Grehan } 1889366f6083SPeter Grehan pci_set_cfgdata32(pi, coff, bar); 1890cd942e0fSPeter Grehan 1891366f6083SPeter Grehan } else if (pci_emul_iscap(pi, coff)) { 1892366f6083SPeter Grehan pci_emul_capwrite(pi, coff, bytes, *eax); 189354335630SNeel Natu } else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) { 189454335630SNeel Natu pci_emul_cmdsts_write(pi, coff, *eax, bytes); 1895366f6083SPeter Grehan } else { 1896366f6083SPeter Grehan CFGWRITE(pi, coff, *eax, bytes); 1897366f6083SPeter Grehan } 1898366f6083SPeter Grehan } 189912a6eb99SNeel Natu } 1900366f6083SPeter Grehan 190112a6eb99SNeel Natu static int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff; 190212a6eb99SNeel Natu 190312a6eb99SNeel Natu static int 190412a6eb99SNeel Natu pci_emul_cfgaddr(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 190512a6eb99SNeel Natu uint32_t *eax, void *arg) 190612a6eb99SNeel Natu { 190712a6eb99SNeel Natu uint32_t x; 190812a6eb99SNeel Natu 190912a6eb99SNeel Natu if (bytes != 4) { 191012a6eb99SNeel Natu if (in) 191112a6eb99SNeel Natu *eax = (bytes == 2) ? 0xffff : 0xff; 191212a6eb99SNeel Natu return (0); 191312a6eb99SNeel Natu } 191412a6eb99SNeel Natu 191512a6eb99SNeel Natu if (in) { 191612a6eb99SNeel Natu x = (cfgbus << 16) | (cfgslot << 11) | (cfgfunc << 8) | cfgoff; 191712a6eb99SNeel Natu if (cfgenable) 191812a6eb99SNeel Natu x |= CONF1_ENABLE; 191912a6eb99SNeel Natu *eax = x; 192012a6eb99SNeel Natu } else { 192112a6eb99SNeel Natu x = *eax; 192212a6eb99SNeel Natu cfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE; 192312a6eb99SNeel Natu cfgoff = x & PCI_REGMAX; 192412a6eb99SNeel Natu cfgfunc = (x >> 8) & PCI_FUNCMAX; 192512a6eb99SNeel Natu cfgslot = (x >> 11) & PCI_SLOTMAX; 192612a6eb99SNeel Natu cfgbus = (x >> 16) & PCI_BUSMAX; 192712a6eb99SNeel Natu } 192812a6eb99SNeel Natu 192912a6eb99SNeel Natu return (0); 193012a6eb99SNeel Natu } 193112a6eb99SNeel Natu INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_INOUT, pci_emul_cfgaddr); 193212a6eb99SNeel Natu 193312a6eb99SNeel Natu static int 193412a6eb99SNeel Natu pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 193512a6eb99SNeel Natu uint32_t *eax, void *arg) 193612a6eb99SNeel Natu { 193712a6eb99SNeel Natu int coff; 193812a6eb99SNeel Natu 193912a6eb99SNeel Natu assert(bytes == 1 || bytes == 2 || bytes == 4); 194012a6eb99SNeel Natu 194112a6eb99SNeel Natu coff = cfgoff + (port - CONF1_DATA_PORT); 194212a6eb99SNeel Natu if (cfgenable) { 194312a6eb99SNeel Natu pci_cfgrw(ctx, vcpu, in, cfgbus, cfgslot, cfgfunc, coff, bytes, 194412a6eb99SNeel Natu eax); 194512a6eb99SNeel Natu } else { 194612a6eb99SNeel Natu /* Ignore accesses to cfgdata if not enabled by cfgaddr */ 194712a6eb99SNeel Natu if (in) 194812a6eb99SNeel Natu *eax = 0xffffffff; 194912a6eb99SNeel Natu } 1950366f6083SPeter Grehan return (0); 1951366f6083SPeter Grehan } 1952366f6083SPeter Grehan 1953366f6083SPeter Grehan INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+0, IOPORT_F_INOUT, pci_emul_cfgdata); 1954366f6083SPeter Grehan INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+1, IOPORT_F_INOUT, pci_emul_cfgdata); 1955366f6083SPeter Grehan INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+2, IOPORT_F_INOUT, pci_emul_cfgdata); 1956366f6083SPeter Grehan INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+3, IOPORT_F_INOUT, pci_emul_cfgdata); 1957366f6083SPeter Grehan 1958366f6083SPeter Grehan #define PCI_EMUL_TEST 1959366f6083SPeter Grehan #ifdef PCI_EMUL_TEST 1960366f6083SPeter Grehan /* 1961366f6083SPeter Grehan * Define a dummy test device 1962366f6083SPeter Grehan */ 1963d84882caSNeel Natu #define DIOSZ 8 19644d1e669cSPeter Grehan #define DMEMSZ 4096 1965366f6083SPeter Grehan struct pci_emul_dsoftc { 19664d1e669cSPeter Grehan uint8_t ioregs[DIOSZ]; 1967fd4e0d4cSNeel Natu uint8_t memregs[2][DMEMSZ]; 1968366f6083SPeter Grehan }; 1969366f6083SPeter Grehan 19704d1e669cSPeter Grehan #define PCI_EMUL_MSI_MSGS 4 19714d1e669cSPeter Grehan #define PCI_EMUL_MSIX_MSGS 16 1972366f6083SPeter Grehan 1973b67e81dbSJohn Baldwin static int 1974366f6083SPeter Grehan pci_emul_dinit(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 1975366f6083SPeter Grehan { 1976366f6083SPeter Grehan int error; 1977366f6083SPeter Grehan struct pci_emul_dsoftc *sc; 1978366f6083SPeter Grehan 1979994f858aSXin LI sc = calloc(1, sizeof(struct pci_emul_dsoftc)); 1980366f6083SPeter Grehan 1981366f6083SPeter Grehan pi->pi_arg = sc; 1982366f6083SPeter Grehan 1983366f6083SPeter Grehan pci_set_cfgdata16(pi, PCIR_DEVICE, 0x0001); 1984366f6083SPeter Grehan pci_set_cfgdata16(pi, PCIR_VENDOR, 0x10DD); 1985366f6083SPeter Grehan pci_set_cfgdata8(pi, PCIR_CLASS, 0x02); 1986366f6083SPeter Grehan 19874d1e669cSPeter Grehan error = pci_emul_add_msicap(pi, PCI_EMUL_MSI_MSGS); 1988366f6083SPeter Grehan assert(error == 0); 1989366f6083SPeter Grehan 19904d1e669cSPeter Grehan error = pci_emul_alloc_bar(pi, 0, PCIBAR_IO, DIOSZ); 19914d1e669cSPeter Grehan assert(error == 0); 19924d1e669cSPeter Grehan 19934d1e669cSPeter Grehan error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, DMEMSZ); 1994366f6083SPeter Grehan assert(error == 0); 1995366f6083SPeter Grehan 1996fd4e0d4cSNeel Natu error = pci_emul_alloc_bar(pi, 2, PCIBAR_MEM32, DMEMSZ); 1997fd4e0d4cSNeel Natu assert(error == 0); 1998fd4e0d4cSNeel Natu 1999366f6083SPeter Grehan return (0); 2000366f6083SPeter Grehan } 2001366f6083SPeter Grehan 2002b67e81dbSJohn Baldwin static void 20034d1e669cSPeter Grehan pci_emul_diow(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, 20044d1e669cSPeter Grehan uint64_t offset, int size, uint64_t value) 2005366f6083SPeter Grehan { 2006366f6083SPeter Grehan int i; 2007366f6083SPeter Grehan struct pci_emul_dsoftc *sc = pi->pi_arg; 2008366f6083SPeter Grehan 20094d1e669cSPeter Grehan if (baridx == 0) { 20104d1e669cSPeter Grehan if (offset + size > DIOSZ) { 20114d1e669cSPeter Grehan printf("diow: iow too large, offset %ld size %d\n", 20124d1e669cSPeter Grehan offset, size); 2013366f6083SPeter Grehan return; 2014366f6083SPeter Grehan } 2015366f6083SPeter Grehan 2016366f6083SPeter Grehan if (size == 1) { 20174d1e669cSPeter Grehan sc->ioregs[offset] = value & 0xff; 2018366f6083SPeter Grehan } else if (size == 2) { 20194d1e669cSPeter Grehan *(uint16_t *)&sc->ioregs[offset] = value & 0xffff; 20204d1e669cSPeter Grehan } else if (size == 4) { 20214d1e669cSPeter Grehan *(uint32_t *)&sc->ioregs[offset] = value; 2022366f6083SPeter Grehan } else { 20234d1e669cSPeter Grehan printf("diow: iow unknown size %d\n", size); 2024366f6083SPeter Grehan } 2025366f6083SPeter Grehan 2026366f6083SPeter Grehan /* 2027366f6083SPeter Grehan * Special magic value to generate an interrupt 2028366f6083SPeter Grehan */ 2029366f6083SPeter Grehan if (offset == 4 && size == 4 && pci_msi_enabled(pi)) 20304f8be175SNeel Natu pci_generate_msi(pi, value % pci_msi_maxmsgnum(pi)); 2031366f6083SPeter Grehan 2032366f6083SPeter Grehan if (value == 0xabcdef) { 20334f8be175SNeel Natu for (i = 0; i < pci_msi_maxmsgnum(pi); i++) 2034366f6083SPeter Grehan pci_generate_msi(pi, i); 2035366f6083SPeter Grehan } 2036366f6083SPeter Grehan } 2037366f6083SPeter Grehan 2038fd4e0d4cSNeel Natu if (baridx == 1 || baridx == 2) { 20394d1e669cSPeter Grehan if (offset + size > DMEMSZ) { 20404d1e669cSPeter Grehan printf("diow: memw too large, offset %ld size %d\n", 20414d1e669cSPeter Grehan offset, size); 20424d1e669cSPeter Grehan return; 20434d1e669cSPeter Grehan } 20444d1e669cSPeter Grehan 2045fd4e0d4cSNeel Natu i = baridx - 1; /* 'memregs' index */ 2046fd4e0d4cSNeel Natu 20474d1e669cSPeter Grehan if (size == 1) { 2048fd4e0d4cSNeel Natu sc->memregs[i][offset] = value; 20494d1e669cSPeter Grehan } else if (size == 2) { 2050fd4e0d4cSNeel Natu *(uint16_t *)&sc->memregs[i][offset] = value; 20514d1e669cSPeter Grehan } else if (size == 4) { 2052fd4e0d4cSNeel Natu *(uint32_t *)&sc->memregs[i][offset] = value; 20534d1e669cSPeter Grehan } else if (size == 8) { 2054fd4e0d4cSNeel Natu *(uint64_t *)&sc->memregs[i][offset] = value; 20554d1e669cSPeter Grehan } else { 20564d1e669cSPeter Grehan printf("diow: memw unknown size %d\n", size); 20574d1e669cSPeter Grehan } 20584d1e669cSPeter Grehan 20594d1e669cSPeter Grehan /* 20604d1e669cSPeter Grehan * magic interrupt ?? 20614d1e669cSPeter Grehan */ 20624d1e669cSPeter Grehan } 20634d1e669cSPeter Grehan 20649f3dba68SPedro F. Giffuni if (baridx > 2 || baridx < 0) { 20654d1e669cSPeter Grehan printf("diow: unknown bar idx %d\n", baridx); 20664d1e669cSPeter Grehan } 20674d1e669cSPeter Grehan } 20684d1e669cSPeter Grehan 20694d1e669cSPeter Grehan static uint64_t 20704d1e669cSPeter Grehan pci_emul_dior(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, 20714d1e669cSPeter Grehan uint64_t offset, int size) 2072366f6083SPeter Grehan { 2073366f6083SPeter Grehan struct pci_emul_dsoftc *sc = pi->pi_arg; 2074366f6083SPeter Grehan uint32_t value; 2075fd4e0d4cSNeel Natu int i; 2076366f6083SPeter Grehan 20774d1e669cSPeter Grehan if (baridx == 0) { 20784d1e669cSPeter Grehan if (offset + size > DIOSZ) { 20794d1e669cSPeter Grehan printf("dior: ior too large, offset %ld size %d\n", 20804d1e669cSPeter Grehan offset, size); 2081366f6083SPeter Grehan return (0); 2082366f6083SPeter Grehan } 2083366f6083SPeter Grehan 20846e43f3edSPedro F. Giffuni value = 0; 2085366f6083SPeter Grehan if (size == 1) { 20864d1e669cSPeter Grehan value = sc->ioregs[offset]; 2087366f6083SPeter Grehan } else if (size == 2) { 20884d1e669cSPeter Grehan value = *(uint16_t *) &sc->ioregs[offset]; 20894d1e669cSPeter Grehan } else if (size == 4) { 20904d1e669cSPeter Grehan value = *(uint32_t *) &sc->ioregs[offset]; 2091366f6083SPeter Grehan } else { 20924d1e669cSPeter Grehan printf("dior: ior unknown size %d\n", size); 20934d1e669cSPeter Grehan } 20944d1e669cSPeter Grehan } 20954d1e669cSPeter Grehan 2096fd4e0d4cSNeel Natu if (baridx == 1 || baridx == 2) { 20974d1e669cSPeter Grehan if (offset + size > DMEMSZ) { 20984d1e669cSPeter Grehan printf("dior: memr too large, offset %ld size %d\n", 20994d1e669cSPeter Grehan offset, size); 21004d1e669cSPeter Grehan return (0); 21014d1e669cSPeter Grehan } 21024d1e669cSPeter Grehan 2103fd4e0d4cSNeel Natu i = baridx - 1; /* 'memregs' index */ 2104fd4e0d4cSNeel Natu 21054d1e669cSPeter Grehan if (size == 1) { 2106fd4e0d4cSNeel Natu value = sc->memregs[i][offset]; 21074d1e669cSPeter Grehan } else if (size == 2) { 2108fd4e0d4cSNeel Natu value = *(uint16_t *) &sc->memregs[i][offset]; 21094d1e669cSPeter Grehan } else if (size == 4) { 2110fd4e0d4cSNeel Natu value = *(uint32_t *) &sc->memregs[i][offset]; 21114d1e669cSPeter Grehan } else if (size == 8) { 2112fd4e0d4cSNeel Natu value = *(uint64_t *) &sc->memregs[i][offset]; 21134d1e669cSPeter Grehan } else { 21144d1e669cSPeter Grehan printf("dior: ior unknown size %d\n", size); 21154d1e669cSPeter Grehan } 21164d1e669cSPeter Grehan } 21174d1e669cSPeter Grehan 21184d1e669cSPeter Grehan 21199f3dba68SPedro F. Giffuni if (baridx > 2 || baridx < 0) { 21204d1e669cSPeter Grehan printf("dior: unknown bar idx %d\n", baridx); 21214d1e669cSPeter Grehan return (0); 2122366f6083SPeter Grehan } 2123366f6083SPeter Grehan 2124366f6083SPeter Grehan return (value); 2125366f6083SPeter Grehan } 2126366f6083SPeter Grehan 2127366f6083SPeter Grehan struct pci_devemu pci_dummy = { 2128366f6083SPeter Grehan .pe_emu = "dummy", 2129366f6083SPeter Grehan .pe_init = pci_emul_dinit, 21304d1e669cSPeter Grehan .pe_barwrite = pci_emul_diow, 21314d1e669cSPeter Grehan .pe_barread = pci_emul_dior 2132366f6083SPeter Grehan }; 2133366f6083SPeter Grehan PCI_EMUL_SET(pci_dummy); 2134366f6083SPeter Grehan 2135366f6083SPeter Grehan #endif /* PCI_EMUL_TEST */ 2136