Skip to content

Commit

Permalink
core: ivhsmem: Factor out architecture-specific parts
Browse files Browse the repository at this point in the history
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 <jan.kiszka@siemens.com>
  • Loading branch information
jan-kiszka committed Jun 27, 2016
1 parent e1ff6c5 commit 40cd9f5
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 72 deletions.
4 changes: 2 additions & 2 deletions hypervisor/arch/x86/Makefile
@@ -1,7 +1,7 @@
#
# Jailhouse, a Linux-based partitioning hypervisor
#
# Copyright (c) Siemens AG, 2013
# Copyright (c) Siemens AG, 2013-2016
# Copyright (c) Valentine Sinitsyn, 2014
#
# Authors:
Expand All @@ -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 \
../../ivshmem.o
../../ivshmem.o ivshmem.o

always := $(BUILT_IN_OBJECTS)

Expand Down
22 changes: 22 additions & 0 deletions 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 <jan.kiszka@siemens.com>
*
* 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 */
71 changes: 71 additions & 0 deletions hypervisor/arch/x86/ivshmem.c
@@ -0,0 +1,71 @@
/*
* Jailhouse, a Linux-based partitioning hypervisor
*
* Copyright (c) Siemens AG, 2014-2016
*
* Author:
* Henning Schild <henning.schild@siemens.com>
*
* 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;
}
2 changes: 1 addition & 1 deletion hypervisor/arch/x86/vtd.c
Expand Up @@ -394,7 +394,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);
Expand Down
20 changes: 18 additions & 2 deletions hypervisor/include/jailhouse/ivshmem.h
Expand Up @@ -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)
Expand All @@ -32,7 +32,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);
Expand All @@ -43,5 +43,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 */
78 changes: 12 additions & 66 deletions hypervisor/ivshmem.c
Expand Up @@ -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
Expand Down Expand Up @@ -66,22 +66,6 @@ static const u32 default_cspace[IVSHMEM_CFG_SIZE / sizeof(u32)] = {
(PCI_CFG_BAR/8 + 2),
};

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)
{
Expand All @@ -95,7 +79,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;
Expand All @@ -105,7 +89,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;

Expand All @@ -125,50 +115,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;
Expand All @@ -189,7 +135,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];
Expand All @@ -215,7 +161,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;
}
Expand Down Expand Up @@ -253,7 +199,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;
}
Expand Down
2 changes: 1 addition & 1 deletion hypervisor/pci.c
Expand Up @@ -798,7 +798,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;
Expand Down

0 comments on commit 40cd9f5

Please sign in to comment.