Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Jan 2014 14:56:48 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r261268 - in head: lib/libvmmapi sys/amd64/include sys/amd64/vmm usr.sbin/bhyve
Message-ID:  <201401291456.s0TEum0D097293@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Wed Jan 29 14:56:48 2014
New Revision: 261268
URL: http://svnweb.freebsd.org/changeset/base/261268

Log:
  Enhance the support for PCI legacy INTx interrupts and enable them in
  the virtio backends.
  - Add a new ioctl to export the count of pins on the I/O APIC from vmm
    to the hypervisor.
  - Use pins on the I/O APIC >= 16 for PCI interrupts leaving 0-15 for
    ISA interrupts.
  - Populate the MP Table with I/O interrupt entries for any PCI INTx
    interrupts.
  - Create a _PRT table under the PCI root bridge in ACPI to route any
    PCI INTx interrupts appropriately.
  - Track which INTx interrupts are in use per-slot so that functions
    that share a slot attempt to distribute their INTx interrupts across
    the four available pins.
  - Implicitly mask INTx interrupts if either MSI or MSI-X is enabled
    and when the INTx DIS bit is set in a function's PCI command register.
    Either assert or deassert the associated I/O APIC pin when the
    state of one of those conditions changes.
  - Add INTx support to the virtio backends.
  - Always advertise the MSI capability in the virtio backends.
  
  Submitted by:	neel (7)
  Reviewed by:	neel
  MFC after:	2 weeks

Added:
  head/usr.sbin/bhyve/ioapic.c   (contents, props changed)
  head/usr.sbin/bhyve/ioapic.h   (contents, props changed)
Deleted:
  head/usr.sbin/bhyve/legacy_irq.c
  head/usr.sbin/bhyve/legacy_irq.h
Modified:
  head/lib/libvmmapi/vmmapi.c
  head/lib/libvmmapi/vmmapi.h
  head/sys/amd64/include/vmm_dev.h
  head/sys/amd64/vmm/vmm_dev.c
  head/usr.sbin/bhyve/Makefile
  head/usr.sbin/bhyve/bhyverun.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_uart.c
  head/usr.sbin/bhyve/pci_virtio_block.c
  head/usr.sbin/bhyve/pci_virtio_net.c
  head/usr.sbin/bhyve/virtio.c
  head/usr.sbin/bhyve/virtio.h

Modified: head/lib/libvmmapi/vmmapi.c
==============================================================================
--- head/lib/libvmmapi/vmmapi.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/lib/libvmmapi/vmmapi.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -454,6 +454,13 @@ vm_ioapic_pulse_irq(struct vmctx *ctx, i
 }
 
 int
+vm_ioapic_pincount(struct vmctx *ctx, int *pincount)
+{
+
+	return (ioctl(ctx->fd, VM_IOAPIC_PINCOUNT, pincount));
+}
+
+int
 vm_inject_nmi(struct vmctx *ctx, int vcpu)
 {
 	struct vm_nmi vmnmi;

Modified: head/lib/libvmmapi/vmmapi.h
==============================================================================
--- head/lib/libvmmapi/vmmapi.h	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/lib/libvmmapi/vmmapi.h	Wed Jan 29 14:56:48 2014	(r261268)
@@ -72,6 +72,7 @@ int	vm_lapic_msi(struct vmctx *ctx, uint
 int	vm_ioapic_assert_irq(struct vmctx *ctx, int irq);
 int	vm_ioapic_deassert_irq(struct vmctx *ctx, int irq);
 int	vm_ioapic_pulse_irq(struct vmctx *ctx, int irq);
+int	vm_ioapic_pincount(struct vmctx *ctx, int *pincount);
 int	vm_inject_nmi(struct vmctx *ctx, int vcpu);
 int	vm_capability_name2type(const char *capname);
 const char *vm_capability_type2name(int type);

Modified: head/sys/amd64/include/vmm_dev.h
==============================================================================
--- head/sys/amd64/include/vmm_dev.h	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/sys/amd64/include/vmm_dev.h	Wed Jan 29 14:56:48 2014	(r261268)
@@ -181,7 +181,8 @@ enum {
 	IOCNUM_IOAPIC_DEASSERT_IRQ = 34,
 	IOCNUM_IOAPIC_PULSE_IRQ = 35,
 	IOCNUM_LAPIC_MSI = 36,
-	IOCNUM_LAPIC_LOCAL_IRQ = 37, 
+	IOCNUM_LAPIC_LOCAL_IRQ = 37,
+	IOCNUM_IOAPIC_PINCOUNT = 38,
 
 	/* PCI pass-thru */
 	IOCNUM_BIND_PPTDEV = 40,
@@ -228,6 +229,8 @@ enum {
 	_IOW('v', IOCNUM_IOAPIC_DEASSERT_IRQ, struct vm_ioapic_irq)
 #define	VM_IOAPIC_PULSE_IRQ	\
 	_IOW('v', IOCNUM_IOAPIC_PULSE_IRQ, struct vm_ioapic_irq)
+#define	VM_IOAPIC_PINCOUNT	\
+	_IOR('v', IOCNUM_IOAPIC_PINCOUNT, int)
 #define	VM_SET_CAPABILITY \
 	_IOW('v', IOCNUM_SET_CAPABILITY, struct vm_capability)
 #define	VM_GET_CAPABILITY \

Modified: head/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- head/sys/amd64/vmm/vmm_dev.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/sys/amd64/vmm/vmm_dev.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -318,6 +318,9 @@ vmmdev_ioctl(struct cdev *cdev, u_long c
 		ioapic_irq = (struct vm_ioapic_irq *)data;
 		error = vioapic_pulse_irq(sc->vm, ioapic_irq->irq);
 		break;
+	case VM_IOAPIC_PINCOUNT:
+		*(int *)data = vioapic_pincount(sc->vm);
+		break;
 	case VM_MAP_MEMORY:
 		seg = (struct vm_memory_segment *)data;
 		error = vm_malloc(sc->vm, seg->gpa, seg->len);

Modified: head/usr.sbin/bhyve/Makefile
==============================================================================
--- head/usr.sbin/bhyve/Makefile	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/Makefile	Wed Jan 29 14:56:48 2014	(r261268)
@@ -17,7 +17,7 @@ SRCS=	\
 	dbgport.c		\
 	elcr.c			\
 	inout.c			\
-	legacy_irq.c		\
+	ioapic.c		\
 	mem.c			\
 	mevent.c		\
 	mptbl.c			\

Modified: head/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- head/usr.sbin/bhyve/bhyverun.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/bhyverun.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$");
 #include "acpi.h"
 #include "inout.h"
 #include "dbgport.h"
-#include "legacy_irq.h"
+#include "ioapic.h"
 #include "mem.h"
 #include "mevent.h"
 #include "mptbl.h"
@@ -695,7 +695,7 @@ main(int argc, char *argv[])
 
 	init_mem();
 	init_inout();
-	legacy_irq_init();
+	ioapic_init(ctx);
 
 	rtc_init(ctx);
 

Added: head/usr.sbin/bhyve/ioapic.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bhyve/ioapic.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2014 Advanced Computing Technologies LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <machine/vmm.h>
+#include <vmmapi.h>
+
+#include "ioapic.h"
+
+/*
+ * Assign PCI INTx interrupts to I/O APIC pins in a round-robin
+ * fashion.  Note that we have no idea what the HPET is using, but the
+ * HPET is also programmable whereas this is intended for hardwired
+ * PCI interrupts.
+ *
+ * This assumes a single I/O APIC where pins >= 16 are permitted for
+ * PCI devices.
+ */
+static int pci_pins;
+
+void
+ioapic_init(struct vmctx *ctx)
+{
+
+	if (vm_ioapic_pincount(ctx, &pci_pins) < 0) {
+		pci_pins = 0;
+		return;
+	}
+
+	/* Ignore the first 16 pins. */
+	if (pci_pins <= 16) {
+		pci_pins = 0;
+		return;
+	}
+	pci_pins -= 16;
+}
+
+int
+ioapic_pci_alloc_irq(void)
+{
+	static int last_pin;
+
+	if (pci_pins == 0)
+		return (-1);
+	return (16 + (last_pin++ % pci_pins));
+}

Added: head/usr.sbin/bhyve/ioapic.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bhyve/ioapic.h	Wed Jan 29 14:56:48 2014	(r261268)
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2014 Advanced Computing Technologies LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IOAPIC_H_
+#define	_IOAPIC_H_
+
+/*
+ * Allocate a PCI IRQ from the I/O APIC.
+ */
+void	ioapic_init(struct vmctx *ctx);
+int	ioapic_pci_alloc_irq(void);
+
+#endif

Modified: head/usr.sbin/bhyve/mptbl.c
==============================================================================
--- head/usr.sbin/bhyve/mptbl.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/mptbl.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 #include "acpi.h"
 #include "bhyverun.h"
 #include "mptbl.h"
+#include "pci_emul.h"
 
 #define MPTABLE_BASE		0xF0000
 
@@ -75,9 +76,6 @@ __FBSDID("$FreeBSD$");
 /* Number of local intr entries */
 #define	MPEII_NUM_LOCAL_IRQ	2
 
-/* Number of i/o intr entries */
-#define	MPEII_MAX_IRQ		24
-
 /* Bus entry defines */
 #define MPE_NUM_BUSES		2
 #define MPE_BUSNAME_LEN		6
@@ -195,8 +193,42 @@ mpt_build_ioapic_entries(io_apic_entry_p
 	mpei->apic_address = IOAPIC_PADDR;
 }
 
+static int
+mpt_count_ioint_entries(void)
+{
+
+	/*
+	 * Always include entries for the first 16 pins along with a entry
+	 * for each active PCI INTx pin.
+	 */
+	return (16 + pci_count_lintr());
+}
+
 static void
-mpt_build_ioint_entries(int_entry_ptr mpie, int num_pins, int id)
+mpt_generate_pci_int(int slot, int pin, int ioapic_irq, void *arg)
+{
+	int_entry_ptr *mpiep, mpie;
+
+	mpiep = arg;
+	mpie = *mpiep;
+	memset(mpie, 0, sizeof(*mpie));
+
+	/*
+	 * This is always after another I/O interrupt entry, so cheat
+	 * and fetch the I/O APIC ID from the prior entry.
+	 */
+	mpie->type = MPCT_ENTRY_INT;
+	mpie->int_type = INTENTRY_TYPE_INT;
+	mpie->src_bus_id = 0;
+	mpie->src_bus_irq = slot << 2 | (pin - 1);
+	mpie->dst_apic_id = mpie[-1].dst_apic_id;
+	mpie->dst_apic_int = ioapic_irq;
+
+	*mpiep = mpie + 1;
+}
+
+static void
+mpt_build_ioint_entries(int_entry_ptr mpie, int id)
 {
 	int pin;
 
@@ -206,8 +238,8 @@ mpt_build_ioint_entries(int_entry_ptr mp
 	 * just use the default config, tweek later if needed.
 	 */
 
-	/* Run through all 16 pins. */
-	for (pin = 0; pin < num_pins; pin++) {
+	/* First, generate the first 16 pins. */
+	for (pin = 0; pin < 16; pin++) {
 		memset(mpie, 0, sizeof(*mpie));
 		mpie->type = MPCT_ENTRY_INT;
 		mpie->src_bus_id = 1;
@@ -235,16 +267,6 @@ mpt_build_ioint_entries(int_entry_ptr mp
 			mpie->int_type = INTENTRY_TYPE_INT;
 			mpie->src_bus_irq = SCI_INT;
 			break;
-		case 5:
-		case 10:
-		case 11:
-			/*
-			 * PCI Irqs set to level triggered and active-lo.
-			 */
-			mpie->int_flags = INTENTRY_FLAGS_POLARITY_ACTIVELO |
-			    INTENTRY_FLAGS_TRIGGER_LEVEL;
-			mpie->src_bus_id = 0;
-			/* fall through.. */
 		default:
 			/* All other pins are identity mapped. */
 			mpie->int_type = INTENTRY_TYPE_INT;
@@ -254,6 +276,8 @@ mpt_build_ioint_entries(int_entry_ptr mp
 		mpie++;
 	}
 
+	/* Next, generate entries for any PCI INTx interrupts. */
+	pci_walk_lintr(mpt_generate_pci_int, &mpie); 
 }
 
 void
@@ -273,6 +297,7 @@ mptable_build(struct vmctx *ctx, int ncp
 	proc_entry_ptr		mpep;
 	mpfps_t			mpfp;
 	int_entry_ptr		mpie;
+	int			ioints;
 	char 			*curraddr;
 	char 			*startaddr;
 
@@ -307,9 +332,10 @@ mptable_build(struct vmctx *ctx, int ncp
 	mpch->entry_count++;
 
 	mpie = (int_entry_ptr) curraddr;
-	mpt_build_ioint_entries(mpie, MPEII_MAX_IRQ, 0);
-	curraddr += sizeof(*mpie) * MPEII_MAX_IRQ;
-	mpch->entry_count += MPEII_MAX_IRQ;
+	ioints = mpt_count_ioint_entries();
+	mpt_build_ioint_entries(mpie, 0);
+	curraddr += sizeof(*mpie) * ioints;
+	mpch->entry_count += ioints;
 
 	mpie = (int_entry_ptr)curraddr;
 	mpt_build_localint_entries(mpie);

Modified: head/usr.sbin/bhyve/pci_emul.c
==============================================================================
--- head/usr.sbin/bhyve/pci_emul.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/pci_emul.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/errno.h>
 
 #include <ctype.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -47,7 +48,7 @@ __FBSDID("$FreeBSD$");
 #include "acpi.h"
 #include "bhyverun.h"
 #include "inout.h"
-#include "legacy_irq.h"
+#include "ioapic.h"
 #include "mem.h"
 #include "pci_emul.h"
 #include "pci_lpc.h"
@@ -71,11 +72,21 @@ do {									\
 #define MAXSLOTS	(PCI_SLOTMAX + 1)
 #define	MAXFUNCS	(PCI_FUNCMAX + 1)
 
-static struct slotinfo {
-	char	*si_name;
-	char	*si_param;
-	struct pci_devinst *si_devi;
-} pci_slotinfo[MAXSLOTS][MAXFUNCS];
+struct funcinfo {
+	char	*fi_name;
+	char	*fi_param;
+	struct pci_devinst *fi_devi;
+};
+
+struct intxinfo {
+	int	ii_count;
+	int	ii_ioapic_irq;
+};
+
+struct slotinfo {
+	struct intxinfo si_intpins[4];
+	struct funcinfo si_funcs[MAXFUNCS];
+} pci_slotinfo[MAXSLOTS];
 
 SET_DECLARE(pci_devemu_set, struct pci_devemu);
 
@@ -92,6 +103,7 @@ static uint64_t pci_emul_membase64;
 #define	PCI_EMUL_MEMLIMIT64	0xFD00000000UL
 
 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;
@@ -154,7 +166,7 @@ pci_parse_slot(char *opt)
 		goto done;
 	}
 
-	if (pci_slotinfo[snum][fnum].si_name != NULL) {
+	if (pci_slotinfo[snum].si_funcs[fnum].fi_name != NULL) {
 		fprintf(stderr, "pci slot %d:%d already occupied!\n",
 			snum, fnum);
 		goto done;
@@ -167,8 +179,8 @@ pci_parse_slot(char *opt)
 	}
 
 	error = 0;
-	pci_slotinfo[snum][fnum].si_name = emul;
-	pci_slotinfo[snum][fnum].si_param = config;
+	pci_slotinfo[snum].si_funcs[fnum].fi_name = emul;
+	pci_slotinfo[snum].si_funcs[fnum].fi_param = config;
 
 done:
 	if (error)
@@ -666,7 +678,10 @@ pci_emul_init(struct vmctx *ctx, struct 
 	pdi->pi_bus = 0;
 	pdi->pi_slot = slot;
 	pdi->pi_func = func;
-	pdi->pi_lintr_pin = -1;
+	pthread_mutex_init(&pdi->pi_lintr.lock, NULL);
+	pdi->pi_lintr.pin = 0;
+	pdi->pi_lintr.state = IDLE;
+	pdi->pi_lintr.ioapic_irq = 0;
 	pdi->pi_d = pde;
 	snprintf(pdi->pi_name, PI_NAMESZ, "%s-pci-%d", pde->pe_emu, slot);
 
@@ -682,7 +697,7 @@ pci_emul_init(struct vmctx *ctx, struct 
 		free(pdi);
 	} else {
 		pci_emul_devices++;
-		pci_slotinfo[slot][func].si_devi = pdi;
+		pci_slotinfo[slot].si_funcs[func].fi_devi = pdi;
 	}
 
 	return (err);
@@ -816,6 +831,7 @@ msixcap_cfgwrite(struct pci_devinst *pi,
 
 		pi->pi_msix.enabled = val & PCIM_MSIXCTRL_MSIX_ENABLE;
 		pi->pi_msix.function_mask = val & PCIM_MSIXCTRL_FUNCTION_MASK;
+		pci_lintr_update(pi);
 	} 
 	
 	CFGWRITE(pi, offset, val, bytes);
@@ -854,6 +870,7 @@ msicap_cfgwrite(struct pci_devinst *pi, 
 		} else {
 			pi->pi_msi.maxmsgnum = 0;
 		}
+		pci_lintr_update(pi);
 	}
 
 	CFGWRITE(pi, offset, val, bytes);
@@ -993,7 +1010,7 @@ int
 init_pci(struct vmctx *ctx)
 {
 	struct pci_devemu *pde;
-	struct slotinfo *si;
+	struct funcinfo *fi;
 	size_t lowmem;
 	int slot, func;
 	int error;
@@ -1004,12 +1021,12 @@ init_pci(struct vmctx *ctx)
 
 	for (slot = 0; slot < MAXSLOTS; slot++) {
 		for (func = 0; func < MAXFUNCS; func++) {
-			si = &pci_slotinfo[slot][func];
-			if (si->si_name != NULL) {
-				pde = pci_emul_finddev(si->si_name);
+			fi = &pci_slotinfo[slot].si_funcs[func];
+			if (fi->fi_name != NULL) {
+				pde = pci_emul_finddev(fi->fi_name);
 				assert(pde != NULL);
 				error = pci_emul_init(ctx, pde, slot, func,
-					    si->si_param);
+					    fi->fi_param);
 				if (error)
 					return (error);
 			}
@@ -1042,11 +1059,27 @@ init_pci(struct vmctx *ctx)
 	return (0);
 }
 
+static void
+pci_prt_entry(int slot, int pin, int ioapic_irq, void *arg)
+{
+	int *count;
+
+	count = arg;
+	dsdt_line("  Package (0x04)");
+	dsdt_line("  {");
+	dsdt_line("    0x%X,", slot << 16 | 0xffff);
+	dsdt_line("    0x%02X,", pin - 1);
+	dsdt_line("    Zero,");
+	dsdt_line("    0x%X", ioapic_irq);
+	dsdt_line("  }%s", *count == 1 ? "" : ",");
+	(*count)--;
+}
+
 void
 pci_write_dsdt(void)
 {
 	struct pci_devinst *pi;
-	int slot, func;
+	int count, slot, func;
 
 	dsdt_indent(1);
 	dsdt_line("Scope (_SB)");
@@ -1107,11 +1140,20 @@ pci_write_dsdt(void)
 	    PCI_EMUL_MEMLIMIT64 - PCI_EMUL_MEMBASE64);
 	dsdt_line("        ,, , AddressRangeMemory, TypeStatic)");
 	dsdt_line("    })");
+	count = pci_count_lintr();
+	if (count != 0) {
+		dsdt_indent(2);
+		dsdt_line("Name (_PRT, Package (0x%02X)", count);
+		dsdt_line("{");
+		pci_walk_lintr(pci_prt_entry, &count);
+		dsdt_line("})");
+		dsdt_unindent(2);
+	}
 
 	dsdt_indent(2);
 	for (slot = 0; slot < MAXSLOTS; slot++) {
 		for (func = 0; func < MAXFUNCS; func++) {
-			pi = pci_slotinfo[slot][func].si_devi;
+			pi = pci_slotinfo[slot].si_funcs[func].fi_devi;
 			if (pi != NULL && pi->pi_d->pe_write_dsdt != NULL)
 				pi->pi_d->pe_write_dsdt(pi);
 		}
@@ -1176,18 +1218,54 @@ pci_generate_msi(struct pci_devinst *pi,
 	}
 }
 
+static bool
+pci_lintr_permitted(struct pci_devinst *pi)
+{
+	uint16_t cmd;
+
+	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
+	return (!(pi->pi_msi.enabled || pi->pi_msix.enabled ||
+		(cmd & PCIM_CMD_INTxDIS)));
+}
+
 int
-pci_lintr_request(struct pci_devinst *pi, int req)
+pci_lintr_request(struct pci_devinst *pi)
 {
-	int irq;
+	struct slotinfo *si;
+	int bestpin, bestcount, irq, pin;
 
-	irq = legacy_irq_alloc(req);
-	if (irq < 0)
-		return (-1);
+	/*
+	 * First, allocate a pin from our slot.
+	 */
+	si = &pci_slotinfo[pi->pi_slot];
+	bestpin = 0;
+	bestcount = si->si_intpins[0].ii_count;
+	for (pin = 1; pin < 4; pin++) {
+		if (si->si_intpins[pin].ii_count < bestcount) {
+			bestpin = pin;
+			bestcount = si->si_intpins[pin].ii_count;
+		}
+	}
+
+	/*
+	 * Attempt to allocate an I/O APIC pin for this intpin.  If
+	 * 8259A support is added we will need a separate field to
+	 * assign the intpin to an input pin on the PCI interrupt
+	 * router.
+	 */
+	if (si->si_intpins[bestpin].ii_count == 0) {
+		irq = ioapic_pci_alloc_irq();
+		if (irq < 0)
+			return (-1);		
+		si->si_intpins[bestpin].ii_ioapic_irq = irq;
+	} else
+		irq = si->si_intpins[bestpin].ii_ioapic_irq;
+	si->si_intpins[bestpin].ii_count++;
 
-	pi->pi_lintr_pin = irq;
+	pi->pi_lintr.pin = bestpin + 1;
+	pi->pi_lintr.ioapic_irq = irq;
 	pci_set_cfgdata8(pi, PCIR_INTLINE, irq);
-	pci_set_cfgdata8(pi, PCIR_INTPIN, 1);
+	pci_set_cfgdata8(pi, PCIR_INTPIN, bestpin + 1);
 	return (0);
 }
 
@@ -1195,23 +1273,77 @@ void
 pci_lintr_assert(struct pci_devinst *pi)
 {
 
-	assert(pi->pi_lintr_pin >= 0);
+	assert(pi->pi_lintr.pin > 0);
 
-	if (pi->pi_lintr_state == 0) {
-		pi->pi_lintr_state = 1;
-		vm_ioapic_assert_irq(pi->pi_vmctx, pi->pi_lintr_pin);
+	pthread_mutex_lock(&pi->pi_lintr.lock);
+	if (pi->pi_lintr.state == IDLE) {
+		if (pci_lintr_permitted(pi)) {
+			pi->pi_lintr.state = ASSERTED;
+			vm_ioapic_assert_irq(pi->pi_vmctx,
+			    pi->pi_lintr.ioapic_irq);
+		} else
+			pi->pi_lintr.state = PENDING;
 	}
+	pthread_mutex_unlock(&pi->pi_lintr.lock);
 }
 
 void
 pci_lintr_deassert(struct pci_devinst *pi)
 {
 
-	assert(pi->pi_lintr_pin >= 0);
+	assert(pi->pi_lintr.pin > 0);
+
+	pthread_mutex_lock(&pi->pi_lintr.lock);
+	if (pi->pi_lintr.state == ASSERTED) {
+		pi->pi_lintr.state = IDLE;
+		vm_ioapic_deassert_irq(pi->pi_vmctx, pi->pi_lintr.ioapic_irq);
+	} else if (pi->pi_lintr.state == PENDING)
+		pi->pi_lintr.state = IDLE;
+	pthread_mutex_unlock(&pi->pi_lintr.lock);
+}
+
+static void
+pci_lintr_update(struct pci_devinst *pi)
+{
 
-	if (pi->pi_lintr_state == 1) {
-		pi->pi_lintr_state = 0;
-		vm_ioapic_deassert_irq(pi->pi_vmctx, pi->pi_lintr_pin);
+	pthread_mutex_lock(&pi->pi_lintr.lock);
+	if (pi->pi_lintr.state == ASSERTED && !pci_lintr_permitted(pi)) {
+		vm_ioapic_deassert_irq(pi->pi_vmctx, pi->pi_lintr.ioapic_irq);
+		pi->pi_lintr.state = PENDING;
+	} else if (pi->pi_lintr.state == PENDING && pci_lintr_permitted(pi)) {
+		pi->pi_lintr.state = ASSERTED;
+		vm_ioapic_assert_irq(pi->pi_vmctx, pi->pi_lintr.ioapic_irq);
+	}
+	pthread_mutex_unlock(&pi->pi_lintr.lock);
+}
+
+int
+pci_count_lintr(void)
+{
+	int count, slot, pin;
+
+	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++;
+		}
+	}
+	return (count);
+}
+
+void
+pci_walk_lintr(pci_lintr_cb cb, void *arg)
+{
+	struct intxinfo *ii;
+	int slot, pin;
+
+	for (slot = 0; slot < MAXSLOTS; slot++) {
+		for (pin = 0; pin < 4; pin++) {
+			ii = &pci_slotinfo[slot].si_intpins[pin];
+			if (ii->ii_count != 0)
+				cb(slot, pin + 1, ii->ii_ioapic_irq, arg);
+		}
 	}
 }
 
@@ -1226,7 +1358,7 @@ pci_emul_is_mfdev(int slot)
 
 	numfuncs = 0;
 	for (f = 0; f < MAXFUNCS; f++) {
-		if (pci_slotinfo[slot][f].si_devi != NULL) {
+		if (pci_slotinfo[slot].si_funcs[f].fi_devi != NULL) {
 			numfuncs++;
 		}
 	}
@@ -1348,6 +1480,12 @@ pci_emul_cmdwrite(struct pci_devinst *pi
 				assert(0); 
 		}
 	}
+
+	/*
+	 * If INTx has been unmasked and is pending, assert the
+	 * interrupt.
+	 */
+	pci_lintr_update(pi);
 }	
 
 static int
@@ -1362,7 +1500,7 @@ pci_emul_cfgdata(struct vmctx *ctx, int 
 	assert(bytes == 1 || bytes == 2 || bytes == 4);
 	
 	if (cfgbus == 0)
-		pi = pci_slotinfo[cfgslot][cfgfunc].si_devi;
+		pi = pci_slotinfo[cfgslot].si_funcs[cfgfunc].fi_devi;
 	else
 		pi = NULL;
 

Modified: head/usr.sbin/bhyve/pci_emul.h
==============================================================================
--- head/usr.sbin/bhyve/pci_emul.h	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/pci_emul.h	Wed Jan 29 14:56:48 2014	(r261268)
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/kernel.h>
+#include <sys/_pthreadtypes.h>
 
 #include <dev/pci/pcireg.h>
 
@@ -102,16 +103,27 @@ struct msix_table_entry {
 #define MAX_MSIX_TABLE_ENTRIES	2048
 #define PBA_TABLE_ENTRY_SIZE	8
 
+enum lintr_stat {
+	IDLE,
+	ASSERTED,
+	PENDING
+};
+
 struct pci_devinst {
 	struct pci_devemu *pi_d;
 	struct vmctx *pi_vmctx;
 	uint8_t	  pi_bus, pi_slot, pi_func;
-	int8_t    pi_lintr_pin;
-	int8_t	  pi_lintr_state;
 	char	  pi_name[PI_NAMESZ];
 	int	  pi_bar_getsize;
 
 	struct {
+		int8_t    	pin;
+		enum lintr_stat	state;
+		int	  	ioapic_irq;
+		pthread_mutex_t	lock;
+	} pi_lintr;
+
+	struct {
 		int		enabled;
 		uint64_t	addr;
 		uint64_t	msg_data;
@@ -187,6 +199,8 @@ struct pciecap {
 	uint16_t	slot_status2;
 } __packed;
 
+typedef void (*pci_lintr_cb)(int slot, int pin, int ioapic_irq, void *arg);
+
 int	init_pci(struct vmctx *ctx);
 void	msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
 	    int bytes, uint32_t val);
@@ -203,7 +217,7 @@ void	pci_generate_msi(struct pci_devinst
 void	pci_generate_msix(struct pci_devinst *pi, int msgnum);
 void	pci_lintr_assert(struct pci_devinst *pi);
 void	pci_lintr_deassert(struct pci_devinst *pi);
-int	pci_lintr_request(struct pci_devinst *pi, int ivec);
+int	pci_lintr_request(struct pci_devinst *pi);
 int	pci_msi_enabled(struct pci_devinst *pi);
 int	pci_msix_enabled(struct pci_devinst *pi);
 int	pci_msix_table_bar(struct pci_devinst *pi);
@@ -215,6 +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);
 void	pci_write_dsdt(void);
 
 static __inline void 

Modified: head/usr.sbin/bhyve/pci_uart.c
==============================================================================
--- head/usr.sbin/bhyve/pci_uart.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/pci_uart.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -91,7 +91,7 @@ pci_uart_init(struct vmctx *ctx, struct 
 	struct uart_softc *sc;
 
 	pci_emul_alloc_bar(pi, 0, PCIBAR_IO, UART_IO_BAR_SIZE);
-	pci_lintr_request(pi, -1);
+	pci_lintr_request(pi);
 
 	/* initialize config space */
 	pci_set_cfgdata16(pi, PCIR_DEVICE, COM_DEV);

Modified: head/usr.sbin/bhyve/pci_virtio_block.c
==============================================================================
--- head/usr.sbin/bhyve/pci_virtio_block.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/pci_virtio_block.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -117,6 +117,7 @@ static int pci_vtblk_debug;
  */
 struct pci_vtblk_softc {
 	struct virtio_softc vbsc_vs;
+	pthread_mutex_t vsc_mtx;
 	struct vqueue_info vbsc_vq;
 	int		vbsc_fd;
 	struct vtblk_config vbsc_cfg;	
@@ -304,8 +305,12 @@ pci_vtblk_init(struct vmctx *ctx, struct
 	/* record fd of storage device/file */
 	sc->vbsc_fd = fd;
 
+	pthread_mutex_init(&sc->vsc_mtx, NULL);
+
 	/* init virtio softc and virtqueues */
 	vi_softc_linkup(&sc->vbsc_vs, &vtblk_vi_consts, sc, pi, &sc->vbsc_vq);
+	sc->vbsc_vs.vs_mtx = &sc->vsc_mtx;
+
 	sc->vbsc_vq.vq_qsize = VTBLK_RINGSZ;
 	/* sc->vbsc_vq.vq_notify = we have no per-queue notify */
 
@@ -339,6 +344,8 @@ pci_vtblk_init(struct vmctx *ctx, struct
 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_BLOCK);
 
+	pci_lintr_request(pi);
+
 	if (vi_intr_init(&sc->vbsc_vs, 1, fbsdrun_virtio_msix()))
 		return (1);
 	vi_set_io_bar(&sc->vbsc_vs, 0);

Modified: head/usr.sbin/bhyve/pci_virtio_net.c
==============================================================================
--- head/usr.sbin/bhyve/pci_virtio_net.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/pci_virtio_net.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -519,6 +519,8 @@ pci_vtnet_init(struct vmctx *ctx, struct
 	pthread_mutex_init(&sc->vsc_mtx, NULL);
 
 	vi_softc_linkup(&sc->vsc_vs, &vtnet_vi_consts, sc, pi, sc->vsc_queues);
+	sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
+
 	sc->vsc_queues[VTNET_RXQ].vq_qsize = VTNET_RINGSZ;
 	sc->vsc_queues[VTNET_RXQ].vq_notify = pci_vtnet_ping_rxq;
 	sc->vsc_queues[VTNET_TXQ].vq_qsize = VTNET_RINGSZ;
@@ -608,6 +610,8 @@ pci_vtnet_init(struct vmctx *ctx, struct
 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);
 
+	pci_lintr_request(pi);
+
 	/* link always up */
 	sc->vsc_config.status = 1;
 	

Modified: head/usr.sbin/bhyve/virtio.c
==============================================================================
--- head/usr.sbin/bhyve/virtio.c	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/virtio.c	Wed Jan 29 14:56:48 2014	(r261268)
@@ -99,7 +99,11 @@ vi_reset_dev(struct virtio_softc *vs)
 	vs->vs_negotiated_caps = 0;
 	vs->vs_curq = 0;
 	/* vs->vs_status = 0; -- redundant */
+	VS_LOCK(vs);
+	if (vs->vs_isr)
+		pci_lintr_deassert(vs->vs_pi);
 	vs->vs_isr = 0;
+	VS_UNLOCK(vs);
 	vs->vs_msix_cfg_idx = VIRTIO_MSI_NO_VECTOR;
 }
 
@@ -137,11 +141,10 @@ vi_intr_init(struct virtio_softc *vs, in
 		nvec = vs->vs_vc->vc_nvq + 1;
 		if (pci_emul_add_msixcap(vs->vs_pi, nvec, barnum))
 			return (1);
-	} else {
+	} else
 		vs->vs_flags &= ~VIRTIO_USE_MSIX;
-		/* Only 1 MSI vector for bhyve */
-		pci_emul_add_msicap(vs->vs_pi, 1);
-	}
+	/* Only 1 MSI vector for bhyve */
+	pci_emul_add_msicap(vs->vs_pi, 1);
 	return (0);
 }
 
@@ -591,6 +594,8 @@ bad:
 	case VTCFG_R_ISR:
 		value = vs->vs_isr;
 		vs->vs_isr = 0;		/* a read clears this flag */
+		if (value)
+			pci_lintr_deassert(pi);
 		break;
 	case VTCFG_R_CFGVEC:
 		value = vs->vs_msix_cfg_idx;

Modified: head/usr.sbin/bhyve/virtio.h
==============================================================================
--- head/usr.sbin/bhyve/virtio.h	Wed Jan 29 14:14:09 2014	(r261267)
+++ head/usr.sbin/bhyve/virtio.h	Wed Jan 29 14:56:48 2014	(r261268)
@@ -328,6 +328,18 @@ struct virtio_softc {
 	uint16_t vs_msix_cfg_idx;	/* MSI-X vector for config event */
 };
 
+#define	VS_LOCK(vs)							\
+do {									\
+	if (vs->vs_mtx)							\
+		pthread_mutex_lock(vs->vs_mtx);				\
+} while (0)
+
+#define	VS_UNLOCK(vs)							\
+do {									\
+	if (vs->vs_mtx)							\
+		pthread_mutex_unlock(vs->vs_mtx);			\
+} while (0)
+
 struct virtio_consts {
 	const char *vc_name;		/* name of driver (for diagnostics) */
 	int	vc_nvq;			/* number of virtual queues */
@@ -431,11 +443,14 @@ static inline void
 vq_interrupt(struct virtio_softc *vs, struct vqueue_info *vq)
 {
 
-	if (vs->vs_flags & VIRTIO_USE_MSIX)
+	if (pci_msix_enabled(vs->vs_pi))
 		pci_generate_msix(vs->vs_pi, vq->vq_msix_idx);
 	else {
+		VS_LOCK(vs);
 		vs->vs_isr |= VTCFG_ISR_QUEUES;
 		pci_generate_msi(vs->vs_pi, 0);
+		pci_lintr_assert(vs->vs_pi);
+		VS_UNLOCK(vs);
 	}
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201401291456.s0TEum0D097293>