]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
core: ivshmem: Migrate to generic MMIO dispatcher
authorJan Kiszka <jan.kiszka@siemens.com>
Wed, 5 Aug 2015 09:08:40 +0000 (11:08 +0200)
committerJan Kiszka <jan.kiszka@siemens.com>
Fri, 14 Aug 2015 06:17:40 +0000 (08:17 +0200)
This only migrates the ivshmem parts of the PCI subsystem to the new
MMIO dispatcher, namely its MMIO BAR 0 and the MSI-X BAR 4.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/x86/mmio.c
hypervisor/include/jailhouse/pci.h
hypervisor/pci.c
hypervisor/pci_ivshmem.c

index 8b469a0e51d3a5aefb51c340fd0e80a289636b36..cefe17a5ac129f1a4df892d0a5a595c0580181dc 100644 (file)
@@ -175,5 +175,6 @@ error:
 
 unsigned int arch_mmio_count_regions(struct cell *cell)
 {
-       return ioapic_mmio_count_regions(cell) + iommu_mmio_count_regions(cell);
+       return pci_mmio_count_regions(cell) + ioapic_mmio_count_regions(cell) +
+               iommu_mmio_count_regions(cell);
 }
index 62fe8ef92cb800a0691ce9561a146ee1e9ed88fc..f511d508a38548993a0def8b4e6093f7e338f8d0 100644 (file)
 #define PCI_CAP_MSI            0x05
 #define PCI_CAP_MSIX           0x11
 
+#define PCI_IVSHMEM_NUM_MMIO_REGIONS   2
+
+struct cell;
+
 /**
  * @defgroup PCI PCI Subsystem
  *
@@ -144,6 +148,8 @@ struct pci_device {
        union pci_msix_vector msix_vector_array[PCI_EMBEDDED_MSIX_VECTS];
 };
 
+unsigned int pci_mmio_count_regions(struct cell *cell);
+
 int pci_init(void);
 
 u32 pci_read_config(u16 bdf, u16 address, unsigned int size);
@@ -255,8 +261,6 @@ enum pci_access pci_ivshmem_cfg_write(struct pci_device *device,
                                      unsigned int row, u32 mask, u32 value);
 enum pci_access pci_ivshmem_cfg_read(struct pci_device *device, u16 address,
                                     u32 *value);
-int ivshmem_mmio_access_handler(const struct cell *cell, bool is_write,
-                               u64 addr, u32 *value);
 /** @} PCI-IVSHMEM */
 /** @} PCI */
 #endif /* !_JAILHOUSE_PCI_H */
index 069e657f70c43d43ad8d11e05635f4b5e3b095a6..ddc1033abeecc60f8717fb71b0c69e5a6fcf7836 100644 (file)
@@ -65,6 +65,19 @@ static void *pci_space;
 static u64 mmcfg_start, mmcfg_end;
 static u8 end_bus;
 
+unsigned int pci_mmio_count_regions(struct cell *cell)
+{
+       const struct jailhouse_pci_device *dev_infos =
+               jailhouse_cell_pci_devices(cell->config);
+       unsigned int n, regions = 0;
+
+       for (n = 0; n < cell->config->num_pci_devices; n++)
+               if (dev_infos[n].type == JAILHOUSE_PCI_TYPE_IVSHMEM)
+                       regions += PCI_IVSHMEM_NUM_MMIO_REGIONS;
+
+       return regions;
+}
+
 static void *pci_get_device_mmcfg_base(u16 bdf)
 {
        return pci_space + ((unsigned long)bdf << 12);
@@ -436,15 +449,9 @@ int pci_mmio_access_handler(const struct cell *cell, bool is_write,
        u32 mmcfg_offset, reg_addr;
        struct pci_device *device;
        enum pci_access access;
-       int ret;
-
-       if (!pci_space || addr < mmcfg_start || addr > mmcfg_end) {
-               ret = pci_msix_access_handler(cell, is_write, addr, value);
-               if (ret == 0)
-                       ret = ivshmem_mmio_access_handler(cell, is_write, addr,
-                                                         value);
-               return ret;
-       }
+
+       if (!pci_space || addr < mmcfg_start || addr > mmcfg_end)
+               return pci_msix_access_handler(cell, is_write, addr, value);
 
        mmcfg_offset = addr - mmcfg_start;
        reg_addr = mmcfg_offset & 0xfff;
index 0b3b7f643192c1498cb5cff40a89ffee1eabef29..5c1e6a73a341e672bd3953bcd5295649872f707a 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <jailhouse/control.h>
+#include <jailhouse/mmio.h>
 #include <jailhouse/pci.h>
 #include <jailhouse/printk.h>
 #include <jailhouse/string.h>
@@ -50,6 +51,8 @@
 struct pci_ivshmem_endpoint {
        u32 cspace[IVSHMEM_CFG_SIZE / sizeof(u32)];
        u32 ivpos;
+       u64 bar0_address;
+       u64 bar4_address;
        struct pci_device *device;
        struct pci_ivshmem_endpoint *remote;
        struct apic_irq_message irq_msg;
@@ -92,25 +95,27 @@ static void ivshmem_write_doorbell(struct pci_ivshmem_endpoint *ive)
                apic_send_irq(irq_msg);
 }
 
-static int ivshmem_register_mmio(struct pci_ivshmem_endpoint *ive,
-                                bool is_write, u32 offset, u32 *value)
+static enum mmio_result ivshmem_register_mmio(void *arg,
+                                             struct mmio_access *mmio)
 {
+       struct pci_ivshmem_endpoint *ive = arg;
+
        /* read-only IVPosition */
-       if (offset == IVSHMEM_REG_IVPOS && !is_write) {
-               *value = ive->ivpos;
-               return 1;
+       if (mmio->address == IVSHMEM_REG_IVPOS && !mmio->is_write) {
+               mmio->value = ive->ivpos;
+               return MMIO_HANDLED;
        }
 
-       if (offset == IVSHMEM_REG_DBELL) {
-               if (is_write)
+       if (mmio->address == IVSHMEM_REG_DBELL) {
+               if (mmio->is_write)
                        ivshmem_write_doorbell(ive);
                else
-                       *value = 0;
-               return 1;
+                       mmio->value = 0;
+               return MMIO_HANDLED;
        }
        panic_printk("FATAL: Invalid ivshmem register %s, number %02x\n",
-                    is_write ? "write" : "read", offset);
-       return -1;
+                    mmio->is_write ? "write" : "read", mmio->address);
+       return MMIO_ERROR;
 }
 
 static bool ivshmem_is_msix_masked(struct pci_ivshmem_endpoint *ive)
@@ -170,38 +175,38 @@ static int ivshmem_update_msix(struct pci_ivshmem_endpoint *ive)
        return 0;
 }
 
-static int ivshmem_msix_mmio(struct pci_ivshmem_endpoint *ive, bool is_write,
-                            u32 offset, u32 *value)
+static enum mmio_result ivshmem_msix_mmio(void *arg, struct mmio_access *mmio)
 {
+       struct pci_ivshmem_endpoint *ive = arg;
        u32 *msix_table = (u32 *)ive->device->msix_vectors;
 
-       if (offset % 4)
+       if (mmio->address % 4)
                goto fail;
 
        /* MSI-X PBA */
-       if (offset >= 0x10 * IVSHMEM_MSIX_VECTORS) {
-               if (is_write) {
+       if (mmio->address >= 0x10 * IVSHMEM_MSIX_VECTORS) {
+               if (mmio->is_write) {
                        goto fail;
                } else {
-                       *value = 0;
-                       return 1;
+                       mmio->value = 0;
+                       return MMIO_HANDLED;
                }
        /* MSI-X Table */
        } else {
-               if (is_write) {
-                       msix_table[offset/4] = *value;
+               if (mmio->is_write) {
+                       msix_table[mmio->address / 4] = mmio->value;
                        if (ivshmem_update_msix(ive))
-                               return -1;
+                               return MMIO_ERROR;
                } else {
-                       *value = msix_table[offset/4];
+                       mmio->value = msix_table[mmio->address / 4];
                }
-               return 1;
+               return MMIO_HANDLED;
        }
 
 fail:
        panic_printk("FATAL: Invalid PCI MSI-X table/PBA access, device "
                     "%02x:%02x.%x\n", PCI_BDF_PARAMS(ive->device->info->bdf));
-       return -1;
+       return MMIO_ERROR;
 }
 
 /**
@@ -211,6 +216,7 @@ fail:
 static int ivshmem_write_command(struct pci_ivshmem_endpoint *ive, u16 val)
 {
        u16 *cmd = (u16 *)&ive->cspace[PCI_CFG_COMMAND/4];
+       struct pci_device *device = ive->device;
        int err;
 
        if ((val & PCI_CMD_MASTER) != (*cmd & PCI_CMD_MASTER)) {
@@ -220,7 +226,25 @@ static int ivshmem_write_command(struct pci_ivshmem_endpoint *ive, u16 val)
                        return err;
        }
 
-       *cmd = (*cmd & ~PCI_CMD_MEM) | (val & PCI_CMD_MEM);
+       if ((val & PCI_CMD_MEM) != (*cmd & PCI_CMD_MEM)) {
+               if (*cmd & PCI_CMD_MEM) {
+                       mmio_region_unregister(device->cell, ive->bar0_address);
+                       mmio_region_unregister(device->cell, ive->bar4_address);
+               }
+               if (val & PCI_CMD_MEM) {
+                       ive->bar0_address = (*(u64 *)&device->bar[0]) & ~0xfL;
+                       mmio_region_register(device->cell, ive->bar0_address,
+                                            IVSHMEM_BAR0_SIZE,
+                                            ivshmem_register_mmio, ive);
+
+                       ive->bar4_address = (*(u64 *)&device->bar[4]) & ~0xfL;
+                       mmio_region_register(device->cell, ive->bar4_address,
+                                            IVSHMEM_BAR4_SIZE,
+                                            ivshmem_msix_mmio, ive);
+               }
+               *cmd = (*cmd & ~PCI_CMD_MEM) | (val & PCI_CMD_MEM);
+       }
+
        return 0;
 }
 
@@ -303,57 +327,18 @@ static void ivshmem_disconnect_cell(struct pci_ivshmem_data *iv, int cellnum)
 {
        struct pci_ivshmem_endpoint *remote = &iv->eps[(cellnum + 1) % 2];
        struct pci_ivshmem_endpoint *ive = &iv->eps[cellnum];
+       u16 cmd = *(u16 *)&ive->cspace[PCI_CFG_COMMAND / 4];
 
+       if (cmd & PCI_CMD_MEM) {
+               mmio_region_unregister(this_cell(), ive->bar0_address);
+               mmio_region_unregister(this_cell(), ive->bar4_address);
+       }
        ive->device->ivshmem_endpoint = NULL;
        ive->device = NULL;
        ive->remote = NULL;
        remote->remote = NULL;
 }
 
-/**
- * Handler for MMIO-accesses to this virtual PCI devices memory. Both for the
- * BAR containing the registers, and the MSI-X BAR.
- * @param cell         The cell that issued the access.
- * @param is_write     True if write access.
- * @param addr         Address accessed.
- * @param value                Pointer to value for reading/writing.
- *
- * @return 1 if handled successfully, 0 if unhandled, -1 on access error.
- *
- * @see pci_mmio_access_handler
- */
-int ivshmem_mmio_access_handler(const struct cell *cell, bool is_write,
-                               u64 addr, u32 *value)
-{
-       struct pci_ivshmem_endpoint *ive;
-       struct pci_device *device;
-       u64 mem_start;
-
-       for (device = cell->virtual_device_list; device;
-            device = device->next_virtual_device) {
-               ive = device->ivshmem_endpoint;
-               if ((ive->cspace[PCI_CFG_COMMAND/4] & PCI_CMD_MEM) == 0)
-                       continue;
-
-               /* BAR0: registers */
-               mem_start = (*(u64 *)&device->bar[0]) & ~0xfL;
-               if (addr >= mem_start &&
-                   addr <= (mem_start + IVSHMEM_BAR0_SIZE - 4))
-                       return ivshmem_register_mmio(ive, is_write,
-                                                    addr - mem_start,
-                                                    value);
-
-               /* BAR4: MSI-X */
-               mem_start = (*(u64 *)&device->bar[4]) & ~0xfL;
-               if (addr >= mem_start &&
-                   addr <= (mem_start + IVSHMEM_BAR4_SIZE - 4))
-                       return ivshmem_msix_mmio(ive, is_write,
-                                                addr - mem_start, value);
-       }
-
-       return 0;
-}
-
 /**
  * Handler for MMIO-write-accesses to PCI config space of this virtual device.
  * @param device       The device that access should be performed on.