[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v3 06/26] ARM: GICv3 ITS: introduce device mapping



Hi Andre,

Mostly repeating my comments from the previous version.

On 31/03/17 19:05, Andre Przywara wrote:

[...]

+static int its_send_cmd_mapd(struct host_its *its, uint32_t deviceid,
+                             uint8_t size_bits, paddr_t itt_addr, bool valid)
+{
+    uint64_t cmd[4];
+
+    if ( valid )
+    {
+        ASSERT(size_bits < 32);

Again, it would be better if you do the check against the real number in hardware (i.e GITS_TYPER.ID_bits).

+        ASSERT(!(itt_addr & ~GENMASK_ULL(51, 8)));
+    }
+    cmd[0] = GITS_CMD_MAPD | ((uint64_t)deviceid << 32);
+    cmd[1] = size_bits;

I would have expected to see size_bits - 1 to accommodate all the helpers rather than relying on them.

[...]

+static int remove_mapped_guest_device(struct its_devices *dev)
+{
+    int ret;
+
+    if ( dev->hw_its )
+    {
+        /* MAPD also discards all events with this device ID. */
+        int ret = its_send_cmd_mapd(dev->hw_its, dev->host_devid, 0, 0, false);

You are re-defining ret. Why?

[...]

+static struct host_its *gicv3_its_find_by_doorbell(paddr_t doorbell_address)
+{
+    struct host_its *hw_its;
+
+    list_for_each_entry(hw_its, &host_its_list, entry)
+    {
+        if ( hw_its->addr + ITS_DOORBELL_OFFSET == doorbell_address )

Again, why not storing the ITS address rather than the doorbell to avoid "+ ITS_DOORBELL_OFFSET" ?

[...]

+/*
+ * Map a hardware device, identified by a certain host ITS and its device ID
+ * to domain d, a guest ITS (identified by its doorbell address) and device ID.
+ * Also provide the number of events (MSIs) needed for that device.
+ * This does not check if this particular hardware device is already mapped
+ * at another domain, it is expected that this would be done by the caller.
+ */
+int gicv3_its_map_guest_device(struct domain *d,
+                               paddr_t host_doorbell, uint32_t host_devid,
+                               paddr_t guest_doorbell, uint32_t guest_devid,
+                               uint32_t nr_events, bool valid)

I am sure I said it somewhere in this series, nr_events likely needs to be sanitized against the hardware value. Same for host_devid.

[...]

+        parent = *new;
+        cmp = compare_its_guest_devices(temp, guest_doorbell, guest_devid);
+        if ( !cmp )
+        {
+            if ( !valid )
+                rb_erase(&temp->rbnode, &d->arch.vgic.its_devices);
+
+            spin_unlock(&d->arch.vgic.its_devices_lock);
+
+            if ( valid )

Again, a printk(XENLOG_GUEST...) here would be useful to know which host DeviceID was associated to the guest DeviceID.

+                return -EBUSY;
+
+            return remove_mapped_guest_device(temp);

Again, just above you removed the device from the RB-tree but this function may fail and never free the memory. This means that memory will be leaked leading to a potential denial of service.

+        }
+
+        if ( cmp > 0 )
+            new = &((*new)->rb_left);
+        else
+            new = &((*new)->rb_right);
+    }
+
+    if ( !valid )
+        goto out_unlock;
+
+    ret = -ENOMEM;
+
+    /* An Interrupt Translation Table needs to be 256-byte aligned. */
+    itt_addr = _xzalloc(nr_events * hw_its->itte_size, 256);

See Vijay's comment. But why don't you round up nr_events at the beginning once for all rather than doing it in the middle?

[...]

+out_unlock:
+    spin_unlock(&d->arch.vgic.its_devices_lock);
+    if ( dev )
+    {
+        xfree(dev->pend_irqs);
+        xfree(dev->host_lpi_blocks);

Where is host_lpi_blocks allocated? Why is it freed here?

+    }
+    xfree(itt_addr);
+    xfree(dev);
+    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, but suboptimal 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.
+     */

Well, you updated the comment but it does not make the performance problem going away... Xen cannot be preempted, so if it takes too long, you will have an impact on the overall system.

As said previously, I think it would be fair to assume that all devices will be deassigned before the ITS is destroyed. So I would just drop this function. Not that we have the same assumption in the SMMU driver.

If you disagree please say why. But ignoring comments will not help here.

+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);
+}
+
 /* 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)
 {
@@ -459,6 +685,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);

This should be in patch #5.


         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..6242252 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;
+

Again, the placement of those 2 lines are likely wrong. This should belong to the vITS and not the vgic-v3.

I think it would make sense to get a patch that introduces a skeleton for the vITS before this patch and start plumbing through.

     /*
      * Domain 0 gets the hardware address.
      * Guests get the virtual platform layout.
@@ -1522,6 +1525,7 @@ static int vgic_v3_domain_init(struct domain *d)

 static void vgic_v3_domain_free(struct domain *d)
 {
+    gicv3_its_unmap_all_devices(d);

See my comment above regarding this function.

     xfree(d->arch.vgic.rdist_regions);
 }


[...]

diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index 4c2ae1c..4ade5f6 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -48,6 +48,10 @@
 #define GITS_TYPER_DEVICE_ID_BITS(r)    (((r & GITS_TYPER_DEVIDS_MASK) >> \
                                                GITS_TYPER_DEVIDS_SHIFT) + 1)
 #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) + 1)

 #define GITS_IIDR_VALUE                 0x34c

@@ -94,7 +98,10 @@
 #define GITS_CMD_MOVALL                 0x0e
 #define GITS_CMD_DISCARD                0x0f

+#define ITS_DOORBELL_OFFSET             0x10040
+
 #include <xen/device_tree.h>
+#include <xen/rbtree.h>

 #define HOST_ITS_FLUSH_CMD_QUEUE        (1U << 0)
 #define HOST_ITS_USES_PTA               (1U << 1)
@@ -109,6 +116,7 @@ struct host_its {
     unsigned int devid_bits;
     spinlock_t cmd_lock;
     void *cmd_buf;
+    unsigned int itte_size;

Stefano mentioned:
"I would move itte_size and its initialization to the patch that
introduced struct host_its."

     unsigned int flags;
 };

Cheers,

--
Julien Grall

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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.