All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andre Przywara <andre.przywara@arm.com>
To: Stefano Stabellini <sstabellini@kernel.org>,
	Julien Grall <julien.grall@arm.com>
Cc: xen-devel@lists.xenproject.org, Vijay Kilari <vijay.kilari@gmail.com>
Subject: [PATCH 07/28] ARM: GICv3 ITS: introduce device mapping
Date: Mon, 30 Jan 2017 18:31:32 +0000	[thread overview]
Message-ID: <20170130183153.28566-8-andre.przywara@arm.com> (raw)
In-Reply-To: <20170130183153.28566-1-andre.przywara@arm.com>

The ITS uses device IDs to map LPIs to a device. Dom0 will later use
those IDs, which we directly pass on to the host.
For this we have to map each device that Dom0 may request to a host
ITS device with the same identifier.
Allocate the respective memory and enter each device into an rbtree to
later be able to iterate over it or to easily teardown guests.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic-v3-its.c        | 188 ++++++++++++++++++++++++++++++++++++++-
 xen/arch/arm/vgic-v3.c           |   3 +
 xen/include/asm-arm/domain.h     |   3 +
 xen/include/asm-arm/gic_v3_its.h |  28 ++++++
 4 files changed, 221 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 6578e8a..4a3a394 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -21,8 +21,10 @@
 #include <xen/device_tree.h>
 #include <xen/delay.h>
 #include <xen/libfdt/libfdt.h>
-#include <xen/mm.h>
+#include <xen/rbtree.h>
+#include <xen/sched.h>
 #include <xen/sizes.h>
+#include <xen/domain.h>
 #include <asm/gic.h>
 #include <asm/gic_v3_defs.h>
 #include <asm/gic_v3_its.h>
@@ -94,6 +96,21 @@ static int its_send_cmd_mapc(struct host_its *its, int collection_id, int cpu)
     return its_send_command(its, cmd);
 }
 
+static int its_send_cmd_mapd(struct host_its *its, uint32_t deviceid,
+                             int size, uint64_t itt_addr, bool valid)
+{
+    uint64_t cmd[4];
+
+    cmd[0] = GITS_CMD_MAPD | ((uint64_t)deviceid << 32);
+    cmd[1] = size & GENMASK(4, 0);
+    cmd[2] = itt_addr & GENMASK(51, 8);
+    if ( valid )
+        cmd[2] |= GITS_VALID_BIT;
+    cmd[3] = 0x00;
+
+    return its_send_command(its, cmd);
+}
+
 /* Set up the (1:1) collection mapping for the given host CPU. */
 int gicv3_its_setup_collection(int cpu)
 {
@@ -293,6 +310,7 @@ int gicv3_its_init(struct host_its *hw_its)
     reg = readq_relaxed(hw_its->its_base + GITS_TYPER);
     if ( reg & GITS_TYPER_PTA )
         hw_its->flags |= HOST_ITS_USES_PTA;
+    hw_its->itte_size = GITS_TYPER_ITT_SIZE(reg);
 
     for ( i = 0; i < GITS_BASER_NR_REGS; i++ )
     {
@@ -339,6 +357,173 @@ int gicv3_its_init(struct host_its *hw_its)
     return 0;
 }
 
+static void remove_mapped_guest_device(struct its_devices *dev)
+{
+    if ( dev->hw_its )
+        its_send_cmd_mapd(dev->hw_its, dev->host_devid, 0, 0, false);
+
+    xfree(dev->itt_addr);
+    xfree(dev);
+}
+
+int gicv3_its_map_guest_device(struct domain *d, int host_devid,
+                               int guest_devid, int bits, bool valid)
+{
+    void *itt_addr = NULL;
+    struct its_devices *dev, *temp;
+    struct rb_node **new = &d->arch.vgic.its_devices.rb_node, *parent = NULL;
+    struct host_its *hw_its;
+    int ret;
+
+    /* check for already existing mappings */
+    spin_lock(&d->arch.vgic.its_devices_lock);
+    while (*new)
+    {
+        temp = rb_entry(*new, struct its_devices, rbnode);
+
+        if ( temp->guest_devid == guest_devid )
+        {
+            if ( !valid )
+                rb_erase(&temp->rbnode, &d->arch.vgic.its_devices);
+
+            spin_unlock(&d->arch.vgic.its_devices_lock);
+
+            if ( valid )
+                return -EBUSY;
+
+            remove_mapped_guest_device(temp);
+
+            return 0;
+        }
+
+        if ( guest_devid < temp->guest_devid )
+            new = &((*new)->rb_right);
+        else
+            new = &((*new)->rb_left);
+    }
+
+    if ( !valid )
+    {
+        ret = -ENOENT;
+        goto out_unlock;
+    }
+
+    /*
+     * TODO: Work out the correct hardware ITS to use here.
+     * Maybe a per-platform function: devid -> ITS?
+     * Or parsing the DT to find the msi_parent?
+     * Or get Dom0 to give us this information?
+     * For now just use the first ITS.
+     */
+    hw_its = list_first_entry(&host_its_list, struct host_its, entry);
+
+    ret = -ENOMEM;
+
+    itt_addr = _xmalloc(BIT(bits) * hw_its->itte_size, 256);
+    if ( !itt_addr )
+        goto out_unlock;
+
+    dev = xmalloc(struct its_devices);
+    if ( !dev )
+    {
+        xfree(itt_addr);
+        goto out_unlock;
+    }
+
+    ret = its_send_cmd_mapd(hw_its, host_devid, bits - 1,
+                            virt_to_maddr(itt_addr), true);
+    if ( ret )
+    {
+        xfree(itt_addr);
+        xfree(dev);
+        goto out_unlock;
+    }
+
+    dev->itt_addr = itt_addr;
+    dev->hw_its = hw_its;
+    dev->guest_devid = guest_devid;
+    dev->host_devid = host_devid;
+    dev->eventids = BIT(bits);
+
+    rb_link_node(&dev->rbnode, parent, new);
+    rb_insert_color(&dev->rbnode, &d->arch.vgic.its_devices);
+
+    spin_unlock(&d->arch.vgic.its_devices_lock);
+
+    return 0;
+
+out_unlock:
+    spin_unlock(&d->arch.vgic.its_devices_lock);
+    return ret;
+}
+
+/* Removing any connections a domain had to any ITS in the system. */
+void gicv3_its_unmap_all_devices(struct domain *d)
+{
+    struct rb_node *victim;
+    struct its_devices *dev;
+
+    /*
+     * This is an easily readable, yet inefficient implementation.
+     * It uses the provided iteration wrapper and erases each node, which
+     * possibly triggers rebalancing.
+     * This seems overkill since we are going to abolish the whole tree, but
+     * avoids an open-coded re-implementation of the traversal functions with
+     * some recursive function calls.
+     * Performance does not matter here, since we are destroying a domain.
+     */
+restart:
+    spin_lock(&d->arch.vgic.its_devices_lock);
+    if ( (victim = rb_first(&d->arch.vgic.its_devices)) )
+    {
+        dev = rb_entry(victim, struct its_devices, rbnode);
+        rb_erase(victim, &d->arch.vgic.its_devices);
+
+        spin_unlock(&d->arch.vgic.its_devices_lock);
+
+        remove_mapped_guest_device(dev);
+
+        goto restart;
+    }
+
+    spin_unlock(&d->arch.vgic.its_devices_lock);
+}
+
+int gicv3_its_unmap_device(struct domain *d, int guest_devid)
+{
+    struct rb_node *node;
+
+    spin_lock(&d->arch.vgic.its_devices_lock);
+    node = d->arch.vgic.its_devices.rb_node;
+    while (node)
+    {
+        struct its_devices *dev = rb_entry(node, struct its_devices, rbnode);
+
+        if ( dev->guest_devid > guest_devid )
+        {
+            node = node->rb_left;
+            continue;
+        }
+        if ( dev->guest_devid < guest_devid )
+        {
+            node = node->rb_right;
+            continue;
+        }
+
+        rb_erase(node, &d->arch.vgic.its_devices);
+
+        spin_unlock(&d->arch.vgic.its_devices_lock);
+
+        remove_mapped_guest_device(dev);
+
+        return 0;
+
+    }
+    spin_unlock(&d->arch.vgic.its_devices_lock);
+
+    return -ENOENT;
+}
+
 /* Scan the DT for any ITS nodes and create a list of host ITSes out of it. */
 void gicv3_its_dt_init(const struct dt_device_node *node)
 {
@@ -369,6 +554,7 @@ void gicv3_its_dt_init(const struct dt_device_node *node)
         its_data->addr = addr;
         its_data->size = size;
         its_data->dt_node = its;
+        spin_lock_init(&its_data->cmd_lock);
 
         printk("GICv3: Found ITS @0x%lx\n", addr);
 
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index d61479d..1fadb00 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1450,6 +1450,9 @@ static int vgic_v3_domain_init(struct domain *d)
     d->arch.vgic.nr_regions = rdist_count;
     d->arch.vgic.rdist_regions = rdist_regions;
 
+    spin_lock_init(&d->arch.vgic.its_devices_lock);
+    d->arch.vgic.its_devices = RB_ROOT;
+
     /*
      * Domain 0 gets the hardware address.
      * Guests get the virtual platform layout.
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 2d6fbb1..00b9c1a 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -11,6 +11,7 @@
 #include <asm/gic.h>
 #include <public/hvm/params.h>
 #include <xen/serial.h>
+#include <xen/rbtree.h>
 
 struct hvm_domain
 {
@@ -109,6 +110,8 @@ struct arch_domain
         } *rdist_regions;
         int nr_regions;                     /* Number of rdist regions */
         uint32_t rdist_stride;              /* Re-Distributor stride */
+        struct rb_root its_devices;         /* devices mapped to an ITS */
+        spinlock_t its_devices_lock;        /* protects the its_devices tree */
 #endif
     } vgic;
 
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index 8288185..9c5dcf3 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -42,6 +42,10 @@
 
 #define GITS_TYPER_PTA                  BIT_ULL(19)
 #define GITS_TYPER_IDBITS_SHIFT         8
+#define GITS_TYPER_ITT_SIZE_SHIFT       4
+#define GITS_TYPER_ITT_SIZE_MASK        (0xfUL << GITS_TYPER_ITT_SIZE_SHIFT)
+#define GITS_TYPER_ITT_SIZE(r)          (((r) & GITS_TYPER_ITT_SIZE_MASK) >> \
+                                                GITS_TYPER_ITT_SIZE_SHIFT)
 
 #define GITS_IIDR_VALUE                 0x34c
 
@@ -88,6 +92,7 @@
 
 #ifndef __ASSEMBLY__
 #include <xen/device_tree.h>
+#include <xen/rbtree.h>
 
 #define HOST_ITS_FLUSH_CMD_QUEUE        (1U << 0)
 #define HOST_ITS_USES_PTA               (1U << 1)
@@ -101,9 +106,19 @@ struct host_its {
     void __iomem *its_base;
     spinlock_t cmd_lock;
     void *cmd_buf;
+    int itte_size;
     unsigned int flags;
 };
 
+struct its_devices {
+    struct rb_node rbnode;
+    struct host_its *hw_its;
+    void *itt_addr;
+    uint32_t guest_devid;
+    uint32_t host_devid;
+    uint32_t eventids;
+};
+
 extern struct list_head host_its_list;
 
 #ifdef CONFIG_HAS_ITS
@@ -128,6 +143,13 @@ uint64_t gicv3_get_redist_address(int cpu, bool use_pta);
 /* Map a collection for this host CPU to each host ITS. */
 int gicv3_its_setup_collection(int cpu);
 
+/* Map a device on the host by allocating an ITT on the host (ITS).
+ * "bits" specifies how many events (interrupts) this device will need.
+ * Setting "valid" to false deallocates the device.
+ */
+int gicv3_its_map_guest_device(struct domain *d, int host_devid,
+                               int guest_devid, int bits, bool valid);
+
 #else
 
 static inline void gicv3_its_dt_init(const struct dt_device_node *node)
@@ -156,6 +178,12 @@ static inline int gicv3_its_setup_collection(int cpu)
 {
     return 0;
 }
+static inline int gicv3_its_map_guest_device(struct domain *d, int host_devid,
+                                             int guest_devid, int bits,
+                                             bool valid)
+{
+    return -ENODEV;
+}
 
 #endif /* CONFIG_HAS_ITS */
 
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

  parent reply	other threads:[~2017-01-30 18:30 UTC|newest]

Thread overview: 106+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-30 18:31 [PATCH 00/28] arm64: Dom0 ITS emulation Andre Przywara
2017-01-30 18:31 ` [PATCH 01/28] ARM: export __flush_dcache_area() Andre Przywara
2017-02-06 11:23   ` Julien Grall
2017-01-30 18:31 ` [PATCH 02/28] ARM: GICv3 ITS: parse and store ITS subnodes from hardware DT Andre Przywara
2017-02-06 12:39   ` Julien Grall
2017-02-16 17:44     ` Andre Przywara
2017-02-16 18:15       ` Julien Grall
2017-02-06 12:58   ` Julien Grall
2017-02-27 11:43     ` Andre Przywara
2017-02-27 12:51       ` Julien Grall
2017-01-30 18:31 ` [PATCH 03/28] ARM: GICv3: allocate LPI pending and property table Andre Przywara
2017-02-06 16:26   ` Julien Grall
2017-02-27 11:34     ` Andre Przywara
2017-02-27 12:48       ` Julien Grall
2017-02-14  0:47   ` Stefano Stabellini
2017-01-30 18:31 ` [PATCH 04/28] ARM: GICv3 ITS: allocate device and collection table Andre Przywara
2017-02-06 17:19   ` Julien Grall
2017-02-14  0:55     ` Stefano Stabellini
2017-02-06 17:36   ` Julien Grall
2017-02-06 17:43   ` Julien Grall
2017-03-23 18:06     ` Andre Przywara
2017-03-23 18:08       ` Julien Grall
2017-02-14  0:54   ` Stefano Stabellini
2017-02-15 18:31   ` Shanker Donthineni
2017-02-16 19:03   ` Shanker Donthineni
2017-02-24 19:29     ` Shanker Donthineni
2017-02-27 10:23       ` Andre Przywara
2017-01-30 18:31 ` [PATCH 05/28] ARM: GICv3 ITS: map ITS command buffer Andre Przywara
2017-02-06 17:43   ` Julien Grall
2017-02-14  0:59   ` Stefano Stabellini
2017-02-14 20:50     ` Julien Grall
2017-02-14 21:00       ` Stefano Stabellini
2017-01-30 18:31 ` [PATCH 06/28] ARM: GICv3 ITS: introduce ITS command handling Andre Przywara
2017-02-06 19:16   ` Julien Grall
2017-02-07 11:44     ` Julien Grall
2017-03-07 18:08     ` Andre Przywara
2017-03-08 15:28       ` Julien Grall
2017-03-08 16:16         ` Andre Przywara
2017-02-07 11:59   ` Julien Grall
2017-01-30 18:31 ` Andre Przywara [this message]
2017-02-07 14:05   ` [PATCH 07/28] ARM: GICv3 ITS: introduce device mapping Julien Grall
2017-02-15 16:30   ` Julien Grall
2017-02-22  7:06   ` Vijay Kilari
2017-02-24 19:37     ` Shanker Donthineni
2017-02-22 13:17   ` Julien Grall
2017-01-30 18:31 ` [PATCH 08/28] ARM: GICv3 ITS: introduce host LPI array Andre Przywara
2017-02-07 18:01   ` Julien Grall
2017-02-14 20:05   ` Stefano Stabellini
2017-01-30 18:31 ` [PATCH 09/28] ARM: GICv3 ITS: map device and LPIs to the ITS on physdev_op hypercall Andre Przywara
2017-01-31 10:29   ` Jaggi, Manish
2017-01-31 12:43     ` Julien Grall
2017-01-31 13:19       ` Jaggi, Manish
2017-01-31 13:46         ` Julien Grall
2017-01-31 14:08           ` Jaggi, Manish
2017-01-31 15:17             ` Julien Grall
2017-01-31 16:02               ` Jaggi, Manish
2017-01-31 16:18                 ` Julien Grall
2017-02-24 19:57                   ` Shanker Donthineni
2017-02-24 20:28                     ` Julien Grall
2017-02-27 17:20                     ` Andre Przywara
2017-02-28 18:29                       ` Julien Grall
2017-03-01 19:42                         ` Shanker Donthineni
2017-03-03 15:53                           ` Julien Grall
2017-01-31 13:28       ` Jaggi, Manish
2017-02-14 20:11   ` Stefano Stabellini
2017-01-30 18:31 ` [PATCH 10/28] ARM: GICv3: introduce separate pending_irq structs for LPIs Andre Przywara
2017-02-14 20:39   ` Stefano Stabellini
2017-02-15 17:06     ` Julien Grall
2017-02-15 17:03   ` Julien Grall
2017-01-30 18:31 ` [PATCH 11/28] ARM: GICv3: forward pending LPIs to guests Andre Przywara
2017-02-14 21:00   ` Stefano Stabellini
2017-02-15 17:18     ` Julien Grall
2017-02-15 21:25       ` Stefano Stabellini
2017-03-02 20:56         ` Julien Grall
2017-03-03  7:58           ` Jan Beulich
2017-03-03 14:53             ` Julien Grall
2017-02-15 17:30   ` Julien Grall
2017-01-30 18:31 ` [PATCH 12/28] ARM: GICv3: enable ITS and LPIs on the host Andre Przywara
2017-02-14 22:41   ` Stefano Stabellini
2017-02-15 17:35   ` Julien Grall
2017-01-30 18:31 ` [PATCH 13/28] ARM: vGICv3: handle virtual LPI pending and property tables Andre Przywara
2017-02-14 23:56   ` Stefano Stabellini
2017-02-15 18:44   ` Julien Grall
2017-01-30 18:31 ` [PATCH 14/28] ARM: vGICv3: Handle disabled LPIs Andre Przywara
2017-02-14 23:58   ` Stefano Stabellini
2017-01-30 18:31 ` [PATCH 15/28] ARM: vGICv3: introduce basic ITS emulation bits Andre Przywara
2017-02-15 20:06   ` Shanker Donthineni
2017-01-30 18:31 ` [PATCH 16/28] ARM: vITS: introduce translation table walks Andre Przywara
2017-01-30 18:31 ` [PATCH 17/28] ARM: vITS: handle CLEAR command Andre Przywara
2017-02-15  0:07   ` Stefano Stabellini
2017-01-30 18:31 ` [PATCH 18/28] ARM: vITS: handle INT command Andre Przywara
2017-01-30 18:31 ` [PATCH 19/28] ARM: vITS: handle MAPC command Andre Przywara
2017-01-30 18:31 ` [PATCH 20/28] ARM: vITS: handle MAPD command Andre Przywara
2017-02-15  0:17   ` Stefano Stabellini
2017-01-30 18:31 ` [PATCH 21/28] ARM: vITS: handle MAPTI command Andre Przywara
2017-01-30 18:31 ` [PATCH 22/28] ARM: vITS: handle MOVI command Andre Przywara
2017-01-30 18:31 ` [PATCH 23/28] ARM: vITS: handle DISCARD command Andre Przywara
2017-01-30 18:31 ` [PATCH 24/28] ARM: vITS: handle INV command Andre Przywara
2017-01-30 18:31 ` [PATCH 25/28] ARM: vITS: handle INVALL command Andre Przywara
2017-01-30 18:31 ` [PATCH 26/28] ARM: vITS: create and initialize virtual ITSes for Dom0 Andre Przywara
2017-01-30 18:31 ` [PATCH 27/28] ARM: vITS: create ITS subnodes for Dom0 DT Andre Przywara
2017-01-30 18:31 ` [PATCH 28/28] ARM: vGIC: advertising LPI support Andre Przywara
2017-02-13 13:53 ` [PATCH 00/28] arm64: Dom0 ITS emulation Vijay Kilari
2017-02-14 22:00   ` Stefano Stabellini
2017-02-15 15:59   ` Julien Grall
2017-02-15 17:55 ` Julien Grall

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170130183153.28566-8-andre.przywara@arm.com \
    --to=andre.przywara@arm.com \
    --cc=julien.grall@arm.com \
    --cc=sstabellini@kernel.org \
    --cc=vijay.kilari@gmail.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.