diff options
-rw-r--r-- | sys/amd64/amd64/machdep.c | 1 | ||||
-rw-r--r-- | sys/conf/files.amd64 | 2 | ||||
-rw-r--r-- | sys/conf/files.i386 | 1 | ||||
-rw-r--r-- | sys/dev/acpica/acpi_pci.c | 2 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 3 | ||||
-rw-r--r-- | sys/x86/include/init.h | 1 | ||||
-rw-r--r-- | sys/x86/x86/local_apic.c | 3 | ||||
-rw-r--r-- | sys/x86/xen/pv.c | 3 | ||||
-rw-r--r-- | sys/x86/xen/xen_intr.c | 60 | ||||
-rw-r--r-- | sys/x86/xen/xen_msi.c | 125 | ||||
-rw-r--r-- | sys/x86/xen/xen_nexus.c | 45 | ||||
-rw-r--r-- | sys/x86/xen/xen_pci.c | 108 | ||||
-rw-r--r-- | sys/xen/interface/physdev.h | 1 | ||||
-rw-r--r-- | sys/xen/xen_intr.h | 22 | ||||
-rw-r--r-- | sys/xen/xen_msi.h | 39 |
15 files changed, 414 insertions, 2 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 278409d..ab82771 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -177,6 +177,7 @@ struct init_ops init_ops = { .mp_bootaddress = mp_bootaddress, .start_all_aps = native_start_all_aps, #endif + .msi_init = msi_init, }; /* diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index b75732f..9e5a2ed 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -582,3 +582,5 @@ x86/xen/pvcpu_enum.c optional xenhvm x86/xen/xen_apic.c optional xenhvm x86/xen/xenpv.c optional xenhvm x86/xen/xen_nexus.c optional xenhvm +x86/xen/xen_msi.c optional xenhvm +x86/xen/xen_pci.c optional xenhvm diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index db6b2aa..0e4519d 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -599,3 +599,4 @@ x86/xen/xen_intr.c optional xen | xenhvm x86/xen/xen_apic.c optional xenhvm x86/xen/xenpv.c optional xen | xenhvm x86/xen/xen_nexus.c optional xen | xenhvm +x86/xen/xen_msi.c optional xen | xenhvm diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c index f4e794a..d94b6f0 100644 --- a/sys/dev/acpica/acpi_pci.c +++ b/sys/dev/acpica/acpi_pci.c @@ -282,7 +282,7 @@ acpi_pci_probe(device_t dev) if (acpi_get_handle(dev) == NULL) return (ENXIO); device_set_desc(dev, "ACPI PCI bus"); - return (0); + return (BUS_PROBE_DEFAULT); } static int diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index a3990ed..8892c56 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -248,6 +248,9 @@ struct mem_range_softc mem_range_softc; struct init_ops init_ops = { .early_clock_source_init = i8254_init, .early_delay = i8254_delay, +#ifdef DEV_APIC + .msi_init = msi_init, +#endif }; static void diff --git a/sys/x86/include/init.h b/sys/x86/include/init.h index 47dc4f5..7cc6798 100644 --- a/sys/x86/include/init.h +++ b/sys/x86/include/init.h @@ -41,6 +41,7 @@ struct init_ops { void (*parse_memmap)(caddr_t, vm_paddr_t *, int *); u_int (*mp_bootaddress)(u_int); int (*start_all_aps)(void); + void (*msi_init)(void); }; extern struct init_ops init_ops; diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index 50f00d0..2aa18f5 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$"); #include <machine/md_var.h> #include <machine/smp.h> #include <machine/specialreg.h> +#include <x86/init.h> #ifdef DDB #include <sys/interrupt.h> @@ -1438,7 +1439,7 @@ apic_setup_io(void *dummy __unused) lapic_dump("BSP"); /* Enable the MSI "pic". */ - msi_init(); + init_ops.msi_init(); } SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_THIRD, apic_setup_io, NULL); diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c index ee2cd6b..140d13f 100644 --- a/sys/x86/xen/pv.c +++ b/sys/x86/xen/pv.c @@ -60,11 +60,13 @@ __FBSDID("$FreeBSD$"); #include <x86/init.h> #include <machine/pc/bios.h> #include <machine/smp.h> +#include <machine/intr_machdep.h> #include <xen/xen-os.h> #include <xen/hypervisor.h> #include <xen/xenstore/xenstorevar.h> #include <xen/xen_pv.h> +#include <xen/xen_msi.h> #include <xen/interface/vcpu.h> @@ -117,6 +119,7 @@ struct init_ops xen_init_ops = { #ifdef SMP .start_all_aps = xen_pv_start_all_aps, #endif + .msi_init = xen_msi_init, }; static struct bios_smap xen_smap[MAX_E820_ENTRIES]; diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c index 40b65f7..83f1db3 100644 --- a/sys/x86/xen/xen_intr.c +++ b/sys/x86/xen/xen_intr.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <machine/intr_machdep.h> #include <x86/apicvar.h> +#include <x86/apicreg.h> #include <machine/smp.h> #include <machine/stdarg.h> @@ -63,6 +64,7 @@ __FBSDID("$FreeBSD$"); #include <xen/evtchn/evtchnvar.h> #include <dev/xen/xenpci/xenpcivar.h> +#include <dev/pci/pcivar.h> #ifdef DDB #include <ddb/ddb.h> @@ -1373,6 +1375,64 @@ xen_register_pirq(int vector, enum intr_trigger trig, enum intr_polarity pol) } int +xen_register_msi(device_t dev, int vector, int count) +{ + struct physdev_map_pirq msi_irq; + struct xenisrc *isrc; + int ret; + + memset(&msi_irq, 0, sizeof(msi_irq)); + msi_irq.domid = DOMID_SELF; + msi_irq.type = count == 1 ? + MAP_PIRQ_TYPE_MSI_SEG : MAP_PIRQ_TYPE_MULTI_MSI; + msi_irq.index = -1; + msi_irq.pirq = -1; + msi_irq.bus = pci_get_bus(dev) | (pci_get_domain(dev) << 16); + msi_irq.devfn = (pci_get_slot(dev) << 3) | pci_get_function(dev); + msi_irq.entry_nr = count; + + ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &msi_irq); + if (ret != 0) + return (ret); + if (count != msi_irq.entry_nr) { + panic("unable to setup all requested MSI vectors " + "(expected %d got %d)", count, msi_irq.entry_nr); + } + + mtx_lock(&xen_intr_isrc_lock); + for (int i = 0; i < count; i++) { + isrc = xen_intr_alloc_isrc(EVTCHN_TYPE_PIRQ, vector + i); + KASSERT(isrc != NULL, + ("xen: unable to allocate isrc for interrupt")); + isrc->xi_pirq = msi_irq.pirq + i; + } + mtx_unlock(&xen_intr_isrc_lock); + + return (0); +} + +int +xen_release_msi(int vector) +{ + struct physdev_unmap_pirq unmap; + struct xenisrc *isrc; + int ret; + + isrc = (struct xenisrc *)intr_lookup_source(vector); + if (isrc == NULL) + return (ENXIO); + + unmap.pirq = isrc->xi_pirq; + ret = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap); + if (ret != 0) + return (ret); + + xen_intr_release_isrc(isrc); + + return (0); +} + +int xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...) { char descr[MAXCOMLEN + 1]; diff --git a/sys/x86/xen/xen_msi.c b/sys/x86/xen/xen_msi.c new file mode 100644 index 0000000..0f678b1 --- /dev/null +++ b/sys/x86/xen/xen_msi.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com> + * 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/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/sx.h> +#include <sys/systm.h> +#include <x86/apicreg.h> +#include <machine/cputypes.h> +#include <machine/md_var.h> +#include <machine/frame.h> +#include <machine/intr_machdep.h> +#include <x86/apicvar.h> +#include <machine/specialreg.h> +#include <dev/pci/pcivar.h> + +#include <xen/xen_intr.h> +#include <xen/xen_msi.h> + +static struct mtx msi_lock; +static int msi_last_irq; + +void +xen_msi_init(void) +{ + + mtx_init(&msi_lock, "msi", NULL, MTX_DEF); +} + +/* + * Try to allocate 'count' interrupt sources with contiguous IDT values. + */ +int +xen_msi_alloc(device_t dev, int count, int maxcount, int *irqs) +{ + int i, ret = 0; + + mtx_lock(&msi_lock); + + /* If we would exceed the max, give up. */ + if ((msi_last_irq + count) > NUM_MSI_INTS) { + mtx_unlock(&msi_lock); + return (ENXIO); + } + + /* Allocate MSI vectors */ + for (i = 0; i < count; i++) + irqs[i] = FIRST_MSI_INT + msi_last_irq++; + + mtx_unlock(&msi_lock); + + ret = xen_register_msi(dev, irqs[0], count); + if (ret != 0) + return (ret); + + for (i = 0; i < count; i++) + nexus_add_irq(irqs[i]); + + return (0); +} + +int +xen_msi_release(int *irqs, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = xen_release_msi(irqs[i]); + if (ret != 0) + return (ret); + } + + return (0); +} + +int +xen_msi_map(int irq, uint64_t *addr, uint32_t *data) +{ + + return (0); +} + +int +xen_msix_alloc(device_t dev, int *irq) +{ + + return (ENXIO); +} + +int +xen_msix_release(int irq) +{ + + return (ENOENT); +} diff --git a/sys/x86/xen/xen_nexus.c b/sys/x86/xen/xen_nexus.c index e4634f9..1baeb7d 100644 --- a/sys/x86/xen/xen_nexus.c +++ b/sys/x86/xen/xen_nexus.c @@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$"); #include <xen/xen-os.h> #include <xen/xen_intr.h> +#include <xen/xen_msi.h> + +#include "pcib_if.h" /* * Xen nexus(4) driver. @@ -111,6 +114,41 @@ nexus_xen_config_intr(device_t dev, int irq, enum intr_trigger trig, return (intr_config_intr(irq, trig, pol)); } +static int +nexus_xen_alloc_msix(device_t pcib, device_t dev, int *irq) +{ + + return (xen_msix_alloc(dev, irq)); +} + +static int +nexus_xen_release_msix(device_t pcib, device_t dev, int irq) +{ + + return (xen_msix_release(irq)); +} + +static int +nexus_xen_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) +{ + + return (xen_msi_alloc(dev, count, maxcount, irqs)); +} + +static int +nexus_xen_release_msi(device_t pcib, device_t dev, int count, int *irqs) +{ + + return (xen_msi_release(irqs, count)); +} + +static int +nexus_xen_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) +{ + + return (xen_msi_map(irq, addr, data)); +} + static device_method_t nexus_xen_methods[] = { /* Device interface */ DEVMETHOD(device_probe, nexus_xen_probe), @@ -119,6 +157,13 @@ static device_method_t nexus_xen_methods[] = { /* INTR */ DEVMETHOD(bus_config_intr, nexus_xen_config_intr), + /* MSI */ + DEVMETHOD(pcib_alloc_msi, nexus_xen_alloc_msi), + DEVMETHOD(pcib_release_msi, nexus_xen_release_msi), + DEVMETHOD(pcib_alloc_msix, nexus_xen_alloc_msix), + DEVMETHOD(pcib_release_msix, nexus_xen_release_msix), + DEVMETHOD(pcib_map_msi, nexus_xen_map_msi), + { 0, 0 } }; diff --git a/sys/x86/xen/xen_pci.c b/sys/x86/xen/xen_pci.c new file mode 100644 index 0000000..5a186c5 --- /dev/null +++ b/sys/x86/xen/xen_pci.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com> + * 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/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/module.h> + +#include <sys/pciio.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pci_private.h> + +#include <xen/xen-os.h> + +#include "pcib_if.h" +#include "pci_if.h" + +static int xen_pci_probe(device_t dev); + +static void xen_pci_enable_msi_method(device_t dev, device_t child, + uint64_t address, uint16_t data); +static void xen_pci_disable_msi_method(device_t dev, device_t child); + +static device_method_t xen_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, xen_pci_probe), + + /* PCI interface overwrites */ + DEVMETHOD(pci_enable_msi, xen_pci_enable_msi_method), + DEVMETHOD(pci_disable_msi, xen_pci_disable_msi_method), + + DEVMETHOD_END +}; + +static devclass_t pci_devclass; + +DECLARE_CLASS(acpi_pci_driver); +DEFINE_CLASS_1(pci, xen_pci_driver, xen_pci_methods, sizeof(struct pci_softc), + acpi_pci_driver); +DRIVER_MODULE(xen_pci, pcib, xen_pci_driver, pci_devclass, 0, 0); +MODULE_DEPEND(xen_pci, pci, 1, 1, 1); +MODULE_DEPEND(xen_pci, acpi, 1, 1, 1); +MODULE_VERSION(xen_pci, 1); + +static int +xen_pci_probe(device_t dev) +{ + + device_set_desc(dev, "Xen PCI bus"); + + if (!xen_pv_domain()) + return (ENXIO); + + return (BUS_PROBE_SPECIFIC); +} + +static void +xen_pci_enable_msi_method(device_t dev, device_t child, uint64_t address, + uint16_t data) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct pcicfg_msi *msi = &dinfo->cfg.msi; + + /* Enable MSI in the control register. */ + msi->msi_ctrl |= PCIM_MSICTRL_MSI_ENABLE; + pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL, + msi->msi_ctrl, 2); +} + +static void +xen_pci_disable_msi_method(device_t dev, device_t child) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct pcicfg_msi *msi = &dinfo->cfg.msi; + + msi->msi_ctrl &= ~PCIM_MSICTRL_MSI_ENABLE; + pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL, + msi->msi_ctrl, 2); +} diff --git a/sys/xen/interface/physdev.h b/sys/xen/interface/physdev.h index b78eeba..56b8be0 100644 --- a/sys/xen/interface/physdev.h +++ b/sys/xen/interface/physdev.h @@ -151,6 +151,7 @@ DEFINE_XEN_GUEST_HANDLE(physdev_irq_t); #define MAP_PIRQ_TYPE_GSI 0x1 #define MAP_PIRQ_TYPE_UNKNOWN 0x2 #define MAP_PIRQ_TYPE_MSI_SEG 0x3 +#define MAP_PIRQ_TYPE_MULTI_MSI 0x4 #define PHYSDEVOP_map_pirq 13 struct physdev_map_pirq { diff --git a/sys/xen/xen_intr.h b/sys/xen/xen_intr.h index a1ff666..a29414d 100644 --- a/sys/xen/xen_intr.h +++ b/sys/xen/xen_intr.h @@ -224,4 +224,26 @@ void xen_intr_signal(xen_intr_handle_t handle); */ evtchn_port_t xen_intr_port(xen_intr_handle_t handle); +/** + * Setup MSI vector interrupt(s). + * + * \param dev The device that requests the binding. + * + * \param vector Requested initial vector to bind the MSI interrupt(s) to. + * + * \param count Number of vectors to allocate. + * + * \returns 0 on success, otherwise an errno. + */ +int xen_register_msi(device_t dev, int vector, int count); + +/** + * Teardown a MSI vector interrupt. + * + * \param vector Requested vector to release. + * + * \returns 0 on success, otherwise an errno. + */ +int xen_release_msi(int vector); + #endif /* _XEN_INTR_H_ */ diff --git a/sys/xen/xen_msi.h b/sys/xen/xen_msi.h new file mode 100644 index 0000000..baec4c1a --- /dev/null +++ b/sys/xen/xen_msi.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com> + * 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 __XEN_MSI_H__ +#define __XEN_MSI_H__ + +void xen_msi_init(void); +int xen_msi_map(int irq, uint64_t *addr, uint32_t *data); +int xen_msi_alloc(device_t dev, int count, int maxcount, int *irqs); +int xen_msi_release(int *irqs, int count); +int xen_msix_alloc(device_t dev, int *irq); +int xen_msix_release(int irq); + +#endif /* !__XEN_MSI_H__ */
\ No newline at end of file |