diff options
Diffstat (limited to 'meta-agl-jailhouse/recipes-kernel/linux/linux/0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch')
-rw-r--r-- | meta-agl-jailhouse/recipes-kernel/linux/linux/0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch | 311 |
1 files changed, 0 insertions, 311 deletions
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch deleted file mode 100644 index f98670c3..00000000 --- a/meta-agl-jailhouse/recipes-kernel/linux/linux/0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch +++ /dev/null @@ -1,311 +0,0 @@ -From 205cdad2dc9fc8a6a7204b2a71408b43085dd45f Mon Sep 17 00:00:00 2001 -From: Jan Kiszka <jan.kiszka@siemens.com> -Date: Tue, 4 Jun 2019 18:40:25 +0200 -Subject: [PATCH 12/32] uio: Add driver for inter-VM shared memory device - -This adds a UIO driver the ivshmem device, found in QEMU and the -Jailhouse hypervisor. It exposes the MMIO register region and all shared -memory section to userspace. Interrupts are configured in one-shot mode -so that userspace needs to re-enable them after each event via the -Interrupt Control register. The driver registers all possible MSI-X -vectors, coalescing them into the single notifier UIO provides. - -Note: Specification work for the interface is ongoing, so details may -still change. - -Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> ---- - drivers/uio/Kconfig | 7 ++ - drivers/uio/Makefile | 1 + - drivers/uio/uio_ivshmem.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++ - include/linux/pci_ids.h | 1 + - 4 files changed, 250 insertions(+) - create mode 100644 drivers/uio/uio_ivshmem.c - -diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig -index 202ee81cfc2b..a130500f46b8 100644 ---- a/drivers/uio/Kconfig -+++ b/drivers/uio/Kconfig -@@ -165,4 +165,11 @@ config UIO_HV_GENERIC - to network and storage devices from userspace. - - If you compile this as a module, it will be called uio_hv_generic. -+ -+config UIO_IVSHMEM -+ tristate "Inter-VM Shared Memory driver" -+ depends on PCI -+ help -+ Userspace I/O driver for the inter-VM shared memory PCI device -+ as provided by QEMU and the Jailhouse hypervisor. - endif -diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile -index c285dd2a4539..3911fefb2a7e 100644 ---- a/drivers/uio/Makefile -+++ b/drivers/uio/Makefile -@@ -11,3 +11,4 @@ obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o - obj-$(CONFIG_UIO_MF624) += uio_mf624.o - obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o - obj-$(CONFIG_UIO_HV_GENERIC) += uio_hv_generic.o -+obj-$(CONFIG_UIO_IVSHMEM) += uio_ivshmem.o -diff --git a/drivers/uio/uio_ivshmem.c b/drivers/uio/uio_ivshmem.c -new file mode 100644 -index 000000000000..0c16d428c6ed ---- /dev/null -+++ b/drivers/uio/uio_ivshmem.c -@@ -0,0 +1,241 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * UIO driver for Inter-VM shared memory PCI device -+ * -+ * Copyright (c) Siemens AG, 2019 -+ * -+ * Authors: -+ * Jan Kiszka <jan.kiszka@siemens.com> -+ */ -+ -+#include <linux/ivshmem.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/uio_driver.h> -+ -+#define DRV_NAME "uio_ivshmem" -+ -+struct ivshm_dev { -+ struct uio_info info; -+ struct pci_dev *pdev; -+ struct ivshm_regs __iomem *regs; -+ int vectors; -+}; -+ -+static irqreturn_t ivshm_irq_handler(int irq, void *dev_id) -+{ -+ struct ivshm_dev *ivshm_dev = (struct ivshm_dev *)dev_id; -+ -+ /* nothing else to do, we configured one-shot interrupt mode */ -+ uio_event_notify(&ivshm_dev->info); -+ -+ return IRQ_HANDLED; -+} -+ -+static u64 get_config_qword(struct pci_dev *pdev, unsigned int pos) -+{ -+ u32 lo, hi; -+ -+ pci_read_config_dword(pdev, pos, &lo); -+ pci_read_config_dword(pdev, pos + 4, &hi); -+ return lo | ((u64)hi << 32); -+} -+ -+static int ivshm_release(struct uio_info *info, struct inode *inode) -+{ -+ struct ivshm_dev *ivshm_dev = -+ container_of(info, struct ivshm_dev, info); -+ -+ writel(0, &ivshm_dev->regs->state); -+ return 0; -+} -+ -+static int ivshm_probe(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ resource_size_t rw_section_sz, output_section_sz; -+ struct ivshm_dev *ivshm_dev; -+ phys_addr_t section_addr; -+ int err, vendor_cap, i; -+ unsigned int cap_pos; -+ struct uio_mem *mem; -+ char *device_name; -+ u32 dword; -+ -+ ivshm_dev = devm_kzalloc(&pdev->dev, sizeof(struct ivshm_dev), -+ GFP_KERNEL); -+ if (!ivshm_dev) -+ return -ENOMEM; -+ -+ err = pcim_enable_device(pdev); -+ if (err) -+ return err; -+ -+ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s[%s]", DRV_NAME, -+ dev_name(&pdev->dev)); -+ if (!device_name) -+ return -ENOMEM; -+ -+ ivshm_dev->info.name = device_name; -+ ivshm_dev->info.version = "1"; -+ ivshm_dev->info.release = ivshm_release; -+ -+ err = pcim_iomap_regions(pdev, BIT(0), device_name); -+ if (err) -+ return err; -+ ivshm_dev->regs = pcim_iomap_table(pdev)[0]; -+ -+ mem = &ivshm_dev->info.mem[0]; -+ -+ mem->name = "registers"; -+ mem->addr = pci_resource_start(pdev, 0); -+ if (!mem->addr) -+ return -ENODEV; -+ mem->size = pci_resource_len(pdev, 0); -+ mem->memtype = UIO_MEM_PHYS; -+ -+ vendor_cap = pci_find_capability(pdev, PCI_CAP_ID_VNDR); -+ if (vendor_cap < 0) -+ return -ENODEV; -+ -+ if (pci_resource_len(pdev, 2) > 0) { -+ section_addr = pci_resource_start(pdev, 2); -+ } else { -+ cap_pos = vendor_cap + IVSHM_CFG_ADDRESS; -+ section_addr = get_config_qword(pdev, cap_pos); -+ } -+ -+ mem++; -+ mem->name = "state_table"; -+ mem->addr = section_addr; -+ cap_pos = vendor_cap + IVSHM_CFG_STATE_TAB_SZ; -+ pci_read_config_dword(pdev, cap_pos, &dword); -+ mem->size = dword; -+ mem->memtype = UIO_MEM_IOVA; -+ mem->readonly = true; -+ if (!devm_request_mem_region(&pdev->dev, mem->addr, mem->size, -+ device_name)) -+ return -EBUSY; -+ dev_info(&pdev->dev, "%s at %pa, size %pa\n", mem->name, &mem->addr, -+ &mem->size); -+ -+ cap_pos = vendor_cap + IVSHM_CFG_RW_SECTION_SZ; -+ rw_section_sz = get_config_qword(pdev, cap_pos); -+ if (rw_section_sz > 0) { -+ section_addr += mem->size; -+ -+ mem++; -+ mem->name = "rw_section"; -+ mem->addr = section_addr; -+ mem->size = rw_section_sz; -+ mem->memtype = UIO_MEM_IOVA; -+ if (!devm_request_mem_region(&pdev->dev, mem->addr, mem->size, -+ device_name)) -+ return -EBUSY; -+ dev_info(&pdev->dev, "%s at %pa, size %pa\n", mem->name, -+ &mem->addr, &mem->size); -+ } -+ -+ cap_pos = vendor_cap + IVSHM_CFG_OUTPUT_SECTION_SZ; -+ output_section_sz = get_config_qword(pdev, cap_pos); -+ if (output_section_sz > 0) { -+ section_addr += mem->size; -+ -+ mem++; -+ mem->name = "input_sections"; -+ mem->addr = section_addr; -+ mem->size = -+ readl(&ivshm_dev->regs->max_peers) * output_section_sz; -+ mem->memtype = UIO_MEM_IOVA; -+ mem->readonly = true; -+ if (!devm_request_mem_region(&pdev->dev, mem->addr, mem->size, -+ device_name)) -+ return -EBUSY; -+ dev_info(&pdev->dev, "%s at %pa, size %pa\n", mem->name, -+ &mem->addr, &mem->size); -+ -+ mem++; -+ mem->name = "output_section"; -+ mem->addr = section_addr + -+ readl(&ivshm_dev->regs->id) * output_section_sz; -+ mem->size = output_section_sz; -+ mem->memtype = UIO_MEM_IOVA; -+ dev_info(&pdev->dev, "%s at %pa, size %pa\n", mem->name, -+ &mem->addr, &mem->size); -+ } -+ -+ pci_write_config_byte(pdev, vendor_cap + IVSHM_CFG_PRIV_CNTL, -+ IVSHM_PRIV_CNTL_ONESHOT_INT); -+ -+ /* -+ * Grab all vectors although we can only coalesce them into a single -+ * notifier. This avoids missing any event. -+ */ -+ ivshm_dev->vectors = pci_msix_vec_count(pdev); -+ if (ivshm_dev->vectors < 0) -+ ivshm_dev->vectors = 1; -+ -+ err = pci_alloc_irq_vectors(pdev, ivshm_dev->vectors, -+ ivshm_dev->vectors, -+ PCI_IRQ_LEGACY | PCI_IRQ_MSIX); -+ if (err < 0) -+ return err; -+ -+ for (i = 0; i < ivshm_dev->vectors; i++) { -+ err = request_irq(pci_irq_vector(pdev, i), ivshm_irq_handler, -+ IRQF_SHARED, ivshm_dev->info.name, ivshm_dev); -+ if (err) -+ goto error; -+ } -+ -+ ivshm_dev->info.irq = UIO_IRQ_CUSTOM; -+ -+ err = uio_register_device(&pdev->dev, &ivshm_dev->info); -+ if (err) -+ goto error; -+ -+ pci_set_master(pdev); -+ -+ pci_set_drvdata(pdev, ivshm_dev); -+ -+ return 0; -+ -+error: -+ while (--i > 0) -+ free_irq(pci_irq_vector(pdev, i), ivshm_dev); -+ pci_free_irq_vectors(pdev); -+ return err; -+} -+ -+static void ivshm_remove(struct pci_dev *pdev) -+{ -+ struct ivshm_dev *ivshm_dev = pci_get_drvdata(pdev); -+ int i; -+ -+ writel(0, &ivshm_dev->regs->int_control); -+ pci_clear_master(pdev); -+ -+ uio_unregister_device(&ivshm_dev->info); -+ -+ for (i = 0; i < ivshm_dev->vectors; i++) -+ free_irq(pci_irq_vector(pdev, i), ivshm_dev); -+ -+ pci_free_irq_vectors(pdev); -+} -+ -+static const struct pci_device_id ivshm_device_id_table[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_IVSHMEM), -+ (PCI_CLASS_OTHERS << 16) | IVSHM_PROTO_UNDEFINED, 0xffffff }, -+ { 0 } -+}; -+MODULE_DEVICE_TABLE(pci, ivshm_device_id_table); -+ -+static struct pci_driver uio_ivshm_driver = { -+ .name = DRV_NAME, -+ .id_table = ivshm_device_id_table, -+ .probe = ivshm_probe, -+ .remove = ivshm_remove, -+}; -+module_pci_driver(uio_ivshm_driver); -+ -+MODULE_AUTHOR("Jan Kiszka <jan.kiszka@siemens.com>"); -+MODULE_LICENSE("GPL v2"); -diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h -index 21a572469a4e..e450458c8ba8 100644 ---- a/include/linux/pci_ids.h -+++ b/include/linux/pci_ids.h -@@ -1477,6 +1477,7 @@ - - #define PCI_VENDOR_ID_SIEMENS 0x110A - #define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102 -+#define PCI_DEVICE_ID_IVSHMEM 0x4106 - - #define PCI_VENDOR_ID_VORTEX 0x1119 - #define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000 --- -2.11.0 - |