So far the ivshmem code assumed to run only on x86. In order to prepare it for reuse on other architectures (ARM, ARM64), factor out the bits and pieces that are arch-specific and implement them for x86.
Signed-off-by: Jan Kiszka <[email protected]> --- hypervisor/arch/x86/Kbuild | 2 +- hypervisor/arch/x86/include/asm/ivshmem.h | 22 +++++++++ hypervisor/arch/x86/ivshmem.c | 71 +++++++++++++++++++++++++++ hypervisor/arch/x86/vtd.c | 2 +- hypervisor/include/jailhouse/ivshmem.h | 20 +++++++- hypervisor/ivshmem.c | 80 +++++-------------------------- hypervisor/pci.c | 2 +- 7 files changed, 127 insertions(+), 72 deletions(-) create mode 100644 hypervisor/arch/x86/include/asm/ivshmem.h create mode 100644 hypervisor/arch/x86/ivshmem.c diff --git a/hypervisor/arch/x86/Kbuild b/hypervisor/arch/x86/Kbuild index 4157fcd..8fe595f 100644 --- a/hypervisor/arch/x86/Kbuild +++ b/hypervisor/arch/x86/Kbuild @@ -15,7 +15,7 @@ BUILT_IN_OBJECTS := built-in-amd.o built-in-intel.o COMMON_OBJECTS := apic.o dbg-write.o entry.o setup.o control.o mmio.o iommu.o \ paging.o ../../pci.o pci.o ioapic.o i8042.o vcpu.o \ - uart.o vga.o ../../ivshmem.o + uart.o vga.o ../../ivshmem.o ivshmem.o always := $(BUILT_IN_OBJECTS) diff --git a/hypervisor/arch/x86/include/asm/ivshmem.h b/hypervisor/arch/x86/include/asm/ivshmem.h new file mode 100644 index 0000000..081d4a2 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/ivshmem.h @@ -0,0 +1,22 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka <[email protected]> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_IVSHMEM_H +#define _JAILHOUSE_ASM_IVSHMEM_H + +#include <asm/apic.h> + +struct arch_pci_ivshmem { + struct apic_irq_message irq_msg; +}; + +#endif /* !_JAILHOUSE_ASM_IVSHMEM_H */ diff --git a/hypervisor/arch/x86/ivshmem.c b/hypervisor/arch/x86/ivshmem.c new file mode 100644 index 0000000..49f74e7 --- /dev/null +++ b/hypervisor/arch/x86/ivshmem.c @@ -0,0 +1,71 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Author: + * Henning Schild <[email protected]> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include <jailhouse/cell.h> +#include <jailhouse/ivshmem.h> +#include <jailhouse/pci.h> +#include <jailhouse/printk.h> +#include <asm/pci.h> + +void arch_ivshmem_write_doorbell(struct ivshmem_endpoint *ive) +{ + struct ivshmem_endpoint *remote = ive->remote; + struct apic_irq_message irq_msg; + + if (!remote) + return; + + /* get a copy of the struct before using it, the read barrier makes + * sure the copy is consistent */ + irq_msg = remote->arch.irq_msg; + memory_load_barrier(); + if (irq_msg.valid) + apic_send_irq(irq_msg); +} + +int arch_ivshmem_update_msix(struct pci_device *device) +{ + struct ivshmem_endpoint *ive = device->ivshmem_endpoint; + union x86_msi_vector msi = { + .raw.address = device->msix_vectors[0].address, + .raw.data = device->msix_vectors[0].data, + }; + struct apic_irq_message irq_msg; + + /* before doing anything mark the cached irq_msg as invalid, + * on success it will be valid on return. */ + ive->arch.irq_msg.valid = 0; + memory_barrier(); + + if (ivshmem_is_msix_masked(ive)) + return 0; + + irq_msg = x86_pci_translate_msi(device, 0, 0, msi); + if (!irq_msg.valid) + return 0; + + if (!apic_filter_irq_dest(device->cell, &irq_msg)) { + panic_printk("FATAL: ivshmem MSI-X target outside of " + "cell \"%s\" device %02x:%02x.%x\n", + device->cell->config->name, + PCI_BDF_PARAMS(device->info->bdf)); + return -EPERM; + } + /* now copy the whole struct into our cache and mark the cache + * valid at the end */ + irq_msg.valid = 0; + ive->arch.irq_msg = irq_msg; + memory_barrier(); + ive->arch.irq_msg.valid = 1; + + return 0; +} diff --git a/hypervisor/arch/x86/vtd.c b/hypervisor/arch/x86/vtd.c index a1b2add..39e0d89 100644 --- a/hypervisor/arch/x86/vtd.c +++ b/hypervisor/arch/x86/vtd.c @@ -393,7 +393,7 @@ static int vtd_emulate_inv_int(unsigned int unit_no, unsigned int index) device = pci_get_assigned_device(&root_cell, irte_usage->device_id); if (device && device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) - return ivshmem_update_msix(device); + return arch_ivshmem_update_msix(device); irq_msg = iommu_get_remapped_root_int(unit_no, irte_usage->device_id, irte_usage->vector, index); diff --git a/hypervisor/include/jailhouse/ivshmem.h b/hypervisor/include/jailhouse/ivshmem.h index 5c3c415..c0fd520 100644 --- a/hypervisor/include/jailhouse/ivshmem.h +++ b/hypervisor/include/jailhouse/ivshmem.h @@ -15,7 +15,7 @@ #define _JAILHOUSE_IVSHMEM_H #include <jailhouse/pci.h> -#include <asm/apic.h> +#include <asm/ivshmem.h> #define IVSHMEM_CFG_MSIX_CAP 0x50 #define IVSHMEM_CFG_SIZE (IVSHMEM_CFG_MSIX_CAP + 12) @@ -33,7 +33,7 @@ struct ivshmem_endpoint { u64 bar4_address; struct pci_device *device; struct ivshmem_endpoint *remote; - struct apic_irq_message irq_msg; + struct arch_pci_ivshmem arch; }; int ivshmem_init(struct cell *cell, struct pci_device *device); @@ -44,5 +44,21 @@ enum pci_access ivshmem_pci_cfg_write(struct pci_device *device, enum pci_access ivshmem_pci_cfg_read(struct pci_device *device, u16 address, u32 *value); +bool ivshmem_is_msix_masked(struct ivshmem_endpoint *ive); + +/** + * Handle write to doorbell register. + * @param ive Ivshmem endpoint the write was performed on. + */ +void arch_ivshmem_write_doorbell(struct ivshmem_endpoint *ive); + +/** + * Update cached MSI-X state (if any) of the given ivshmem device. + * @param device The device to be updated. + * + * @return 0 on success, negative error code otherwise. + */ +int arch_ivshmem_update_msix(struct pci_device *device); + /** @} IVSHMEM */ #endif /* !_JAILHOUSE_IVSHMEM_H */ diff --git a/hypervisor/ivshmem.c b/hypervisor/ivshmem.c index cd4b6c1..6f628a7 100644 --- a/hypervisor/ivshmem.c +++ b/hypervisor/ivshmem.c @@ -26,7 +26,7 @@ #include <jailhouse/string.h> #include <jailhouse/utils.h> #include <jailhouse/processor.h> -#include <asm/pci.h> +#include <asm/percpu.h> #define VIRTIO_VENDOR_ID 0x1af4 #define IVSHMEM_DEVICE_ID 0x1110 @@ -67,22 +67,6 @@ static const u32 default_cspace[IVSHMEM_CFG_SIZE / sizeof(u32)] = { [(IVSHMEM_CFG_MSIX_CAP + 0x8)/4] = 0x10 * IVSHMEM_MSIX_VECTORS | 4, }; -static void ivshmem_write_doorbell(struct ivshmem_endpoint *ive) -{ - struct ivshmem_endpoint *remote = ive->remote; - struct apic_irq_message irq_msg; - - if (!remote) - return; - - /* get a copy of the struct before using it, the read barrier makes - * sure the copy is consistent */ - irq_msg = remote->irq_msg; - memory_load_barrier(); - if (irq_msg.valid) - apic_send_irq(irq_msg); -} - static enum mmio_result ivshmem_register_mmio(void *arg, struct mmio_access *mmio) { @@ -96,7 +80,7 @@ static enum mmio_result ivshmem_register_mmio(void *arg, if (mmio->address == IVSHMEM_REG_DBELL) { if (mmio->is_write) - ivshmem_write_doorbell(ive); + arch_ivshmem_write_doorbell(ive); else mmio->value = 0; return MMIO_HANDLED; @@ -106,7 +90,7 @@ static enum mmio_result ivshmem_register_mmio(void *arg, if (mmio->is_write) { ive->state = mmio->value; memory_barrier(); - ivshmem_write_doorbell(ive); + arch_ivshmem_write_doorbell(ive); } else { mmio->value = ive->state; } @@ -126,7 +110,13 @@ static enum mmio_result ivshmem_register_mmio(void *arg, return MMIO_ERROR; } -static bool ivshmem_is_msix_masked(struct ivshmem_endpoint *ive) +/** + * Check if MSI-X doorbell interrupt is masked. + * @param ive Ivshmem endpoint the mask should be checked for. + * + * @return True if MSI-X interrupt is masked. + */ +bool ivshmem_is_msix_masked(struct ivshmem_endpoint *ive) { union pci_msix_registers c; @@ -146,50 +136,6 @@ static bool ivshmem_is_msix_masked(struct ivshmem_endpoint *ive) return false; } -/** - * Update cached MSI-X state of the given ivshmem device. - * @param device The device to be updated. - * - * @return 0 on success, negative error code otherwise. - */ -int ivshmem_update_msix(struct pci_device *device) -{ - struct ivshmem_endpoint *ive = device->ivshmem_endpoint; - union x86_msi_vector msi = { - .raw.address = device->msix_vectors[0].address, - .raw.data = device->msix_vectors[0].data, - }; - struct apic_irq_message irq_msg; - - /* before doing anything mark the cached irq_msg as invalid, - * on success it will be valid on return. */ - ive->irq_msg.valid = 0; - memory_barrier(); - - if (ivshmem_is_msix_masked(ive)) - return 0; - - irq_msg = x86_pci_translate_msi(device, 0, 0, msi); - if (!irq_msg.valid) - return 0; - - if (!apic_filter_irq_dest(ive->device->cell, &irq_msg)) { - panic_printk("FATAL: ivshmem MSI-X target outside of " - "cell \"%s\" device %02x:%02x.%x\n", - device->cell->config->name, - PCI_BDF_PARAMS(device->info->bdf)); - return -EPERM; - } - /* now copy the whole struct into our cache and mark the cache - * valid at the end */ - irq_msg.valid = 0; - ive->irq_msg = irq_msg; - memory_barrier(); - ive->irq_msg.valid = 1; - - return 0; -} - static enum mmio_result ivshmem_msix_mmio(void *arg, struct mmio_access *mmio) { struct ivshmem_endpoint *ive = arg; @@ -210,7 +156,7 @@ static enum mmio_result ivshmem_msix_mmio(void *arg, struct mmio_access *mmio) } else { if (mmio->is_write) { msix_table[mmio->address / 4] = mmio->value; - if (ivshmem_update_msix(ive->device)) + if (arch_ivshmem_update_msix(ive->device)) return MMIO_ERROR; } else { mmio->value = msix_table[mmio->address / 4]; @@ -236,7 +182,7 @@ static int ivshmem_write_command(struct ivshmem_endpoint *ive, u16 val) if ((val & PCI_CMD_MASTER) != (*cmd & PCI_CMD_MASTER)) { *cmd = (*cmd & ~PCI_CMD_MASTER) | (val & PCI_CMD_MASTER); - err = ivshmem_update_msix(device); + err = arch_ivshmem_update_msix(device); if (err) return err; } @@ -274,7 +220,7 @@ static int ivshmem_write_msix_control(struct ivshmem_endpoint *ive, u32 val) newval.fmask = p->fmask; if (ive->cspace[IVSHMEM_CFG_MSIX_CAP/4] != newval.raw) { ive->cspace[IVSHMEM_CFG_MSIX_CAP/4] = newval.raw; - return ivshmem_update_msix(ive->device); + return arch_ivshmem_update_msix(ive->device); } return 0; } diff --git a/hypervisor/pci.c b/hypervisor/pci.c index 4a652e8..3806073 100644 --- a/hypervisor/pci.c +++ b/hypervisor/pci.c @@ -776,7 +776,7 @@ void pci_config_commit(struct cell *cell_added_removed) goto error; } if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) { - err = ivshmem_update_msix(device); + err = arch_ivshmem_update_msix(device); if (err) { cap = NULL; goto error; -- 2.1.4 -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
