aboutsummaryrefslogtreecommitdiffstats
path: root/meta-agl-jailhouse/recipes-kernel/linux/linux/0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch
diff options
context:
space:
mode:
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.patch311
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
-