Changeset View
Standalone View
usr.sbin/bhyve/pci_emul.c
Show All 40 Lines | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <strings.h> | #include <strings.h> | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#include <machine/vmm_snapshot.h> | #include <machine/vmm_snapshot.h> | ||||
#include <machine/cpufunc.h> | |||||
#include <machine/specialreg.h> | |||||
#include <vmmapi.h> | #include <vmmapi.h> | ||||
#include "acpi.h" | #include "acpi.h" | ||||
#include "bhyverun.h" | #include "bhyverun.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
#include "inout.h" | #include "inout.h" | ||||
#include "ioapic.h" | #include "ioapic.h" | ||||
#include "mem.h" | #include "mem.h" | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
#define PCI_EMUL_IOLIMIT 0x10000 | #define PCI_EMUL_IOLIMIT 0x10000 | ||||
#define PCI_EMUL_ECFG_BASE 0xE0000000 /* 3.5GB */ | #define PCI_EMUL_ECFG_BASE 0xE0000000 /* 3.5GB */ | ||||
#define PCI_EMUL_ECFG_SIZE (MAXBUSES * 1024 * 1024) /* 1MB per bus */ | #define PCI_EMUL_ECFG_SIZE (MAXBUSES * 1024 * 1024) /* 1MB per bus */ | ||||
SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE); | SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE); | ||||
#define PCI_EMUL_MEMLIMIT32 PCI_EMUL_ECFG_BASE | #define PCI_EMUL_MEMLIMIT32 PCI_EMUL_ECFG_BASE | ||||
#define PCI_EMUL_MEMBASE64 0xD000000000UL | #define PCI_EMUL_MEMRESV64 0x1000000000UL /* Must be power of 2 */ | ||||
#define PCI_EMUL_MEMLIMIT64 0xFD00000000UL | |||||
static struct pci_devemu *pci_emul_finddev(char *name); | static struct pci_devemu *pci_emul_finddev(char *name); | ||||
static void pci_lintr_route(struct pci_devinst *pi); | static void pci_lintr_route(struct pci_devinst *pi); | ||||
static void pci_lintr_update(struct pci_devinst *pi); | static void pci_lintr_update(struct pci_devinst *pi); | ||||
static void pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, | static void pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, | ||||
int func, int coff, int bytes, uint32_t *val); | int func, int coff, int bytes, uint32_t *val); | ||||
static __inline void | static __inline void | ||||
▲ Show 20 Lines • Show All 496 Lines • ▼ Show 20 Lines | case PCIBAR_IO: | ||||
enbit = PCIM_CMD_PORTEN; | enbit = PCIM_CMD_PORTEN; | ||||
break; | break; | ||||
case PCIBAR_MEM64: | case PCIBAR_MEM64: | ||||
/* | /* | ||||
* XXX | * XXX | ||||
* Some drivers do not work well if the 64-bit BAR is allocated | * Some drivers do not work well if the 64-bit BAR is allocated | ||||
* above 4GB. Allow for this by allocating small requests under | * above 4GB. Allow for this by allocating small requests under | ||||
* 4GB unless then allocation size is larger than some arbitrary | * 4GB unless then allocation size is larger than some arbitrary | ||||
* number (32MB currently). | * number (128MB currently). | ||||
grehan: Comment should be 128 | |||||
*/ | */ | ||||
if (size > 32 * 1024 * 1024) { | if (size > 128 * 1024 * 1024) { | ||||
/* | /* | ||||
Done Inline ActionsThis bit of code can be removed: it was a relic leftover from supporting a Netapp 8G BAR NVRAM adapter that required a 1:1 GPA:HPA mapping for peer-peer DMA. grehan: This bit of code can be removed: it was a relic leftover from supporting a Netapp 8G BAR NVRAM… | |||||
Done Inline ActionsI can do it as followup. kib: I can do it as followup. | |||||
* XXX special case for device requiring peer-peer DMA | * XXX special case for device requiring peer-peer DMA | ||||
*/ | */ | ||||
if (size == 0x100000000UL) | if (size == 0x100000000UL) | ||||
baseptr = &hostbase; | baseptr = &hostbase; | ||||
else | else | ||||
baseptr = &pci_emul_membase64; | baseptr = &pci_emul_membase64; | ||||
limit = PCI_EMUL_MEMLIMIT64; | limit = PCI_EMUL_MEMRESV64; | ||||
mask = PCIM_BAR_MEM_BASE; | mask = PCIM_BAR_MEM_BASE; | ||||
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 | | lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 | | ||||
PCIM_BAR_MEM_PREFETCH; | PCIM_BAR_MEM_PREFETCH; | ||||
} else { | } else { | ||||
baseptr = &pci_emul_membase32; | baseptr = &pci_emul_membase32; | ||||
limit = PCI_EMUL_MEMLIMIT32; | limit = PCI_EMUL_MEMLIMIT32; | ||||
mask = PCIM_BAR_MEM_BASE; | mask = PCIM_BAR_MEM_BASE; | ||||
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64; | lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64; | ||||
▲ Show 20 Lines • Show All 452 Lines • ▼ Show 20 Lines | |||||
init_pci(struct vmctx *ctx) | init_pci(struct vmctx *ctx) | ||||
{ | { | ||||
struct mem_range mr; | struct mem_range mr; | ||||
struct pci_devemu *pde; | struct pci_devemu *pde; | ||||
struct businfo *bi; | struct businfo *bi; | ||||
struct slotinfo *si; | struct slotinfo *si; | ||||
struct funcinfo *fi; | struct funcinfo *fi; | ||||
size_t lowmem; | size_t lowmem; | ||||
int bus, slot, func; | uint64_t cpu_maxphysaddr; | ||||
int error; | u_int regs[4]; | ||||
int bus, slot, func, error; | |||||
pci_emul_iobase = PCI_EMUL_IOBASE; | pci_emul_iobase = PCI_EMUL_IOBASE; | ||||
pci_emul_membase32 = vm_get_lowmem_limit(ctx); | pci_emul_membase32 = vm_get_lowmem_limit(ctx); | ||||
pci_emul_membase64 = PCI_EMUL_MEMBASE64; | |||||
do_cpuid(0x80000008, regs); | |||||
cpu_maxphysaddr = 1ULL << (regs[0] & 0xff); | |||||
/* | |||||
Done Inline ActionsThis should be dropped down to the next lowest and largest power-of-2 address, since BAR allocations are always on pow2 boundaries. grehan: This should be dropped down to the next lowest and largest power-of-2 address, since BAR… | |||||
Not Done Inline ActionsMaybe an easier way would be to start at the next 1G boundary past the end of configured guest RAM. and use from there until the end of phys address space for the region. That should cover just about any alignment/size. grehan: Maybe an easier way would be to start at the next 1G boundary past the end of configured guest… | |||||
Done Inline ActionsI experimented some with the suggestion, and I prefer the approach from the patch. I still need to calculate maxphysaddr to see how much memresv64 can be. And with the suggestion, I need to find the TOM as well. kib: I experimented some with the suggestion, and I prefer the approach from the patch. I still… | |||||
* Max power of 2 that is less then cpu_maxphysaddr - | |||||
* PCI_EMUL_MEMRESV64. | |||||
Done Inline ActionsIt could be even simpler to just set pci_emul_membase64 to 3/4 * cpu_maxphysaddr I should have been a bit clearer: the boundary doesn't have to be a power-of-2; just a multiple of a power-of-2, and that becomes the largest BAR size that could be placed. However, 3/4 of max phys addr is still an enormous number. However, I'm fine with what you have. grehan: It could be even simpler to just set pci_emul_membase64 to 3/4 * cpu_maxphysaddr
I should have… | |||||
Done Inline ActionsI am working on the proper resource tracking for BAR allocation, in particular I already ported subr_vmem.c to userspace library. Having starting address be power of two is useful I believe, as the start of the resource region. kib: I am working on the proper resource tracking for BAR allocation, in particular I already ported… | |||||
*/ | |||||
pci_emul_membase64 = 1ULL << (flsl(cpu_maxphysaddr - | |||||
PCI_EMUL_MEMRESV64) - 1); | |||||
for (bus = 0; bus < MAXBUSES; bus++) { | for (bus = 0; bus < MAXBUSES; bus++) { | ||||
if ((bi = pci_businfo[bus]) == NULL) | if ((bi = pci_businfo[bus]) == NULL) | ||||
continue; | continue; | ||||
/* | /* | ||||
* Keep track of the i/o and memory resources allocated to | * Keep track of the i/o and memory resources allocated to | ||||
* this bus. | * this bus. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 1,226 Lines • Show Last 20 Lines |
Comment should be 128