svn commit: r261904 - head/usr.sbin/bhyve

Neel Natu neel at FreeBSD.org
Fri Feb 14 21:34:09 UTC 2014


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);


More information about the svn-src-all mailing list