On 03/01/20 10:22 pm, Jan Kiszka wrote:
Please make sure a "From:" line is at the top so that I don't have to
add that manually. git will add that line when you set a different
--from when calling format-patch.
Sure, This time i used git format-patch ..... -4 to format, annotate and send directly.
will check why the from: line is missing

On 30.12.19 14:24, 'Nikhil Devshatwar' via Jailhouse wrote:
Add support for Texas Instrument's Peripheral Virtualization Unit
* Define a new IOMMU type and extra fields in the platform_data
* Add new cofig option CONFIG_IOMMU_TI_PVU
* Integrate with the arm iommu support such that multiple types
   of IOMMU can be supported.

Signed-off-by: Nikhil Devshatwar <[email protected]>
---
  hypervisor/arch/arm-common/include/asm/cell.h |   7 +
  .../arch/arm-common/include/asm/iommu.h       |   1 +
  .../arch/arm-common/include/asm/ti-pvu.h      |  32 +
  hypervisor/arch/arm-common/iommu.c            |   9 +
  hypervisor/arch/arm64/Kbuild                  |   1 +
  hypervisor/arch/arm64/ti-pvu.c                | 556 ++++++++++++++++++
  hypervisor/arch/arm64/ti-pvu_priv.h           | 141 +++++
  include/jailhouse/cell-config.h               |   4 +
  8 files changed, 751 insertions(+)
  create mode 100644 hypervisor/arch/arm-common/include/asm/ti-pvu.h
  create mode 100644 hypervisor/arch/arm64/ti-pvu.c
  create mode 100644 hypervisor/arch/arm64/ti-pvu_priv.h

diff --git a/hypervisor/arch/arm-common/include/asm/cell.h b/hypervisor/arch/arm-common/include/asm/cell.h
index 5b1e4207..9c6e8c6f 100644
--- a/hypervisor/arch/arm-common/include/asm/cell.h
+++ b/hypervisor/arch/arm-common/include/asm/cell.h
@@ -15,10 +15,17 @@

  #include <jailhouse/paging.h>

+struct pvu_tlb_entry;
+
  struct arch_cell {
      struct paging_structures mm;

      u32 irq_bitmap[1024/32];
+
+    struct {
+        u8 ent_count;
+        struct pvu_tlb_entry *entries;
+    } iommu_pvu; /**< ARM PVU specific fields. */
  };

  #endif /* !_JAILHOUSE_ASM_CELL_H */
diff --git a/hypervisor/arch/arm-common/include/asm/iommu.h b/hypervisor/arch/arm-common/include/asm/iommu.h
index dde762c0..399248dc 100644
--- a/hypervisor/arch/arm-common/include/asm/iommu.h
+++ b/hypervisor/arch/arm-common/include/asm/iommu.h
@@ -16,6 +16,7 @@
  #include <jailhouse/cell.h>
  #include <jailhouse/utils.h>
  #include <jailhouse/cell-config.h>
+#include <asm/ti-pvu.h>

  #define for_each_stream_id(sid, config, counter)                   \
      for ((sid) = (jailhouse_cell_stream_ids(config)[0]), (counter) = 0;    \ diff --git a/hypervisor/arch/arm-common/include/asm/ti-pvu.h b/hypervisor/arch/arm-common/include/asm/ti-pvu.h
new file mode 100644
index 00000000..a3ef72f7
--- /dev/null
+++ b/hypervisor/arch/arm-common/include/asm/ti-pvu.h
@@ -0,0 +1,32 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * TI PVU IOMMU unit API headers
+ *
+ * Authors:
+ *  Nikhil Devshatwar <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef _IOMMMU_PVU_H_
+#define _IOMMMU_PVU_H_

Re-inclusion protection should only be added when actually needed.

Got it
+
+#include <jailhouse/config.h>
+
+#ifdef CONFIG_IOMMU_TI_PVU

Can we try to model this without a compile-time switch?

Only reason I put a config is because this applies only to one platform.
Will remove this in v2

+
+int pvu_iommu_map_memory(struct cell *cell,
+        const struct jailhouse_memory *mem);
+
+int pvu_iommu_unmap_memory(struct cell *cell,
+        const struct jailhouse_memory *mem);
+
+int pvu_iommu_config_commit(struct cell *cell);
+
+#endif /* CONFIG_IOMMU_TI_PVU */
+
+#endif /* _IOMMMU_PVU_H_ */
diff --git a/hypervisor/arch/arm-common/iommu.c b/hypervisor/arch/arm-common/iommu.c
index b3100d03..b6b61f52 100644
--- a/hypervisor/arch/arm-common/iommu.c
+++ b/hypervisor/arch/arm-common/iommu.c
@@ -26,15 +26,24 @@ unsigned int iommu_count_units(void)
  int iommu_map_memory_region(struct cell *cell,
                  const struct jailhouse_memory *mem)
  {
+#ifdef CONFIG_IOMMU_TI_PVU
+    return pvu_iommu_map_memory(cell, mem);
+#endif
      return 0;
  }

  int iommu_unmap_memory_region(struct cell *cell,
                    const struct jailhouse_memory *mem)
  {
+#ifdef CONFIG_IOMMU_TI_PVU
+    return pvu_iommu_unmap_memory(cell, mem);
+#endif
      return 0;
  }

  void iommu_config_commit(struct cell *cell)
  {
+#ifdef CONFIG_IOMMU_TI_PVU
+    pvu_iommu_config_commit(cell);
+#endif
  }
diff --git a/hypervisor/arch/arm64/Kbuild b/hypervisor/arch/arm64/Kbuild
index 323b78b6..8012c46e 100644
--- a/hypervisor/arch/arm64/Kbuild
+++ b/hypervisor/arch/arm64/Kbuild
@@ -21,3 +21,4 @@ always := lib.a

  lib-y := $(common-objs-y)
  lib-y += entry.o setup.o control.o mmio.o paging.o caches.o traps.o smmu-v3.o
+lib-$(CONFIG_IOMMU_TI_PVU) += ti-pvu.o
diff --git a/hypervisor/arch/arm64/ti-pvu.c b/hypervisor/arch/arm64/ti-pvu.c
new file mode 100644
index 00000000..02380baa
--- /dev/null
+++ b/hypervisor/arch/arm64/ti-pvu.c
@@ -0,0 +1,556 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * TI PVU IOMMU unit
+ *
+ * Peripheral Virtualization Unit(PVU) is an IOMMU (memory management
+ * unit for DMA) which is designed for 2nd stage address translation in a
+ * real time manner.
+ *
+ * Unlike ARM-SMMU, all the memory mapping information is stored in the
+ * local registers instead of the in-memory page tables.
+ *
+ * There are limitations on the number of available contexts, page sizes,
+ * number of pages that can be mapped, etc.
+ *
+ * PVU is desgined to be programmed with all the memory mapping at once. + * Therefore, it defers the actual register programming till config_commit.
+ * Also, it does not support unmapping of the pages at runtime.
+ *
+ * Authors:
+ *  Nikhil Devshatwar <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <jailhouse/unit.h>
+#include <jailhouse/cell.h>
+#include <jailhouse/entry.h>
+#include <jailhouse/paging.h>
+#include <jailhouse/control.h>
+#include <jailhouse/printk.h>
+#include <asm/iommu.h>
+#include <asm/ti-pvu.h>
+#include "ti-pvu_priv.h"

Single-user header - let's fold this in.
alright

+
+#define MAX_PVU_ENTRIES        (PAGE_SIZE / sizeof (struct pvu_tlb_entry))
+#define MAX_VIRTID          7
+
+static struct pvu_dev pvu_units[JAILHOUSE_MAX_IOMMU_UNITS];
+static unsigned int pvu_count;
+
+static const u64 PVU_PAGE_SIZE_BYTES[] = {

This is not a macro or define, so let's decapitalize its name.
will do

+    [LPAE_PAGE_SZ_4K]        =   4 * 1024,
+    [LPAE_PAGE_SZ_16K]        =  16 * 1024,
+    [LPAE_PAGE_SZ_64K]        =  64 * 1024,
+    [LPAE_PAGE_SZ_2M]        =   2 * 1024 * 1024,
+    [LPAE_PAGE_SZ_32M]        =  32 * 1024 * 1024,
+    [LPAE_PAGE_SZ_512M]        = 512 * 1024 * 1024,
+    [LPAE_PAGE_SZ_1G]        =   1 * 1024 * 1024 * 1024,
+    [LPAE_PAGE_SZ_16G]        =  16ULL * 1024 * 1024 * 1024,

Is there another use case the LPAE_PAGE_SZ constants in sight?
Otherwise, I would simply fill the array in the right order with the
actual values.

will do
+};
+
+static inline u32 is_aligned(u64 addr, u64 size)
+{
+    return (addr % size) == 0;
+}
+
+static void pvu_tlb_enable(struct pvu_dev *dev, u16 tlbnum)
+{
+    struct pvu_hw_tlb *tlb;
+
+    tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum;
+    mmio_write32_field(&tlb->chain, PVU_TLB_LOG_DIS_MASK, 0);
+    mmio_write32_field(&tlb->chain, PVU_TLB_EN_MASK, 1);
+}
+
+static void pvu_tlb_disable(struct pvu_dev *dev, u16 tlbnum)
+{
+    struct pvu_hw_tlb *tlb;
+
+    tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum;
+    mmio_write32_field(&tlb->chain, PVU_TLB_EN_MASK, 0);
+    mmio_write32_field(&tlb->chain, PVU_TLB_LOG_DIS_MASK, 1);
+}
+
+static u32 pvu_tlb_is_enabled(struct pvu_dev *dev, u16 tlbnum)
+{
+    struct pvu_hw_tlb *tlb;
+
+    tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum;
+    if (mmio_read32_field(&tlb->chain, PVU_TLB_EN_MASK))
+        return 1;
+    else
+        return 0;
+}
+
+static int pvu_tlb_chain(struct pvu_dev *dev, u16 tlbnum, u16 tlb_next)
+{
+    struct pvu_hw_tlb *tlb;
+
+    if (tlb_next <= tlbnum || tlb_next <= dev->max_virtid)
+        return -EINVAL;
+
+    tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum;
+    mmio_write32_field(&tlb->chain, PVU_TLB_CHAIN_MASK, tlb_next);
+    return 0;
+}
+
+static u32 pvu_tlb_next(struct pvu_dev *dev, u16 tlbnum)
+{
+    struct pvu_hw_tlb *tlb;
+
+    tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum;
+    return mmio_read32_field(&tlb->chain, PVU_TLB_CHAIN_MASK);
+}
+
+static u32 pvu_tlb_alloc(struct pvu_dev *dev, u16 virtid)
+{
+    int i;

Let's use an appropriate unsigned type here, e.g. unsigned int.
will review signedness of all variables and fix it

+
+    for (i = dev->max_virtid + 1; i < dev->num_tlbs; i++) {
+        if (dev->tlb_data[i] == 0) {
+            dev->tlb_data[i] = virtid << dev->num_entries;
+            return i;
+        }
+

[snip]

+{
+    /*
+     * dummy unmap for now
+     * PVU does not support dynamic unmap
+     * Works well for static partitioning

Huh!? But this breaks cell create/destroy cycles, without any user
notice, no? And will root cell devices keep access to inmate memory that
is carved out during cell creation?

Is that a hardware limitation?

Looks like a blocker...
Yes, this is a hardware limitation. I it designed for static partitioning.
Although, I made sure to not break memory isolatio with the following workaround:

When booting a root cell for Jailhouse, you would typically carveout  memory for the inmate cell. I have defined the cell configs such that, in the root cell config, RAM region for inmate is
NOT marked with MEM_DMA, this way it never gets mapped in PVU.

When creating cell, root cell maps the inmate RAM loadable region, here that memory is not
mapped in IO space.
---> Limitation of this is that you cannot DMA copy the images in the loadable sections,
   which we are not doing anyways

When destroying the cell, Jailhouse should map the memory back to the root cell. Here, again, the inmate RAM region gets ignored in IO mapping because of lacking flag MEM_DMA

cell_create  and cell_destroy work in regression, tested successfully.



+     */
+    return 0;
+}
+
+int pvu_iommu_config_commit(struct cell *cell)
+{

[snip]

+#define LPAE_PAGE_SZ_2M            3
+#define LPAE_PAGE_SZ_32M        4
+#define LPAE_PAGE_SZ_512M        5
+#define LPAE_PAGE_SZ_1G            6
+#define LPAE_PAGE_SZ_16G        7
+
+#define LPAE_PAGE_PERM_UR        (1 << 15)
+#define LPAE_PAGE_PERM_UW        (1 << 14)
+#define LPAE_PAGE_PERM_UX        (1 << 13)
+#define LPAE_PAGE_PERM_SR        (1 << 12)
+#define LPAE_PAGE_PERM_SW        (1 << 11)
+#define LPAE_PAGE_PERM_SX        (1 << 10)
+
+#define LPAE_PAGE_MEM_DEVICE        (0 << 8)
+#define LPAE_PAGE_MEM_WRITEBACK        (1 << 8)

These two are unused - accidentally?

Unused, will remove
+#define LPAE_PAGE_MEM_WRITETHROUGH    (2 << 8) > +
+#define LPAE_PAGE_PREFETCH        (1 << 6)
+#define LPAE_PAGE_INNER_SHARABLE    (1 << 5)

These two as well. I would recommend adding only used constants.
will do

+#define LPAE_PAGE_OUTER_SHARABLE    (1 << 4)
+
+#define LPAE_PAGE_IS_NOALLOC        (0 << 2)
+#define LPAE_PAGE_IS_WR_ALLOC        (1 << 2)
+#define LPAE_PAGE_IS_RD_ALLOC        (2 << 2)
+#define LPAE_PAGE_IS_RDWR_ALLOC        (3 << 2)
+
+#define LPAE_PAGE_OS_NOALLOC        (0 << 0)
+#define LPAE_PAGE_OS_WR_ALLOC        (1 << 0)
+#define LPAE_PAGE_OS_RD_ALLOC        (2 << 0)
+#define LPAE_PAGE_OS_RDWR_ALLOC        (3 << 0)

Here are some unused consts as well.
will remove

+
+struct pvu_hw_tlb_entry {
+    u32        reg0;
+    u32        reg1;
+    u32        reg2;
+    u32        reg3;
+    u32        reg4;
+    u32        reg5;
+    u32        reg6;
+    u32        reg7;

Do these regs really have no names? Can we use an array then?
Yes, the TRM actually has these names for the TLB entry


+};
+
+#define PVU_TLB_EN_MASK            (1 << 31)
+#define PVU_TLB_LOG_DIS_MASK        (1 << 30)
+#define PVU_TLB_FAULT_MASK        (1 << 29)
+#define PVU_TLB_CHAIN_MASK        (0xfff)
+
+struct pvu_hw_tlb {
+    u32            chain;
+    u8            resv_32[28];
+    struct pvu_hw_tlb_entry    entry[8];
+    u8            resv_4096[3808];
+};
+
+struct pvu_tlb_entry {
+    u64        virt_addr;
+    u64        phys_addr;
+    u64        size;
+    u64        flags;
+};
+
+struct pvu_dev {
+    u32        *cfg_base;
+    u32        *tlb_base;
+
+    u32        num_tlbs;
+    u32        num_entries;
+    u16        max_virtid;
+
+    u16        tlb_data[PVU_NUM_TLBS];
+};
+
+#endif /* __TI_PVU_PRIV_H__ */
diff --git a/include/jailhouse/cell-config.h b/include/jailhouse/cell-config.h
index d435b9f7..9bb84492 100644
--- a/include/jailhouse/cell-config.h
+++ b/include/jailhouse/cell-config.h
@@ -203,6 +203,7 @@ struct jailhouse_pci_capability {
  #define JAILHOUSE_IOMMU_AMD        1
  #define JAILHOUSE_IOMMU_INTEL        2
  #define JAILHOUSE_IOMMU_SMMUV3        3
+#define JAILHOUSE_IOMMU_PVU        4

  struct jailhouse_iommu {
      __u32 type;
@@ -213,6 +214,9 @@ struct jailhouse_iommu {
      __u8 amd_base_cap;
      __u8 amd_msi_cap;
      __u32 amd_features;
+
+    __u64 tipvu_tlb_base;
+    __u32 tipvu_tlb_size;

Time to stick the amd fields in their own sub-struct, as well as the
tipvu ones, and then put both struct into a union. Analogously to
jailhouse_system.platform_info.
Agreed, I will do that.

  } __attribute__((packed));

  struct jailhouse_pio {


Jan

Thanks for the review
Nikhil Devshatwar

--
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/22d04be0-c674-16a7-f36f-89f06419372c%40ti.com.

Reply via email to