Date: Fri, 14 Feb 2014 21:34:08 +0000 (UTC) From: Neel Natu <neel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r261904 - head/usr.sbin/bhyve Message-ID: <201402142134.s1ELY8fe046194@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: neel Date: Fri Feb 14 21:34:08 2014 New Revision: 261904 URL: http://svnweb.freebsd.org/changeset/base/261904 Log: Allow PCI devices to be configured on all valid bus numbers from 0 to 255. This is done by representing each bus as root PCI device in ACPI. The device implements the _BBN method to return the PCI bus number to the guest OS. Each PCI bus keeps track of the resources that is decodes for devices configured on the bus: i/o, mmio (32-bit) and mmio (64-bit). These windows are advertised to the guest via the _CRS object of the root device. Bus 0 is treated specially since it consumes the I/O ports to access the PCI config space [0xcf8-0xcff]. It also decodes the legacy I/O ports that are consumed by devices on the LPC bus. For this reason the LPC bridge can be configured only on bus 0. The bus number can be specified using the following command line option to bhyve(8): "-s <bus>:<slot>:<func>,<emul>[,<config>]" Discussed with: grehan@ Reviewed by: jhb@ Modified: head/usr.sbin/bhyve/acpi.c head/usr.sbin/bhyve/mptbl.c head/usr.sbin/bhyve/pci_emul.c head/usr.sbin/bhyve/pci_emul.h head/usr.sbin/bhyve/pci_lpc.c Modified: head/usr.sbin/bhyve/acpi.c ============================================================================== --- head/usr.sbin/bhyve/acpi.c Fri Feb 14 21:20:16 2014 (r261903) +++ head/usr.sbin/bhyve/acpi.c Fri Feb 14 21:34:08 2014 (r261904) @@ -713,7 +713,7 @@ basl_fwrite_dsdt(FILE *fp) pci_write_dsdt(); dsdt_line(""); - dsdt_line(" Scope (_SB.PCI0)"); + dsdt_line(" Scope (_SB.PC00)"); dsdt_line(" {"); dsdt_line(" Device (HPET)"); dsdt_line(" {"); Modified: head/usr.sbin/bhyve/mptbl.c ============================================================================== --- head/usr.sbin/bhyve/mptbl.c Fri Feb 14 21:20:16 2014 (r261903) +++ head/usr.sbin/bhyve/mptbl.c Fri Feb 14 21:34:08 2014 (r261904) @@ -196,16 +196,21 @@ mpt_build_ioapic_entries(io_apic_entry_p static int mpt_count_ioint_entries(void) { + int bus, count; + + count = 0; + for (bus = 0; bus <= PCI_BUSMAX; bus++) + count += pci_count_lintr(bus); /* * Always include entries for the first 16 pins along with a entry * for each active PCI INTx pin. */ - return (16 + pci_count_lintr()); + return (16 + count); } static void -mpt_generate_pci_int(int slot, int pin, int ioapic_irq, void *arg) +mpt_generate_pci_int(int bus, int slot, int pin, int ioapic_irq, void *arg) { int_entry_ptr *mpiep, mpie; @@ -219,7 +224,7 @@ mpt_generate_pci_int(int slot, int pin, */ mpie->type = MPCT_ENTRY_INT; mpie->int_type = INTENTRY_TYPE_INT; - mpie->src_bus_id = 0; + mpie->src_bus_id = bus; mpie->src_bus_irq = slot << 2 | (pin - 1); mpie->dst_apic_id = mpie[-1].dst_apic_id; mpie->dst_apic_int = ioapic_irq; @@ -230,7 +235,7 @@ mpt_generate_pci_int(int slot, int pin, static void mpt_build_ioint_entries(int_entry_ptr mpie, int id) { - int pin; + int pin, bus; /* * The following config is taken from kernel mptable.c @@ -277,7 +282,8 @@ mpt_build_ioint_entries(int_entry_ptr mp } /* Next, generate entries for any PCI INTx interrupts. */ - pci_walk_lintr(mpt_generate_pci_int, &mpie); + for (bus = 0; bus <= PCI_BUSMAX; bus++) + pci_walk_lintr(bus, mpt_generate_pci_int, &mpie); } void Modified: head/usr.sbin/bhyve/pci_emul.c ============================================================================== --- head/usr.sbin/bhyve/pci_emul.c Fri Feb 14 21:20:16 2014 (r261903) +++ head/usr.sbin/bhyve/pci_emul.c Fri Feb 14 21:34:08 2014 (r261904) @@ -69,6 +69,7 @@ do { \ } \ } while (0) +#define MAXBUSES (PCI_BUSMAX + 1) #define MAXSLOTS (PCI_SLOTMAX + 1) #define MAXFUNCS (PCI_FUNCMAX + 1) @@ -86,7 +87,16 @@ struct intxinfo { struct slotinfo { struct intxinfo si_intpins[4]; struct funcinfo si_funcs[MAXFUNCS]; -} pci_slotinfo[MAXSLOTS]; +}; + +struct businfo { + uint16_t iobase, iolimit; /* I/O window */ + uint32_t membase32, memlimit32; /* mmio window below 4GB */ + uint64_t membase64, memlimit64; /* mmio window above 4GB */ + struct slotinfo slotinfo[MAXSLOTS]; +}; + +static struct businfo *pci_businfo[MAXBUSES]; SET_DECLARE(pci_devemu_set, struct pci_devemu); @@ -97,7 +107,7 @@ static uint64_t pci_emul_membase64; #define PCI_EMUL_IOBASE 0x2000 #define PCI_EMUL_IOLIMIT 0x10000 -#define PCI_EMUL_MEMLIMIT32 0xE0000000 /* 3.5GB */ +#define PCI_EMUL_MEMLIMIT32 0xE0000000 /* 3.5GB */ #define PCI_EMUL_MEMBASE64 0xD000000000UL #define PCI_EMUL_MEMLIMIT64 0xFD00000000UL @@ -105,7 +115,6 @@ static uint64_t pci_emul_membase64; static struct pci_devemu *pci_emul_finddev(char *name); static void pci_lintr_update(struct pci_devinst *pi); -static int pci_emul_devices; static struct mem_range pci_mem_hole; /* @@ -115,6 +124,7 @@ static struct mem_range pci_mem_hole; /* * Slot options are in the form: * + * <bus>:<slot>:<func>,<emul>[,<config>] * <slot>[:<func>],<emul>[,<config>] * * slot is 0..31 @@ -136,37 +146,53 @@ pci_parse_slot_usage(char *aopt) int pci_parse_slot(char *opt) { - char *slot, *func, *emul, *config; - char *str, *cpy; - int error, snum, fnum; + struct businfo *bi; + struct slotinfo *si; + char *emul, *config, *str, *cp; + int error, bnum, snum, fnum; error = -1; - str = cpy = strdup(opt); + str = strdup(opt); - slot = strsep(&str, ","); - func = NULL; - if (strchr(slot, ':') != NULL) { - func = cpy; - (void) strsep(&func, ":"); - } - - emul = strsep(&str, ","); - config = str; - - if (emul == NULL) { + emul = config = NULL; + if ((cp = strchr(str, ',')) != NULL) { + *cp = '\0'; + emul = cp + 1; + if ((cp = strchr(emul, ',')) != NULL) { + *cp = '\0'; + config = cp + 1; + } + } else { pci_parse_slot_usage(opt); goto done; } - snum = atoi(slot); - fnum = func ? atoi(func) : 0; + /* <bus>:<slot>:<func> */ + if (sscanf(str, "%d:%d:%d", &bnum, &snum, &fnum) != 3) { + bnum = 0; + /* <slot>:<func> */ + if (sscanf(str, "%d:%d", &snum, &fnum) != 2) { + fnum = 0; + /* <slot> */ + if (sscanf(str, "%d", &snum) != 1) { + snum = -1; + } + } + } - if (snum < 0 || snum >= MAXSLOTS || fnum < 0 || fnum >= MAXFUNCS) { + if (bnum < 0 || bnum >= MAXBUSES || snum < 0 || snum >= MAXSLOTS || + fnum < 0 || fnum >= MAXFUNCS) { pci_parse_slot_usage(opt); goto done; } - if (pci_slotinfo[snum].si_funcs[fnum].fi_name != NULL) { + if (pci_businfo[bnum] == NULL) + pci_businfo[bnum] = calloc(1, sizeof(struct businfo)); + + bi = pci_businfo[bnum]; + si = &bi->slotinfo[snum]; + + if (si->si_funcs[fnum].fi_name != NULL) { fprintf(stderr, "pci slot %d:%d already occupied!\n", snum, fnum); goto done; @@ -179,12 +205,12 @@ pci_parse_slot(char *opt) } error = 0; - pci_slotinfo[snum].si_funcs[fnum].fi_name = emul; - pci_slotinfo[snum].si_funcs[fnum].fi_param = config; + si->si_funcs[fnum].fi_name = emul; + si->si_funcs[fnum].fi_param = config; done: if (error) - free(cpy); + free(str); return (error); } @@ -665,8 +691,8 @@ pci_emul_finddev(char *name) } static int -pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int slot, int func, - char *params) +pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int bus, int slot, + int func, struct funcinfo *fi) { struct pci_devinst *pdi; int err; @@ -675,7 +701,7 @@ pci_emul_init(struct vmctx *ctx, struct bzero(pdi, sizeof(*pdi)); pdi->pi_vmctx = ctx; - pdi->pi_bus = 0; + pdi->pi_bus = bus; pdi->pi_slot = slot; pdi->pi_func = func; pthread_mutex_init(&pdi->pi_lintr.lock, NULL); @@ -692,13 +718,11 @@ pci_emul_init(struct vmctx *ctx, struct pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); - err = (*pde->pe_init)(ctx, pdi, params); - if (err != 0) { + err = (*pde->pe_init)(ctx, pdi, fi->fi_param); + if (err == 0) + fi->fi_devi = pdi; + else free(pdi); - } else { - pci_emul_devices++; - pci_slotinfo[slot].si_funcs[func].fi_devi = pdi; - } return (err); } @@ -1006,31 +1030,68 @@ pci_emul_fallback_handler(struct vmctx * return (0); } +#define BUSIO_ROUNDUP 32 +#define BUSMEM_ROUNDUP (1024 * 1024) + int init_pci(struct vmctx *ctx) { struct pci_devemu *pde; + struct businfo *bi; + struct slotinfo *si; struct funcinfo *fi; size_t lowmem; - int slot, func; + int bus, slot, func; int error; pci_emul_iobase = PCI_EMUL_IOBASE; pci_emul_membase32 = vm_get_lowmem_limit(ctx); pci_emul_membase64 = PCI_EMUL_MEMBASE64; - for (slot = 0; slot < MAXSLOTS; slot++) { - for (func = 0; func < MAXFUNCS; func++) { - fi = &pci_slotinfo[slot].si_funcs[func]; - if (fi->fi_name != NULL) { + for (bus = 0; bus < MAXBUSES; bus++) { + if ((bi = pci_businfo[bus]) == NULL) + continue; + /* + * Keep track of the i/o and memory resources allocated to + * this bus. + */ + bi->iobase = pci_emul_iobase; + bi->membase32 = pci_emul_membase32; + bi->membase64 = pci_emul_membase64; + + for (slot = 0; slot < MAXSLOTS; slot++) { + si = &bi->slotinfo[slot]; + for (func = 0; func < MAXFUNCS; func++) { + fi = &si->si_funcs[func]; + if (fi->fi_name == NULL) + continue; pde = pci_emul_finddev(fi->fi_name); assert(pde != NULL); - error = pci_emul_init(ctx, pde, slot, func, - fi->fi_param); + error = pci_emul_init(ctx, pde, bus, slot, + func, fi); if (error) return (error); } } + + /* + * Add some slop to the I/O and memory resources decoded by + * this bus to give a guest some flexibility if it wants to + * reprogram the BARs. + */ + pci_emul_iobase += BUSIO_ROUNDUP; + pci_emul_iobase = roundup2(pci_emul_iobase, BUSIO_ROUNDUP); + bi->iolimit = pci_emul_iobase; + + pci_emul_membase32 += BUSMEM_ROUNDUP; + pci_emul_membase32 = roundup2(pci_emul_membase32, + BUSMEM_ROUNDUP); + bi->memlimit32 = pci_emul_membase32; + + pci_emul_membase64 += BUSMEM_ROUNDUP; + pci_emul_membase64 = roundup2(pci_emul_membase64, + BUSMEM_ROUNDUP); + bi->memlimit64 = pci_emul_membase64; } /* @@ -1060,7 +1121,7 @@ init_pci(struct vmctx *ctx) } static void -pci_prt_entry(int slot, int pin, int ioapic_irq, void *arg) +pci_prt_entry(int bus, int slot, int pin, int ioapic_irq, void *arg) { int *count; @@ -1075,96 +1136,158 @@ pci_prt_entry(int slot, int pin, int ioa (*count)--; } -void -pci_write_dsdt(void) +/* + * A bhyve virtual machine has a flat PCI hierarchy with a root port + * corresponding to each PCI bus. + */ +static void +pci_bus_write_dsdt(int bus) { + struct businfo *bi; + struct slotinfo *si; struct pci_devinst *pi; int count, slot, func; + /* + * If there are no devices on this 'bus' then just return. + */ + if ((bi = pci_businfo[bus]) == NULL) { + /* + * Bus 0 is special because it decodes the I/O ports used + * for PCI config space access even if there are no devices + * on it. + */ + if (bus != 0) + return; + } + dsdt_indent(1); dsdt_line("Scope (_SB)"); dsdt_line("{"); - dsdt_line(" Device (PCI0)"); + dsdt_line(" Device (PC%02X)", bus); dsdt_line(" {"); dsdt_line(" Name (_HID, EisaId (\"PNP0A03\"))"); dsdt_line(" Name (_ADR, Zero)"); + + dsdt_line(" Method (_BBN, 0, NotSerialized)"); + dsdt_line(" {"); + dsdt_line(" Return (0x%08X)", bus); + dsdt_line(" }"); dsdt_line(" Name (_CRS, ResourceTemplate ()"); dsdt_line(" {"); dsdt_line(" WordBusNumber (ResourceProducer, MinFixed, " "MaxFixed, PosDecode,"); dsdt_line(" 0x0000, // Granularity"); - dsdt_line(" 0x0000, // Range Minimum"); - dsdt_line(" 0x00FF, // Range Maximum"); + dsdt_line(" 0x%04X, // Range Minimum", bus); + dsdt_line(" 0x%04X, // Range Maximum", bus); dsdt_line(" 0x0000, // Translation Offset"); - dsdt_line(" 0x0100, // Length"); + dsdt_line(" 0x0001, // Length"); dsdt_line(" ,, )"); - dsdt_indent(3); - dsdt_fixed_ioport(0xCF8, 8); - dsdt_unindent(3); - dsdt_line(" WordIO (ResourceProducer, MinFixed, MaxFixed, " - "PosDecode, EntireRange,"); - dsdt_line(" 0x0000, // Granularity"); - dsdt_line(" 0x0000, // Range Minimum"); - dsdt_line(" 0x0CF7, // Range Maximum"); - dsdt_line(" 0x0000, // Translation Offset"); - dsdt_line(" 0x0CF8, // Length"); - dsdt_line(" ,, , TypeStatic)"); + + if (bus == 0) { + dsdt_indent(3); + dsdt_fixed_ioport(0xCF8, 8); + dsdt_unindent(3); + + dsdt_line(" WordIO (ResourceProducer, MinFixed, MaxFixed, " + "PosDecode, EntireRange,"); + dsdt_line(" 0x0000, // Granularity"); + dsdt_line(" 0x0000, // Range Minimum"); + dsdt_line(" 0x0CF7, // Range Maximum"); + dsdt_line(" 0x0000, // Translation Offset"); + dsdt_line(" 0x0CF8, // Length"); + dsdt_line(" ,, , TypeStatic)"); + + dsdt_line(" WordIO (ResourceProducer, MinFixed, MaxFixed, " + "PosDecode, EntireRange,"); + dsdt_line(" 0x0000, // Granularity"); + dsdt_line(" 0x0D00, // Range Minimum"); + dsdt_line(" 0x%04X, // Range Maximum", + PCI_EMUL_IOBASE - 1); + dsdt_line(" 0x0000, // Translation Offset"); + dsdt_line(" 0x%04X, // Length", + PCI_EMUL_IOBASE - 0x0D00); + dsdt_line(" ,, , TypeStatic)"); + + if (bi == NULL) { + dsdt_line(" })"); + goto done; + } + } + assert(bi != NULL); + + /* i/o window */ dsdt_line(" WordIO (ResourceProducer, MinFixed, MaxFixed, " "PosDecode, EntireRange,"); dsdt_line(" 0x0000, // Granularity"); - dsdt_line(" 0x0D00, // Range Minimum"); - dsdt_line(" 0xFFFF, // Range Maximum"); + dsdt_line(" 0x%04X, // Range Minimum", bi->iobase); + dsdt_line(" 0x%04X, // Range Maximum", + bi->iolimit - 1); dsdt_line(" 0x0000, // Translation Offset"); - dsdt_line(" 0xF300, // Length"); + dsdt_line(" 0x%04X, // Length", + bi->iolimit - bi->iobase); dsdt_line(" ,, , TypeStatic)"); + + /* mmio window (32-bit) */ dsdt_line(" DWordMemory (ResourceProducer, PosDecode, " "MinFixed, MaxFixed, NonCacheable, ReadWrite,"); dsdt_line(" 0x00000000, // Granularity"); - dsdt_line(" 0x%08lX, // Range Minimum\n", - pci_mem_hole.base); + dsdt_line(" 0x%08X, // Range Minimum\n", bi->membase32); dsdt_line(" 0x%08X, // Range Maximum\n", - PCI_EMUL_MEMLIMIT32 - 1); + bi->memlimit32 - 1); dsdt_line(" 0x00000000, // Translation Offset"); - dsdt_line(" 0x%08lX, // Length\n", - PCI_EMUL_MEMLIMIT32 - pci_mem_hole.base); + dsdt_line(" 0x%08X, // Length\n", + bi->memlimit32 - bi->membase32); dsdt_line(" ,, , AddressRangeMemory, TypeStatic)"); + + /* mmio window (64-bit) */ dsdt_line(" QWordMemory (ResourceProducer, PosDecode, " "MinFixed, MaxFixed, NonCacheable, ReadWrite,"); dsdt_line(" 0x0000000000000000, // Granularity"); - dsdt_line(" 0x%016lX, // Range Minimum\n", - PCI_EMUL_MEMBASE64); + dsdt_line(" 0x%016lX, // Range Minimum\n", bi->membase64); dsdt_line(" 0x%016lX, // Range Maximum\n", - PCI_EMUL_MEMLIMIT64 - 1); + bi->memlimit64 - 1); dsdt_line(" 0x0000000000000000, // Translation Offset"); dsdt_line(" 0x%016lX, // Length\n", - PCI_EMUL_MEMLIMIT64 - PCI_EMUL_MEMBASE64); + bi->memlimit64 - bi->membase64); dsdt_line(" ,, , AddressRangeMemory, TypeStatic)"); dsdt_line(" })"); - count = pci_count_lintr(); + + count = pci_count_lintr(bus); if (count != 0) { dsdt_indent(2); dsdt_line("Name (_PRT, Package (0x%02X)", count); dsdt_line("{"); - pci_walk_lintr(pci_prt_entry, &count); + pci_walk_lintr(bus, pci_prt_entry, &count); dsdt_line("})"); dsdt_unindent(2); } dsdt_indent(2); for (slot = 0; slot < MAXSLOTS; slot++) { + si = &bi->slotinfo[slot]; for (func = 0; func < MAXFUNCS; func++) { - pi = pci_slotinfo[slot].si_funcs[func].fi_devi; + pi = si->si_funcs[func].fi_devi; if (pi != NULL && pi->pi_d->pe_write_dsdt != NULL) pi->pi_d->pe_write_dsdt(pi); } } dsdt_unindent(2); - +done: dsdt_line(" }"); dsdt_line("}"); dsdt_unindent(1); } +void +pci_write_dsdt(void) +{ + int bus; + + for (bus = 0; bus < MAXBUSES; bus++) + pci_bus_write_dsdt(bus); +} + int pci_msi_enabled(struct pci_devinst *pi) { @@ -1231,13 +1354,17 @@ pci_lintr_permitted(struct pci_devinst * int pci_lintr_request(struct pci_devinst *pi) { + struct businfo *bi; struct slotinfo *si; int bestpin, bestcount, irq, pin; + bi = pci_businfo[pi->pi_bus]; + assert(bi != NULL); + /* * First, allocate a pin from our slot. */ - si = &pci_slotinfo[pi->pi_slot]; + si = &bi->slotinfo[pi->pi_slot]; bestpin = 0; bestcount = si->si_intpins[0].ii_count; for (pin = 1; pin < 4; pin++) { @@ -1318,31 +1445,41 @@ pci_lintr_update(struct pci_devinst *pi) } int -pci_count_lintr(void) +pci_count_lintr(int bus) { int count, slot, pin; + struct slotinfo *slotinfo; count = 0; - for (slot = 0; slot < MAXSLOTS; slot++) { - for (pin = 0; pin < 4; pin++) { - if (pci_slotinfo[slot].si_intpins[pin].ii_count != 0) - count++; + if (pci_businfo[bus] != NULL) { + for (slot = 0; slot < MAXSLOTS; slot++) { + slotinfo = &pci_businfo[bus]->slotinfo[slot]; + for (pin = 0; pin < 4; pin++) { + if (slotinfo->si_intpins[pin].ii_count != 0) + count++; + } } } return (count); } void -pci_walk_lintr(pci_lintr_cb cb, void *arg) +pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg) { + struct businfo *bi; + struct slotinfo *si; struct intxinfo *ii; int slot, pin; + if ((bi = pci_businfo[bus]) == NULL) + return; + for (slot = 0; slot < MAXSLOTS; slot++) { + si = &bi->slotinfo[slot]; for (pin = 0; pin < 4; pin++) { - ii = &pci_slotinfo[slot].si_intpins[pin]; + ii = &si->si_intpins[pin]; if (ii->ii_count != 0) - cb(slot, pin + 1, ii->ii_ioapic_irq, arg); + cb(bus, slot, pin + 1, ii->ii_ioapic_irq, arg); } } } @@ -1352,14 +1489,19 @@ pci_walk_lintr(pci_lintr_cb cb, void *ar * Return 0 otherwise. */ static int -pci_emul_is_mfdev(int slot) +pci_emul_is_mfdev(int bus, int slot) { + struct businfo *bi; + struct slotinfo *si; int f, numfuncs; numfuncs = 0; - for (f = 0; f < MAXFUNCS; f++) { - if (pci_slotinfo[slot].si_funcs[f].fi_devi != NULL) { - numfuncs++; + if ((bi = pci_businfo[bus]) != NULL) { + si = &bi->slotinfo[slot]; + for (f = 0; f < MAXFUNCS; f++) { + if (si->si_funcs[f].fi_devi != NULL) { + numfuncs++; + } } } return (numfuncs > 1); @@ -1370,12 +1512,12 @@ pci_emul_is_mfdev(int slot) * whether or not is a multi-function being emulated in the pci 'slot'. */ static void -pci_emul_hdrtype_fixup(int slot, int off, int bytes, uint32_t *rv) +pci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv) { int mfdev; if (off <= PCIR_HDRTYPE && off + bytes > PCIR_HDRTYPE) { - mfdev = pci_emul_is_mfdev(slot); + mfdev = pci_emul_is_mfdev(bus, slot); switch (bytes) { case 1: case 2: @@ -1492,16 +1634,19 @@ static int pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { + struct businfo *bi; + struct slotinfo *si; struct pci_devinst *pi; struct pci_devemu *pe; int coff, idx, needcfg; uint64_t addr, bar, mask; assert(bytes == 1 || bytes == 2 || bytes == 4); - - if (cfgbus == 0) - pi = pci_slotinfo[cfgslot].si_funcs[cfgfunc].fi_devi; - else + + if ((bi = pci_businfo[cfgbus]) != NULL) { + si = &bi->slotinfo[cfgslot]; + pi = si->si_funcs[cfgfunc].fi_devi; + } else pi = NULL; coff = cfgoff + (port - CONF1_DATA_PORT); @@ -1544,7 +1689,7 @@ pci_emul_cfgdata(struct vmctx *ctx, int *eax = pci_get_cfgdata32(pi, coff); } - pci_emul_hdrtype_fixup(cfgslot, coff, bytes, eax); + pci_emul_hdrtype_fixup(cfgbus, cfgslot, coff, bytes, eax); } else { /* Let the device emulation override the default handler */ if (pe->pe_cfgwrite != NULL && @@ -1646,7 +1791,7 @@ SYSRES_IO(0xC00, 2); /* * Define a dummy test device */ -#define DIOSZ 20 +#define DIOSZ 8 #define DMEMSZ 4096 struct pci_emul_dsoftc { uint8_t ioregs[DIOSZ]; Modified: head/usr.sbin/bhyve/pci_emul.h ============================================================================== --- head/usr.sbin/bhyve/pci_emul.h Fri Feb 14 21:20:16 2014 (r261903) +++ head/usr.sbin/bhyve/pci_emul.h Fri Feb 14 21:34:08 2014 (r261904) @@ -199,7 +199,7 @@ struct pciecap { uint16_t slot_status2; } __packed; -typedef void (*pci_lintr_cb)(int slot, int pin, int ioapic_irq, void *arg); +typedef void (*pci_lintr_cb)(int b, int s, int pin, int ioapic_irq, void *arg); int init_pci(struct vmctx *ctx); void msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset, @@ -229,8 +229,8 @@ int pci_emul_add_msixcap(struct pci_devi int pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size, uint64_t value); uint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size); -int pci_count_lintr(void); -void pci_walk_lintr(pci_lintr_cb cb, void *arg); +int pci_count_lintr(int bus); +void pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg); void pci_write_dsdt(void); static __inline void Modified: head/usr.sbin/bhyve/pci_lpc.c ============================================================================== --- head/usr.sbin/bhyve/pci_lpc.c Fri Feb 14 21:20:16 2014 (r261903) +++ head/usr.sbin/bhyve/pci_lpc.c Fri Feb 14 21:34:08 2014 (r261904) @@ -277,8 +277,20 @@ pci_lpc_init(struct vmctx *ctx, struct p /* * Do not allow more than one LPC bridge to be configured. */ - if (lpc_bridge != NULL) + if (lpc_bridge != NULL) { + fprintf(stderr, "Only one LPC bridge is allowed.\n"); return (-1); + } + + /* + * Enforce that the LPC can only be configured on bus 0. This + * simplifies the ACPI DSDT because it can provide a decode for + * all legacy i/o ports behind bus 0. + */ + if (pi->pi_bus != 0) { + fprintf(stderr, "LPC bridge can be present only on bus 0.\n"); + return (-1); + } if (lpc_init() != 0) return (-1);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402142134.s1ELY8fe046194>