summaryrefslogtreecommitdiffstats
path: root/meta-agl-jailhouse/recipes-kernel
diff options
context:
space:
mode:
Diffstat (limited to 'meta-agl-jailhouse/recipes-kernel')
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux-jailhouse-5.4.inc39
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux-yocto_5.4%.bbappend1
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0001-x86-jailhouse-Improve-setup-data-version-comparison.patch198
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0002-x86-jailhouse-Only-enable-platform-UARTs-if-availabl.patch200
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0003-jailhouse-Add-simple-debug-console-via-the-hyperviso.patch174
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0004-arm-Export-__boot_cpu_mode-for-use-in-Jailhouse-driv.patch43
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0005-mm-Re-export-ioremap_page_range.patch25
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0006-arm-arm64-export-__hyp_stub_vectors.patch57
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0007-x86-Export-lapic_timer_period.patch28
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0008-arm64-dts-marvell-armada-37xx-Set-pci-domain.patch31
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0009-arm64-dts-marvell-armada-8030-mcbin-Set-pci-domain.patch31
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0010-uio-Enable-read-only-mappings.patch57
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0011-ivshmem-Add-header-file.patch52
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch311
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0013-ivshmem-net-virtual-network-device-for-Jailhouse.patch968
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0014-ivshmem-net-Map-shmem-region-as-RAM.patch30
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0015-ivshmem-net-fix-race-in-state-machine.patch140
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0016-ivshmem-net-Remove-unused-variable.patch28
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0017-ivshmem-net-Enable-INTx.patch55
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0018-ivshmem-net-Improve-identification-of-resources.patch59
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0019-ivshmem-net-Switch-to-reset-state-on-each-net-stop-a.patch47
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0020-ivshmem-net-Add-ethtool-register-dump.patch61
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0021-ivshmem-net-Fix-stuck-state-machine-during-setup.patch30
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0022-ivshmem-net-Switch-to-relative-descriptor-addresses.patch49
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0023-ivshmem-net-Switch-to-pci_alloc_irq_vectors.patch146
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0024-ivshmem-net-fill-in-and-check-used-descriptor-chain-.patch70
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0025-ivshmem-net-slightly-improve-debug-output.patch29
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0026-ivshmem-net-set-and-check-descriptor-flags.patch43
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0027-ivshmem-net-add-MAC-changing-interface.patch41
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0028-ivshmem-net-Silence-compiler-warning.patch28
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0029-ivshmem-net-Fix-bogus-transition-to-RESET-state.patch31
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0030-ivshmem-net-Refactor-and-comment-ivshm_net_state_cha.patch68
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0031-ivshmem-net-Switch-to-netdev_xmit_more-helper.patch59
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/0032-ivshmem-net-Adjust-to-reworked-version-of-ivshmem-in.patch650
-rw-r--r--meta-agl-jailhouse/recipes-kernel/linux/linux/jailhouse.cfg10
35 files changed, 3889 insertions, 0 deletions
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux-jailhouse-5.4.inc b/meta-agl-jailhouse/recipes-kernel/linux/linux-jailhouse-5.4.inc
new file mode 100644
index 00000000..4b571ffd
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux-jailhouse-5.4.inc
@@ -0,0 +1,39 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/linux:"
+
+SRC_URI_append = " file://jailhouse.cfg"
+
+SRC_URI_append = " \
+file://0001-x86-jailhouse-Improve-setup-data-version-comparison.patch \
+file://0002-x86-jailhouse-Only-enable-platform-UARTs-if-availabl.patch \
+file://0003-jailhouse-Add-simple-debug-console-via-the-hyperviso.patch \
+file://0004-arm-Export-__boot_cpu_mode-for-use-in-Jailhouse-driv.patch \
+file://0005-mm-Re-export-ioremap_page_range.patch \
+file://0006-arm-arm64-export-__hyp_stub_vectors.patch \
+file://0007-x86-Export-lapic_timer_period.patch \
+file://0008-arm64-dts-marvell-armada-37xx-Set-pci-domain.patch \
+file://0009-arm64-dts-marvell-armada-8030-mcbin-Set-pci-domain.patch \
+file://0010-uio-Enable-read-only-mappings.patch \
+file://0011-ivshmem-Add-header-file.patch \
+file://0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch \
+file://0013-ivshmem-net-virtual-network-device-for-Jailhouse.patch \
+file://0014-ivshmem-net-Map-shmem-region-as-RAM.patch \
+file://0015-ivshmem-net-fix-race-in-state-machine.patch \
+file://0016-ivshmem-net-Remove-unused-variable.patch \
+file://0017-ivshmem-net-Enable-INTx.patch \
+file://0018-ivshmem-net-Improve-identification-of-resources.patch \
+file://0019-ivshmem-net-Switch-to-reset-state-on-each-net-stop-a.patch \
+file://0020-ivshmem-net-Add-ethtool-register-dump.patch \
+file://0021-ivshmem-net-Fix-stuck-state-machine-during-setup.patch \
+file://0022-ivshmem-net-Switch-to-relative-descriptor-addresses.patch \
+file://0023-ivshmem-net-Switch-to-pci_alloc_irq_vectors.patch \
+file://0024-ivshmem-net-fill-in-and-check-used-descriptor-chain-.patch \
+file://0025-ivshmem-net-slightly-improve-debug-output.patch \
+file://0026-ivshmem-net-set-and-check-descriptor-flags.patch \
+file://0027-ivshmem-net-add-MAC-changing-interface.patch \
+file://0028-ivshmem-net-Silence-compiler-warning.patch \
+file://0029-ivshmem-net-Fix-bogus-transition-to-RESET-state.patch \
+file://0030-ivshmem-net-Refactor-and-comment-ivshm_net_state_cha.patch \
+file://0031-ivshmem-net-Switch-to-netdev_xmit_more-helper.patch \
+file://0032-ivshmem-net-Adjust-to-reworked-version-of-ivshmem-in.patch \
+"
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux-yocto_5.4%.bbappend b/meta-agl-jailhouse/recipes-kernel/linux/linux-yocto_5.4%.bbappend
new file mode 100644
index 00000000..b13f1eb1
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux-yocto_5.4%.bbappend
@@ -0,0 +1 @@
+require recipes-kernel/linux/linux-jailhouse-5.4.inc
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0001-x86-jailhouse-Improve-setup-data-version-comparison.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0001-x86-jailhouse-Improve-setup-data-version-comparison.patch
new file mode 100644
index 00000000..6b5032df
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0001-x86-jailhouse-Improve-setup-data-version-comparison.patch
@@ -0,0 +1,198 @@
+From d47ad4c29f1cd34aff896a88b3dfc4a861a15a6a Mon Sep 17 00:00:00 2001
+From: Ralf Ramsauer <ralf.ramsauer@oth-regensburg.de>
+Date: Thu, 10 Oct 2019 12:21:01 +0200
+Subject: [PATCH 01/32] x86/jailhouse: Improve setup data version comparison
+
+Soon, setup_data will contain information on passed-through platform
+UARTs. This requires some preparational work for the sanity check of the
+header and the check of the version.
+
+Use the following strategy:
+
+ 1. Ensure that the header declares at least enough space for the
+ version and the compatible_version as it must hold that fields for
+ any version. The location and semantics of header+version fields
+ will never change.
+
+ 2. Copy over data -- as much as as possible. The length is either
+ limited by the header length or the length of setup_data.
+
+ 3. Things are now in place -- sanity check if the header length
+ complies the actual version.
+
+For future versions of the setup_data, only step 3 requires alignment.
+
+Signed-off-by: Ralf Ramsauer <ralf.ramsauer@oth-regensburg.de>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Reviewed-by: Jan Kiszka <jan.kiszka@siemens.com>
+Cc: Baoquan He <bhe@redhat.com>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: jailhouse-dev@googlegroups.com
+Cc: Juergen Gross <jgross@suse.com>
+Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: x86-ml <x86@kernel.org>
+Link: https://lkml.kernel.org/r/20191010102102.421035-2-ralf.ramsauer@oth-regensburg.de
+---
+ arch/x86/include/uapi/asm/bootparam.h | 22 ++++++++-------
+ arch/x86/kernel/jailhouse.c | 51 ++++++++++++++++++++++-------------
+ 2 files changed, 45 insertions(+), 28 deletions(-)
+
+diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
+index c895df5482c5..43be437c9c71 100644
+--- a/arch/x86/include/uapi/asm/bootparam.h
++++ b/arch/x86/include/uapi/asm/bootparam.h
+@@ -139,15 +139,19 @@ struct boot_e820_entry {
+ * setup data structure.
+ */
+ struct jailhouse_setup_data {
+- __u16 version;
+- __u16 compatible_version;
+- __u16 pm_timer_address;
+- __u16 num_cpus;
+- __u64 pci_mmconfig_base;
+- __u32 tsc_khz;
+- __u32 apic_khz;
+- __u8 standard_ioapic;
+- __u8 cpu_ids[255];
++ struct {
++ __u16 version;
++ __u16 compatible_version;
++ } __attribute__((packed)) hdr;
++ struct {
++ __u16 pm_timer_address;
++ __u16 num_cpus;
++ __u64 pci_mmconfig_base;
++ __u32 tsc_khz;
++ __u32 apic_khz;
++ __u8 standard_ioapic;
++ __u8 cpu_ids[255];
++ } __attribute__((packed)) v1;
+ } __attribute__((packed));
+
+ /* The so-called "zeropage" */
+diff --git a/arch/x86/kernel/jailhouse.c b/arch/x86/kernel/jailhouse.c
+index 3ad34f01de2a..cf4eb37ad97b 100644
+--- a/arch/x86/kernel/jailhouse.c
++++ b/arch/x86/kernel/jailhouse.c
+@@ -22,6 +22,8 @@
+ #include <asm/jailhouse_para.h>
+
+ static __initdata struct jailhouse_setup_data setup_data;
++#define SETUP_DATA_V1_LEN (sizeof(setup_data.hdr) + sizeof(setup_data.v1))
++
+ static unsigned int precalibrated_tsc_khz;
+
+ static uint32_t jailhouse_cpuid_base(void)
+@@ -45,7 +47,7 @@ static void jailhouse_get_wallclock(struct timespec64 *now)
+
+ static void __init jailhouse_timer_init(void)
+ {
+- lapic_timer_period = setup_data.apic_khz * (1000 / HZ);
++ lapic_timer_period = setup_data.v1.apic_khz * (1000 / HZ);
+ }
+
+ static unsigned long jailhouse_get_tsc(void)
+@@ -88,14 +90,14 @@ static void __init jailhouse_get_smp_config(unsigned int early)
+
+ register_lapic_address(0xfee00000);
+
+- for (cpu = 0; cpu < setup_data.num_cpus; cpu++) {
+- generic_processor_info(setup_data.cpu_ids[cpu],
++ for (cpu = 0; cpu < setup_data.v1.num_cpus; cpu++) {
++ generic_processor_info(setup_data.v1.cpu_ids[cpu],
+ boot_cpu_apic_version);
+ }
+
+ smp_found_config = 1;
+
+- if (setup_data.standard_ioapic) {
++ if (setup_data.v1.standard_ioapic) {
+ mp_register_ioapic(0, 0xfec00000, gsi_top, &ioapic_cfg);
+
+ /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
+@@ -126,9 +128,9 @@ static int __init jailhouse_pci_arch_init(void)
+ pcibios_last_bus = 0xff;
+
+ #ifdef CONFIG_PCI_MMCONFIG
+- if (setup_data.pci_mmconfig_base) {
++ if (setup_data.v1.pci_mmconfig_base) {
+ pci_mmconfig_add(0, 0, pcibios_last_bus,
+- setup_data.pci_mmconfig_base);
++ setup_data.v1.pci_mmconfig_base);
+ pci_mmcfg_arch_init();
+ }
+ #endif
+@@ -139,6 +141,7 @@ static int __init jailhouse_pci_arch_init(void)
+ static void __init jailhouse_init_platform(void)
+ {
+ u64 pa_data = boot_params.hdr.setup_data;
++ unsigned long setup_data_len;
+ struct setup_data header;
+ void *mapping;
+
+@@ -163,16 +166,8 @@ static void __init jailhouse_init_platform(void)
+ memcpy(&header, mapping, sizeof(header));
+ early_memunmap(mapping, sizeof(header));
+
+- if (header.type == SETUP_JAILHOUSE &&
+- header.len >= sizeof(setup_data)) {
+- pa_data += offsetof(struct setup_data, data);
+-
+- mapping = early_memremap(pa_data, sizeof(setup_data));
+- memcpy(&setup_data, mapping, sizeof(setup_data));
+- early_memunmap(mapping, sizeof(setup_data));
+-
++ if (header.type == SETUP_JAILHOUSE)
+ break;
+- }
+
+ pa_data = header.next;
+ }
+@@ -180,13 +175,27 @@ static void __init jailhouse_init_platform(void)
+ if (!pa_data)
+ panic("Jailhouse: No valid setup data found");
+
+- if (setup_data.compatible_version > JAILHOUSE_SETUP_REQUIRED_VERSION)
+- panic("Jailhouse: Unsupported setup data structure");
++ /* setup data must at least contain the header */
++ if (header.len < sizeof(setup_data.hdr))
++ goto unsupported;
+
+- pmtmr_ioport = setup_data.pm_timer_address;
++ pa_data += offsetof(struct setup_data, data);
++ setup_data_len = min_t(unsigned long, sizeof(setup_data),
++ (unsigned long)header.len);
++ mapping = early_memremap(pa_data, setup_data_len);
++ memcpy(&setup_data, mapping, setup_data_len);
++ early_memunmap(mapping, setup_data_len);
++
++ if (setup_data.hdr.version == 0 ||
++ setup_data.hdr.compatible_version !=
++ JAILHOUSE_SETUP_REQUIRED_VERSION ||
++ (setup_data.hdr.version >= 1 && header.len < SETUP_DATA_V1_LEN))
++ goto unsupported;
++
++ pmtmr_ioport = setup_data.v1.pm_timer_address;
+ pr_debug("Jailhouse: PM-Timer IO Port: %#x\n", pmtmr_ioport);
+
+- precalibrated_tsc_khz = setup_data.tsc_khz;
++ precalibrated_tsc_khz = setup_data.v1.tsc_khz;
+ setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+
+ pci_probe = 0;
+@@ -196,6 +205,10 @@ static void __init jailhouse_init_platform(void)
+ * are none in a non-root cell.
+ */
+ disable_acpi();
++ return;
++
++unsupported:
++ panic("Jailhouse: Unsupported setup data structure");
+ }
+
+ bool jailhouse_paravirt(void)
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0002-x86-jailhouse-Only-enable-platform-UARTs-if-availabl.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0002-x86-jailhouse-Only-enable-platform-UARTs-if-availabl.patch
new file mode 100644
index 00000000..d1db6c71
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0002-x86-jailhouse-Only-enable-platform-UARTs-if-availabl.patch
@@ -0,0 +1,200 @@
+From 7f87114a29351547ffb9bd16c4cafb37524806c6 Mon Sep 17 00:00:00 2001
+From: Ralf Ramsauer <ralf.ramsauer@oth-regensburg.de>
+Date: Thu, 10 Oct 2019 12:21:02 +0200
+Subject: [PATCH 02/32] x86/jailhouse: Only enable platform UARTs if available
+
+ACPI tables aren't available if Linux runs as guest of the hypervisor
+Jailhouse. This makes the 8250 driver probe for all platform UARTs as it
+assumes that all UARTs are present in case of !ACPI. Jailhouse will stop
+execution of Linux guest due to port access violation.
+
+So far, these access violations were solved by tuning the 8250.nr_uarts
+cmdline parameter, but this has limitations: Only consecutive platform
+UARTs can be mapped to Linux, and only in the sequence 0x3f8, 0x2f8,
+0x3e8, 0x2e8.
+
+Beginning from setup_data version 2, Jailhouse will place information of
+available platform UARTs in setup_data. This allows for selective
+activation of platform UARTs.
+
+Query setup_data version and only activate available UARTS. This
+patch comes with backward compatibility, and will still support older
+setup_data versions. In case of older setup_data versions, Linux falls
+back to the old behaviour.
+
+Signed-off-by: Ralf Ramsauer <ralf.ramsauer@oth-regensburg.de>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Reviewed-by: Jan Kiszka <jan.kiszka@siemens.com>
+Cc: Baoquan He <bhe@redhat.com>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: jailhouse-dev@googlegroups.com
+Cc: Juergen Gross <jgross@suse.com>
+Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: x86-ml <x86@kernel.org>
+Link: https://lkml.kernel.org/r/20191010102102.421035-3-ralf.ramsauer@oth-regensburg.de
+---
+ arch/x86/include/uapi/asm/bootparam.h | 3 ++
+ arch/x86/kernel/jailhouse.c | 85 +++++++++++++++++++++++++++++------
+ 2 files changed, 75 insertions(+), 13 deletions(-)
+
+diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
+index 43be437c9c71..db1e24e56e94 100644
+--- a/arch/x86/include/uapi/asm/bootparam.h
++++ b/arch/x86/include/uapi/asm/bootparam.h
+@@ -152,6 +152,9 @@ struct jailhouse_setup_data {
+ __u8 standard_ioapic;
+ __u8 cpu_ids[255];
+ } __attribute__((packed)) v1;
++ struct {
++ __u32 flags;
++ } __attribute__((packed)) v2;
+ } __attribute__((packed));
+
+ /* The so-called "zeropage" */
+diff --git a/arch/x86/kernel/jailhouse.c b/arch/x86/kernel/jailhouse.c
+index cf4eb37ad97b..6eb8b50ea07e 100644
+--- a/arch/x86/kernel/jailhouse.c
++++ b/arch/x86/kernel/jailhouse.c
+@@ -11,6 +11,7 @@
+ #include <linux/acpi_pmtmr.h>
+ #include <linux/kernel.h>
+ #include <linux/reboot.h>
++#include <linux/serial_8250.h>
+ #include <asm/apic.h>
+ #include <asm/cpu.h>
+ #include <asm/hypervisor.h>
+@@ -21,11 +22,24 @@
+ #include <asm/setup.h>
+ #include <asm/jailhouse_para.h>
+
+-static __initdata struct jailhouse_setup_data setup_data;
++static struct jailhouse_setup_data setup_data;
+ #define SETUP_DATA_V1_LEN (sizeof(setup_data.hdr) + sizeof(setup_data.v1))
++#define SETUP_DATA_V2_LEN (SETUP_DATA_V1_LEN + sizeof(setup_data.v2))
+
+ static unsigned int precalibrated_tsc_khz;
+
++static void jailhouse_setup_irq(unsigned int irq)
++{
++ struct mpc_intsrc mp_irq = {
++ .type = MP_INTSRC,
++ .irqtype = mp_INT,
++ .irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE,
++ .srcbusirq = irq,
++ .dstirq = irq,
++ };
++ mp_save_irq(&mp_irq);
++}
++
+ static uint32_t jailhouse_cpuid_base(void)
+ {
+ if (boot_cpu_data.cpuid_level < 0 ||
+@@ -79,11 +93,6 @@ static void __init jailhouse_get_smp_config(unsigned int early)
+ .type = IOAPIC_DOMAIN_STRICT,
+ .ops = &mp_ioapic_irqdomain_ops,
+ };
+- struct mpc_intsrc mp_irq = {
+- .type = MP_INTSRC,
+- .irqtype = mp_INT,
+- .irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE,
+- };
+ unsigned int cpu;
+
+ jailhouse_x2apic_init();
+@@ -100,12 +109,12 @@ static void __init jailhouse_get_smp_config(unsigned int early)
+ if (setup_data.v1.standard_ioapic) {
+ mp_register_ioapic(0, 0xfec00000, gsi_top, &ioapic_cfg);
+
+- /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
+- mp_irq.srcbusirq = mp_irq.dstirq = 3;
+- mp_save_irq(&mp_irq);
+-
+- mp_irq.srcbusirq = mp_irq.dstirq = 4;
+- mp_save_irq(&mp_irq);
++ if (IS_ENABLED(CONFIG_SERIAL_8250) &&
++ setup_data.hdr.version < 2) {
++ /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
++ jailhouse_setup_irq(3);
++ jailhouse_setup_irq(4);
++ }
+ }
+ }
+
+@@ -138,6 +147,53 @@ static int __init jailhouse_pci_arch_init(void)
+ return 0;
+ }
+
++#ifdef CONFIG_SERIAL_8250
++static inline bool jailhouse_uart_enabled(unsigned int uart_nr)
++{
++ return setup_data.v2.flags & BIT(uart_nr);
++}
++
++static void jailhouse_serial_fixup(int port, struct uart_port *up,
++ u32 *capabilities)
++{
++ static const u16 pcuart_base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
++ unsigned int n;
++
++ for (n = 0; n < ARRAY_SIZE(pcuart_base); n++) {
++ if (pcuart_base[n] != up->iobase)
++ continue;
++
++ if (jailhouse_uart_enabled(n)) {
++ pr_info("Enabling UART%u (port 0x%lx)\n", n,
++ up->iobase);
++ jailhouse_setup_irq(up->irq);
++ } else {
++ /* Deactivate UART if access isn't allowed */
++ up->iobase = 0;
++ }
++ break;
++ }
++}
++
++static void __init jailhouse_serial_workaround(void)
++{
++ /*
++ * There are flags inside setup_data that indicate availability of
++ * platform UARTs since setup data version 2.
++ *
++ * In case of version 1, we don't know which UARTs belong Linux. In
++ * this case, unconditionally register 1:1 mapping for legacy UART IRQs
++ * 3 and 4.
++ */
++ if (setup_data.hdr.version > 1)
++ serial8250_set_isa_configurator(jailhouse_serial_fixup);
++}
++#else /* !CONFIG_SERIAL_8250 */
++static inline void jailhouse_serial_workaround(void)
++{
++}
++#endif /* CONFIG_SERIAL_8250 */
++
+ static void __init jailhouse_init_platform(void)
+ {
+ u64 pa_data = boot_params.hdr.setup_data;
+@@ -189,7 +245,8 @@ static void __init jailhouse_init_platform(void)
+ if (setup_data.hdr.version == 0 ||
+ setup_data.hdr.compatible_version !=
+ JAILHOUSE_SETUP_REQUIRED_VERSION ||
+- (setup_data.hdr.version >= 1 && header.len < SETUP_DATA_V1_LEN))
++ (setup_data.hdr.version == 1 && header.len < SETUP_DATA_V1_LEN) ||
++ (setup_data.hdr.version >= 2 && header.len < SETUP_DATA_V2_LEN))
+ goto unsupported;
+
+ pmtmr_ioport = setup_data.v1.pm_timer_address;
+@@ -205,6 +262,8 @@ static void __init jailhouse_init_platform(void)
+ * are none in a non-root cell.
+ */
+ disable_acpi();
++
++ jailhouse_serial_workaround();
+ return;
+
+ unsupported:
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0003-jailhouse-Add-simple-debug-console-via-the-hyperviso.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0003-jailhouse-Add-simple-debug-console-via-the-hyperviso.patch
new file mode 100644
index 00000000..289f54ac
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0003-jailhouse-Add-simple-debug-console-via-the-hyperviso.patch
@@ -0,0 +1,174 @@
+From faa349f4d096554c6d5bfe74634599d2e26f64a7 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 11 Sep 2016 23:30:04 +0200
+Subject: [PATCH 03/32] jailhouse: Add simple debug console via the hypervisor
+
+Jailhouse allows explicitly enabled cells to write character-wise
+messages to the hypervisor debug console. Make use of this for a
+platform-agnostic boot diagnosis channel, specifically for non-root
+cells. This also comes with earlycon support.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ MAINTAINERS | 1 +
+ drivers/virt/Kconfig | 11 +++++
+ drivers/virt/Makefile | 1 +
+ drivers/virt/jailhouse_dbgcon.c | 103 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 116 insertions(+)
+ create mode 100644 drivers/virt/jailhouse_dbgcon.c
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 9d3a5c54a41d..07cb4d674c93 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -8761,6 +8761,7 @@ L: jailhouse-dev@googlegroups.com
+ S: Maintained
+ F: arch/x86/kernel/jailhouse.c
+ F: arch/x86/include/asm/jailhouse_para.h
++F: drivers/virt/jailhouse_dbgcon.c
+
+ JC42.4 TEMPERATURE SENSOR DRIVER
+ M: Guenter Roeck <linux@roeck-us.net>
+diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
+index 363af2eaf2ba..99c5eaca6952 100644
+--- a/drivers/virt/Kconfig
++++ b/drivers/virt/Kconfig
+@@ -31,5 +31,16 @@ config FSL_HV_MANAGER
+ 4) A kernel interface for receiving callbacks when a managed
+ partition shuts down.
+
++config JAILHOUSE_DBGCON
++ tristate "Jailhouse console driver"
++ depends on X86 || ARM || ARM64
++ help
++ The Jailhouse hypervisor provides a simple write-only console for
++ debugging the bootstrap process of its cells. This driver registers
++ a console with the kernel to make use of it.
++
++ Note that Jailhouse has to be configured to permit a cell the usage
++ of the console interface.
++
+ source "drivers/virt/vboxguest/Kconfig"
+ endif
+diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
+index fd331247c27a..89e86a1d0f19 100644
+--- a/drivers/virt/Makefile
++++ b/drivers/virt/Makefile
+@@ -4,4 +4,5 @@
+ #
+
+ obj-$(CONFIG_FSL_HV_MANAGER) += fsl_hypervisor.o
++obj-$(CONFIG_JAILHOUSE_DBGCON) += jailhouse_dbgcon.o
+ obj-y += vboxguest/
+diff --git a/drivers/virt/jailhouse_dbgcon.c b/drivers/virt/jailhouse_dbgcon.c
+new file mode 100644
+index 000000000000..1fd201ea1460
+--- /dev/null
++++ b/drivers/virt/jailhouse_dbgcon.c
+@@ -0,0 +1,103 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Console driver for running over the Jailhouse partitioning hypervisor
++ *
++ * Copyright (c) Siemens AG, 2016-2018
++ *
++ * Authors:
++ * Jan Kiszka <jan.kiszka@siemens.com>
++ */
++
++#include <linux/console.h>
++#include <linux/hypervisor.h>
++#include <linux/module.h>
++#include <linux/serial_core.h>
++#ifdef CONFIG_X86
++#include <asm/alternative.h>
++#endif
++#ifdef CONFIG_ARM
++#include <asm/opcodes-virt.h>
++#endif
++
++#define JAILHOUSE_HC_DEBUG_CONSOLE_PUTC 8
++
++static void hypervisor_putc(char c)
++{
++#if defined(CONFIG_X86)
++ int result;
++
++ asm volatile(
++ ALTERNATIVE(".byte 0x0f,0x01,0xc1", ".byte 0x0f,0x01,0xd9",
++ X86_FEATURE_VMMCALL)
++ : "=a" (result)
++ : "a" (JAILHOUSE_HC_DEBUG_CONSOLE_PUTC), "D" (c)
++ : "memory");
++#elif defined(CONFIG_ARM)
++ register u32 num_res asm("r0") = JAILHOUSE_HC_DEBUG_CONSOLE_PUTC;
++ register u32 arg1 asm("r1") = c;
++
++ asm volatile(
++ __HVC(0x4a48)
++ : "=r" (num_res)
++ : "r" (num_res), "r" (arg1)
++ : "memory");
++#elif defined(CONFIG_ARM64)
++ register u64 num_res asm("x0") = JAILHOUSE_HC_DEBUG_CONSOLE_PUTC;
++ register u64 arg1 asm("x1") = c;
++
++ asm volatile(
++ "hvc #0x4a48\n\t"
++ : "=r" (num_res)
++ : "r" (num_res), "r" (arg1)
++ : "memory");
++#else
++#error Unsupported architecture.
++#endif
++}
++
++static void jailhouse_dbgcon_write(struct console *con, const char *s,
++ unsigned count)
++{
++ while (count > 0) {
++ hypervisor_putc(*s);
++ count--;
++ s++;
++ }
++}
++
++static int __init early_jailhouse_dbgcon_setup(struct earlycon_device *device,
++ const char *options)
++{
++ device->con->write = jailhouse_dbgcon_write;
++ return 0;
++}
++
++EARLYCON_DECLARE(jailhouse, early_jailhouse_dbgcon_setup);
++
++static struct console jailhouse_dbgcon = {
++ .name = "jailhouse",
++ .write = jailhouse_dbgcon_write,
++ .flags = CON_PRINTBUFFER | CON_ANYTIME,
++ .index = -1,
++};
++
++static int __init jailhouse_dbgcon_init(void)
++{
++ if (!jailhouse_paravirt())
++ return -ENODEV;
++
++ register_console(&jailhouse_dbgcon);
++ return 0;
++}
++
++static void __exit jailhouse_dbgcon_exit(void)
++{
++ unregister_console(&jailhouse_dbgcon);
++}
++
++module_init(jailhouse_dbgcon_init);
++module_exit(jailhouse_dbgcon_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Jailhouse debug console driver");
++MODULE_AUTHOR("Jan Kiszka <jan.kiszka@siemens.com>");
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0004-arm-Export-__boot_cpu_mode-for-use-in-Jailhouse-driv.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0004-arm-Export-__boot_cpu_mode-for-use-in-Jailhouse-driv.patch
new file mode 100644
index 00000000..6e4470f0
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0004-arm-Export-__boot_cpu_mode-for-use-in-Jailhouse-driv.patch
@@ -0,0 +1,43 @@
+From 56e5aace5a675af0557b87a137b98e40454d8e22 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 3 Jul 2016 10:02:40 +0200
+Subject: [PATCH 04/32] arm: Export __boot_cpu_mode for use in Jailhouse driver
+ module
+
+Onlining a CPU while Jailhouse was running sets BOOT_CPU_MODE_MISMATCH
+because the kernel detect that the CPU will now only come up in SVC
+mode. Therefore, we need to fix up the flag after disabling Jailhouse
+again.
+
+Moreover, exporting the symbol allows to use is_hyp_mode_available() in
+the driver, thus prevents us from crashing during Jailhouse activation
+when there is no hyp stub installed.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ arch/arm/kernel/armksyms.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
+index 98bdea51089d..f2fa635bccf7 100644
+--- a/arch/arm/kernel/armksyms.c
++++ b/arch/arm/kernel/armksyms.c
+@@ -17,6 +17,7 @@
+
+ #include <asm/checksum.h>
+ #include <asm/ftrace.h>
++#include <asm/virt.h>
+
+ /*
+ * libgcc functions - functions that are used internally by the
+@@ -176,3 +177,7 @@ EXPORT_SYMBOL(__pv_offset);
+ EXPORT_SYMBOL(__arm_smccc_smc);
+ EXPORT_SYMBOL(__arm_smccc_hvc);
+ #endif
++
++#ifdef CONFIG_ARM_VIRT_EXT
++EXPORT_SYMBOL_GPL(__boot_cpu_mode);
++#endif
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0005-mm-Re-export-ioremap_page_range.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0005-mm-Re-export-ioremap_page_range.patch
new file mode 100644
index 00000000..e6bf1c35
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0005-mm-Re-export-ioremap_page_range.patch
@@ -0,0 +1,25 @@
+From cf5d27beb6aad2b69d716b0aee08f43619c338a9 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 7 Feb 2017 17:52:00 +0100
+Subject: [PATCH 05/32] mm: Re-export ioremap_page_range
+
+We need this in Jailhouse to map at specific virtual addresses, at
+least for the moment.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ lib/ioremap.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/lib/ioremap.c b/lib/ioremap.c
+index 0a2ffadc6d71..baefdda8f32c 100644
+--- a/lib/ioremap.c
++++ b/lib/ioremap.c
+@@ -231,3 +231,4 @@ int ioremap_page_range(unsigned long addr,
+
+ return err;
+ }
++EXPORT_SYMBOL_GPL(ioremap_page_range);
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0006-arm-arm64-export-__hyp_stub_vectors.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0006-arm-arm64-export-__hyp_stub_vectors.patch
new file mode 100644
index 00000000..42f3ea48
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0006-arm-arm64-export-__hyp_stub_vectors.patch
@@ -0,0 +1,57 @@
+From 27588702a6792ff86a57317ef60d6e218796598e Mon Sep 17 00:00:00 2001
+From: Ralf Ramsauer <ralf.ramsauer@oth-regensburg.de>
+Date: Wed, 7 Jun 2017 15:48:43 +0200
+Subject: [PATCH 06/32] arm, arm64: export __hyp_stub_vectors
+
+HVC_GET_VECTORS got removed. External hypervisors, like Jailhouse, need
+this address when they are deactivated, in order to restore original
+state.
+
+Signed-off-by: Ralf Ramsauer <ralf.ramsauer@oth-regensburg.de>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ arch/arm/kernel/hyp-stub.S | 2 ++
+ arch/arm64/kernel/hyp-stub.S | 2 ++
+ 2 files changed, 4 insertions(+)
+
+diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S
+index ae5020302de4..463366ccd2c9 100644
+--- a/arch/arm/kernel/hyp-stub.S
++++ b/arch/arm/kernel/hyp-stub.S
+@@ -6,6 +6,7 @@
+ #include <linux/init.h>
+ #include <linux/irqchip/arm-gic-v3.h>
+ #include <linux/linkage.h>
++#include <asm-generic/export.h>
+ #include <asm/assembler.h>
+ #include <asm/virt.h>
+
+@@ -269,4 +270,5 @@ __hyp_stub_trap: W(b) __hyp_stub_do_trap
+ __hyp_stub_irq: W(b) .
+ __hyp_stub_fiq: W(b) .
+ ENDPROC(__hyp_stub_vectors)
++EXPORT_SYMBOL_GPL(__hyp_stub_vectors)
+
+diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
+index 73d46070b315..ef2503bba71d 100644
+--- a/arch/arm64/kernel/hyp-stub.S
++++ b/arch/arm64/kernel/hyp-stub.S
+@@ -10,6 +10,7 @@
+ #include <linux/linkage.h>
+ #include <linux/irqchip/arm-gic-v3.h>
+
++#include <asm-generic/export.h>
+ #include <asm/assembler.h>
+ #include <asm/kvm_arm.h>
+ #include <asm/kvm_asm.h>
+@@ -42,6 +43,7 @@ ENTRY(__hyp_stub_vectors)
+ ventry el1_fiq_invalid // FIQ 32-bit EL1
+ ventry el1_error_invalid // Error 32-bit EL1
+ ENDPROC(__hyp_stub_vectors)
++EXPORT_SYMBOL_GPL(__hyp_stub_vectors)
+
+ .align 11
+
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0007-x86-Export-lapic_timer_period.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0007-x86-Export-lapic_timer_period.patch
new file mode 100644
index 00000000..9b2a2f2c
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0007-x86-Export-lapic_timer_period.patch
@@ -0,0 +1,28 @@
+From 3f87075ce9d3e04e8e43de2e88dd7728b3777eb8 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 23 Nov 2017 07:12:57 +0100
+Subject: [PATCH 07/32] x86: Export lapic_timer_period
+
+Required for the Jailhouse driver in order to forward the calibration
+value to other cells.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ arch/x86/kernel/apic/apic.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
+index 2b0faf86da1b..0428ad289899 100644
+--- a/arch/x86/kernel/apic/apic.c
++++ b/arch/x86/kernel/apic/apic.c
+@@ -196,6 +196,7 @@ static struct resource lapic_resource = {
+ };
+
+ unsigned int lapic_timer_period = 0;
++EXPORT_SYMBOL_GPL(lapic_timer_period);
+
+ static void apic_pm_activate(void);
+
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0008-arm64-dts-marvell-armada-37xx-Set-pci-domain.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0008-arm64-dts-marvell-armada-37xx-Set-pci-domain.patch
new file mode 100644
index 00000000..963989cf
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0008-arm64-dts-marvell-armada-37xx-Set-pci-domain.patch
@@ -0,0 +1,31 @@
+From 764a3a5da899b596474edf916b44dfc034443445 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Mon, 17 Sep 2018 08:08:08 +0200
+Subject: [PATCH 08/32] arm64: dts: marvell: armada-37xx: Set pci-domain
+
+This is a nop for normal operation but allows the device tree overlay
+that the Jailhouse hypervisor injects to use pci-domain as well
+(linux,pci-domain has to be applied consistently in a system). That will
+assign a stable PCI domain to the secondary, virtual host controller of
+Jailhouse.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+index 000c135e39b7..d839cea9d361 100644
+--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+@@ -482,6 +482,7 @@
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x00 0xff>;
++ linux,pci-domain = <0>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ #interrupt-cells = <1>;
+ msi-parent = <&pcie0>;
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0009-arm64-dts-marvell-armada-8030-mcbin-Set-pci-domain.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0009-arm64-dts-marvell-armada-8030-mcbin-Set-pci-domain.patch
new file mode 100644
index 00000000..8e99fa12
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0009-arm64-dts-marvell-armada-8030-mcbin-Set-pci-domain.patch
@@ -0,0 +1,31 @@
+From 1f916502347d2b902002b430cffe18b11685f211 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 30 Sep 2018 21:22:32 +0200
+Subject: [PATCH 09/32] arm64: dts: marvell: armada-8030-mcbin: Set pci-domain
+
+This is a nop for normal operation but allows the device tree overlay
+that the Jailhouse hypervisor injects to use pci-domain as well
+(linux,pci-domain has to be applied consistently in a system). That will
+assign a stable PCI domain to the secondary, virtual host controller of
+Jailhouse.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi
+index d250f4b2bfed..58bac50b06eb 100644
+--- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi
++++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi
+@@ -174,6 +174,7 @@
+ };
+
+ &cp0_pcie0 {
++ linux,pci-domain = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cp0_pcie_pins>;
+ num-lanes = <4>;
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0010-uio-Enable-read-only-mappings.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0010-uio-Enable-read-only-mappings.patch
new file mode 100644
index 00000000..2fa65641
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0010-uio-Enable-read-only-mappings.patch
@@ -0,0 +1,57 @@
+From 9c8885c6e020451e4a4578be9db318e5c07227ea Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 4 Jun 2019 14:40:09 +0200
+Subject: [PATCH 10/32] uio: Enable read-only mappings
+
+This allows to tag memory regions read-only, denying userspace to map
+them writable. Default remains read/write.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/uio/uio.c | 9 +++++++++
+ include/linux/uio_driver.h | 2 ++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
+index a57698985f9c..ac18542ee4fe 100644
+--- a/drivers/uio/uio.c
++++ b/drivers/uio/uio.c
+@@ -790,6 +790,15 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
+ goto out;
+ }
+
++ if (idev->info->mem[mi].readonly) {
++ if (vma->vm_flags & VM_WRITE) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ vma->vm_flags &= ~VM_MAYWRITE;
++ }
++
+ if (idev->info->mmap) {
+ ret = idev->info->mmap(idev->info, vma);
+ goto out;
+diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
+index 01081c4726c0..ebfc06e36ca2 100644
+--- a/include/linux/uio_driver.h
++++ b/include/linux/uio_driver.h
+@@ -31,6 +31,7 @@ struct uio_map;
+ * @offs: offset of device memory within the page
+ * @size: size of IO (multiple of page size)
+ * @memtype: type of memory addr points to
++ * @readonly: true of region is read-only
+ * @internal_addr: ioremap-ped version of addr, for driver internal use
+ * @map: for use by the UIO core only.
+ */
+@@ -40,6 +41,7 @@ struct uio_mem {
+ unsigned long offs;
+ resource_size_t size;
+ int memtype;
++ bool readonly;
+ void __iomem *internal_addr;
+ struct uio_map *map;
+ };
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0011-ivshmem-Add-header-file.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0011-ivshmem-Add-header-file.patch
new file mode 100644
index 00000000..f143d150
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0011-ivshmem-Add-header-file.patch
@@ -0,0 +1,52 @@
+From 61d003be018fb5b874e6ffbf746684c53556c00e Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 1 Oct 2019 12:33:25 +0200
+Subject: [PATCH 11/32] ivshmem: Add header file
+
+Common defines and structures for the ivshmem device.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ include/linux/ivshmem.h | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+ create mode 100644 include/linux/ivshmem.h
+
+diff --git a/include/linux/ivshmem.h b/include/linux/ivshmem.h
+new file mode 100644
+index 000000000000..bad8547f071b
+--- /dev/null
++++ b/include/linux/ivshmem.h
+@@ -0,0 +1,30 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++#ifndef _LINUX_IVSHMEM_H
++#define _LINUX_IVSHMEM_H
++
++#include <linux/types.h>
++
++#define IVSHM_PROTO_UNDEFINED 0x0000
++#define IVSHM_PROTO_NET 0x0001
++#define IVSHM_PROTO_VIRTIO_FRONT 0x8000
++#define IVSHM_PROTO_VIRTIO_BACK 0xc000
++#define IVSHM_PROTO_VIRTIO_DEVID_MASK 0x7fff
++
++#define IVSHM_CFG_PRIV_CNTL 0x03
++# define IVSHM_PRIV_CNTL_ONESHOT_INT BIT(0)
++#define IVSHM_CFG_STATE_TAB_SZ 0x04
++#define IVSHM_CFG_RW_SECTION_SZ 0x08
++#define IVSHM_CFG_OUTPUT_SECTION_SZ 0x10
++#define IVSHM_CFG_ADDRESS 0x18
++
++struct ivshm_regs {
++ u32 id;
++ u32 max_peers;
++ u32 int_control;
++ u32 doorbell;
++ u32 state;
++};
++
++#define IVSHM_INT_ENABLE BIT(0)
++
++#endif /* _LINUX_IVSHMEM_H */
+--
+2.11.0
+
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
new file mode 100644
index 00000000..f98670c3
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0012-uio-Add-driver-for-inter-VM-shared-memory-device.patch
@@ -0,0 +1,311 @@
+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
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0013-ivshmem-net-virtual-network-device-for-Jailhouse.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0013-ivshmem-net-virtual-network-device-for-Jailhouse.patch
new file mode 100644
index 00000000..ae5ac475
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0013-ivshmem-net-virtual-network-device-for-Jailhouse.patch
@@ -0,0 +1,968 @@
+From fa0e2362149bb814d6b7431a7c42989d33002f60 Mon Sep 17 00:00:00 2001
+From: Mans Rullgard <mans@mansr.com>
+Date: Thu, 26 May 2016 16:04:02 +0100
+Subject: [PATCH 13/32] ivshmem-net: virtual network device for Jailhouse
+
+Work in progress.
+---
+ drivers/net/Kconfig | 4 +
+ drivers/net/Makefile | 2 +
+ drivers/net/ivshmem-net.c | 923 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 929 insertions(+)
+ create mode 100644 drivers/net/ivshmem-net.c
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index df1c7989e13d..8c65f55163e3 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -527,4 +527,8 @@ config NET_FAILOVER
+ a VM with direct attached VF by failing over to the paravirtual
+ datapath when the VF is unplugged.
+
++config IVSHMEM_NET
++ tristate "IVSHMEM virtual network device"
++ depends on PCI
++
+ endif # NETDEVICES
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index 0d3ba056cda3..5041c293d4d0 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -79,3 +79,5 @@ thunderbolt-net-y += thunderbolt.o
+ obj-$(CONFIG_THUNDERBOLT_NET) += thunderbolt-net.o
+ obj-$(CONFIG_NETDEVSIM) += netdevsim/
+ obj-$(CONFIG_NET_FAILOVER) += net_failover.o
++
++obj-$(CONFIG_IVSHMEM_NET) += ivshmem-net.o
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+new file mode 100644
+index 000000000000..b676bed2cc2e
+--- /dev/null
++++ b/drivers/net/ivshmem-net.c
+@@ -0,0 +1,923 @@
++/*
++ * Copyright 2016 Mans Rullgard <mans@mansr.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <linux/bitops.h>
++#include <linux/interrupt.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/virtio_ring.h>
++
++#define DRV_NAME "ivshmem-net"
++
++#define JAILHOUSE_CFG_SHMEM_PTR 0x40
++#define JAILHOUSE_CFG_SHMEM_SZ 0x48
++
++#define IVSHM_NET_STATE_RESET 0
++#define IVSHM_NET_STATE_INIT 1
++#define IVSHM_NET_STATE_READY 2
++#define IVSHM_NET_STATE_RUN 3
++
++#define IVSHM_NET_MTU_MIN 256
++#define IVSHM_NET_MTU_MAX 65535
++#define IVSHM_NET_MTU_DEF 16384
++
++#define IVSHM_NET_FRAME_SIZE(s) ALIGN(18 + (s), SMP_CACHE_BYTES)
++
++#define IVSHM_NET_VQ_ALIGN 64
++
++struct ivshmem_regs {
++ u32 imask;
++ u32 istat;
++ u32 ivpos;
++ u32 doorbell;
++ u32 lstate;
++ u32 rstate;
++};
++
++struct ivshm_net_queue {
++ struct vring vr;
++ u32 free_head;
++ u32 num_free;
++ u32 num_added;
++ u16 last_avail_idx;
++ u16 last_used_idx;
++
++ void *data;
++ void *end;
++ u32 size;
++ u32 head;
++ u32 tail;
++};
++
++struct ivshm_net_stats {
++ u32 interrupts;
++ u32 tx_packets;
++ u32 tx_notify;
++ u32 tx_pause;
++ u32 rx_packets;
++ u32 rx_notify;
++ u32 napi_poll;
++ u32 napi_complete;
++ u32 napi_poll_n[10];
++};
++
++struct ivshm_net {
++ struct ivshm_net_queue rx;
++ struct ivshm_net_queue tx;
++
++ u32 vrsize;
++ u32 qlen;
++ u32 qsize;
++
++ spinlock_t tx_free_lock;
++ spinlock_t tx_clean_lock;
++
++ struct napi_struct napi;
++
++ u32 lstate;
++ u32 rstate;
++
++ struct workqueue_struct *state_wq;
++ struct work_struct state_work;
++
++ struct ivshm_net_stats stats;
++
++ struct ivshmem_regs __iomem *ivshm_regs;
++ void *shm;
++ phys_addr_t shmaddr;
++ resource_size_t shmlen;
++ u32 peer_id;
++
++ struct pci_dev *pdev;
++ struct msix_entry msix;
++ bool using_msix;
++};
++
++static void *ivshm_net_desc_data(struct ivshm_net *in,
++ struct ivshm_net_queue *q,
++ struct vring_desc *desc,
++ u32 *len)
++{
++ u64 addr = READ_ONCE(desc->addr);
++ u32 dlen = READ_ONCE(desc->len);
++ void *data;
++
++ if (addr < in->shmaddr || desc->addr > in->shmaddr + in->shmlen)
++ return NULL;
++
++ data = in->shm + (addr - in->shmaddr);
++
++ if (data < q->data || data >= q->end)
++ return NULL;
++
++ if (dlen > q->end - data)
++ return NULL;
++
++ *len = dlen;
++
++ return data;
++}
++
++static void ivshm_net_init_queue(struct ivshm_net *in,
++ struct ivshm_net_queue *q,
++ void *mem, unsigned int len)
++{
++ memset(q, 0, sizeof(*q));
++
++ vring_init(&q->vr, len, mem, IVSHM_NET_VQ_ALIGN);
++ q->data = mem + in->vrsize;
++ q->end = q->data + in->qsize;
++ q->size = in->qsize;
++}
++
++static void ivshm_net_init_queues(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ int ivpos = readl(&in->ivshm_regs->ivpos);
++ void *tx;
++ void *rx;
++ int i;
++
++ tx = in->shm + ivpos * in->shmlen / 2;
++ rx = in->shm + !ivpos * in->shmlen / 2;
++
++ memset(tx, 0, in->shmlen / 2);
++
++ ivshm_net_init_queue(in, &in->rx, rx, in->qlen);
++ ivshm_net_init_queue(in, &in->tx, tx, in->qlen);
++
++ swap(in->rx.vr.used, in->tx.vr.used);
++
++ in->tx.num_free = in->tx.vr.num;
++
++ for (i = 0; i < in->tx.vr.num - 1; i++)
++ in->tx.vr.desc[i].next = i + 1;
++}
++
++static int ivshm_net_calc_qsize(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ unsigned int vrsize;
++ unsigned int qsize;
++ unsigned int qlen;
++
++ for (qlen = 4096; qlen > 32; qlen >>= 1) {
++ vrsize = vring_size(qlen, IVSHM_NET_VQ_ALIGN);
++ vrsize = ALIGN(vrsize, IVSHM_NET_VQ_ALIGN);
++ if (vrsize < in->shmlen / 16)
++ break;
++ }
++
++ if (vrsize > in->shmlen / 2)
++ return -EINVAL;
++
++ qsize = in->shmlen / 2 - vrsize;
++
++ if (qsize < 4 * IVSHM_NET_MTU_MIN)
++ return -EINVAL;
++
++ in->vrsize = vrsize;
++ in->qlen = qlen;
++ in->qsize = qsize;
++
++ return 0;
++}
++
++static void ivshm_net_notify_tx(struct ivshm_net *in, unsigned int num)
++{
++ u16 evt, old, new;
++
++ virt_mb();
++
++ evt = READ_ONCE(vring_avail_event(&in->tx.vr));
++ old = in->tx.last_avail_idx - num;
++ new = in->tx.last_avail_idx;
++
++ if (vring_need_event(evt, new, old)) {
++ writel(in->peer_id << 16, &in->ivshm_regs->doorbell);
++ in->stats.tx_notify++;
++ }
++}
++
++static void ivshm_net_enable_rx_irq(struct ivshm_net *in)
++{
++ vring_avail_event(&in->rx.vr) = in->rx.last_avail_idx;
++ virt_wmb();
++}
++
++static void ivshm_net_notify_rx(struct ivshm_net *in, unsigned int num)
++{
++ u16 evt, old, new;
++
++ virt_mb();
++
++ evt = vring_used_event(&in->rx.vr);
++ old = in->rx.last_used_idx - num;
++ new = in->rx.last_used_idx;
++
++ if (vring_need_event(evt, new, old)) {
++ writel(in->peer_id << 16, &in->ivshm_regs->doorbell);
++ in->stats.rx_notify++;
++ }
++}
++
++static void ivshm_net_enable_tx_irq(struct ivshm_net *in)
++{
++ vring_used_event(&in->tx.vr) = in->tx.last_used_idx;
++ virt_wmb();
++}
++
++static bool ivshm_net_rx_avail(struct ivshm_net *in)
++{
++ virt_mb();
++ return READ_ONCE(in->rx.vr.avail->idx) != in->rx.last_avail_idx;
++}
++
++static size_t ivshm_net_tx_space(struct ivshm_net *in)
++{
++ struct ivshm_net_queue *tx = &in->tx;
++ u32 tail = tx->tail;
++ u32 head = tx->head;
++ u32 space;
++
++ if (head < tail)
++ space = tail - head;
++ else
++ space = max(tx->size - head, tail);
++
++ return space;
++}
++
++static bool ivshm_net_tx_ok(struct ivshm_net *in, unsigned int mtu)
++{
++ return in->tx.num_free >= 2 &&
++ ivshm_net_tx_space(in) >= 2 * IVSHM_NET_FRAME_SIZE(mtu);
++}
++
++static u32 ivshm_net_tx_advance(struct ivshm_net_queue *q, u32 *pos, u32 len)
++{
++ u32 p = *pos;
++
++ len = IVSHM_NET_FRAME_SIZE(len);
++
++ if (q->size - p < len)
++ p = 0;
++ *pos = p + len;
++
++ return p;
++}
++
++static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ struct ivshm_net_queue *tx = &in->tx;
++ struct vring *vr = &tx->vr;
++ struct vring_desc *desc;
++ unsigned int desc_idx;
++ unsigned int avail;
++ u32 head;
++ void *buf;
++
++ BUG_ON(tx->num_free < 1);
++
++ spin_lock(&in->tx_free_lock);
++ desc_idx = tx->free_head;
++ desc = &vr->desc[desc_idx];
++ tx->free_head = desc->next;
++ tx->num_free--;
++ spin_unlock(&in->tx_free_lock);
++
++ head = ivshm_net_tx_advance(tx, &tx->head, skb->len);
++
++ buf = tx->data + head;
++ skb_copy_and_csum_dev(skb, buf);
++
++ desc->addr = in->shmaddr + (buf - in->shm);
++ desc->len = skb->len;
++
++ avail = tx->last_avail_idx++ & (vr->num - 1);
++ vr->avail->ring[avail] = desc_idx;
++ tx->num_added++;
++
++ if (!skb->xmit_more) {
++ virt_store_release(&vr->avail->idx, tx->last_avail_idx);
++ ivshm_net_notify_tx(in, tx->num_added);
++ tx->num_added = 0;
++ }
++
++ return 0;
++}
++
++static void ivshm_net_tx_clean(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ struct ivshm_net_queue *tx = &in->tx;
++ struct vring *vr = &tx->vr;
++ struct vring_desc *desc;
++ struct vring_desc *fdesc;
++ unsigned int used;
++ unsigned int num;
++ u16 used_idx;
++ u16 last;
++ u32 fhead;
++
++ if (!spin_trylock(&in->tx_clean_lock))
++ return;
++
++ used_idx = virt_load_acquire(&vr->used->idx);
++ last = tx->last_used_idx;
++
++ fdesc = NULL;
++ num = 0;
++
++ while (last != used_idx) {
++ void *data;
++ u32 len;
++ u32 tail;
++
++ used = vr->used->ring[last & (vr->num - 1)].id;
++ if (used >= vr->num) {
++ netdev_err(ndev, "invalid tx used %d\n", used);
++ break;
++ }
++
++ desc = &vr->desc[used];
++
++ data = ivshm_net_desc_data(in, &in->tx, desc, &len);
++ if (!data) {
++ netdev_err(ndev, "bad tx descriptor\n");
++ break;
++ }
++
++ tail = ivshm_net_tx_advance(tx, &tx->tail, len);
++ if (data != tx->data + tail) {
++ netdev_err(ndev, "bad tx descriptor\n");
++ break;
++ }
++
++ if (!num)
++ fdesc = desc;
++ else
++ desc->next = fhead;
++
++ fhead = used;
++ last++;
++ num++;
++ }
++
++ tx->last_used_idx = last;
++
++ spin_unlock(&in->tx_clean_lock);
++
++ if (num) {
++ spin_lock(&in->tx_free_lock);
++ fdesc->next = tx->free_head;
++ tx->free_head = fhead;
++ tx->num_free += num;
++ BUG_ON(tx->num_free > vr->num);
++ spin_unlock(&in->tx_free_lock);
++ }
++}
++
++static struct vring_desc *ivshm_net_rx_desc(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ struct ivshm_net_queue *rx = &in->rx;
++ struct vring *vr = &rx->vr;
++ unsigned int avail;
++ u16 avail_idx;
++
++ avail_idx = virt_load_acquire(&vr->avail->idx);
++
++ if (avail_idx == rx->last_avail_idx)
++ return NULL;
++
++ avail = vr->avail->ring[rx->last_avail_idx++ & (vr->num - 1)];
++ if (avail >= vr->num) {
++ netdev_err(ndev, "invalid rx avail %d\n", avail);
++ return NULL;
++ }
++
++ return &vr->desc[avail];
++}
++
++static void ivshm_net_rx_finish(struct ivshm_net *in, struct vring_desc *desc)
++{
++ struct ivshm_net_queue *rx = &in->rx;
++ struct vring *vr = &rx->vr;
++ unsigned int desc_id = desc - vr->desc;
++ unsigned int used;
++
++ used = rx->last_used_idx++ & (vr->num - 1);
++ vr->used->ring[used].id = desc_id;
++
++ virt_store_release(&vr->used->idx, rx->last_used_idx);
++}
++
++static int ivshm_net_poll(struct napi_struct *napi, int budget)
++{
++ struct net_device *ndev = napi->dev;
++ struct ivshm_net *in = container_of(napi, struct ivshm_net, napi);
++ int received = 0;
++
++ in->stats.napi_poll++;
++
++ ivshm_net_tx_clean(ndev);
++
++ while (received < budget) {
++ struct vring_desc *desc;
++ struct sk_buff *skb;
++ void *data;
++ u32 len;
++
++ desc = ivshm_net_rx_desc(ndev);
++ if (!desc)
++ break;
++
++ data = ivshm_net_desc_data(in, &in->rx, desc, &len);
++ if (!data) {
++ netdev_err(ndev, "bad rx descriptor\n");
++ break;
++ }
++
++ skb = napi_alloc_skb(napi, len);
++
++ if (skb) {
++ memcpy(skb_put(skb, len), data, len);
++ skb->protocol = eth_type_trans(skb, ndev);
++ napi_gro_receive(napi, skb);
++ }
++
++ ndev->stats.rx_packets++;
++ ndev->stats.rx_bytes += len;
++
++ ivshm_net_rx_finish(in, desc);
++ received++;
++ }
++
++ if (received < budget) {
++ in->stats.napi_complete++;
++ napi_complete_done(napi, received);
++ ivshm_net_enable_rx_irq(in);
++ if (ivshm_net_rx_avail(in))
++ napi_schedule(napi);
++ }
++
++ if (received)
++ ivshm_net_notify_rx(in, received);
++
++ in->stats.rx_packets += received;
++ in->stats.napi_poll_n[received ? 1 + min(ilog2(received), 8) : 0]++;
++
++ if (ivshm_net_tx_ok(in, ndev->mtu))
++ netif_wake_queue(ndev);
++
++ return received;
++}
++
++static netdev_tx_t ivshm_net_xmit(struct sk_buff *skb, struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++
++ ivshm_net_tx_clean(ndev);
++
++ if (!ivshm_net_tx_ok(in, ndev->mtu)) {
++ ivshm_net_enable_tx_irq(in);
++ netif_stop_queue(ndev);
++ skb->xmit_more = 0;
++ in->stats.tx_pause++;
++ }
++
++ ivshm_net_tx_frame(ndev, skb);
++
++ in->stats.tx_packets++;
++ ndev->stats.tx_packets++;
++ ndev->stats.tx_bytes += skb->len;
++
++ dev_consume_skb_any(skb);
++
++ return NETDEV_TX_OK;
++}
++
++static void ivshm_net_set_state(struct ivshm_net *in, u32 state)
++{
++ virt_wmb();
++ WRITE_ONCE(in->lstate, state);
++ writel(state, &in->ivshm_regs->lstate);
++}
++
++static void ivshm_net_run(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++
++ netif_start_queue(ndev);
++ napi_enable(&in->napi);
++ napi_schedule(&in->napi);
++ ivshm_net_set_state(in, IVSHM_NET_STATE_RUN);
++}
++
++static void ivshm_net_state_change(struct work_struct *work)
++{
++ struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
++ struct net_device *ndev = in->napi.dev;
++ u32 rstate = readl(&in->ivshm_regs->rstate);
++
++
++ switch (in->lstate) {
++ case IVSHM_NET_STATE_RESET:
++ if (rstate < IVSHM_NET_STATE_READY)
++ ivshm_net_set_state(in, IVSHM_NET_STATE_INIT);
++ break;
++
++ case IVSHM_NET_STATE_INIT:
++ if (rstate > IVSHM_NET_STATE_RESET) {
++ ivshm_net_init_queues(ndev);
++ ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
++
++ rtnl_lock();
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, ndev);
++ rtnl_unlock();
++ }
++ break;
++
++ case IVSHM_NET_STATE_READY:
++ if (rstate >= IVSHM_NET_STATE_READY) {
++ netif_carrier_on(ndev);
++ if (ndev->flags & IFF_UP)
++ ivshm_net_run(ndev);
++ } else {
++ netif_carrier_off(ndev);
++ ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
++ }
++ break;
++
++ case IVSHM_NET_STATE_RUN:
++ if (rstate < IVSHM_NET_STATE_READY) {
++ netif_stop_queue(ndev);
++ napi_disable(&in->napi);
++ netif_carrier_off(ndev);
++ ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
++ }
++ break;
++ }
++
++ virt_wmb();
++ WRITE_ONCE(in->rstate, rstate);
++}
++
++static bool ivshm_net_check_state(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ u32 rstate = readl(&in->ivshm_regs->rstate);
++
++ if (rstate != READ_ONCE(in->rstate) ||
++ in->lstate != IVSHM_NET_STATE_RUN) {
++ queue_work(in->state_wq, &in->state_work);
++ return false;
++ }
++
++ return true;
++}
++
++static irqreturn_t ivshm_net_int(int irq, void *data)
++{
++ struct net_device *ndev = data;
++ struct ivshm_net *in = netdev_priv(ndev);
++
++ in->stats.interrupts++;
++
++ ivshm_net_check_state(ndev);
++ napi_schedule_irqoff(&in->napi);
++
++ return IRQ_HANDLED;
++}
++
++static int ivshm_net_open(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++
++ netdev_reset_queue(ndev);
++ ndev->operstate = IF_OPER_UP;
++
++ if (in->lstate == IVSHM_NET_STATE_READY)
++ ivshm_net_run(ndev);
++
++ return 0;
++}
++
++static int ivshm_net_stop(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++
++ ndev->operstate = IF_OPER_DOWN;
++
++ if (in->lstate == IVSHM_NET_STATE_RUN) {
++ napi_disable(&in->napi);
++ netif_stop_queue(ndev);
++ ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
++ }
++
++ return 0;
++}
++
++static int ivshm_net_change_mtu(struct net_device *ndev, int mtu)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ struct ivshm_net_queue *tx = &in->tx;
++
++ if (mtu < IVSHM_NET_MTU_MIN || mtu > IVSHM_NET_MTU_MAX)
++ return -EINVAL;
++
++ if (in->tx.size / mtu < 4)
++ return -EINVAL;
++
++ if (ivshm_net_tx_space(in) < 2 * IVSHM_NET_FRAME_SIZE(mtu))
++ return -EBUSY;
++
++ if (in->tx.size - tx->head < IVSHM_NET_FRAME_SIZE(mtu) &&
++ tx->head < tx->tail)
++ return -EBUSY;
++
++ netif_tx_lock_bh(ndev);
++ if (in->tx.size - tx->head < IVSHM_NET_FRAME_SIZE(mtu))
++ tx->head = 0;
++ netif_tx_unlock_bh(ndev);
++
++ ndev->mtu = mtu;
++
++ return 0;
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void ivshm_net_poll_controller(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++
++ napi_schedule(&in->napi);
++}
++#endif
++
++static const struct net_device_ops ivshm_net_ops = {
++ .ndo_open = ivshm_net_open,
++ .ndo_stop = ivshm_net_stop,
++ .ndo_start_xmit = ivshm_net_xmit,
++ .ndo_change_mtu = ivshm_net_change_mtu,
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ .ndo_poll_controller = ivshm_net_poll_controller,
++#endif
++};
++
++static const char ivshm_net_stats[][ETH_GSTRING_LEN] = {
++ "interrupts",
++ "tx_packets",
++ "tx_notify",
++ "tx_pause",
++ "rx_packets",
++ "rx_notify",
++ "napi_poll",
++ "napi_complete",
++ "napi_poll_0",
++ "napi_poll_1",
++ "napi_poll_2",
++ "napi_poll_4",
++ "napi_poll_8",
++ "napi_poll_16",
++ "napi_poll_32",
++ "napi_poll_64",
++ "napi_poll_128",
++ "napi_poll_256",
++};
++
++#define NUM_STATS ARRAY_SIZE(ivshm_net_stats)
++
++static int ivshm_net_get_sset_count(struct net_device *ndev, int sset)
++{
++ if (sset == ETH_SS_STATS)
++ return NUM_STATS;
++
++ return -EOPNOTSUPP;
++}
++
++static void ivshm_net_get_strings(struct net_device *ndev, u32 sset, u8 *buf)
++{
++ if (sset == ETH_SS_STATS)
++ memcpy(buf, &ivshm_net_stats, sizeof(ivshm_net_stats));
++}
++
++static void ivshm_net_get_ethtool_stats(struct net_device *ndev,
++ struct ethtool_stats *estats, u64 *st)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ unsigned int n = 0;
++ unsigned int i;
++
++ st[n++] = in->stats.interrupts;
++ st[n++] = in->stats.tx_packets;
++ st[n++] = in->stats.tx_notify;
++ st[n++] = in->stats.tx_pause;
++ st[n++] = in->stats.rx_packets;
++ st[n++] = in->stats.rx_notify;
++ st[n++] = in->stats.napi_poll;
++ st[n++] = in->stats.napi_complete;
++
++ for (i = 0; i < ARRAY_SIZE(in->stats.napi_poll_n); i++)
++ st[n++] = in->stats.napi_poll_n[i];
++
++ memset(&in->stats, 0, sizeof(in->stats));
++}
++
++static const struct ethtool_ops ivshm_net_ethtool_ops = {
++ .get_sset_count = ivshm_net_get_sset_count,
++ .get_strings = ivshm_net_get_strings,
++ .get_ethtool_stats = ivshm_net_get_ethtool_stats,
++};
++
++static int ivshm_net_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ struct net_device *ndev;
++ struct ivshm_net *in;
++ struct ivshmem_regs __iomem *regs;
++ resource_size_t shmaddr;
++ resource_size_t shmlen;
++ int interrupt;
++ void *shm;
++ u32 ivpos;
++ int err;
++
++ err = pcim_enable_device(pdev);
++ if (err) {
++ dev_err(&pdev->dev, "pci_enable_device: %d\n", err);
++ return err;
++ }
++
++ err = pcim_iomap_regions(pdev, BIT(0), DRV_NAME);
++ if (err) {
++ dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", err);
++ return err;
++ }
++
++ regs = pcim_iomap_table(pdev)[0];
++
++ shmlen = pci_resource_len(pdev, 2);
++
++ if (shmlen) {
++ shmaddr = pci_resource_start(pdev, 2);
++ } else {
++ union { u64 v; u32 hl[2]; } val;
++
++ pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_PTR,
++ &val.hl[0]);
++ pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_PTR + 4,
++ &val.hl[1]);
++ shmaddr = val.v;
++
++ pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_SZ,
++ &val.hl[0]);
++ pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_SZ + 4,
++ &val.hl[1]);
++ shmlen = val.v;
++ }
++
++
++ if (!devm_request_mem_region(&pdev->dev, shmaddr, shmlen, DRV_NAME))
++ return -EBUSY;
++
++ shm = devm_memremap(&pdev->dev, shmaddr, shmlen, MEMREMAP_WC);
++ if (!shm)
++ return -ENOMEM;
++
++ ivpos = readl(&regs->ivpos);
++ if (ivpos > 1) {
++ dev_err(&pdev->dev, "invalid IVPosition %d\n", ivpos);
++ return -EINVAL;
++ }
++
++ dev_info(&pdev->dev, "shared memory size %pa\n", &shmlen);
++
++ ndev = alloc_etherdev(sizeof(*in));
++ if (!ndev)
++ return -ENOMEM;
++
++ pci_set_drvdata(pdev, ndev);
++ SET_NETDEV_DEV(ndev, &pdev->dev);
++
++ in = netdev_priv(ndev);
++ in->ivshm_regs = regs;
++ in->shm = shm;
++ in->shmaddr = shmaddr;
++ in->shmlen = shmlen;
++ in->peer_id = !ivpos;
++ in->pdev = pdev;
++ spin_lock_init(&in->tx_free_lock);
++ spin_lock_init(&in->tx_clean_lock);
++
++ err = ivshm_net_calc_qsize(ndev);
++ if (err)
++ goto err_free;
++
++ in->state_wq = alloc_ordered_workqueue(DRV_NAME, 0);
++ if (!in->state_wq)
++ goto err_free;
++
++ INIT_WORK(&in->state_work, ivshm_net_state_change);
++
++ eth_random_addr(ndev->dev_addr);
++ ndev->netdev_ops = &ivshm_net_ops;
++ ndev->ethtool_ops = &ivshm_net_ethtool_ops;
++ ndev->mtu = min_t(u32, IVSHM_NET_MTU_DEF, in->qsize / 16);
++ ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG;
++ ndev->features = ndev->hw_features;
++
++ netif_carrier_off(ndev);
++ netif_napi_add(ndev, &in->napi, ivshm_net_poll, NAPI_POLL_WEIGHT);
++
++ err = register_netdev(ndev);
++ if (err)
++ goto err_wq;
++
++ err = pci_enable_msix(pdev, &in->msix, 1);
++ if (!err) {
++ interrupt = in->msix.vector;
++ in->using_msix = true;
++ } else {
++ interrupt = pdev->irq;
++ in->using_msix = false;
++ }
++
++ err = request_irq(interrupt, ivshm_net_int, 0, DRV_NAME, ndev);
++ if (err)
++ goto err_int;
++
++ pci_set_master(pdev);
++
++ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
++
++ return 0;
++
++err_int:
++ if (in->using_msix)
++ pci_disable_msix(pdev);
++ unregister_netdev(ndev);
++err_wq:
++ destroy_workqueue(in->state_wq);
++err_free:
++ free_netdev(ndev);
++
++ return err;
++}
++
++static void ivshm_net_remove(struct pci_dev *pdev)
++{
++ struct net_device *ndev = pci_get_drvdata(pdev);
++ struct ivshm_net *in = netdev_priv(ndev);
++
++ if (in->using_msix) {
++ free_irq(in->msix.vector, ndev);
++ pci_disable_msix(pdev);
++ } else {
++ free_irq(pdev->irq, ndev);
++ }
++
++ unregister_netdev(ndev);
++ cancel_work_sync(&in->state_work);
++ destroy_workqueue(in->state_wq);
++ free_netdev(ndev);
++}
++
++static const struct pci_device_id ivshm_net_id_table[] = {
++ { PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, 0x1110),
++ (PCI_CLASS_OTHERS << 16) | (0x01 << 8), 0xffff00 },
++ { 0 }
++};
++MODULE_DEVICE_TABLE(pci, ivshm_net_id_table);
++
++static struct pci_driver ivshm_net_driver = {
++ .name = DRV_NAME,
++ .id_table = ivshm_net_id_table,
++ .probe = ivshm_net_probe,
++ .remove = ivshm_net_remove,
++};
++module_pci_driver(ivshm_net_driver);
++
++MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
++MODULE_LICENSE("GPL");
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0014-ivshmem-net-Map-shmem-region-as-RAM.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0014-ivshmem-net-Map-shmem-region-as-RAM.patch
new file mode 100644
index 00000000..de66d7a7
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0014-ivshmem-net-Map-shmem-region-as-RAM.patch
@@ -0,0 +1,30 @@
+From b70f2ecb71b212225f403a8f26d3d5bdca70a107 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 24 Nov 2016 08:27:45 +0100
+Subject: [PATCH 14/32] ivshmem-net: Map shmem region as RAM
+
+No need for special caching, simply map the shared memory region like
+RAM, thus write-back. This gives us another order of magnitude in
+throughput.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index b676bed2cc2e..a535cb71adde 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -802,7 +802,7 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ if (!devm_request_mem_region(&pdev->dev, shmaddr, shmlen, DRV_NAME))
+ return -EBUSY;
+
+- shm = devm_memremap(&pdev->dev, shmaddr, shmlen, MEMREMAP_WC);
++ shm = devm_memremap(&pdev->dev, shmaddr, shmlen, MEMREMAP_WB);
+ if (!shm)
+ return -ENOMEM;
+
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0015-ivshmem-net-fix-race-in-state-machine.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0015-ivshmem-net-fix-race-in-state-machine.patch
new file mode 100644
index 00000000..ecb5c485
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0015-ivshmem-net-fix-race-in-state-machine.patch
@@ -0,0 +1,140 @@
+From 1349a457e5e33580fb26afab087e6b932b1a4372 Mon Sep 17 00:00:00 2001
+From: Mans Rullgard <mans@mansr.com>
+Date: Thu, 24 Nov 2016 18:46:41 +0000
+Subject: [PATCH 15/32] ivshmem-net: fix race in state machine
+
+---
+ drivers/net/ivshmem-net.c | 60 ++++++++++++++++++++++++-----------------------
+ 1 file changed, 31 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index a535cb71adde..acd00e47acd7 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -36,6 +36,8 @@
+ #define IVSHM_NET_STATE_READY 2
+ #define IVSHM_NET_STATE_RUN 3
+
++#define IVSHM_NET_FLAG_RUN 0
++
+ #define IVSHM_NET_MTU_MIN 256
+ #define IVSHM_NET_MTU_MAX 65535
+ #define IVSHM_NET_MTU_DEF 16384
+@@ -96,6 +98,8 @@ struct ivshm_net {
+ u32 lstate;
+ u32 rstate;
+
++ unsigned long flags;
++
+ struct workqueue_struct *state_wq;
+ struct work_struct state_work;
+
+@@ -529,12 +533,32 @@ static void ivshm_net_run(struct net_device *ndev)
+ {
+ struct ivshm_net *in = netdev_priv(ndev);
+
++ if (in->lstate < IVSHM_NET_STATE_READY)
++ return;
++
++ if (!netif_running(ndev))
++ return;
++
++ if (test_and_set_bit(IVSHM_NET_FLAG_RUN, &in->flags))
++ return;
++
+ netif_start_queue(ndev);
+ napi_enable(&in->napi);
+ napi_schedule(&in->napi);
+ ivshm_net_set_state(in, IVSHM_NET_STATE_RUN);
+ }
+
++static void ivshm_net_do_stop(struct net_device *ndev)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++
++ if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
++ return;
++
++ netif_stop_queue(ndev);
++ napi_disable(&in->napi);
++}
++
+ static void ivshm_net_state_change(struct work_struct *work)
+ {
+ struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
+@@ -560,21 +584,13 @@ static void ivshm_net_state_change(struct work_struct *work)
+ break;
+
+ case IVSHM_NET_STATE_READY:
++ case IVSHM_NET_STATE_RUN:
+ if (rstate >= IVSHM_NET_STATE_READY) {
+ netif_carrier_on(ndev);
+- if (ndev->flags & IFF_UP)
+- ivshm_net_run(ndev);
++ ivshm_net_run(ndev);
+ } else {
+ netif_carrier_off(ndev);
+- ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
+- }
+- break;
+-
+- case IVSHM_NET_STATE_RUN:
+- if (rstate < IVSHM_NET_STATE_READY) {
+- netif_stop_queue(ndev);
+- napi_disable(&in->napi);
+- netif_carrier_off(ndev);
++ ivshm_net_do_stop(ndev);
+ ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
+ }
+ break;
+@@ -584,18 +600,13 @@ static void ivshm_net_state_change(struct work_struct *work)
+ WRITE_ONCE(in->rstate, rstate);
+ }
+
+-static bool ivshm_net_check_state(struct net_device *ndev)
++static void ivshm_net_check_state(struct net_device *ndev)
+ {
+ struct ivshm_net *in = netdev_priv(ndev);
+ u32 rstate = readl(&in->ivshm_regs->rstate);
+
+- if (rstate != READ_ONCE(in->rstate) ||
+- in->lstate != IVSHM_NET_STATE_RUN) {
++ if (rstate != in->rstate || !test_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ queue_work(in->state_wq, &in->state_work);
+- return false;
+- }
+-
+- return true;
+ }
+
+ static irqreturn_t ivshm_net_int(int irq, void *data)
+@@ -617,24 +628,15 @@ static int ivshm_net_open(struct net_device *ndev)
+
+ netdev_reset_queue(ndev);
+ ndev->operstate = IF_OPER_UP;
+-
+- if (in->lstate == IVSHM_NET_STATE_READY)
+- ivshm_net_run(ndev);
++ ivshm_net_run(ndev);
+
+ return 0;
+ }
+
+ static int ivshm_net_stop(struct net_device *ndev)
+ {
+- struct ivshm_net *in = netdev_priv(ndev);
+-
+ ndev->operstate = IF_OPER_DOWN;
+-
+- if (in->lstate == IVSHM_NET_STATE_RUN) {
+- napi_disable(&in->napi);
+- netif_stop_queue(ndev);
+- ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
+- }
++ ivshm_net_do_stop(ndev);
+
+ return 0;
+ }
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0016-ivshmem-net-Remove-unused-variable.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0016-ivshmem-net-Remove-unused-variable.patch
new file mode 100644
index 00000000..dfaca493
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0016-ivshmem-net-Remove-unused-variable.patch
@@ -0,0 +1,28 @@
+From 85362cf2e682d196fc3a88d05e21f0603cb0c48a Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Fri, 25 Nov 2016 17:31:51 +0100
+Subject: [PATCH 16/32] ivshmem-net: Remove unused variable
+
+Became unused by previous change.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index acd00e47acd7..ccef65d0f038 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -624,8 +624,6 @@ static irqreturn_t ivshm_net_int(int irq, void *data)
+
+ static int ivshm_net_open(struct net_device *ndev)
+ {
+- struct ivshm_net *in = netdev_priv(ndev);
+-
+ netdev_reset_queue(ndev);
+ ndev->operstate = IF_OPER_UP;
+ ivshm_net_run(ndev);
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0017-ivshmem-net-Enable-INTx.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0017-ivshmem-net-Enable-INTx.patch
new file mode 100644
index 00000000..e0f4be44
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0017-ivshmem-net-Enable-INTx.patch
@@ -0,0 +1,55 @@
+From 9683ab979a373932e9c332d2db8115b6c23303d0 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 27 Nov 2016 15:15:51 +0100
+Subject: [PATCH 17/32] ivshmem-net: Enable INTx
+
+Activate INTx notification when it has to be used instead of MSI-X,
+disable it after use.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index ccef65d0f038..591d04195e57 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -31,6 +31,8 @@
+ #define JAILHOUSE_CFG_SHMEM_PTR 0x40
+ #define JAILHOUSE_CFG_SHMEM_SZ 0x48
+
++#define IVSHMEM_INTX_ENABLE 0x1
++
+ #define IVSHM_NET_STATE_RESET 0
+ #define IVSHM_NET_STATE_INIT 1
+ #define IVSHM_NET_STATE_READY 2
+@@ -47,7 +49,7 @@
+ #define IVSHM_NET_VQ_ALIGN 64
+
+ struct ivshmem_regs {
+- u32 imask;
++ u32 intxctrl;
+ u32 istat;
+ u32 ivpos;
+ u32 doorbell;
+@@ -869,6 +871,8 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ goto err_int;
+
+ pci_set_master(pdev);
++ if (!in->using_msix)
++ writel(IVSHMEM_INTX_ENABLE, &in->ivshm_regs->intxctrl);
+
+ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+
+@@ -895,6 +899,7 @@ static void ivshm_net_remove(struct pci_dev *pdev)
+ free_irq(in->msix.vector, ndev);
+ pci_disable_msix(pdev);
+ } else {
++ writel(0, &in->ivshm_regs->intxctrl);
+ free_irq(pdev->irq, ndev);
+ }
+
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0018-ivshmem-net-Improve-identification-of-resources.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0018-ivshmem-net-Improve-identification-of-resources.patch
new file mode 100644
index 00000000..e51b94aa
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0018-ivshmem-net-Improve-identification-of-resources.patch
@@ -0,0 +1,59 @@
+From d60c7b69f68961c6868ca870d645ed7d4f73e751 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Wed, 21 Dec 2016 08:20:18 +0100
+Subject: [PATCH 18/32] ivshmem-net: Improve identification of resources
+
+Pass a device name consisting of driver name and PCI ID to request_irq
+and alloc_ordered_workqueue. This helps correlating resources with
+devices in case there are multiple of them.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 591d04195e57..cff6aa0be71d 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -762,6 +762,7 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ resource_size_t shmaddr;
+ resource_size_t shmlen;
+ int interrupt;
++ char *device_name;
+ void *shm;
+ u32 ivpos;
+ int err;
+@@ -814,7 +815,10 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ return -EINVAL;
+ }
+
+- dev_info(&pdev->dev, "shared memory size %pa\n", &shmlen);
++ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s[%s]", DRV_NAME,
++ dev_name(&pdev->dev));
++ if (!device_name)
++ return -ENOMEM;
+
+ ndev = alloc_etherdev(sizeof(*in));
+ if (!ndev)
+@@ -837,7 +841,7 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ if (err)
+ goto err_free;
+
+- in->state_wq = alloc_ordered_workqueue(DRV_NAME, 0);
++ in->state_wq = alloc_ordered_workqueue(device_name, 0);
+ if (!in->state_wq)
+ goto err_free;
+
+@@ -866,7 +870,7 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ in->using_msix = false;
+ }
+
+- err = request_irq(interrupt, ivshm_net_int, 0, DRV_NAME, ndev);
++ err = request_irq(interrupt, ivshm_net_int, 0, device_name, ndev);
+ if (err)
+ goto err_int;
+
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0019-ivshmem-net-Switch-to-reset-state-on-each-net-stop-a.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0019-ivshmem-net-Switch-to-reset-state-on-each-net-stop-a.patch
new file mode 100644
index 00000000..512bcaf2
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0019-ivshmem-net-Switch-to-reset-state-on-each-net-stop-a.patch
@@ -0,0 +1,47 @@
+From a16c80c305b2e11fe3efd0905bbe7db8388bf545 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 1 Jan 2017 15:43:37 +0100
+Subject: [PATCH 19/32] ivshmem-net: Switch to reset state on each net stop and
+ on driver removal
+
+Improves the state signaling to the remote side after ifconfig down and
+driver removal.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index cff6aa0be71d..09484d652add 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -554,6 +554,8 @@ static void ivshm_net_do_stop(struct net_device *ndev)
+ {
+ struct ivshm_net *in = netdev_priv(ndev);
+
++ ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
++
+ if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ return;
+
+@@ -593,7 +595,6 @@ static void ivshm_net_state_change(struct work_struct *work)
+ } else {
+ netif_carrier_off(ndev);
+ ivshm_net_do_stop(ndev);
+- ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
+ }
+ break;
+ }
+@@ -899,6 +900,8 @@ static void ivshm_net_remove(struct pci_dev *pdev)
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ivshm_net *in = netdev_priv(ndev);
+
++ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
++
+ if (in->using_msix) {
+ free_irq(in->msix.vector, ndev);
+ pci_disable_msix(pdev);
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0020-ivshmem-net-Add-ethtool-register-dump.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0020-ivshmem-net-Add-ethtool-register-dump.patch
new file mode 100644
index 00000000..d0a562a7
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0020-ivshmem-net-Add-ethtool-register-dump.patch
@@ -0,0 +1,61 @@
+From 98f68e69e2e950b44e7324bbcc94700705193443 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 1 Jan 2017 15:46:26 +0100
+Subject: [PATCH 20/32] ivshmem-net: Add ethtool register dump
+
+Helps debugging inconsistent states.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 09484d652add..c52727ef40c1 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -748,10 +748,41 @@ static void ivshm_net_get_ethtool_stats(struct net_device *ndev,
+ memset(&in->stats, 0, sizeof(in->stats));
+ }
+
++#define IVSHM_NET_REGS_LEN (3 * sizeof(u32) + 6 * sizeof(u16))
++
++static int ivshm_net_get_regs_len(struct net_device *ndev)
++{
++ return IVSHM_NET_REGS_LEN;
++}
++
++static void ivshm_net_get_regs(struct net_device *ndev,
++ struct ethtool_regs *regs, void *p)
++{
++ struct ivshm_net *in = netdev_priv(ndev);
++ u32 *reg32 = p;
++ u16 *reg16;
++
++ *reg32++ = in->lstate;
++ *reg32++ = in->rstate;
++ *reg32++ = in->qlen;
++
++ reg16 = (u16 *)reg32;
++
++ *reg16++ = in->tx.vr.avail ? in->tx.vr.avail->idx : 0;
++ *reg16++ = in->tx.vr.used ? in->tx.vr.used->idx : 0;
++ *reg16++ = in->tx.vr.avail ? vring_avail_event(&in->tx.vr) : 0;
++
++ *reg16++ = in->rx.vr.avail ? in->rx.vr.avail->idx : 0;
++ *reg16++ = in->rx.vr.used ? in->rx.vr.used->idx : 0;
++ *reg16++ = in->rx.vr.avail ? vring_avail_event(&in->rx.vr) : 0;
++}
++
+ static const struct ethtool_ops ivshm_net_ethtool_ops = {
+ .get_sset_count = ivshm_net_get_sset_count,
+ .get_strings = ivshm_net_get_strings,
+ .get_ethtool_stats = ivshm_net_get_ethtool_stats,
++ .get_regs_len = ivshm_net_get_regs_len,
++ .get_regs = ivshm_net_get_regs,
+ };
+
+ static int ivshm_net_probe(struct pci_dev *pdev,
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0021-ivshmem-net-Fix-stuck-state-machine-during-setup.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0021-ivshmem-net-Fix-stuck-state-machine-during-setup.patch
new file mode 100644
index 00000000..4e40341e
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0021-ivshmem-net-Fix-stuck-state-machine-during-setup.patch
@@ -0,0 +1,30 @@
+From b8d8821cfa8aa53aa29c0b230330afcd79ee7f60 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 1 Jan 2017 15:54:55 +0100
+Subject: [PATCH 21/32] ivshmem-net: Fix stuck state machine during setup
+
+If the remote side is already in INIT state (or even higher) and has a
+cached rstate of RESET, we won't make progress when signaling RESET
+again because the remote side won't send a state update. Fix this by
+enforcing a local check after probe completion.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index c52727ef40c1..9f307ec4d677 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -911,6 +911,7 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ writel(IVSHMEM_INTX_ENABLE, &in->ivshm_regs->intxctrl);
+
+ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
++ ivshm_net_check_state(ndev);
+
+ return 0;
+
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0022-ivshmem-net-Switch-to-relative-descriptor-addresses.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0022-ivshmem-net-Switch-to-relative-descriptor-addresses.patch
new file mode 100644
index 00000000..aca00e26
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0022-ivshmem-net-Switch-to-relative-descriptor-addresses.patch
@@ -0,0 +1,49 @@
+From d1a0011e9857e105e38d9a0ea6fd7b8e7e6d8dc9 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 3 Jan 2017 08:50:01 +0100
+Subject: [PATCH 22/32] ivshmem-net: Switch to relative descriptor addresses
+
+Make sure that we do not depend on identity-mapped shared memory
+regions.
+
+This also fixes an off-by-one in the range check of ivshm_net_desc_data.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 9f307ec4d677..0e770ca293a4 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -123,14 +123,14 @@ static void *ivshm_net_desc_data(struct ivshm_net *in,
+ struct vring_desc *desc,
+ u32 *len)
+ {
+- u64 addr = READ_ONCE(desc->addr);
++ u64 offs = READ_ONCE(desc->addr);
+ u32 dlen = READ_ONCE(desc->len);
+ void *data;
+
+- if (addr < in->shmaddr || desc->addr > in->shmaddr + in->shmlen)
++ if (offs >= in->shmlen)
+ return NULL;
+
+- data = in->shm + (addr - in->shmaddr);
++ data = in->shm + offs;
+
+ if (data < q->data || data >= q->end)
+ return NULL;
+@@ -317,7 +317,7 @@ static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb)
+ buf = tx->data + head;
+ skb_copy_and_csum_dev(skb, buf);
+
+- desc->addr = in->shmaddr + (buf - in->shm);
++ desc->addr = buf - in->shm;
+ desc->len = skb->len;
+
+ avail = tx->last_avail_idx++ & (vr->num - 1);
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0023-ivshmem-net-Switch-to-pci_alloc_irq_vectors.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0023-ivshmem-net-Switch-to-pci_alloc_irq_vectors.patch
new file mode 100644
index 00000000..fcc2cac3
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0023-ivshmem-net-Switch-to-pci_alloc_irq_vectors.patch
@@ -0,0 +1,146 @@
+From 77920ddb91fa49f7085875d29dd2a2c7e783af3a Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 23 May 2017 17:41:00 +0200
+Subject: [PATCH 23/32] ivshmem-net: Switch to pci_alloc_irq_vectors
+
+Required by 4.12, and it also simplifies our code. Needs to be folded
+into the initial patch eventually.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 66 ++++++++++++++++++++---------------------------
+ 1 file changed, 28 insertions(+), 38 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 0e770ca293a4..fd7d78b84576 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -114,8 +114,6 @@ struct ivshm_net {
+ u32 peer_id;
+
+ struct pci_dev *pdev;
+- struct msix_entry msix;
+- bool using_msix;
+ };
+
+ static void *ivshm_net_desc_data(struct ivshm_net *in,
+@@ -793,22 +791,21 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ struct ivshmem_regs __iomem *regs;
+ resource_size_t shmaddr;
+ resource_size_t shmlen;
+- int interrupt;
+ char *device_name;
+ void *shm;
+ u32 ivpos;
+- int err;
++ int ret;
+
+- err = pcim_enable_device(pdev);
+- if (err) {
+- dev_err(&pdev->dev, "pci_enable_device: %d\n", err);
+- return err;
++ ret = pcim_enable_device(pdev);
++ if (ret) {
++ dev_err(&pdev->dev, "pci_enable_device: %d\n", ret);
++ return ret;
+ }
+
+- err = pcim_iomap_regions(pdev, BIT(0), DRV_NAME);
+- if (err) {
+- dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", err);
+- return err;
++ ret = pcim_iomap_regions(pdev, BIT(0), DRV_NAME);
++ if (ret) {
++ dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", ret);
++ return ret;
+ }
+
+ regs = pcim_iomap_table(pdev)[0];
+@@ -869,8 +866,8 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ spin_lock_init(&in->tx_free_lock);
+ spin_lock_init(&in->tx_clean_lock);
+
+- err = ivshm_net_calc_qsize(ndev);
+- if (err)
++ ret = ivshm_net_calc_qsize(ndev);
++ if (ret)
+ goto err_free;
+
+ in->state_wq = alloc_ordered_workqueue(device_name, 0);
+@@ -889,25 +886,21 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ netif_carrier_off(ndev);
+ netif_napi_add(ndev, &in->napi, ivshm_net_poll, NAPI_POLL_WEIGHT);
+
+- err = register_netdev(ndev);
+- if (err)
++ ret = register_netdev(ndev);
++ if (ret)
+ goto err_wq;
+
+- err = pci_enable_msix(pdev, &in->msix, 1);
+- if (!err) {
+- interrupt = in->msix.vector;
+- in->using_msix = true;
+- } else {
+- interrupt = pdev->irq;
+- in->using_msix = false;
+- }
++ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY | PCI_IRQ_MSIX);
++ if (ret < 0)
++ goto err_alloc_irq;
+
+- err = request_irq(interrupt, ivshm_net_int, 0, device_name, ndev);
+- if (err)
+- goto err_int;
++ ret = request_irq(pci_irq_vector(pdev, 0), ivshm_net_int, 0,
++ device_name, ndev);
++ if (ret)
++ goto err_request_irq;
+
+ pci_set_master(pdev);
+- if (!in->using_msix)
++ if (!pdev->msix_enabled)
+ writel(IVSHMEM_INTX_ENABLE, &in->ivshm_regs->intxctrl);
+
+ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+@@ -915,16 +908,16 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+
+ return 0;
+
+-err_int:
+- if (in->using_msix)
+- pci_disable_msix(pdev);
++err_request_irq:
++ pci_free_irq_vectors(pdev);
++err_alloc_irq:
+ unregister_netdev(ndev);
+ err_wq:
+ destroy_workqueue(in->state_wq);
+ err_free:
+ free_netdev(ndev);
+
+- return err;
++ return ret;
+ }
+
+ static void ivshm_net_remove(struct pci_dev *pdev)
+@@ -934,13 +927,10 @@ static void ivshm_net_remove(struct pci_dev *pdev)
+
+ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+
+- if (in->using_msix) {
+- free_irq(in->msix.vector, ndev);
+- pci_disable_msix(pdev);
+- } else {
++ if (!pdev->msix_enabled)
+ writel(0, &in->ivshm_regs->intxctrl);
+- free_irq(pdev->irq, ndev);
+- }
++ free_irq(pci_irq_vector(pdev, 0), ndev);
++ pci_free_irq_vectors(pdev);
+
+ unregister_netdev(ndev);
+ cancel_work_sync(&in->state_work);
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0024-ivshmem-net-fill-in-and-check-used-descriptor-chain-.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0024-ivshmem-net-fill-in-and-check-used-descriptor-chain-.patch
new file mode 100644
index 00000000..7620d682
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0024-ivshmem-net-fill-in-and-check-used-descriptor-chain-.patch
@@ -0,0 +1,70 @@
+From be71104c3d4d682f88a4e56e408683b2e8edaef5 Mon Sep 17 00:00:00 2001
+From: Henning Schild <henning.schild@siemens.com>
+Date: Mon, 18 Sep 2017 18:02:08 +0200
+Subject: [PATCH 24/32] ivshmem-net: fill in and check used descriptor chain
+ len
+
+We are using chains of len==1 make that explicit and expect that from
+the remote.
+
+Signed-off-by: Henning Schild <henning.schild@siemens.com>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index fd7d78b84576..556670e779e7 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -335,10 +335,10 @@ static void ivshm_net_tx_clean(struct net_device *ndev)
+ {
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *tx = &in->tx;
++ struct vring_used_elem *used;
+ struct vring *vr = &tx->vr;
+ struct vring_desc *desc;
+ struct vring_desc *fdesc;
+- unsigned int used;
+ unsigned int num;
+ u16 used_idx;
+ u16 last;
+@@ -358,13 +358,14 @@ static void ivshm_net_tx_clean(struct net_device *ndev)
+ u32 len;
+ u32 tail;
+
+- used = vr->used->ring[last & (vr->num - 1)].id;
+- if (used >= vr->num) {
+- netdev_err(ndev, "invalid tx used %d\n", used);
++ used = vr->used->ring + (last % vr->num);
++ if (used->id >= vr->num || used->len != 1) {
++ netdev_err(ndev, "invalid tx used->id %d ->len %d\n",
++ used->id, used->len);
+ break;
+ }
+
+- desc = &vr->desc[used];
++ desc = &vr->desc[used->id];
+
+ data = ivshm_net_desc_data(in, &in->tx, desc, &len);
+ if (!data) {
+@@ -383,7 +384,7 @@ static void ivshm_net_tx_clean(struct net_device *ndev)
+ else
+ desc->next = fhead;
+
+- fhead = used;
++ fhead = used->id;
+ last++;
+ num++;
+ }
+@@ -433,6 +434,7 @@ static void ivshm_net_rx_finish(struct ivshm_net *in, struct vring_desc *desc)
+
+ used = rx->last_used_idx++ & (vr->num - 1);
+ vr->used->ring[used].id = desc_id;
++ vr->used->ring[used].len = 1;
+
+ virt_store_release(&vr->used->idx, rx->last_used_idx);
+ }
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0025-ivshmem-net-slightly-improve-debug-output.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0025-ivshmem-net-slightly-improve-debug-output.patch
new file mode 100644
index 00000000..cc20c2fd
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0025-ivshmem-net-slightly-improve-debug-output.patch
@@ -0,0 +1,29 @@
+From 5776a8083d73bd137a74ab33f0f7652a2c6ee83a Mon Sep 17 00:00:00 2001
+From: Henning Schild <henning.schild@siemens.com>
+Date: Mon, 18 Sep 2017 18:02:10 +0200
+Subject: [PATCH 25/32] ivshmem-net: slightly improve debug output
+
+There where two lines with the same error message, change one of them.
+
+Signed-off-by: Henning Schild <henning.schild@siemens.com>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 556670e779e7..abc50553e644 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -369,7 +369,7 @@ static void ivshm_net_tx_clean(struct net_device *ndev)
+
+ data = ivshm_net_desc_data(in, &in->tx, desc, &len);
+ if (!data) {
+- netdev_err(ndev, "bad tx descriptor\n");
++ netdev_err(ndev, "bad tx descriptor, data == NULL\n");
+ break;
+ }
+
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0026-ivshmem-net-set-and-check-descriptor-flags.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0026-ivshmem-net-set-and-check-descriptor-flags.patch
new file mode 100644
index 00000000..a7d7ab24
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0026-ivshmem-net-set-and-check-descriptor-flags.patch
@@ -0,0 +1,43 @@
+From 6b095510765e054c4ee641f115ab72798d97ac21 Mon Sep 17 00:00:00 2001
+From: Henning Schild <henning.schild@siemens.com>
+Date: Mon, 18 Sep 2017 18:02:11 +0200
+Subject: [PATCH 26/32] ivshmem-net: set and check descriptor flags
+
+We do not support the use of any flags. Make sure the remote does not
+confuse us using flags.
+
+Signed-off-by: Henning Schild <henning.schild@siemens.com>
+[Jan: Remove wrong removal of next field initialization]
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index abc50553e644..9ecf1d0f0d2d 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -123,8 +123,12 @@ static void *ivshm_net_desc_data(struct ivshm_net *in,
+ {
+ u64 offs = READ_ONCE(desc->addr);
+ u32 dlen = READ_ONCE(desc->len);
++ u16 flags = READ_ONCE(desc->flags);
+ void *data;
+
++ if (flags)
++ return NULL;
++
+ if (offs >= in->shmlen)
+ return NULL;
+
+@@ -317,6 +321,7 @@ static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb)
+
+ desc->addr = buf - in->shm;
+ desc->len = skb->len;
++ desc->flags = 0;
+
+ avail = tx->last_avail_idx++ & (vr->num - 1);
+ vr->avail->ring[avail] = desc_idx;
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0027-ivshmem-net-add-MAC-changing-interface.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0027-ivshmem-net-add-MAC-changing-interface.patch
new file mode 100644
index 00000000..61172afd
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0027-ivshmem-net-add-MAC-changing-interface.patch
@@ -0,0 +1,41 @@
+From 73b98d39ceacd025ae4aaff1b2cbb537e852a03e Mon Sep 17 00:00:00 2001
+From: Henning Schild <henning.schild@siemens.com>
+Date: Wed, 27 Sep 2017 12:59:49 +0200
+Subject: [PATCH 27/32] ivshmem-net: add MAC changing interface
+
+Allow ifconfig, ip and other such tools to change the MAC of the
+virtual NIC.
+
+Signed-off-by: Henning Schild <henning.schild@siemens.com>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 9ecf1d0f0d2d..712dde0ee6f9 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -685,12 +685,14 @@ static void ivshm_net_poll_controller(struct net_device *ndev)
+ #endif
+
+ static const struct net_device_ops ivshm_net_ops = {
+- .ndo_open = ivshm_net_open,
+- .ndo_stop = ivshm_net_stop,
+- .ndo_start_xmit = ivshm_net_xmit,
+- .ndo_change_mtu = ivshm_net_change_mtu,
++ .ndo_open = ivshm_net_open,
++ .ndo_stop = ivshm_net_stop,
++ .ndo_start_xmit = ivshm_net_xmit,
++ .ndo_change_mtu = ivshm_net_change_mtu,
++ .ndo_set_mac_address = eth_mac_addr,
++ .ndo_validate_addr = eth_validate_addr,
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+- .ndo_poll_controller = ivshm_net_poll_controller,
++ .ndo_poll_controller = ivshm_net_poll_controller,
+ #endif
+ };
+
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0028-ivshmem-net-Silence-compiler-warning.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0028-ivshmem-net-Silence-compiler-warning.patch
new file mode 100644
index 00000000..6a1c212f
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0028-ivshmem-net-Silence-compiler-warning.patch
@@ -0,0 +1,28 @@
+From fbefa0a6dcc6011aef4444c771f300c40fca30f1 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 3 Oct 2017 12:24:59 +0200
+Subject: [PATCH 28/32] ivshmem-net: Silence compiler warning
+
+At least Linaro's gcc 6.3 does not see the initialization and usage
+dependency of fhead and num. Let's silence this false positive.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 712dde0ee6f9..6fa7a6c81bf1 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -356,6 +356,7 @@ static void ivshm_net_tx_clean(struct net_device *ndev)
+ last = tx->last_used_idx;
+
+ fdesc = NULL;
++ fhead = 0;
+ num = 0;
+
+ while (last != used_idx) {
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0029-ivshmem-net-Fix-bogus-transition-to-RESET-state.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0029-ivshmem-net-Fix-bogus-transition-to-RESET-state.patch
new file mode 100644
index 00000000..335c6bdb
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0029-ivshmem-net-Fix-bogus-transition-to-RESET-state.patch
@@ -0,0 +1,31 @@
+From 1a0998da61deead1dbb38393fedaefee69f59044 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 4 Mar 2018 13:16:04 +0100
+Subject: [PATCH 29/32] ivshmem-net: Fix bogus transition to RESET state
+
+If we are in READY but the remote is still in INIT, we so far fell back
+to RESET which caused the setup to get stuck. Fix this by only
+transitioning from READY/RUN to RESET in ivshm_net_state_change if the
+remote is in RESET as well.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 6fa7a6c81bf1..0c503194b4ec 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -598,7 +598,7 @@ static void ivshm_net_state_change(struct work_struct *work)
+ if (rstate >= IVSHM_NET_STATE_READY) {
+ netif_carrier_on(ndev);
+ ivshm_net_run(ndev);
+- } else {
++ } else if (rstate == IVSHM_NET_STATE_RESET) {
+ netif_carrier_off(ndev);
+ ivshm_net_do_stop(ndev);
+ }
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0030-ivshmem-net-Refactor-and-comment-ivshm_net_state_cha.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0030-ivshmem-net-Refactor-and-comment-ivshm_net_state_cha.patch
new file mode 100644
index 00000000..42ca05a0
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0030-ivshmem-net-Refactor-and-comment-ivshm_net_state_cha.patch
@@ -0,0 +1,68 @@
+From a3ee1ba8e4948ac4e6e4eae3061b72b3bf867122 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 4 Mar 2018 13:50:24 +0100
+Subject: [PATCH 30/32] ivshmem-net: Refactor and comment
+ ivshm_net_state_change
+
+This should make the state transitioning logic clearer. Also avoid the
+harmless but redundant netif_carrier_on/ivshm_net_run in RUN state.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 23 ++++++++++++++++++++---
+ 1 file changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 0c503194b4ec..aba77c232c48 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -575,14 +575,21 @@ static void ivshm_net_state_change(struct work_struct *work)
+ struct net_device *ndev = in->napi.dev;
+ u32 rstate = readl(&in->ivshm_regs->rstate);
+
+-
+ switch (in->lstate) {
+ case IVSHM_NET_STATE_RESET:
++ /*
++ * Wait for the remote to leave READY/RUN before transitioning
++ * to INIT.
++ */
+ if (rstate < IVSHM_NET_STATE_READY)
+ ivshm_net_set_state(in, IVSHM_NET_STATE_INIT);
+ break;
+
+ case IVSHM_NET_STATE_INIT:
++ /*
++ * Wait for the remote to leave RESET before performing the
++ * initialization and moving to READY.
++ */
+ if (rstate > IVSHM_NET_STATE_RESET) {
+ ivshm_net_init_queues(ndev);
+ ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
+@@ -594,11 +601,21 @@ static void ivshm_net_state_change(struct work_struct *work)
+ break;
+
+ case IVSHM_NET_STATE_READY:
+- case IVSHM_NET_STATE_RUN:
++ /*
++ * Link is up and we are running once the remote is in READY or
++ * RUN.
++ */
+ if (rstate >= IVSHM_NET_STATE_READY) {
+ netif_carrier_on(ndev);
+ ivshm_net_run(ndev);
+- } else if (rstate == IVSHM_NET_STATE_RESET) {
++ break;
++ }
++ /* fall through */
++ case IVSHM_NET_STATE_RUN:
++ /*
++ * If the remote goes to RESET, we need to follow immediately.
++ */
++ if (rstate == IVSHM_NET_STATE_RESET) {
+ netif_carrier_off(ndev);
+ ivshm_net_do_stop(ndev);
+ }
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0031-ivshmem-net-Switch-to-netdev_xmit_more-helper.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0031-ivshmem-net-Switch-to-netdev_xmit_more-helper.patch
new file mode 100644
index 00000000..bedbc59f
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0031-ivshmem-net-Switch-to-netdev_xmit_more-helper.patch
@@ -0,0 +1,59 @@
+From 6c86f9ef9fa5029b8f87867f47fe51d6cc1960a5 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 2 Jun 2019 11:58:20 +0200
+Subject: [PATCH 31/32] ivshmem-net: Switch to netdev_xmit_more helper
+
+The skb field has been removed by 4f296edeb9d4.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index aba77c232c48..9946cef63c1f 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -294,7 +294,8 @@ static u32 ivshm_net_tx_advance(struct ivshm_net_queue *q, u32 *pos, u32 len)
+ return p;
+ }
+
+-static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb)
++static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb,
++ bool xmit_more)
+ {
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *tx = &in->tx;
+@@ -327,7 +328,7 @@ static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb)
+ vr->avail->ring[avail] = desc_idx;
+ tx->num_added++;
+
+- if (!skb->xmit_more) {
++ if (!xmit_more) {
+ virt_store_release(&vr->avail->idx, tx->last_avail_idx);
+ ivshm_net_notify_tx(in, tx->num_added);
+ tx->num_added = 0;
+@@ -509,17 +510,18 @@ static int ivshm_net_poll(struct napi_struct *napi, int budget)
+ static netdev_tx_t ivshm_net_xmit(struct sk_buff *skb, struct net_device *ndev)
+ {
+ struct ivshm_net *in = netdev_priv(ndev);
++ bool xmit_more = netdev_xmit_more();
+
+ ivshm_net_tx_clean(ndev);
+
+ if (!ivshm_net_tx_ok(in, ndev->mtu)) {
+ ivshm_net_enable_tx_irq(in);
+ netif_stop_queue(ndev);
+- skb->xmit_more = 0;
++ xmit_more = false;
+ in->stats.tx_pause++;
+ }
+
+- ivshm_net_tx_frame(ndev, skb);
++ ivshm_net_tx_frame(ndev, skb, xmit_more);
+
+ in->stats.tx_packets++;
+ ndev->stats.tx_packets++;
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/0032-ivshmem-net-Adjust-to-reworked-version-of-ivshmem-in.patch b/meta-agl-jailhouse/recipes-kernel/linux/linux/0032-ivshmem-net-Adjust-to-reworked-version-of-ivshmem-in.patch
new file mode 100644
index 00000000..dc10cd2f
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/0032-ivshmem-net-Adjust-to-reworked-version-of-ivshmem-in.patch
@@ -0,0 +1,650 @@
+From 9caa6a8cab0d7f46475990aaeb7dcc7721547ef0 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Mon, 5 Dec 2016 15:43:53 +0100
+Subject: [PATCH 32/32] ivshmem-net: Adjust to reworked version of ivshmem in
+ Jailhouse
+
+This contains the changes required to work with the new revision of
+ivshmem in Jailhouse, namely:
+
+- changed PCI vendor and device ID
+- vendor capability to communicate region location
+- new MMIO register layout
+- common interrupt control register
+- state table support, removal of rstate register
+- unidirectional shared memory regions
+- vector value has to be written to doorbell register
+- support for multiple vectors, used to split config from tx-rx
+
+Note: Specification work for the interface is ongoing, so details may
+still change.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ivshmem-net.c | 335 ++++++++++++++++++++++++++++++----------------
+ 1 file changed, 223 insertions(+), 112 deletions(-)
+
+diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
+index 9946cef63c1f..18d5a15dbec2 100644
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -1,5 +1,6 @@
+ /*
+ * Copyright 2016 Mans Rullgard <mans@mansr.com>
++ * Copyright (c) Siemens AG, 2016-2020
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -15,6 +16,7 @@
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
++#include <linux/ivshmem.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
+@@ -28,34 +30,28 @@
+
+ #define DRV_NAME "ivshmem-net"
+
+-#define JAILHOUSE_CFG_SHMEM_PTR 0x40
+-#define JAILHOUSE_CFG_SHMEM_SZ 0x48
++#define IVSHM_NET_STATE_RESET 0
++#define IVSHM_NET_STATE_INIT 1
++#define IVSHM_NET_STATE_READY 2
++#define IVSHM_NET_STATE_RUN 3
+
+-#define IVSHMEM_INTX_ENABLE 0x1
++#define IVSHM_NET_FLAG_RUN 0
+
+-#define IVSHM_NET_STATE_RESET 0
+-#define IVSHM_NET_STATE_INIT 1
+-#define IVSHM_NET_STATE_READY 2
+-#define IVSHM_NET_STATE_RUN 3
+-
+-#define IVSHM_NET_FLAG_RUN 0
+-
+-#define IVSHM_NET_MTU_MIN 256
+-#define IVSHM_NET_MTU_MAX 65535
+-#define IVSHM_NET_MTU_DEF 16384
++#define IVSHM_NET_MTU_MIN 256
++#define IVSHM_NET_MTU_MAX 65535
++#define IVSHM_NET_MTU_DEF 16384
+
+ #define IVSHM_NET_FRAME_SIZE(s) ALIGN(18 + (s), SMP_CACHE_BYTES)
+
+ #define IVSHM_NET_VQ_ALIGN 64
+
+-struct ivshmem_regs {
+- u32 intxctrl;
+- u32 istat;
+- u32 ivpos;
+- u32 doorbell;
+- u32 lstate;
+- u32 rstate;
+-};
++#define IVSHM_NET_SECTION_TX 0
++#define IVSHM_NET_SECTION_RX 1
++
++#define IVSHM_NET_MSIX_STATE 0
++#define IVSHM_NET_MSIX_TX_RX 1
++
++#define IVSHM_NET_NUM_VECTORS 2
+
+ struct ivshm_net_queue {
+ struct vring vr;
+@@ -73,7 +69,7 @@ struct ivshm_net_queue {
+ };
+
+ struct ivshm_net_stats {
+- u32 interrupts;
++ u32 tx_rx_interrupts;
+ u32 tx_packets;
+ u32 tx_notify;
+ u32 tx_pause;
+@@ -97,8 +93,9 @@ struct ivshm_net {
+
+ struct napi_struct napi;
+
+- u32 lstate;
+- u32 rstate;
++ u32 state;
++ u32 last_peer_state;
++ u32 *state_table;
+
+ unsigned long flags;
+
+@@ -107,17 +104,19 @@ struct ivshm_net {
+
+ struct ivshm_net_stats stats;
+
+- struct ivshmem_regs __iomem *ivshm_regs;
+- void *shm;
+- phys_addr_t shmaddr;
++ struct ivshm_regs __iomem *ivshm_regs;
++ void *shm[2];
+ resource_size_t shmlen;
+ u32 peer_id;
+
++ u32 tx_rx_vector;
++
+ struct pci_dev *pdev;
+ };
+
+ static void *ivshm_net_desc_data(struct ivshm_net *in,
+ struct ivshm_net_queue *q,
++ unsigned int region,
+ struct vring_desc *desc,
+ u32 *len)
+ {
+@@ -132,7 +131,7 @@ static void *ivshm_net_desc_data(struct ivshm_net *in,
+ if (offs >= in->shmlen)
+ return NULL;
+
+- data = in->shm + offs;
++ data = in->shm[region] + offs;
+
+ if (data < q->data || data >= q->end)
+ return NULL;
+@@ -160,18 +159,17 @@ static void ivshm_net_init_queue(struct ivshm_net *in,
+ static void ivshm_net_init_queues(struct net_device *ndev)
+ {
+ struct ivshm_net *in = netdev_priv(ndev);
+- int ivpos = readl(&in->ivshm_regs->ivpos);
+ void *tx;
+ void *rx;
+ int i;
+
+- tx = in->shm + ivpos * in->shmlen / 2;
+- rx = in->shm + !ivpos * in->shmlen / 2;
++ tx = in->shm[IVSHM_NET_SECTION_TX];
++ rx = in->shm[IVSHM_NET_SECTION_RX];
+
+- memset(tx, 0, in->shmlen / 2);
++ memset(tx, 0, in->shmlen);
+
+- ivshm_net_init_queue(in, &in->rx, rx, in->qlen);
+ ivshm_net_init_queue(in, &in->tx, tx, in->qlen);
++ ivshm_net_init_queue(in, &in->rx, rx, in->qlen);
+
+ swap(in->rx.vr.used, in->tx.vr.used);
+
+@@ -191,14 +189,14 @@ static int ivshm_net_calc_qsize(struct net_device *ndev)
+ for (qlen = 4096; qlen > 32; qlen >>= 1) {
+ vrsize = vring_size(qlen, IVSHM_NET_VQ_ALIGN);
+ vrsize = ALIGN(vrsize, IVSHM_NET_VQ_ALIGN);
+- if (vrsize < in->shmlen / 16)
++ if (vrsize < in->shmlen / 8)
+ break;
+ }
+
+- if (vrsize > in->shmlen / 2)
++ if (vrsize > in->shmlen)
+ return -EINVAL;
+
+- qsize = in->shmlen / 2 - vrsize;
++ qsize = in->shmlen - vrsize;
+
+ if (qsize < 4 * IVSHM_NET_MTU_MIN)
+ return -EINVAL;
+@@ -221,7 +219,8 @@ static void ivshm_net_notify_tx(struct ivshm_net *in, unsigned int num)
+ new = in->tx.last_avail_idx;
+
+ if (vring_need_event(evt, new, old)) {
+- writel(in->peer_id << 16, &in->ivshm_regs->doorbell);
++ writel(in->tx_rx_vector | (in->peer_id << 16),
++ &in->ivshm_regs->doorbell);
+ in->stats.tx_notify++;
+ }
+ }
+@@ -243,7 +242,8 @@ static void ivshm_net_notify_rx(struct ivshm_net *in, unsigned int num)
+ new = in->rx.last_used_idx;
+
+ if (vring_need_event(evt, new, old)) {
+- writel(in->peer_id << 16, &in->ivshm_regs->doorbell);
++ writel(in->tx_rx_vector | (in->peer_id << 16),
++ &in->ivshm_regs->doorbell);
+ in->stats.rx_notify++;
+ }
+ }
+@@ -320,7 +320,7 @@ static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb,
+ buf = tx->data + head;
+ skb_copy_and_csum_dev(skb, buf);
+
+- desc->addr = buf - in->shm;
++ desc->addr = buf - in->shm[IVSHM_NET_SECTION_TX];
+ desc->len = skb->len;
+ desc->flags = 0;
+
+@@ -374,7 +374,8 @@ static void ivshm_net_tx_clean(struct net_device *ndev)
+
+ desc = &vr->desc[used->id];
+
+- data = ivshm_net_desc_data(in, &in->tx, desc, &len);
++ data = ivshm_net_desc_data(in, &in->tx, IVSHM_NET_SECTION_TX,
++ desc, &len);
+ if (!data) {
+ netdev_err(ndev, "bad tx descriptor, data == NULL\n");
+ break;
+@@ -466,7 +467,8 @@ static int ivshm_net_poll(struct napi_struct *napi, int budget)
+ if (!desc)
+ break;
+
+- data = ivshm_net_desc_data(in, &in->rx, desc, &len);
++ data = ivshm_net_desc_data(in, &in->rx, IVSHM_NET_SECTION_RX,
++ desc, &len);
+ if (!data) {
+ netdev_err(ndev, "bad rx descriptor\n");
+ break;
+@@ -535,15 +537,15 @@ static netdev_tx_t ivshm_net_xmit(struct sk_buff *skb, struct net_device *ndev)
+ static void ivshm_net_set_state(struct ivshm_net *in, u32 state)
+ {
+ virt_wmb();
+- WRITE_ONCE(in->lstate, state);
+- writel(state, &in->ivshm_regs->lstate);
++ WRITE_ONCE(in->state, state);
++ writel(state, &in->ivshm_regs->state);
+ }
+
+ static void ivshm_net_run(struct net_device *ndev)
+ {
+ struct ivshm_net *in = netdev_priv(ndev);
+
+- if (in->lstate < IVSHM_NET_STATE_READY)
++ if (in->state < IVSHM_NET_STATE_READY)
+ return;
+
+ if (!netif_running(ndev))
+@@ -575,15 +577,15 @@ static void ivshm_net_state_change(struct work_struct *work)
+ {
+ struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
+ struct net_device *ndev = in->napi.dev;
+- u32 rstate = readl(&in->ivshm_regs->rstate);
++ u32 peer_state = READ_ONCE(in->state_table[in->peer_id]);
+
+- switch (in->lstate) {
++ switch (in->state) {
+ case IVSHM_NET_STATE_RESET:
+ /*
+ * Wait for the remote to leave READY/RUN before transitioning
+ * to INIT.
+ */
+- if (rstate < IVSHM_NET_STATE_READY)
++ if (peer_state < IVSHM_NET_STATE_READY)
+ ivshm_net_set_state(in, IVSHM_NET_STATE_INIT);
+ break;
+
+@@ -592,7 +594,7 @@ static void ivshm_net_state_change(struct work_struct *work)
+ * Wait for the remote to leave RESET before performing the
+ * initialization and moving to READY.
+ */
+- if (rstate > IVSHM_NET_STATE_RESET) {
++ if (peer_state > IVSHM_NET_STATE_RESET) {
+ ivshm_net_init_queues(ndev);
+ ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
+
+@@ -607,7 +609,7 @@ static void ivshm_net_state_change(struct work_struct *work)
+ * Link is up and we are running once the remote is in READY or
+ * RUN.
+ */
+- if (rstate >= IVSHM_NET_STATE_READY) {
++ if (peer_state >= IVSHM_NET_STATE_READY) {
+ netif_carrier_on(ndev);
+ ivshm_net_run(ndev);
+ break;
+@@ -617,7 +619,7 @@ static void ivshm_net_state_change(struct work_struct *work)
+ /*
+ * If the remote goes to RESET, we need to follow immediately.
+ */
+- if (rstate == IVSHM_NET_STATE_RESET) {
++ if (peer_state == IVSHM_NET_STATE_RESET) {
+ netif_carrier_off(ndev);
+ ivshm_net_do_stop(ndev);
+ }
+@@ -625,31 +627,44 @@ static void ivshm_net_state_change(struct work_struct *work)
+ }
+
+ virt_wmb();
+- WRITE_ONCE(in->rstate, rstate);
++ WRITE_ONCE(in->last_peer_state, peer_state);
+ }
+
+-static void ivshm_net_check_state(struct net_device *ndev)
++static void ivshm_net_check_state(struct ivshm_net *in)
+ {
+- struct ivshm_net *in = netdev_priv(ndev);
+- u32 rstate = readl(&in->ivshm_regs->rstate);
+-
+- if (rstate != in->rstate || !test_bit(IVSHM_NET_FLAG_RUN, &in->flags))
++ if (in->state_table[in->peer_id] != in->last_peer_state ||
++ !test_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ queue_work(in->state_wq, &in->state_work);
+ }
+
+-static irqreturn_t ivshm_net_int(int irq, void *data)
++static irqreturn_t ivshm_net_int_state(int irq, void *data)
+ {
+- struct net_device *ndev = data;
+- struct ivshm_net *in = netdev_priv(ndev);
++ struct ivshm_net *in = data;
++
++ ivshm_net_check_state(in);
++
++ return IRQ_HANDLED;
++}
+
+- in->stats.interrupts++;
++static irqreturn_t ivshm_net_int_tx_rx(int irq, void *data)
++{
++ struct ivshm_net *in = data;
++
++ in->stats.tx_rx_interrupts++;
+
+- ivshm_net_check_state(ndev);
+ napi_schedule_irqoff(&in->napi);
+
+ return IRQ_HANDLED;
+ }
+
++static irqreturn_t ivshm_net_intx(int irq, void *data)
++{
++ ivshm_net_int_state(irq, data);
++ ivshm_net_int_tx_rx(irq, data);
++
++ return IRQ_HANDLED;
++}
++
+ static int ivshm_net_open(struct net_device *ndev)
+ {
+ netdev_reset_queue(ndev);
+@@ -717,7 +732,7 @@ static const struct net_device_ops ivshm_net_ops = {
+ };
+
+ static const char ivshm_net_stats[][ETH_GSTRING_LEN] = {
+- "interrupts",
++ "tx_rx_interrupts",
+ "tx_packets",
+ "tx_notify",
+ "tx_pause",
+@@ -760,7 +775,7 @@ static void ivshm_net_get_ethtool_stats(struct net_device *ndev,
+ unsigned int n = 0;
+ unsigned int i;
+
+- st[n++] = in->stats.interrupts;
++ st[n++] = in->stats.tx_rx_interrupts;
+ st[n++] = in->stats.tx_packets;
+ st[n++] = in->stats.tx_notify;
+ st[n++] = in->stats.tx_pause;
+@@ -789,8 +804,8 @@ static void ivshm_net_get_regs(struct net_device *ndev,
+ u32 *reg32 = p;
+ u16 *reg16;
+
+- *reg32++ = in->lstate;
+- *reg32++ = in->rstate;
++ *reg32++ = in->state;
++ *reg32++ = in->last_peer_state;
+ *reg32++ = in->qlen;
+
+ reg16 = (u16 *)reg32;
+@@ -812,17 +827,28 @@ static const struct ethtool_ops ivshm_net_ethtool_ops = {
+ .get_regs = ivshm_net_get_regs,
+ };
+
++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_net_probe(struct pci_dev *pdev,
+- const struct pci_device_id *id)
++ const struct pci_device_id *pci_id)
+ {
++ phys_addr_t output_sections_addr, section_addr;
++ resource_size_t section_sz, output_section_sz;
++ void *state_table, *output_sections;
++ struct ivshm_regs __iomem *regs;
+ struct net_device *ndev;
+ struct ivshm_net *in;
+- struct ivshmem_regs __iomem *regs;
+- resource_size_t shmaddr;
+- resource_size_t shmlen;
++ unsigned int cap_pos;
+ char *device_name;
+- void *shm;
+- u32 ivpos;
++ int vendor_cap;
++ u32 id, dword;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+@@ -839,40 +865,75 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+
+ regs = pcim_iomap_table(pdev)[0];
+
+- shmlen = pci_resource_len(pdev, 2);
++ id = readl(&regs->id);
++ if (id > 1) {
++ dev_err(&pdev->dev, "invalid ID %d\n", id);
++ return -EINVAL;
++ }
++ if (readl(&regs->max_peers) > 2) {
++ dev_err(&pdev->dev, "only 2 peers supported\n");
++ return -EINVAL;
++ }
++
++ vendor_cap = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
++ if (vendor_cap < 0) {
++ dev_err(&pdev->dev, "missing vendor capability\n");
++ return -EINVAL;
++ }
+
+- if (shmlen) {
+- shmaddr = pci_resource_start(pdev, 2);
++ if (pci_resource_len(pdev, 2) > 0) {
++ section_addr = pci_resource_start(pdev, 2);
+ } else {
+- union { u64 v; u32 hl[2]; } val;
+-
+- pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_PTR,
+- &val.hl[0]);
+- pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_PTR + 4,
+- &val.hl[1]);
+- shmaddr = val.v;
+-
+- pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_SZ,
+- &val.hl[0]);
+- pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_SZ + 4,
+- &val.hl[1]);
+- shmlen = val.v;
++ cap_pos = vendor_cap + IVSHM_CFG_ADDRESS;
++ section_addr = get_config_qword(pdev, cap_pos);
+ }
+
++ cap_pos = vendor_cap + IVSHM_CFG_STATE_TAB_SZ;
++ pci_read_config_dword(pdev, cap_pos, &dword);
++ section_sz = dword;
+
+- if (!devm_request_mem_region(&pdev->dev, shmaddr, shmlen, DRV_NAME))
++ if (!devm_request_mem_region(&pdev->dev, section_addr, section_sz,
++ DRV_NAME))
+ return -EBUSY;
+
+- shm = devm_memremap(&pdev->dev, shmaddr, shmlen, MEMREMAP_WB);
+- if (!shm)
++ state_table = devm_memremap(&pdev->dev, section_addr, section_sz,
++ MEMREMAP_WB);
++ if (!state_table)
+ return -ENOMEM;
+
+- ivpos = readl(&regs->ivpos);
+- if (ivpos > 1) {
+- dev_err(&pdev->dev, "invalid IVPosition %d\n", ivpos);
++ output_sections_addr = section_addr + section_sz;
++
++ cap_pos = vendor_cap + IVSHM_CFG_RW_SECTION_SZ;
++ section_sz = get_config_qword(pdev, cap_pos);
++ if (section_sz > 0) {
++ dev_info(&pdev->dev, "R/W section detected - "
++ "unused by this driver version\n");
++ output_sections_addr += section_sz;
++ }
++
++ cap_pos = vendor_cap + IVSHM_CFG_OUTPUT_SECTION_SZ;
++ output_section_sz = get_config_qword(pdev, cap_pos);
++ if (output_section_sz == 0) {
++ dev_err(&pdev->dev, "Missing input/output sections\n");
+ return -EINVAL;
+ }
+
++ if (!devm_request_mem_region(&pdev->dev, output_sections_addr,
++ output_section_sz * 2, DRV_NAME))
++ return -EBUSY;
++
++ output_sections = devm_memremap(&pdev->dev, output_sections_addr,
++ output_section_sz * 2, MEMREMAP_WB);
++ if (!output_sections)
++ return -ENOMEM;
++
++ section_addr = output_sections_addr + output_section_sz * id;
++ dev_info(&pdev->dev, "TX memory at %pa, size %pa\n",
++ &section_addr, &output_section_sz);
++ section_addr = output_sections_addr + output_section_sz * !id;
++ dev_info(&pdev->dev, "RX memory at %pa, size %pa\n",
++ &section_addr, &output_section_sz);
++
+ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s[%s]", DRV_NAME,
+ dev_name(&pdev->dev));
+ if (!device_name)
+@@ -887,10 +948,16 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+
+ in = netdev_priv(ndev);
+ in->ivshm_regs = regs;
+- in->shm = shm;
+- in->shmaddr = shmaddr;
+- in->shmlen = shmlen;
+- in->peer_id = !ivpos;
++ in->state_table = state_table;
++
++ in->shm[IVSHM_NET_SECTION_TX] =
++ output_sections + output_section_sz * id;
++ in->shm[IVSHM_NET_SECTION_RX] =
++ output_sections + output_section_sz * !id;
++
++ in->shmlen = output_section_sz;
++
++ in->peer_id = !id;
+ in->pdev = pdev;
+ spin_lock_init(&in->tx_free_lock);
+ spin_lock_init(&in->tx_clean_lock);
+@@ -919,24 +986,64 @@ static int ivshm_net_probe(struct pci_dev *pdev,
+ if (ret)
+ goto err_wq;
+
+- ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY | PCI_IRQ_MSIX);
++ ret = pci_alloc_irq_vectors(pdev, 1, 2, PCI_IRQ_LEGACY | PCI_IRQ_MSIX);
+ if (ret < 0)
+ goto err_alloc_irq;
+
+- ret = request_irq(pci_irq_vector(pdev, 0), ivshm_net_int, 0,
+- device_name, ndev);
+- if (ret)
+- goto err_request_irq;
++ if (pdev->msix_enabled) {
++ if (ret != 2) {
++ ret = -EBUSY;
++ goto err_request_irq;
++ }
++
++ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
++ "%s-state[%s]", DRV_NAME,
++ dev_name(&pdev->dev));
++ if (!device_name) {
++ ret = -ENOMEM;
++ goto err_request_irq;
++ }
++
++ ret = request_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE),
++ ivshm_net_int_state, 0, device_name, in);
++ if (ret)
++ goto err_request_irq;
++
++ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
++ "%s-tx-rx[%s]", DRV_NAME,
++ dev_name(&pdev->dev));
++ if (!device_name) {
++ ret = -ENOMEM;
++ goto err_request_irq2;
++ }
++
++ ret = request_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_TX_RX),
++ ivshm_net_int_tx_rx, 0, device_name, in);
++ if (ret)
++ goto err_request_irq2;
++
++ in->tx_rx_vector = IVSHM_NET_MSIX_TX_RX;
++ } else {
++ ret = request_irq(pci_irq_vector(pdev, 0), ivshm_net_intx, 0,
++ device_name, in);
++ if (ret)
++ goto err_request_irq;
++
++ in->tx_rx_vector = 0;
++ }
+
+ pci_set_master(pdev);
+- if (!pdev->msix_enabled)
+- writel(IVSHMEM_INTX_ENABLE, &in->ivshm_regs->intxctrl);
+
+- writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+- ivshm_net_check_state(ndev);
++ pci_write_config_byte(pdev, vendor_cap + IVSHM_CFG_PRIV_CNTL, 0);
++ writel(IVSHM_INT_ENABLE, &in->ivshm_regs->int_control);
++
++ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->state);
++ ivshm_net_check_state(in);
+
+ return 0;
+
++err_request_irq2:
++ free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE), in);
+ err_request_irq:
+ pci_free_irq_vectors(pdev);
+ err_alloc_irq:
+@@ -954,11 +1061,15 @@ static void ivshm_net_remove(struct pci_dev *pdev)
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ivshm_net *in = netdev_priv(ndev);
+
+- writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
++ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->state);
++ writel(0, &in->ivshm_regs->int_control);
+
+- if (!pdev->msix_enabled)
+- writel(0, &in->ivshm_regs->intxctrl);
+- free_irq(pci_irq_vector(pdev, 0), ndev);
++ if (pdev->msix_enabled) {
++ free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE), in);
++ free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_TX_RX), in);
++ } else {
++ free_irq(pci_irq_vector(pdev, 0), in);
++ }
+ pci_free_irq_vectors(pdev);
+
+ unregister_netdev(ndev);
+@@ -968,8 +1079,8 @@ static void ivshm_net_remove(struct pci_dev *pdev)
+ }
+
+ static const struct pci_device_id ivshm_net_id_table[] = {
+- { PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, 0x1110),
+- (PCI_CLASS_OTHERS << 16) | (0x01 << 8), 0xffff00 },
++ { PCI_DEVICE(PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_IVSHMEM),
++ (PCI_CLASS_OTHERS << 16) | IVSHM_PROTO_NET, 0xffffff },
+ { 0 }
+ };
+ MODULE_DEVICE_TABLE(pci, ivshm_net_id_table);
+--
+2.11.0
+
diff --git a/meta-agl-jailhouse/recipes-kernel/linux/linux/jailhouse.cfg b/meta-agl-jailhouse/recipes-kernel/linux/linux/jailhouse.cfg
new file mode 100644
index 00000000..d417e556
--- /dev/null
+++ b/meta-agl-jailhouse/recipes-kernel/linux/linux/jailhouse.cfg
@@ -0,0 +1,10 @@
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PCI_HOST_GENERIC=y
+
+CONFIG_HOTPLUG_PCI=y
+CONFIG_IVSHMEM_NET=y
+
+CONFIG_UIO=y
+CONFIG_UIO_IVSHMEM=y
+CONFIG_VIRT_DRIVERS=y
+CONFIG_JAILHOUSE_DBGCON=y