From: Jan Kiszka Date: Wed, 5 Aug 2015 09:08:40 +0000 (+0200) Subject: core: ivshmem: Migrate to generic MMIO dispatcher X-Git-Url: https://rtime.felk.cvut.cz/gitweb/jailhouse.git/commitdiff_plain/4b6f522c3218c4ccb5cf89f39105208aead120b9 core: ivshmem: Migrate to generic MMIO dispatcher 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 --- diff --git a/hypervisor/arch/x86/mmio.c b/hypervisor/arch/x86/mmio.c index 8b469a0..cefe17a 100644 --- a/hypervisor/arch/x86/mmio.c +++ b/hypervisor/arch/x86/mmio.c @@ -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); } diff --git a/hypervisor/include/jailhouse/pci.h b/hypervisor/include/jailhouse/pci.h index 62fe8ef..f511d50 100644 --- a/hypervisor/include/jailhouse/pci.h +++ b/hypervisor/include/jailhouse/pci.h @@ -38,6 +38,10 @@ #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 */ diff --git a/hypervisor/pci.c b/hypervisor/pci.c index 069e657..ddc1033 100644 --- a/hypervisor/pci.c +++ b/hypervisor/pci.c @@ -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; diff --git a/hypervisor/pci_ivshmem.c b/hypervisor/pci_ivshmem.c index 0b3b7f6..5c1e6a7 100644 --- a/hypervisor/pci_ivshmem.c +++ b/hypervisor/pci_ivshmem.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -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.