Discussion:
[PATCH v6 00/31] Add ITS support
(too old to reply)
v***@gmail.com
2015-08-31 11:06:17 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

This is based on DraftG version
http://xenbits.xen.org/people/ianc/vits/draftG.pdf

Following major features are supported
- GICv3 ITS support for arm64 platform
- Only Dom0 is supported. For DomU pci passthrough feature
is required.

Patches shared @ https://github.com/vijaykilari/its_v6.git

Changes in v6:

- Rebased to latest staging branch.
- Compiled all the patches individually for both arm32 and arm64
- Split the patch "xen/arm: ITS: Allocate irq descriptors for LPIs" into two.
One for allocating LPI irq_desc and other patch for allocating pending_irq desc
for LPIs
- Following new patches are introduced
1) xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
2) xen/arm: ITS: Introduce msi_desc for LPIs
3) xen/arm: Move vgic locking inside get_irq_priority callback
4) xen/arm: ITS: Store LPIs allocated and IRQ ID bits per domain
5) xen/arm: ITS: Introduce helper to get number of event IDs
6) xen/arm: ITS: Add virtual ITS availability check helper
7) xen/arm: ITS: Add 32-bit access to GICR_TYPER)
8) xen/arm: ITS: Allocate pending_lpi descriptors for LPIs

- Based on below patch set
http://lists.xen.org/archives/html/xen-devel/2015-08/msg00168.html

Some Major TODOs:
1) Avoid making vits_process_cmd() static in later point of time
2) How to handle LPI that does not have LPI config table entry.
3) Enable/disable ITS to Dom0

Changes in v5:
- Added following new patches
0001-xen-arm-Return-success-if-dt-node-does-not-have-irq-.patch
0004-xen-arm-Set-nr_cpu_ids-to-available-number-of-cpus.patch
0009-xen-arm-ITS-Export-ITS-info-to-Virtual-ITS.patch
0013-xen-arm-ITS-Implement-gic_is_lpi-helper-function.patch
- Split patch #12 into two patches #14 & #16
0014-xen-arm-ITS-Allocate-irq-descriptors-for-LPIs.patch
0016-xen-arm-ITS-Route-LPIs.patch
- Introduce new API to route LPI (route_lpi_to_guest() )
- Moved patch #8 in v4 as patch #19
- irq_descritors for LPIs are allocated dynamically
- Removed RB-tree for managing vitual its devices. Will be
introduced when pci-passthrough is implemented
- its_add_device() api now takes nr_ites and DT its node as parameters
- some function are kept as non-static when introduced in a patch for
compilation purpose and eventually made static when used.
- Tested compilation for arm32

Changes in v4:
- Patch for rate limiting of error message is removed.
- Patch #4 and #5 in v3 is merged
- Merged #13 and #16 as one patch
- hw_irq_controller is implemented for LPIs
- GITS and GICR emulation for LPIs in separate patches
- Removed build functions for ITS command in physical ITS driver
- Added new patch to add and assign devices from platform file
- Enable compilation of vits and pits driver in separate patch
- Replace msi-parent property in all pci dt nodes to single
ITS node generated by Xen for Dom0

Vijaya Kumar K (31):
xen/dt: Handle correctly node with interrupt-map in
dt_for_each_irq_map
xen/arm: Add bitmap_find_next_zero_area helper function
xen: Add log2 functionality
xen/arm: Set nr_cpu_ids to available number of cpus
xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
xen/arm: ITS: Port ITS driver to Xen
xen/arm: ITS: Add helper functions to manage its_devices
xen/arm: ITS: Introduce msi_desc for LPIs
xen/arm: ITS: Add APIs to add and assign device
xen/arm: ITS: Introduce gic_is_lpi helper function
xen/arm: ITS: Enable compilation of physical ITS driver
xen/arm: Move vgic locking inside get_irq_priority callback
xen/arm: ITS: implement hw_irq_controller for LPIs
xen/arm: ITS: Initialize physical ITS and export lpi support
xen/arm: ITS: Add virtual ITS driver
xen/arm: ITS: Add virtual ITS commands support
xen/arm: ITS: Store LPIs allocated and IRQ ID bits per domain
xen/arm: ITS: Enable virtual ITS driver
xen/arm: ITS: Export ITS info to Virtual ITS
xen/arm: ITS: Introduce helper to get number of event IDs
xen/arm: ITS: Add GITS registers emulation
xen/arm: ITS: Add virtual ITS availability check helper
xen/arm: ITS: Add 32-bit access to GICR_TYPER
xen/arm: ITS: Add GICR register emulation
xen/arm: ITS: Allocate irq descriptors for LPIs
xen/arm: ITS: Allocate pending_lpi descriptors for LPIs
xen/arm: ITS: Route LPIs
xen/arm: ITS: Add domain specific ITS initialization
xen/arm: ITS: Map ITS translation space
xen/arm: ITS: Generate ITS node for Dom0
xen/arm: ITS: Add pci devices in ThunderX

xen/arch/arm/Makefile | 2 +
xen/arch/arm/domain_build.c | 11 +
xen/arch/arm/gic-hip04.c | 19 +-
xen/arch/arm/gic-v2.c | 19 +-
xen/arch/arm/gic-v3-its.c | 1594 +++++++++++++++++++++++++++++++++++++
xen/arch/arm/gic-v3.c | 102 ++-
xen/arch/arm/gic.c | 73 +-
xen/arch/arm/irq.c | 176 +++-
xen/arch/arm/platforms/Makefile | 1 +
xen/arch/arm/platforms/thunderx.c | 151 ++++
xen/arch/arm/setup.c | 2 +
xen/arch/arm/vgic-v2.c | 9 +-
xen/arch/arm/vgic-v3-its.c | 993 +++++++++++++++++++++++
xen/arch/arm/vgic-v3.c | 419 +++++++++-
xen/arch/arm/vgic.c | 117 ++-
xen/common/bitmap.c | 39 +
xen/common/device_tree.c | 4 +-
xen/include/asm-arm/domain.h | 11 +
xen/include/asm-arm/gic-its.h | 387 +++++++++
xen/include/asm-arm/gic.h | 27 +-
xen/include/asm-arm/gic_v3_defs.h | 51 +-
xen/include/asm-arm/irq.h | 24 +-
xen/include/asm-arm/vgic.h | 18 +-
xen/include/xen/bitmap.h | 16 +
xen/include/xen/lib.h | 2 +
xen/include/xen/log2.h | 167 ++++
26 files changed, 4357 insertions(+), 77 deletions(-)
create mode 100644 xen/arch/arm/gic-v3-its.c
create mode 100644 xen/arch/arm/platforms/thunderx.c
create mode 100644 xen/arch/arm/vgic-v3-its.c
create mode 100644 xen/include/asm-arm/gic-its.h
create mode 100644 xen/include/xen/log2.h
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:26 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Add APIs to add devices to RB-tree, assign and remove
devices to domain.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Moved this patch #19 to patch #8
- Used col_map to store collection id
- Use helper functions to update msi_desc members
v5: - Removed its_detach_device API
- Pass nr_ites as parameter to its_add_device
v4: - Introduced helper to populate its_device struct
- Fixed freeing of its_device memory
- its_device struct holds domain id
---
xen/arch/arm/gic-v3-its.c | 212 +++++++++++++++++++++++++++++++++++++++++
xen/include/asm-arm/gic-its.h | 6 ++
2 files changed, 218 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index e70c21a..f14c0f4 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -145,6 +145,19 @@ static struct its_collection *dev_event_to_col(struct its_device *dev,
return its->collections + dev->event_map.col_map[event];
}

+static struct its_node *its_get_phys_node(struct dt_device_node *dt)
+{
+ struct its_node *its;
+
+ list_for_each_entry(its, &its_nodes, entry)
+ {
+ if ( its->dt_node == dt )
+ return its;
+ }
+
+ return NULL;
+}
+
/* RB-tree helpers for its_device */
static struct its_device *its_find_device(u32 devid)
{
@@ -522,6 +535,205 @@ static void its_lpi_free(struct its_device *dev)
xfree(dev->event_map.lpi_map);
}

+static void its_discard_lpis(struct its_device *dev, u32 ids)
+{
+ int i;
+
+ for ( i = 0; i < ids; i++)
+ its_send_discard(dev, i);
+}
+
+static inline u32 its_get_plpi(struct its_device *dev, u32 event)
+{
+ return dev->event_map.lpi_base + event;
+}
+
+static int its_alloc_device_irq(struct its_device *dev, u32 *hwirq)
+{
+ int idx;
+
+ idx = find_first_zero_bit(dev->event_map.lpi_map, dev->event_map.nr_lpis);
+ if ( idx == dev->event_map.nr_lpis )
+ return -ENOSPC;
+
+ *hwirq = its_get_plpi(dev, idx);
+ set_bit(idx, dev->event_map.lpi_map);
+
+ return 0;
+}
+
+static void its_free_device(struct its_device *dev)
+{
+ xfree(dev->itt_addr);
+ xfree(dev->event_map.lpi_map);
+ xfree(dev->event_map.col_map);
+ xfree(dev);
+}
+
+static struct its_device *its_alloc_device(u32 devid, u32 nr_ites,
+ struct dt_device_node *dt_its)
+{
+ struct its_device *dev;
+ paddr_t *itt;
+ unsigned long *lpi_map;
+ int lpi_base, sz;
+ u16 *col_map = NULL;
+
+ dev = xzalloc(struct its_device);
+ if ( dev == NULL )
+ return NULL;
+
+ dev->its = its_get_phys_node(dt_its);
+ if (dev->its == NULL)
+ {
+ dprintk(XENLOG_G_ERR,
+ "ITS: Failed to find ITS node for devid 0x%"PRIx32"\n",
+ devid);
+ goto err;
+ }
+
+ sz = nr_ites * dev->its->ite_size;
+ sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
+ itt = xzalloc_bytes(sz);
+ if ( !itt )
+ goto err;
+
+ lpi_map = its_lpi_alloc_chunks(nr_ites, &lpi_base);
+ if ( !lpi_map )
+ goto lpi_err;
+
+ col_map = xzalloc_bytes(sizeof(*col_map) * nr_ites);
+ if ( !col_map )
+ goto col_err;
+ dev->itt_addr = itt;
+ dev->event_map.lpi_map = lpi_map;
+ dev->event_map.lpi_base = lpi_base;
+ dev->event_map.col_map = col_map;
+ dev->event_map.nr_lpis = nr_ites;
+ dev->device_id = devid;
+
+ return dev;
+
+col_err:
+ xfree(lpi_map);
+lpi_err:
+ xfree(itt);
+err:
+ xfree(dev);
+
+ return NULL;
+}
+
+/* Device assignment */
+int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its)
+{
+ struct its_device *dev;
+ u32 i, plpi = 0;
+ struct its_collection *col;
+ struct irq_desc *desc;
+ struct msi_desc *msi = NULL;
+ int res = 0;
+
+ spin_lock(&rb_its_dev_lock);
+ dev = its_find_device(devid);
+ if ( dev )
+ {
+ dprintk(XENLOG_G_ERR, "ITS: Device already exists 0x%"PRIx32"\n",
+ dev->device_id);
+ res = -EEXIST;
+ goto err;
+ }
+
+ dev = its_alloc_device(devid, nr_ites, dt_its);
+ if ( !dev )
+ {
+ res = -ENOMEM;
+ goto err;
+ }
+
+ if ( its_insert_device(dev) )
+ {
+ its_free_device(dev);
+ dprintk(XENLOG_G_ERR, "ITS: failed to insert device 0x%"PRIx32"\n",
+ devid);
+ res = -EINVAL;
+ goto err;
+ }
+
+ DPRINTK("ITS:Add Device 0x%"PRIx32" lpis %"PRIu32" base 0x%"PRIx32"\n",
+ dev->device_id, dev->event_map.nr_lpis, dev->event_map.lpi_base);
+
+ /* Map device to its ITT */
+ its_send_mapd(dev, 1);
+
+ for ( i = 0; i < dev->event_map.nr_lpis; i++ )
+ {
+ msi = xzalloc(struct msi_desc);
+ /* Reserve pLPI */
+ if ( its_alloc_device_irq(dev, &plpi) || !msi )
+ {
+ its_discard_lpis(dev, i);
+ its_lpi_free(dev);
+ its_send_mapd(dev, 0);
+ its_free_device(dev);
+ dprintk(XENLOG_G_ERR, "ITS: Cannot add device 0x%"PRIx32"\n",
+ devid);
+ res = -ENOSPC;
+ goto err;
+ }
+
+ /* For each pLPI send MAPVI command */
+ col = &dev->its->collections[(i % nr_cpu_ids)];
+ desc = irq_to_desc(plpi);
+
+ spin_lock(&desc->lock);
+ dev->event_map.col_map[i] = col->col_id;
+ irq_set_msi_desc(desc, msi);
+ irqdesc_set_lpi_event(desc, i);
+ irqdesc_set_its_device(desc, dev);
+ spin_unlock(&desc->lock);
+
+ its_send_mapvi(dev, plpi, i);
+ }
+
+err:
+ spin_unlock(&rb_its_dev_lock);
+
+ return res;
+}
+
+int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid)
+{
+ struct its_device *pdev;
+ u32 plpi, i;
+
+ DPRINTK("ITS: Assign request for dev 0x%"PRIx32" to domain %"PRIu16"\n",
+ vdevid, d->domain_id);
+
+ spin_lock(&rb_its_dev_lock);
+ pdev = its_find_device(pdevid);
+ if ( !pdev )
+ {
+ spin_unlock(&rb_its_dev_lock);
+ return -ENODEV;
+ }
+ spin_unlock(&rb_its_dev_lock);
+
+ pdev->domain_id = d->domain_id;
+ pdev->virt_device_id = vdevid;
+
+ DPRINTK("ITS: Assign pdevid 0x%"PRIx32" lpis %"PRIu32" for dom %"PRIu16"\n",
+ pdevid, pdev->event_map.nr_lpis, d->domain_id);
+
+ for ( i = 0; i < pdev->event_map.nr_lpis; i++ )
+ {
+ plpi = its_get_plpi(pdev, i);
+ /* TODO: Route lpi */
+ }
+
+ return 0;
+}
+
/*
* We allocate 64kB for PROPBASE. That gives us at most 64K LPIs to
* deal with (one configuration byte per interrupt). PENDBASE has to
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 25c2176..3599c76 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -267,6 +267,10 @@ struct its_device {
struct event_lpi_map event_map;
/* Physical Device id */
u32 device_id;
+ /* Virtual Device id */
+ u32 virt_device_id;
+ /* Domain id */
+ int domain_id;
/* RB-tree entry */
struct rb_node node;
};
@@ -277,6 +281,8 @@ struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
+int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
+int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);

#endif /* __ASM_ARM_GIC_ITS_H__ */
/*
--
1.7.9.5
Julien Grall
2015-09-03 17:34:53 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
Add APIs to add devices to RB-tree, assign and remove
devices to domain.
---
v6: - Moved this patch #19 to patch #8
- Used col_map to store collection id
- Use helper functions to update msi_desc members
v5: - Removed its_detach_device API
- Pass nr_ites as parameter to its_add_device
v4: - Introduced helper to populate its_device struct
- Fixed freeing of its_device memory
- its_device struct holds domain id
---
xen/arch/arm/gic-v3-its.c | 212 +++++++++++++++++++++++++++++++++++++++++
xen/include/asm-arm/gic-its.h | 6 ++
2 files changed, 218 insertions(+)
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index e70c21a..f14c0f4 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -145,6 +145,19 @@ static struct its_collection *dev_event_to_col(struct its_device *dev,
return its->collections + dev->event_map.col_map[event];
}
+static struct its_node *its_get_phys_node(struct dt_device_node *dt)
+{
+ struct its_node *its;
+
+ list_for_each_entry(its, &its_nodes, entry)
+ {
+ if ( its->dt_node == dt )
+ return its;
+ }
+
+ return NULL;
+}
+
/* RB-tree helpers for its_device */
static struct its_device *its_find_device(u32 devid)
{
@@ -522,6 +535,205 @@ static void its_lpi_free(struct its_device *dev)
xfree(dev->event_map.lpi_map);
}
+static void its_discard_lpis(struct its_device *dev, u32 ids)
+{
+ int i;
+
I would have expected a function more complex than that. If you discard
the LPIs, you also need to free the MSI desc and potentially reset the
IRQ desc.

Otherwise you will left the irq_desc in an unknown state for the next one.
Post by v***@gmail.com
+ for ( i = 0; i < ids; i++)
+ its_send_discard(dev, i);
+}
+
+static inline u32 its_get_plpi(struct its_device *dev, u32 event)
+{
+ return dev->event_map.lpi_base + event;
+}
+
+static int its_alloc_device_irq(struct its_device *dev, u32 *hwirq)
+{
+ int idx;
+
+ idx = find_first_zero_bit(dev->event_map.lpi_map, dev->event_map.nr_lpis);
+ if ( idx == dev->event_map.nr_lpis )
+ return -ENOSPC;
+
+ *hwirq = its_get_plpi(dev, idx);
+ set_bit(idx, dev->event_map.lpi_map);
+
+ return 0;
+}
+
+static void its_free_device(struct its_device *dev)
+{
+ xfree(dev->itt_addr);
+ xfree(dev->event_map.lpi_map);
This should be replaced by its_lpi_free. Otherwise you will never
release the reserved LPI ranges in lpi_bitmap.
Post by v***@gmail.com
+ xfree(dev->event_map.col_map);
+ xfree(dev);
+}
+
+static struct its_device *its_alloc_device(u32 devid, u32 nr_ites,
+ struct dt_device_node *dt_its)
+{
+ struct its_device *dev;
+ paddr_t *itt;
Why paddr_t? You only allocate it and pass directly to the hardware.
Post by v***@gmail.com
+ unsigned long *lpi_map;
+ int lpi_base, sz;
+ u16 *col_map = NULL;
+
+ dev = xzalloc(struct its_device);
+ if ( dev == NULL )
+ return NULL;
+
+ dev->its = its_get_phys_node(dt_its);
+ if (dev->its == NULL)
+ {
+ dprintk(XENLOG_G_ERR,
Why XENLOG_G_ERR?

Also, dprintk will be turned into a no-op on non-debug build. Is it what
you expect?
Post by v***@gmail.com
+ "ITS: Failed to find ITS node for devid 0x%"PRIx32"\n",
+ devid);
+ goto err;
+ }
+
+ sz = nr_ites * dev->its->ite_size;
+ sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
+ itt = xzalloc_bytes(sz);
+ if ( !itt )
+ goto err;
+
+ lpi_map = its_lpi_alloc_chunks(nr_ites, &lpi_base);
+ if ( !lpi_map )
+ goto lpi_err;
+
+ col_map = xzalloc_bytes(sizeof(*col_map) * nr_ites);
+ if ( !col_map )
+ goto col_err;
+ dev->itt_addr = itt;
+ dev->event_map.lpi_map = lpi_map;
+ dev->event_map.lpi_base = lpi_base;
+ dev->event_map.col_map = col_map;
+ dev->event_map.nr_lpis = nr_ites;
+ dev->device_id = devid;
+
+ return dev;
+
+ xfree(lpi_map);
This should be replaced by its_lpi_free. Otherwise you will never
release the reserved LPI ranges in lpi_bitmap.
Post by v***@gmail.com
+ xfree(itt);
+ xfree(dev);
By reworking a bit this function, you could directly its_free_device.

For instance if you assign lpi_map directly after allocating,...
Post by v***@gmail.com
+ return NULL;
+}
+
+/* Device assignment */
+int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its)
+{
+ struct its_device *dev;
+ u32 i, plpi = 0;
+ struct its_collection *col;
+ struct irq_desc *desc;
+ struct msi_desc *msi = NULL;
+ int res = 0;
+
+ spin_lock(&rb_its_dev_lock);
+ dev = its_find_device(devid);
+ if ( dev )
+ {
+ dprintk(XENLOG_G_ERR, "ITS: Device already exists 0x%"PRIx32"\n",
+ dev->device_id);
+ res = -EEXIST;
+ goto err;
+ }
+
+ dev = its_alloc_device(devid, nr_ites, dt_its);
+ if ( !dev )
+ {
+ res = -ENOMEM;
+ goto err;
+ }
+
+ if ( its_insert_device(dev) )
+ {
+ its_free_device(dev);
+ dprintk(XENLOG_G_ERR, "ITS: failed to insert device 0x%"PRIx32"\n",
+ devid);
+ res = -EINVAL;
+ goto err;
+ }
+
+ DPRINTK("ITS:Add Device 0x%"PRIx32" lpis %"PRIu32" base 0x%"PRIx32"\n",
+ dev->device_id, dev->event_map.nr_lpis, dev->event_map.lpi_base);
+
+ /* Map device to its ITT */
+ its_send_mapd(dev, 1);
+
+ for ( i = 0; i < dev->event_map.nr_lpis; i++ )
+ {
+ msi = xzalloc(struct msi_desc);
+ /* Reserve pLPI */
This comment is unclear given that the next section of code is mostly
free code. You may want to move the free in another place.
Post by v***@gmail.com
+ if ( its_alloc_device_irq(dev, &plpi) || !msi )
+ {
+ its_discard_lpis(dev, i);
+ its_lpi_free(dev);
IHMO, this should go in its_free_device.
Post by v***@gmail.com
+ its_send_mapd(dev, 0);
+ its_free_device(dev);
You free the device but never removed from the rb_its_dev. So the
RB-tree will contain an invalid pointer.

It would be nice if you can test the error path manually. For example
you can add a bit of code to say "I want to fail on the 3rd device
allocation" and see what happens...

This is a good way to exercise path that you may enter in common case at
runtime.
Post by v***@gmail.com
+ dprintk(XENLOG_G_ERR, "ITS: Cannot add device 0x%"PRIx32"\n",
+ devid);
+ res = -ENOSPC;
+ goto err;
+ }
+
+ /* For each pLPI send MAPVI command */
+ col = &dev->its->collections[(i % nr_cpu_ids)];
Please add a comment to explain how you choose the collection.
Post by v***@gmail.com
+ desc = irq_to_desc(plpi);
+
+ spin_lock(&desc->lock);
+ dev->event_map.col_map[i] = col->col_id;
+ irq_set_msi_desc(desc, msi);
+ irqdesc_set_lpi_event(desc, i);
+ irqdesc_set_its_device(desc, dev);
+ spin_unlock(&desc->lock);
+
+ its_send_mapvi(dev, plpi, i);
+ }
+
+ spin_unlock(&rb_its_dev_lock);
This can be unlocked after inserting the device (i.e its_insert_device).
Post by v***@gmail.com
+
+ return res;
+}
+
+int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid)
+{
+ struct its_device *pdev;
+ u32 plpi, i;
+
+ DPRINTK("ITS: Assign request for dev 0x%"PRIx32" to domain %"PRIu16"\n",
+ vdevid, d->domain_id);
+
+ spin_lock(&rb_its_dev_lock);
+ pdev = its_find_device(pdevid);
+ if ( !pdev )
+ {
+ spin_unlock(&rb_its_dev_lock);
+ return -ENODEV;
+ }
+ spin_unlock(&rb_its_dev_lock);
You never check if the device is used by someone else. You don't even
set to invalid domain ID when allocating the device.

While this could be acceptable until guest ITS is not supported. This
should be fixed before any patch series to add guest.

I.e I want this code fixed or a big fat comment explaining what is
missing here.
Post by v***@gmail.com
+
+ pdev->domain_id = d->domain_id;
+ pdev->virt_device_id = vdevid;
+
+ DPRINTK("ITS: Assign pdevid 0x%"PRIx32" lpis %"PRIu32" for dom %"PRIu16"\n",
+ pdevid, pdev->event_map.nr_lpis, d->domain_id);
+
+ for ( i = 0; i < pdev->event_map.nr_lpis; i++ )
+ {
+ plpi = its_get_plpi(pdev, i);
+ /* TODO: Route lpi */
+ }
+
+ return 0;
+}
+
/*
* We allocate 64kB for PROPBASE. That gives us at most 64K LPIs to
* deal with (one configuration byte per interrupt). PENDBASE has to
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 25c2176..3599c76 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -267,6 +267,10 @@ struct its_device {
struct event_lpi_map event_map;
/* Physical Device id */
u32 device_id;
+ /* Virtual Device id */
+ u32 virt_device_id;
+ /* Domain id */
+ int domain_id;
In general we are storing a pointer to struct domain rather than the
domID because you get directly access to the domain information.

Although, I don't see why you added it as I don't find any usage of it
within this series but here to set the value.
Post by v***@gmail.com
/* RB-tree entry */
struct rb_node node;
};
@@ -277,6 +281,8 @@ struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
+int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
+int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
#endif /* __ASM_ARM_GIC_ITS_H__ */
/*
Regards,
--
Julien Grall
Ian Campbell
2015-09-09 13:28:02 UTC
Permalink
Post by v***@gmail.com
@@ -522,6 +535,205 @@ static void its_lpi_free(struct its_device *dev)
Post by v***@gmail.com
xfree(dev->event_map.lpi_map);
}
+static void its_discard_lpis(struct its_device *dev, u32 ids)
+{
+ int i;
+
I would have expected a function more complex than that. If you discard
the LPIs, you also need to free the MSI desc and potentially reset the
IRQ desc.
Otherwise you will left the irq_desc in an unknown state for the next one.
But discard != free? (or at least "discard" has a specific meaning in its).

If this function is supposed to free everything then I would agree, and
also add that the function is therefore badly (or at least confusingly)
named.

If it is just supposed to discard (==clear any h/w pending state of an LPI
mapped by a given event on a given device) then I think it is correct,
isn't it?
Post by v***@gmail.com
Post by v***@gmail.com
+ xfree(dev->event_map.col_map);
+ xfree(dev);
+}
+
+static struct its_device *its_alloc_device(u32 devid, u32 nr_ites,
+ struct dt_device_node *dt_its)
+{
+ struct its_device *dev;
+ paddr_t *itt;
Why paddr_t? You only allocate it and pass directly to the hardware.
paddr_t seems correct, it the fact that it is a paddr_t * (i.e. a pointer)
which seems odd to me. I think you commented the same thing on dev
->itt_addr which is where this ends up assigned.

Ian.
Julien Grall
2015-09-09 13:44:13 UTC
Permalink
Post by Ian Campbell
Post by v***@gmail.com
@@ -522,6 +535,205 @@ static void its_lpi_free(struct its_device *dev)
Post by v***@gmail.com
xfree(dev->event_map.lpi_map);
}
+static void its_discard_lpis(struct its_device *dev, u32 ids)
+{
+ int i;
+
I would have expected a function more complex than that. If you discard
the LPIs, you also need to free the MSI desc and potentially reset the
IRQ desc.
Otherwise you will left the irq_desc in an unknown state for the next one.
But discard != free? (or at least "discard" has a specific meaning in its).
In the ITS, discard means removing the mapping from the MSI (eventID) to
the LPI.

So after discarding we have to clean up the irq_desc in order to let
some else re-using the IRQ desc. This means:
- Free the MSI desc otherwise there is a leak
- Reset the irq_desc fields in the initial value
- Potentially poke the hardware to disable the interrupt
Post by Ian Campbell
If this function is supposed to free everything then I would agree, and
also add that the function is therefore badly (or at least confusingly)
named.
If it is just supposed to discard (==clear any h/w pending state of an LPI
mapped by a given event on a given device) then I think it is correct,
isn't it?
IHMO, the function is correctly named. Resetting the irq_desc in a valid
state is part of the discard because we just replicate the internal state.

Resetting the irq_desc means free the msi_desc in order to avoid leak.
Although, if the msi_desc would have been allocated in the event_lpi_map
all this extra care wouldn't have been necessary.

I mean having a new field in event_lpi_map msis which is an array of
msi_desc.
Post by Ian Campbell
Post by v***@gmail.com
Post by v***@gmail.com
+ xfree(dev->event_map.col_map);
+ xfree(dev);
+}
+
+static struct its_device *its_alloc_device(u32 devid, u32 nr_ites,
+ struct dt_device_node *dt_its)
+{
+ struct its_device *dev;
+ paddr_t *itt;
Why paddr_t? You only allocate it and pass directly to the hardware.
paddr_t seems correct, it the fact that it is a paddr_t * (i.e. a pointer)
which seems odd to me. I think you commented the same thing on dev
->itt_addr which is where this ends up assigned.
With the current usage, we store the result of xmalloc in the itt
variable. So it's a pointer to a virtual address not a paddr_t.

If we decide to use paddr_t, then we should also update the code.
Although, the Linux ITS code is using void * in order to store the
pointer. So I'd like to keep the same in order to avoid differing too
much for Linux (though with all this coding style it would be difficult
to backport code).

Regards,
--
Julien Grall
Ian Campbell
2015-09-09 15:07:53 UTC
Permalink
Post by Julien Grall
Post by Ian Campbell
Post by v***@gmail.com
@@ -522,6 +535,205 @@ static void its_lpi_free(struct its_device *dev)
Post by v***@gmail.com
xfree(dev->event_map.lpi_map);
}
+static void its_discard_lpis(struct its_device *dev, u32 ids)
+{
+ int i;
+
I would have expected a function more complex than that. If you discard
the LPIs, you also need to free the MSI desc and potentially reset the
IRQ desc.
Otherwise you will left the irq_desc in an unknown state for the next one.
But discard != free? (or at least "discard" has a specific meaning in its).
In the ITS, discard means removing the mapping from the MSI (eventID) to
the LPI.
Table 6-6 in the gic arch spec (ARM IHI 0069A (ID060315)) says about the
discard ITS command "Translates the event defined by EventID and DeviceID
and instructs the appropriate Redistributor to remove the pending state of
the interrupt. It also ensures that any caching in the Redistributors
associated with a specific EventID is consistent with the configuration
held in memory."

And section 6.3.4 seems to agree _except_ for the pseudo code which does
indeed seem to include setting the corresponding ITE entry to invalid.

Given that the pseudocode for CLEAR appears to match how DISCARD is
decribed (infact the descrpitions of CLEAR and DISCARD look functionally
identical to me) I'm inclined to believe the pseudo code for DISCARD, i.e.
the docs are misleading and you are correct that DISCARD is more than just
clearing the pending state.

The older PRD03-GENC-010745 24.0 looks to be more correct.

So sorry for the noise, that'll teach me to believe docs.
Post by Julien Grall
Post by Ian Campbell
Post by v***@gmail.com
Post by v***@gmail.com
+ xfree(dev->event_map.col_map);
+ xfree(dev);
+}
+
+static struct its_device *its_alloc_device(u32 devid, u32 nr_ites,
+ struct dt_device_node *dt_its)
+{
+ struct its_device *dev;
+ paddr_t *itt;
Why paddr_t? You only allocate it and pass directly to the hardware.
paddr_t seems correct, it the fact that it is a paddr_t * (i.e. a pointer)
which seems odd to me. I think you commented the same thing on dev
->itt_addr which is where this ends up assigned.
With the current usage, we store the result of xmalloc in the itt
variable. So it's a pointer to a virtual address not a paddr_t.
Ah, in that case it should indeed have some other type.
Post by Julien Grall
If we decide to use paddr_t, then we should also update the code.
Although, the Linux ITS code is using void * in order to store the
pointer. So I'd like to keep the same in order to avoid differing too
much for Linux (though with all this coding style it would be difficult
to backport code).
Regards,
Julien Grall
2015-09-09 16:19:26 UTC
Permalink
Post by Ian Campbell
Post by Julien Grall
In the ITS, discard means removing the mapping from the MSI (eventID) to
the LPI.
Table 6-6 in the gic arch spec (ARM IHI 0069A (ID060315)) says about the
discard ITS command "Translates the event defined by EventID and DeviceID
and instructs the appropriate Redistributor to remove the pending state of
the interrupt. It also ensures that any caching in the Redistributors
associated with a specific EventID is consistent with the configuration
held in memory."
And section 6.3.4 seems to agree _except_ for the pseudo code which does
indeed seem to include setting the corresponding ITE entry to invalid.
Given that the pseudocode for CLEAR appears to match how DISCARD is
decribed (infact the descrpitions of CLEAR and DISCARD look functionally
identical to me) I'm inclined to believe the pseudo code for DISCARD, i.e.
the docs are misleading and you are correct that DISCARD is more than just
clearing the pending state.
The older PRD03-GENC-010745 24.0 looks to be more correct.
So sorry for the noise, that'll teach me to believe docs.
Actually, I didn't read the newer spec but remembered from what I read
on the PRD03-* one.

After reading the newer spec, the description doesn't match the
pseudo-code. Might be worth to ask ARM about to clarify the behavior?

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:34 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Store number of lpis and number of id bits
in vgic structure

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/irq.c | 9 +++++++++
xen/arch/arm/vgic-v3-its.c | 2 ++
xen/arch/arm/vgic.c | 12 ++++++++++++
xen/include/asm-arm/domain.h | 3 +++
xen/include/asm-arm/irq.h | 3 +++
5 files changed, 29 insertions(+)

diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 24c4f24..93e9411 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -31,6 +31,15 @@
static unsigned int local_irqs_type[NR_LOCAL_IRQS];
static DEFINE_SPINLOCK(local_irqs_type_lock);

+/* Number of LPI supported in XEN */
+/*
+ * LPI number start from 8192. Minimum number of bits
+ * required to represent 8192 is 13 bits. So to Support LPIs minimum
+ * 14 bits are required which can represent maximum LPI 16384.
+ * 16384 - 8192 = 8192. Minimum number of LPIs supported is 8192
+ */
+unsigned int nr_lpis = 8192;
+
/* Describe an IRQ assigned to a guest */
struct irq_guest
{
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index fabbad0..cef6139 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -547,6 +547,8 @@ int vits_domain_init(struct domain *d)

ASSERT(is_hardware_domain(d));

+ d->arch.vgic.nr_lpis = nr_lpis;
+
d->arch.vgic.vits = xzalloc(struct vgic_its);
if ( !d->arch.vgic.vits )
return -ENOMEM;
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index e28c30d..6b6bbce 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -72,8 +72,10 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
{
int i;
int ret;
+ unsigned int irq_lines;

d->arch.vgic.ctlr = 0;
+ d->arch.vgic.nr_lpis = 0;

/* Limit the number of virtual SPIs supported to (1020 - 32) = 988 */
if ( nr_spis > (1020 - NR_LOCAL_IRQS) )
@@ -130,6 +132,16 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
for ( i = 0; i < NR_GIC_SGI; i++ )
set_bit(i, d->arch.vgic.allocated_irqs);

+ irq_lines = d->arch.vgic.nr_spis + 32;
+ /*
+ * If LPIs are supported, then just overwrite nr_spis
+ * in computing id_bits.
+ */
+ if ( d->arch.vgic.nr_lpis != 0 )
+ irq_lines = d->arch.vgic.nr_lpis + FIRST_GIC_LPI;
+
+ d->arch.vgic.id_bits = get_count_order(irq_lines);
+
return 0;
}

diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 986a4d6..269e4bb 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -93,6 +93,9 @@ struct arch_domain
spinlock_t lock;
int ctlr;
int nr_spis; /* Number of SPIs */
+ int nr_lpis; /* Number of LPIs */
+ /* Number of bits required to represent IRQs(SPIs+LPIs) */
+ int id_bits;
unsigned long *allocated_irqs; /* bitmap of IRQs allocated */
struct vgic_irq_rank *shared_irqs;
/*
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index bddd1ea..ff37234 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -33,6 +33,9 @@ struct msi_desc {
#define nr_static_irqs NR_LINE_IRQS
#define arch_hwdom_irqs(domid) NR_LINE_IRQS

+/* Number of LPI supported */
+extern unsigned int nr_lpis;
+
struct irq_desc;
struct irqaction;
--
1.7.9.5
Julien Grall
2015-09-03 16:25:15 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
Store number of lpis and number of id bits
in vgic structure
---
xen/arch/arm/irq.c | 9 +++++++++
xen/arch/arm/vgic-v3-its.c | 2 ++
xen/arch/arm/vgic.c | 12 ++++++++++++
xen/include/asm-arm/domain.h | 3 +++
xen/include/asm-arm/irq.h | 3 +++
5 files changed, 29 insertions(+)
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 24c4f24..93e9411 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -31,6 +31,15 @@
static unsigned int local_irqs_type[NR_LOCAL_IRQS];
static DEFINE_SPINLOCK(local_irqs_type_lock);
+/* Number of LPI supported in XEN */
+/*
Number of LPI supported by Xen.

Also, it's not necessary to have a separate comment for this. It could
be included in the next one. I.e:

/*
* Number of LPI supported by Xen
*
* LPI ....
Post by v***@gmail.com
+ * LPI number start from 8192. Minimum number of bits
+ * required to represent 8192 is 13 bits. So to Support LPIs minimum
+ * 14 bits are required which can represent maximum LPI 16384.
+ * 16384 - 8192 = 8192. Minimum number of LPIs supported is 8192
+ */
The explanation is hard to understand. I would rewrite like:

"The LPI identifier starts from 8192. Given that the hardware is
providing the number of identifier bits, supporting LPIs requires at
least 14 bits. This will represent 16384 interrupt ID of which 8192
LPIs. So the minimum of LPIs supported when the hardware supports LPIs
is 8192 ".
Post by v***@gmail.com
+unsigned int nr_lpis = 8192;
+
I still don't think that it makes sense to introduce the number of LPIs
variable in a patch for vITS. As you describe it, it should be part of
an ITS/GICv3 patch.

Although, I think you should use the field nr_irq_ids in the gic
structure (see patch #10) to avoid problem you currently have with this
solution.

For instance, gic_is_lpi is relying on the number of ID bits exposed by
the hardware but you allocate the IRQ desc for LPIs based on nr_lpis.

It's fine to restrict the value in the GIC compare to hardware.

Furthermore this value should be 0 on platform where LPIs is not
supported in order to make confusion and introduce possible problem with
the code later. I could add that, AFAICT, this new variable (nr_lpis) is
not that often within the code.

Lastly, on a previous version (don't remember which one) we said that
the user should be able to change the value on the command line. What's
your plan for that?
Post by v***@gmail.com
/* Describe an IRQ assigned to a guest */
struct irq_guest
{
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index fabbad0..cef6139 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -547,6 +547,8 @@ int vits_domain_init(struct domain *d)
ASSERT(is_hardware_domain(d));
+ d->arch.vgic.nr_lpis = nr_lpis;
+
With my suggestion, this would turn into gic_nr_irq_ids() - 8192;
Post by v***@gmail.com
d->arch.vgic.vits = xzalloc(struct vgic_its);
if ( !d->arch.vgic.vits )
return -ENOMEM;
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index e28c30d..6b6bbce 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -72,8 +72,10 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
{
int i;
int ret;
+ unsigned int irq_lines;
This will be used as the number of IRQ identifiers which is different as
the number of lines. So please rename into irq_ids.
Post by v***@gmail.com
d->arch.vgic.ctlr = 0;
+ d->arch.vgic.nr_lpis = 0;
/* Limit the number of virtual SPIs supported to (1020 - 32) = 988 */
if ( nr_spis > (1020 - NR_LOCAL_IRQS) )
@@ -130,6 +132,16 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
for ( i = 0; i < NR_GIC_SGI; i++ )
set_bit(i, d->arch.vgic.allocated_irqs);
+ irq_lines = d->arch.vgic.nr_spis + 32;
+ /*
+ * If LPIs are supported, then just overwrite nr_spis
+ * in computing id_bits.
+ */
+ if ( d->arch.vgic.nr_lpis != 0 )
+ irq_lines = d->arch.vgic.nr_lpis + FIRST_GIC_LPI;
+
This would be more logic to do:

if ( !d->arch.vgic.nr_lpis )
irq_ids = d->arch.vgic.nr_spis + 32;
else
irq_ids = d->arch.vgic.nr_lpis + FIRST_GIC_LPI;

You could also use "min()" if you want to avoid the if/else.
Post by v***@gmail.com
+ d->arch.vgic.id_bits = get_count_order(irq_lines);
+
return 0;
}
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 986a4d6..269e4bb 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -93,6 +93,9 @@ struct arch_domain
spinlock_t lock;
int ctlr;
int nr_spis; /* Number of SPIs */
+ int nr_lpis; /* Number of LPIs */
+ /* Number of bits required to represent IRQs(SPIs+LPIs) */
+ int id_bits;
I'm not entirely sure this is worth to expose it given it's only used in
a single place (setup of the property table) which is called rarely.
Post by v***@gmail.com
unsigned long *allocated_irqs; /* bitmap of IRQs allocated */
struct vgic_irq_rank *shared_irqs;
/*
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index bddd1ea..ff37234 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -33,6 +33,9 @@ struct msi_desc {
#define nr_static_irqs NR_LINE_IRQS
#define arch_hwdom_irqs(domid) NR_LINE_IRQS
+/* Number of LPI supported */
+extern unsigned int nr_lpis;
+
struct irq_desc;
struct irqaction;
Regards,
--
Julien Grall
Vijay Kilari
2015-09-07 06:59:15 UTC
Permalink
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
Store number of lpis and number of id bits
in vgic structure
---
xen/arch/arm/irq.c | 9 +++++++++
xen/arch/arm/vgic-v3-its.c | 2 ++
xen/arch/arm/vgic.c | 12 ++++++++++++
xen/include/asm-arm/domain.h | 3 +++
xen/include/asm-arm/irq.h | 3 +++
5 files changed, 29 insertions(+)
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 24c4f24..93e9411 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -31,6 +31,15 @@
static unsigned int local_irqs_type[NR_LOCAL_IRQS];
static DEFINE_SPINLOCK(local_irqs_type_lock);
+/* Number of LPI supported in XEN */
+/*
Number of LPI supported by Xen.
Also, it's not necessary to have a separate comment for this. It could
/*
* Number of LPI supported by Xen
*
* LPI ....
Post by v***@gmail.com
+ * LPI number start from 8192. Minimum number of bits
+ * required to represent 8192 is 13 bits. So to Support LPIs minimum
+ * 14 bits are required which can represent maximum LPI 16384.
+ * 16384 - 8192 = 8192. Minimum number of LPIs supported is 8192
+ */
"The LPI identifier starts from 8192. Given that the hardware is
providing the number of identifier bits, supporting LPIs requires at
least 14 bits. This will represent 16384 interrupt ID of which 8192
LPIs. So the minimum of LPIs supported when the hardware supports LPIs
is 8192 ".
Post by v***@gmail.com
+unsigned int nr_lpis = 8192;
+
I still don't think that it makes sense to introduce the number of LPIs
variable in a patch for vITS. As you describe it, it should be part of
an ITS/GICv3 patch.
Although, I think you should use the field nr_irq_ids in the gic
structure (see patch #10) to avoid problem you currently have with this
solution.
For instance, gic_is_lpi is relying on the number of ID bits exposed by
the hardware but you allocate the IRQ desc for LPIs based on nr_lpis.
You mean to restrict nr_irq_ids to FIRST_GIC_LPI + 8192 (nr_lpis)
instead of HW supported value?
and let gic_is_lpi() always check for Xen supported lpi number instead of hw
supported value?
Post by Julien Grall
It's fine to restrict the value in the GIC compare to hardware.
Furthermore this value should be 0 on platform where LPIs is not
supported in order to make confusion and introduce possible problem with
the code later. I could add that, AFAICT, this new variable (nr_lpis) is
not that often within the code.
nr_lpis is global variable that we define to tell number of LPIs supported
by Xen. If platform does not support LPIs, then vgic.nr_lpis is set to 0.
Post by Julien Grall
Lastly, on a previous version (don't remember which one) we said that
the user should be able to change the value on the command line. What's
your plan for that?
Yes, it was part of our discussion on chat. I will fix it.
Post by Julien Grall
Post by v***@gmail.com
/* Describe an IRQ assigned to a guest */
struct irq_guest
{
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index fabbad0..cef6139 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -547,6 +547,8 @@ int vits_domain_init(struct domain *d)
ASSERT(is_hardware_domain(d));
+ d->arch.vgic.nr_lpis = nr_lpis;
+
With my suggestion, this would turn into gic_nr_irq_ids() - 8192;
As suggested above, if we restrict nr_irq_ids to Xen supported
value (FIRST_GIC_LPI + 8192(nr_lpis) then you suggestion is right.

Regards
Vijay
Julien Grall
2015-09-07 10:56:18 UTC
Permalink
Hi Vijay,
Post by Vijay Kilari
Post by Julien Grall
I still don't think that it makes sense to introduce the number of LPIs
variable in a patch for vITS. As you describe it, it should be part of
an ITS/GICv3 patch.
Although, I think you should use the field nr_irq_ids in the gic
structure (see patch #10) to avoid problem you currently have with this
solution.
For instance, gic_is_lpi is relying on the number of ID bits exposed by
the hardware but you allocate the IRQ desc for LPIs based on nr_lpis.
You mean to restrict nr_irq_ids to FIRST_GIC_LPI + 8192 (nr_lpis)
instead of HW supported value?
and let gic_is_lpi() always check for Xen supported lpi number instead of hw
supported value?
Yes for both.
Post by Vijay Kilari
Post by Julien Grall
It's fine to restrict the value in the GIC compare to hardware.
Furthermore this value should be 0 on platform where LPIs is not
supported in order to make confusion and introduce possible problem with
the code later. I could add that, AFAICT, this new variable (nr_lpis) is
not that often within the code.
nr_lpis is global variable that we define to tell number of LPIs supported
by Xen. If platform does not support LPIs, then vgic.nr_lpis is set to 0.
While you set vgic.nr_lpis to 0, you don't clear nr_lpis. So
technically, someone could decide to use it later but it won't report
the correct value....

It was difficult to find the correct place to comment about this given
that you've introduced the variable in an odd place....
Post by Vijay Kilari
Post by Julien Grall
Lastly, on a previous version (don't remember which one) we said that
the user should be able to change the value on the command line. What's
your plan for that?
Yes, it was part of our discussion on chat. I will fix it.
A summarize would have been nice... like a TODO in the code and/or in
the cover letter. Depends when you plan to handle it.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:28 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Enable compilation of pITS driver.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.c
---
xen/arch/arm/Makefile | 1 +
1 file changed, 1 insertion(+)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 1ef39f7..4708716 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -14,6 +14,7 @@ obj-y += domain_build.o
obj-y += gic.o gic-v2.o
obj-$(CONFIG_ARM_32) += gic-hip04.o
obj-$(HAS_GICV3) += gic-v3.o
+obj-$(HAS_GICV3) += gic-v3-its.o
obj-y += io.o
obj-y += irq.o
obj-y += kernel.o
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:21 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

nr_cpu_ids for arm platforms is set to NR_CPUS irrespective of
number of cpus supported by platform.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Updated nr_cpu_ids in setup.c instead of creating
a helper function
---
xen/arch/arm/setup.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 6626eba..67b5f14 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -772,6 +772,8 @@ void __init start_xen(unsigned long boot_phys_offset,

smp_init_cpus();
cpus = smp_get_max_cpus();
+ printk(XENLOG_INFO "SMP: Allowing %u CPUs\n", cpus);
+ nr_cpu_ids = cpus;

init_xen_time();
--
1.7.9.5
Julien Grall
2015-08-31 14:25:23 UTC
Permalink
title: Set nr_cpu_ids to the number of CPUs available
Post by v***@gmail.com
nr_cpu_ids for arm platforms is set to NR_CPUS irrespective of
s/is set/is incorrectly set/ to make clear that it's the previous
behavior and not the one that you are implemented.
Post by v***@gmail.com
number of cpus supported by platform.
^ the number
With the typos mentioned:

Reviewed-by: Julien Grall <***@citrix.com>

Regards,
--
Julien Grall
Ian Campbell
2015-09-09 12:48:26 UTC
Permalink
Post by Julien Grall
title: Set nr_cpu_ids to the number of CPUs available
Post by v***@gmail.com
nr_cpu_ids for arm platforms is set to NR_CPUS irrespective of
s/is set/is incorrectly set/ to make clear that it's the previous
behavior and not the one that you are implemented.
Post by v***@gmail.com
number of cpus supported by platform.
^ the number
Agreed, with those fixed: Acked-by: Ian Campbell <***@citrix.com>
v***@gmail.com
2015-08-31 11:06:23 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

The linux driver is based on 4.1 with below commit id

3ad2a5f57656a14d964b673a5a0e4ab0e583c870

Only following code from Linux ITS driver is ported
and compiled
- LPI initialization
- ITS configuration code
- Physical command queue management
- ITS command building

Also redistributor information is split into rdist and
rdist_prop structures.

The rdist_prop struct holds the redistributor common
information for all re-distributor and rdist struct
holds the per-cpu specific information.

This per-cpu rdist is defined as global and shared with
physical ITS driver.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6:
- made dump_cmd() static and const parameter
- Include commit 591e5bec13f15feb13fc445b6c9c59954711c4ac
"irqchip/gicv3-its: Fix mapping of LPIs to collections".
- reodered its_alloc_lpi_tables() and its_lpi_init()
v5:
- dump_cmd is called from its_flush_cmd
- Added its_lpi_alloc_chunks, lpi_free, its_send_inv, its_send_mapd,
its_send_mapvi to this patch as these functions are ported from
linux and more logical to be in this patch.
For now these functions are non-static. Will be made static
when used.
- Used this_cpu instead of per_cpu
- Moved GITS_* definitions to git-its.h
v4: Major changes
- Redistributor refactoring patch is merged
- Fixed comments from v3 related to coding style and
removing duplicate code.
- Target address is stored from bits[48:16] to avoid
shifting of target address while building ITS commands
- Removed non-static functions
- Removed usage of command builder functions
- Changed its_cmd_block union to include mix of bit and unsigned
variable types to define ITS command structure
v3:
- Only required changes from Linux ITS driver is ported
- Xen coding style is followed.
---
xen/arch/arm/gic-v3-its.c | 1011 +++++++++++++++++++++++++++++++++++++
xen/arch/arm/gic-v3.c | 15 +-
xen/include/asm-arm/gic-its.h | 282 +++++++++++
xen/include/asm-arm/gic.h | 1 +
xen/include/asm-arm/gic_v3_defs.h | 42 +-
5 files changed, 1344 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
new file mode 100644
index 0000000..4ad8d8e
--- /dev/null
+++ b/xen/arch/arm/gic-v3-its.c
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
+ * Author: Marc Zyngier <***@arm.com>
+ *
+ * Xen changes:
+ * Vijaya Kumar K <***@caviumnetworks.com>
+ * Copyright (C) 2014, 2015 Cavium Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 <xen/config.h>
+#include <xen/bitops.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/errno.h>
+#include <xen/delay.h>
+#include <xen/list.h>
+#include <xen/sizes.h>
+#include <xen/vmap.h>
+#include <asm/p2m.h>
+#include <asm/domain.h>
+#include <asm/io.h>
+#include <asm/device.h>
+#include <asm/gic.h>
+#include <asm/gic_v3_defs.h>
+#include <asm/gic-its.h>
+#include <xen/log2.h>
+
+#define its_print(lvl, fmt, ...) \
+ printk(lvl "GIC-ITS:" fmt, ## __VA_ARGS__)
+
+#define its_err(fmt, ...) its_print(XENLOG_ERR, fmt, ## __VA_ARGS__)
+/* TODO: ratelimit for Xen messages */
+#define its_err_ratelimited(fmt, ...) \
+ its_print(XENLOG_G_ERR, fmt, ## __VA_ARGS__)
+
+#define its_dbg(fmt, ...) \
+ its_print(XENLOG_DEBUG, fmt, ## __VA_ARGS__)
+
+#define its_info(fmt, ...) \
+ its_print(XENLOG_INFO, fmt, ## __VA_ARGS__)
+
+#define its_warn(fmt, ...) \
+ its_print(XENLOG_WARNING, fmt, ## __VA_ARGS__)
+
+//#define DEBUG_GIC_ITS
+
+#ifdef DEBUG_GIC_ITS
+# define DPRINTK(fmt, args...) printk(XENLOG_DEBUG fmt, ##args)
+#else
+# define DPRINTK(fmt, args...) do {} while ( 0 )
+#endif
+
+#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0)
+#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
+
+/*
+ * The ITS structure - contains most of the infrastructure, with the
+ * msi_controller, the command queue, the collections, and the list of
+ * devices writing to it.
+ */
+struct its_node {
+ spinlock_t lock;
+ struct list_head entry;
+ void __iomem *base;
+ paddr_t phys_base;
+ paddr_t phys_size;
+ its_cmd_block *cmd_base;
+ its_cmd_block *cmd_write;
+ void *tables[GITS_BASER_NR_REGS];
+ u32 order[GITS_BASER_NR_REGS];
+ struct its_collection *collections;
+ u64 flags;
+ u32 ite_size;
+ struct dt_device_node *dt_node;
+};
+
+#define ITS_ITT_ALIGN SZ_256
+
+static LIST_HEAD(its_nodes);
+static DEFINE_SPINLOCK(its_lock);
+static struct rdist_prop *gic_rdists;
+
+#define gic_data_rdist() (this_cpu(rdist))
+
+#ifdef DEBUG_GIC_ITS
+static void dump_cmd(const its_cmd_block *cmd)
+{
+ printk(XENLOG_DEBUG
+ "ITS: CMD[0] = 0x%lx CMD[1] = 0x%lx CMD[2] = 0x%lx CMD[3] = 0x%lx\n",
+ cmd->bits[0], cmd->bits[1], cmd->bits[2], cmd->bits[3]);
+}
+#else
+static void dump_cmd(const its_cmd_block *cmd) { }
+#endif
+
+static struct its_collection *dev_event_to_col(struct its_device *dev,
+ u32 event)
+{
+ struct its_node *its = dev->its;
+
+ return its->collections + dev->event_map.col_map[event];
+}
+
+#define ITS_CMD_QUEUE_SZ SZ_64K
+#define ITS_CMD_QUEUE_NR_ENTRIES (ITS_CMD_QUEUE_SZ / sizeof(its_cmd_block))
+
+static u64 its_cmd_ptr_to_offset(struct its_node *its, its_cmd_block *ptr)
+{
+ return (ptr - its->cmd_base) * sizeof(*ptr);
+}
+
+static int its_queue_full(struct its_node *its)
+{
+ int widx;
+ int ridx;
+
+ widx = its->cmd_write - its->cmd_base;
+ ridx = readl_relaxed(its->base + GITS_CREADR) / sizeof(its_cmd_block);
+
+ /* This is incredibly unlikely to happen, unless the ITS locks up. */
+ if ( ((widx + 1) % ITS_CMD_QUEUE_NR_ENTRIES) == ridx )
+ return 1;
+
+ return 0;
+}
+
+static its_cmd_block *its_allocate_entry(struct its_node *its)
+{
+ its_cmd_block *cmd;
+ u32 count = 1000000; /* 1s! */
+
+ while ( its_queue_full(its) )
+ {
+ count--;
+ if ( !count )
+ {
+ its_err_ratelimited("ITS queue not draining\n");
+ return NULL;
+ }
+ cpu_relax();
+ udelay(1);
+ }
+
+ cmd = its->cmd_write++;
+
+ /* Handle queue wrapping */
+ if (its->cmd_write == (its->cmd_base + ITS_CMD_QUEUE_NR_ENTRIES))
+ its->cmd_write = its->cmd_base;
+
+ return cmd;
+}
+
+static its_cmd_block *its_post_commands(struct its_node *its)
+{
+ u64 wr = its_cmd_ptr_to_offset(its, its->cmd_write);
+
+ writel_relaxed(wr, its->base + GITS_CWRITER);
+
+ return its->cmd_write;
+}
+
+static void its_flush_cmd(struct its_node *its, its_cmd_block *cmd)
+{
+ /*
+ * Make sure the commands written to memory are observable by
+ * the ITS.
+ */
+ if ( its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING )
+ clean_and_invalidate_dcache_va_range(cmd, sizeof(*cmd));
+ else
+ dsb(ishst);
+
+ dump_cmd(cmd);
+}
+
+static void its_wait_for_range_completion(struct its_node *its,
+ its_cmd_block *from,
+ its_cmd_block *to)
+{
+ u64 rd_idx, from_idx, to_idx;
+ u32 count = 1000000; /* 1s! */
+
+ from_idx = its_cmd_ptr_to_offset(its, from);
+ to_idx = its_cmd_ptr_to_offset(its, to);
+
+ while ( 1 )
+ {
+ rd_idx = readl_relaxed(its->base + GITS_CREADR);
+ if ( rd_idx >= to_idx || rd_idx < from_idx )
+ break;
+
+ count--;
+ if ( !count )
+ {
+ its_err_ratelimited("ITS queue timeout\n");
+ return;
+ }
+ cpu_relax();
+ udelay(1);
+ }
+}
+
+static void its_send_single_command(struct its_node *its,
+ its_cmd_block *src,
+ struct its_collection *sync_col)
+{
+ its_cmd_block *cmd, *sync_cmd, *next_cmd;
+ unsigned long flags;
+
+ BUILD_BUG_ON(sizeof(its_cmd_block) != 32);
+
+ spin_lock_irqsave(&its->lock, flags);
+
+ cmd = its_allocate_entry(its);
+ if ( !cmd )
+ { /* We're soooooo screewed... */
+ its_err_ratelimited("ITS can't allocate, dropping command\n");
+ spin_unlock_irqrestore(&its->lock, flags);
+ return;
+ }
+
+ memcpy(cmd, src, sizeof(its_cmd_block));
+ its_flush_cmd(its, cmd);
+
+ if ( sync_col )
+ {
+ sync_cmd = its_allocate_entry(its);
+ if ( !sync_cmd )
+ {
+ its_err_ratelimited("ITS can't SYNC, skipping\n");
+ goto post;
+ }
+ sync_cmd->sync.cmd = GITS_CMD_SYNC;
+ sync_cmd->sync.ta = sync_col->target_address;
+
+ its_flush_cmd(its, sync_cmd);
+ }
+
+post:
+ next_cmd = its_post_commands(its);
+ spin_unlock_irqrestore(&its->lock, flags);
+
+ its_wait_for_range_completion(its, cmd, next_cmd);
+}
+
+static void its_send_mapd(struct its_device *dev, int valid)
+{
+ its_cmd_block cmd;
+ unsigned long itt_addr;
+ u8 size;
+
+ size = ilog2(dev->event_map.nr_lpis);
+ itt_addr = __pa(dev->itt_addr);
+ itt_addr = ROUNDUP(itt_addr, ITS_ITT_ALIGN);
+
+ memset(&cmd, 0x0, sizeof(its_cmd_block));
+ cmd.mapd.cmd = GITS_CMD_MAPD;
+ cmd.mapd.devid = dev->device_id;
+ cmd.mapd.size = size - 1;
+ /*
+ * ITT address field of MAPD command holds bit[48:8] of
+ * itt address. Hence shift by 8.
+ */
+ cmd.mapd.itt = itt_addr >> 8;
+ cmd.mapd.valid = !!valid;
+
+ its_send_single_command(dev->its, &cmd, NULL);
+}
+
+static void its_send_mapc(struct its_node *its, struct its_collection *col,
+ int valid)
+{
+ its_cmd_block cmd;
+
+ memset(&cmd, 0x0, sizeof(its_cmd_block));
+ cmd.mapc.cmd = GITS_CMD_MAPC;
+ cmd.mapc.col = col->col_id;
+ cmd.mapc.ta = col->target_address;
+ cmd.mapc.valid = !!valid;
+
+ its_send_single_command(its, &cmd, col);
+}
+
+static void its_send_mapvi(struct its_device *dev, u32 phys_id, u32 event)
+{
+ its_cmd_block cmd;
+ struct its_collection *col = dev_event_to_col(dev, event);
+
+ memset(&cmd, 0x0, sizeof(its_cmd_block));
+ cmd.mapvi.cmd = GITS_CMD_MAPVI;
+ cmd.mapvi.devid = dev->device_id;
+ cmd.mapvi.event = event;
+ cmd.mapvi.phy_id = phys_id;
+ cmd.mapvi.col = col->col_id;
+
+ its_send_single_command(dev->its, &cmd, col);
+}
+
+static void its_send_invall(struct its_node *its, struct its_collection *col)
+{
+ its_cmd_block cmd;
+
+ memset(&cmd, 0x0, sizeof(its_cmd_block));
+ cmd.invall.cmd = GITS_CMD_INVALL;
+ cmd.invall.col = col->col_id;
+
+ its_send_single_command(its, &cmd, NULL);
+}
+
+static void its_send_discard(struct its_device *dev, u32 event)
+{
+ its_cmd_block cmd;
+ struct its_collection *col = dev_event_to_col(dev, event);
+
+ memset(&cmd, 0x0, sizeof(its_cmd_block));
+ cmd.discard.devid = dev->device_id;
+ cmd.discard.event = event;
+
+ its_send_single_command(dev->its, &cmd, col);
+}
+
+/*
+ * How we allocate LPIs:
+ *
+ * The GIC has id_bits bits for interrupt identifiers. From there, we
+ * must subtract 8192 which are reserved for SGIs/PPIs/SPIs. Then, as
+ * we allocate LPIs by chunks of 32, we can shift the whole thing by 5
+ * bits to the right.
+ *
+ * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
+ */
+#define IRQS_PER_CHUNK_SHIFT 5
+#define IRQS_PER_CHUNK (1 << IRQS_PER_CHUNK_SHIFT)
+
+static unsigned long *lpi_bitmap;
+static u32 lpi_chunks;
+static DEFINE_SPINLOCK(lpi_lock);
+
+static int its_lpi_to_chunk(int lpi)
+{
+ return (lpi - 8192) >> IRQS_PER_CHUNK_SHIFT;
+}
+
+static int its_chunk_to_lpi(int chunk)
+{
+ return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
+}
+
+static int its_lpi_init(u32 id_bits)
+{
+ lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
+
+ lpi_bitmap = xzalloc_bytes(BITS_TO_LONGS(lpi_chunks) * sizeof(long));
+ if ( !lpi_bitmap )
+ {
+ lpi_chunks = 0;
+ return -ENOMEM;
+ }
+
+ its_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
+
+ return 0;
+}
+
+static unsigned long *its_lpi_alloc_chunks(int nirqs, int *base)
+{
+ unsigned long *bitmap = NULL;
+ int chunk_id, nr_chunks, nr_ids, i;
+
+ nr_chunks = DIV_ROUND_UP(nirqs, IRQS_PER_CHUNK);
+
+ spin_lock(&lpi_lock);
+
+ do {
+ chunk_id = bitmap_find_next_zero_area(lpi_bitmap, lpi_chunks,
+ 0, nr_chunks, 0);
+ if ( chunk_id < lpi_chunks )
+ break;
+
+ nr_chunks--;
+ } while ( nr_chunks > 0 );
+
+ if ( !nr_chunks )
+ goto out;
+
+ bitmap = xzalloc_bytes(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) *
+ sizeof (long));
+ if ( !bitmap )
+ goto out;
+
+ for ( i = 0; i < nr_chunks; i++ )
+ set_bit(chunk_id + i, lpi_bitmap);
+
+ *base = its_chunk_to_lpi(chunk_id);
+ nr_ids = nr_chunks * IRQS_PER_CHUNK;
+
+ if ( nr_ids < nirqs )
+ {
+ xfree(bitmap);
+ bitmap = NULL;
+ }
+
+out:
+ spin_unlock(&lpi_lock);
+
+ return bitmap;
+}
+
+static void its_lpi_free(struct its_device *dev)
+{
+ int lpi;
+
+ spin_lock(&lpi_lock);
+
+ for ( lpi = dev->event_map.lpi_base;
+ lpi < (dev->event_map.lpi_base + dev->event_map.nr_lpis);
+ lpi += IRQS_PER_CHUNK )
+ {
+ int chunk = its_lpi_to_chunk(lpi);
+
+ if (chunk > lpi_chunks)
+ its_err("Bad LPI chunk %d\n", chunk);
+ if ( test_bit(chunk, lpi_bitmap) )
+ clear_bit(chunk, lpi_bitmap);
+ }
+
+ spin_unlock(&lpi_lock);
+
+ xfree(dev->event_map.lpi_map);
+}
+
+/*
+ * We allocate 64kB for PROPBASE. That gives us at most 64K LPIs to
+ * deal with (one configuration byte per interrupt). PENDBASE has to
+ * be 64kB aligned (one bit per LPI, plus 8192 bits for SPI/PPI/SGI).
+ */
+#define LPI_PROPBASE_SZ SZ_64K
+#define LPI_PENDBASE_SZ (LPI_PROPBASE_SZ / 8 + SZ_1K)
+
+/*
+ * This is how many bits of ID we need, including the useless ones.
+ */
+#define LPI_NRBITS ilog2(LPI_PROPBASE_SZ + SZ_8K)
+
+static int __init its_alloc_lpi_tables(void)
+{
+ paddr_t paddr;
+
+ gic_rdists->prop_page =
+ alloc_xenheap_pages(get_order_from_bytes(LPI_PROPBASE_SZ), 0);
+
+ if ( !gic_rdists->prop_page )
+ {
+ its_err("Failed to allocate PROPBASE\n");
+ return -ENOMEM;
+ }
+
+ paddr = __pa(gic_rdists->prop_page);
+ its_info("GIC: using LPI property table @%pa\n", &paddr);
+
+ /* Set LPI priority and Group-1, but disabled */
+ memset(gic_rdists->prop_page,
+ GIC_PRI_IRQ | LPI_PROP_GROUP1,
+ LPI_PROPBASE_SZ);
+
+ /* Make sure the GIC will observe the written configuration */
+ clean_and_invalidate_dcache_va_range(gic_rdists->prop_page,
+ LPI_PROPBASE_SZ);
+
+ return 0;
+}
+
+static const char *its_base_type_string[] = {
+ [GITS_BASER_TYPE_DEVICE] = "Devices",
+ [GITS_BASER_TYPE_VCPU] = "Virtual CPUs",
+ [GITS_BASER_TYPE_CPU] = "Physical CPUs",
+ [GITS_BASER_TYPE_COLLECTION] = "Interrupt Collections",
+ [GITS_BASER_TYPE_RESERVED5] = "Reserved (5)",
+ [GITS_BASER_TYPE_RESERVED6] = "Reserved (6)",
+ [GITS_BASER_TYPE_RESERVED7] = "Reserved (7)",
+};
+
+static void its_free_tables(struct its_node *its)
+{
+ int i;
+
+ for ( i = 0; i < GITS_BASER_NR_REGS; i++ )
+ {
+ if ( its->tables[i] )
+ {
+ free_xenheap_pages(its->tables[i], its->order[i]);
+ its->tables[i] = NULL;
+ its->order[i] = 0;
+ }
+ }
+}
+
+static int its_alloc_tables(struct its_node *its)
+{
+ int err;
+ int i;
+ int psz = SZ_64K;
+ u64 shr = GITS_BASER_InnerShareable;
+ u64 cache = GITS_BASER_WaWb;
+
+ for ( i = 0; i < GITS_BASER_NR_REGS; i++ )
+ {
+ u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
+ u64 type = GITS_BASER_TYPE(val);
+ u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
+ unsigned int order = get_order_from_bytes(psz);
+ int alloc_size;
+ u64 tmp;
+ void *base;
+
+ if ( type == GITS_BASER_TYPE_NONE )
+ continue;
+
+ /*
+ * Allocate as many entries as required to fit the
+ * range of device IDs that the ITS can grok... The ID
+ * space being incredibly sparse, this results in a
+ * massive waste of memory.
+ *
+ * For other tables, only allocate a single page.
+ */
+ if ( type == GITS_BASER_TYPE_DEVICE )
+ {
+ u64 typer = readq_relaxed(its->base + GITS_TYPER);
+ u32 ids = GITS_TYPER_DEVBITS(typer);
+
+ order = max(get_order_from_bytes((1UL << ids) * entry_size), order);
+ if (order >= MAX_ORDER)
+ {
+ order = MAX_ORDER - 1;
+ its_warn("Device Table too large,reduce its page order to %u\n",
+ order);
+ }
+ }
+
+ alloc_size = (1 << order) * PAGE_SIZE;
+ base = alloc_xenheap_pages(order, 0);
+ if ( !base )
+ {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ memset(base, 0, alloc_size);
+ its->tables[i] = base;
+ its->order[i] = order;
+
+retry_baser:
+ val = (__pa(base) |
+ (type << GITS_BASER_TYPE_SHIFT) |
+ ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) |
+ cache |
+ shr |
+ GITS_BASER_VALID);
+
+ switch (psz) {
+ case SZ_4K:
+ val |= GITS_BASER_PAGE_SIZE_4K;
+ break;
+ case SZ_16K:
+ val |= GITS_BASER_PAGE_SIZE_16K;
+ break;
+ case SZ_64K:
+ val |= GITS_BASER_PAGE_SIZE_64K;
+ break;
+ }
+
+ val |= (alloc_size / psz) - 1;
+
+ writeq_relaxed(val, its->base + GITS_BASER + i * 8);
+ tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
+
+ if ( (val ^ tmp) & GITS_BASER_SHAREABILITY_MASK )
+ {
+ /*
+ * Shareability didn't stick. Just use
+ * whatever the read reported, which is likely
+ * to be the only thing this redistributor
+ * supports.
+ */
+ shr = tmp & GITS_BASER_SHAREABILITY_MASK;
+ if ( !shr )
+ cache = GITS_BASER_nC;
+ goto retry_baser;
+ }
+
+ if ( (val ^ tmp) & GITS_BASER_PAGE_SIZE_MASK )
+ {
+ /*
+ * Page size didn't stick. Let's try a smaller
+ * size and retry. If we reach 4K, then
+ * something is horribly wrong...
+ */
+ switch (psz) {
+ case SZ_16K:
+ psz = SZ_4K;
+ goto retry_baser;
+ case SZ_64K:
+ psz = SZ_16K;
+ goto retry_baser;
+ }
+ }
+
+ if ( val != tmp )
+ {
+ its_err("ITS: GITS_BASER%d doesn't stick: %lx %lx\n",
+ i, (unsigned long) val, (unsigned long) tmp);
+ err = -ENXIO;
+ goto out_free;
+ }
+
+ its_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
+ (int)(alloc_size / entry_size),
+ its_base_type_string[type],
+ (unsigned long)__pa(base),
+ psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
+ }
+
+ return 0;
+
+out_free:
+ its_free_tables(its);
+
+ return err;
+}
+
+static int its_alloc_collections(struct its_node *its)
+{
+ its->collections = xzalloc_array(struct its_collection, nr_cpu_ids);
+ if ( !its->collections )
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void its_cpu_init_lpis(void)
+{
+ void __iomem *rbase = gic_data_rdist().rbase;
+ void *pend_page;
+ u64 val, tmp;
+
+ /* If we didn't allocate the pending table yet, do it now */
+ pend_page = gic_data_rdist().pend_page;
+ if ( !pend_page )
+ {
+ paddr_t paddr;
+ u32 order;
+
+ /*
+ * The pending pages have to be at least 64kB aligned,
+ * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below.
+ */
+ order = get_order_from_bytes(max(LPI_PENDBASE_SZ, SZ_64K));
+ pend_page = alloc_xenheap_pages(order, 0);
+ if ( !pend_page )
+ {
+ its_err("Failed to allocate PENDBASE for CPU%d with order %d\n",
+ smp_processor_id(), order);
+ return;
+ }
+
+ memset(pend_page, 0, max(LPI_PENDBASE_SZ, SZ_64K));
+ /* Make sure the GIC will observe the zero-ed page */
+ clean_and_invalidate_dcache_va_range(pend_page, LPI_PENDBASE_SZ);
+
+ paddr = __pa(pend_page);
+
+ its_info("CPU%d: using LPI pending table @%pa\n",
+ smp_processor_id(), &paddr);
+
+ gic_data_rdist().pend_page = pend_page;
+ }
+
+ /* Disable LPIs */
+ val = readl_relaxed(rbase + GICR_CTLR);
+ val &= ~GICR_CTLR_ENABLE_LPIS;
+ writel_relaxed(val, rbase + GICR_CTLR);
+
+ /*
+ * Make sure any change to the table is observable by the GIC.
+ */
+ dsb(sy);
+
+ /* set PROPBASE */
+ val = (__pa(gic_rdists->prop_page) |
+ GICR_PROPBASER_InnerShareable |
+ GICR_PROPBASER_WaWb |
+ ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK));
+
+ writeq_relaxed(val, rbase + GICR_PROPBASER);
+ tmp = readq_relaxed(rbase + GICR_PROPBASER);
+
+ if ( (tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK )
+ {
+ if ( !(tmp & GICR_PROPBASER_SHAREABILITY_MASK) )
+ {
+ /*
+ * The HW reports non-shareable, we must
+ * remove the cacheability attributes as well.
+ */
+ val &= ~(GICR_PROPBASER_SHAREABILITY_MASK |
+ GICR_PROPBASER_CACHEABILITY_MASK);
+ val |= GICR_PROPBASER_nC;
+ writeq_relaxed(val, rbase + GICR_PROPBASER);
+ }
+
+ its_info("GIC: using cache flushing for LPI property table\n");
+ gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING;
+ }
+
+ /* set PENDBASE */
+ val = (__pa(pend_page) |
+ GICR_PROPBASER_InnerShareable |
+ GICR_PROPBASER_WaWb);
+
+ writeq_relaxed(val, rbase + GICR_PENDBASER);
+ tmp = readq_relaxed(rbase + GICR_PENDBASER);
+
+ if ( !(tmp & GICR_PENDBASER_SHAREABILITY_MASK) )
+ {
+ /*
+ * The HW reports non-shareable, we must remove the
+ * cacheability attributes as well.
+ */
+ val &= ~(GICR_PENDBASER_SHAREABILITY_MASK |
+ GICR_PENDBASER_CACHEABILITY_MASK);
+ val |= GICR_PENDBASER_nC;
+ writeq_relaxed(val, rbase + GICR_PENDBASER);
+ }
+
+ /* Enable LPIs */
+ val = readl_relaxed(rbase + GICR_CTLR);
+ val |= GICR_CTLR_ENABLE_LPIS;
+ writel_relaxed(val, rbase + GICR_CTLR);
+
+ /* Make sure the GIC has seen the above */
+ dsb(sy);
+}
+
+static void its_cpu_init_collection(void)
+{
+ struct its_node *its;
+ int cpu;
+
+ spin_lock(&its_lock);
+ cpu = smp_processor_id();
+
+ list_for_each_entry(its, &its_nodes, entry)
+ {
+ u64 target;
+
+ /*
+ * We now have to bind each collection to its target
+ * redistributor.
+ */
+ if ( readq_relaxed(its->base + GITS_TYPER) & GITS_TYPER_PTA )
+ {
+ target = gic_data_rdist().phys_base;
+ /* ITS command considers only [48:16] of the GICR address */
+ target >>= 16;
+ }
+ else
+ {
+ /*
+ * This ITS wants a linear CPU number.
+ */
+ target = readq_relaxed(gic_data_rdist().rbase + GICR_TYPER);
+ target = GICR_TYPER_CPU_NUMBER(target);
+ }
+
+ /* Perform collection mapping */
+ its->collections[cpu].col_id = cpu;
+ its->collections[cpu].target_address = target;
+
+ its_send_mapc(its, &its->collections[cpu], 1);
+ its_send_invall(its, &its->collections[cpu]);
+ }
+
+ spin_unlock(&its_lock);
+}
+
+static int its_force_quiescent(void __iomem *base)
+{
+ u32 count = 1000000; /* 1s */
+ u32 val;
+
+ val = readl_relaxed(base + GITS_CTLR);
+ if ( val & GITS_CTLR_QUIESCENT )
+ return 0;
+
+ /* Disable the generation of all interrupts to this ITS */
+ val &= ~GITS_CTLR_ENABLE;
+ writel_relaxed(val, base + GITS_CTLR);
+
+ /* Poll GITS_CTLR and wait until ITS becomes quiescent */
+ while ( 1 )
+ {
+ val = readl_relaxed(base + GITS_CTLR);
+ if ( val & GITS_CTLR_QUIESCENT )
+ return 0;
+
+ count--;
+ if ( !count )
+ return -EBUSY;
+
+ cpu_relax();
+ udelay(1);
+ }
+}
+
+static int its_probe(struct dt_device_node *node)
+{
+ paddr_t its_addr, its_size;
+ struct its_node *its;
+ void __iomem *its_base;
+ u32 val, typer;
+ u64 baser, tmp;
+ int err;
+
+ if ( !dt_get_property(node, "msi-controller", NULL) )
+ {
+ its_warn("%s: not a msi-controller\n", node->full_name);
+ return -ENXIO;
+ }
+
+ err = dt_device_get_address(node, 0, &its_addr, &its_size);
+ if ( err )
+ {
+ its_warn("%s: no regs?\n", node->full_name);
+ return -ENXIO;
+ }
+
+ its_base = ioremap_nocache(its_addr, its_size);
+ if ( !its_base )
+ {
+ its_warn("%s: unable to map registers\n", node->full_name);
+ return -ENOMEM;
+ }
+
+ val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_REV_MASK;
+ if ( val != 0x30 && val != 0x40 )
+ {
+ its_warn("%s: no ITS detected, giving up\n", node->full_name);
+ err = -ENODEV;
+ goto out_unmap;
+ }
+
+ err = its_force_quiescent(its_base);
+ if ( err )
+ {
+ its_warn("%s: failed to quiesce, giving up\n",
+ node->full_name);
+ goto out_unmap;
+ }
+
+ its_info("ITS: %s\n", node->full_name);
+
+ its = xzalloc(struct its_node);
+ if ( !its )
+ {
+ err = -ENOMEM;
+ goto out_unmap;
+ }
+
+ spin_lock_init(&its->lock);
+ INIT_LIST_HEAD(&its->entry);
+ its->dt_node = node;
+ its->base = its_base;
+ its->phys_base = its_addr;
+ its->phys_size = its_size;
+ typer = readl_relaxed(its_base + GITS_TYPER);
+ its->ite_size = ((typer >> 4) & 0xf) + 1;
+
+ its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ);
+ if ( !its->cmd_base )
+ {
+ err = -ENOMEM;
+ goto out_free_its;
+ }
+ its->cmd_write = its->cmd_base;
+
+ err = its_alloc_tables(its);
+ if ( err )
+ goto out_free_cmd;
+
+ err = its_alloc_collections(its);
+ if ( err )
+ goto out_free_tables;
+
+ baser = (__pa(its->cmd_base) |
+ GITS_CBASER_WaWb |
+ GITS_CBASER_InnerShareable |
+ (ITS_CMD_QUEUE_SZ / SZ_4K - 1) |
+ GITS_CBASER_VALID);
+
+ writeq_relaxed(baser, its->base + GITS_CBASER);
+ tmp = readq_relaxed(its->base + GITS_CBASER);
+ if ( (tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK )
+ {
+ if (!(tmp & GITS_CBASER_SHAREABILITY_MASK))
+ {
+ /*
+ * The HW reports non-shareable, we must
+ * remove the cacheability attributes as
+ * well.
+ */
+ baser &= ~(GITS_CBASER_SHAREABILITY_MASK |
+ GITS_CBASER_CACHEABILITY_MASK);
+ baser |= GITS_CBASER_nC;
+ writeq_relaxed(baser, its->base + GITS_CBASER);
+ }
+
+ its_info("ITS: using cache flushing for cmd queue\n");
+ its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
+ }
+
+ writeq_relaxed(0, its->base + GITS_CWRITER);
+ writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
+
+ spin_lock(&its_lock);
+ list_add(&its->entry, &its_nodes);
+ spin_unlock(&its_lock);
+
+ return 0;
+
+out_free_tables:
+ its_free_tables(its);
+out_free_cmd:
+ xfree(its->cmd_base);
+out_free_its:
+ xfree(its);
+out_unmap:
+ iounmap(its_base);
+ its_err("ITS: failed probing %s (%d)\n", node->full_name, err);
+ return err;
+}
+
+static bool gic_rdists_supports_plpis(void)
+{
+ return !!(readl_relaxed(gic_data_rdist().rbase + GICR_TYPER) & GICR_TYPER_PLPIS);
+}
+
+int its_cpu_init(void)
+{
+ if ( !list_empty(&its_nodes) )
+ {
+ if ( !gic_rdists_supports_plpis() )
+ {
+ its_info("CPU%d: LPIs not supported\n", smp_processor_id());
+ return -ENXIO;
+ }
+ its_cpu_init_lpis();
+ its_cpu_init_collection();
+ }
+
+ return 0;
+}
+
+int __init its_init(struct rdist_prop *rdists)
+{
+ struct dt_device_node *np = NULL;
+
+ static const struct dt_device_match its_device_ids[] __initconst =
+ {
+ DT_MATCH_GIC_ITS,
+ { /* sentinel */ },
+ };
+
+ for (np = dt_find_matching_node(NULL, its_device_ids); np;
+ np = dt_find_matching_node(np, its_device_ids))
+ its_probe(np);
+
+ if ( list_empty(&its_nodes) )
+ {
+ its_warn("ITS: No ITS available, not enabling LPIs\n");
+ return -ENXIO;
+ }
+
+ gic_rdists = rdists;
+ its_alloc_lpi_tables();
+ its_lpi_init(rdists->id_bits);
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index d1db1ce..5076706 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -45,6 +45,7 @@
/* Global state */
static struct {
void __iomem *map_dbase; /* Mapped address of distributor registers */
+ struct rdist_prop rdist_data;
struct rdist_region *rdist_regions;
uint32_t rdist_stride;
unsigned int rdist_count; /* Number of rdist regions count */
@@ -55,10 +56,10 @@ static struct {
static struct gic_info gicv3_info;

/* per-cpu re-distributor base */
-static DEFINE_PER_CPU(void __iomem*, rbase);
+DEFINE_PER_CPU(struct rdist, rdist);

#define GICD (gicv3.map_dbase)
-#define GICD_RDIST_BASE (this_cpu(rbase))
+#define GICD_RDIST_BASE (this_cpu(rdist).rbase)
#define GICD_RDIST_SGI_BASE (GICD_RDIST_BASE + SZ_64K)

/*
@@ -618,6 +619,7 @@ static int __init gicv3_populate_rdist(void)
uint32_t aff;
uint32_t reg;
uint64_t typer;
+ uint64_t offset;
uint64_t mpidr = cpu_logical_map(smp_processor_id());

/*
@@ -653,9 +655,12 @@ static int __init gicv3_populate_rdist(void)

if ( (typer >> 32) == aff )
{
- this_cpu(rbase) = ptr;
- printk("GICv3: CPU%d: Found redistributor in region %d @%p\n",
- smp_processor_id(), i, ptr);
+ offset = ptr - gicv3.rdist_regions[i].map_base;
+ this_cpu(rdist).rbase = ptr;
+ this_cpu(rdist).phys_base = gicv3.rdist_regions[i].base + offset;
+ printk("GICv3: CPU%d: Found redistributor in region %d @%"PRIpaddr"\n",
+ smp_processor_id(), i,
+ this_cpu(rdist).phys_base);
return 0;
}
if ( gicv3.rdist_stride )
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
new file mode 100644
index 0000000..259b0fe
--- /dev/null
+++ b/xen/include/asm-arm/gic-its.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2015 Cavium Inc.
+ * Vijaya Kumar K <***@caviumnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/>.
+ */
+
+#ifndef __ASM_ARM_GIC_ITS_H__
+#define __ASM_ARM_GIC_ITS_H__
+
+#include <asm/gic_v3_defs.h>
+
+/*
+ * ITS registers, offsets from ITS_base
+ */
+#define GITS_CTLR 0x0000
+#define GITS_IIDR 0x0004
+#define GITS_TYPER 0x0008
+#define GITS_CBASER 0x0080
+#define GITS_CWRITER 0x0088
+#define GITS_CREADR 0x0090
+#define GITS_BASER0 0x0100
+#define GITS_BASER1 0x0108
+#define GITS_BASER 0x0100
+#define GITS_BASERN 0x013c
+#define GITS_PIDR0 GICR_PIDR0
+#define GITS_PIDR1 GICR_PIDR1
+#define GITS_PIDR2 GICR_PIDR2
+#define GITS_PIDR3 GICR_PIDR3
+#define GITS_PIDR4 GICR_PIDR4
+#define GITS_PIDR5 GICR_PIDR5
+#define GITS_PIDR7 GICR_PIDR7
+
+#define GITS_TRANSLATER 0x10040
+#define GITS_CTLR_QUIESCENT (1U << 31)
+#define GITS_CTLR_ENABLE (1U << 0)
+
+#define GITS_TYPER_DEVBITS_SHIFT 13
+#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
+#define GITS_TYPER_IDBITS_SHIFT 8
+#define GITS_TYPER_IDBITS(r) ((((r) >> GITS_TYPER_IDBITS_SHIFT) & 0x1f) + 1)
+#define GITS_TYPER_PTA (1UL << 19)
+#define GITS_TYPER_HCC_SHIFT (24)
+
+#define GITS_CBASER_VALID (1UL << 63)
+#define GITS_CBASER_nC (1UL << 59)
+#define GITS_CBASER_WaWb (5UL << 59)
+#define GITS_CBASER_InnerShareable (1UL << 10)
+#define GITS_CBASER_SHAREABILITY_MASK (3UL << 10)
+#define GITS_CBASER_CACHEABILITY_MASK (7UL << 59)
+
+#define GITS_BASER_NR_REGS 8
+
+#define GITS_BASER_VALID (1UL << 63)
+#define GITS_BASER_nC (1UL << 59)
+#define GITS_BASER_WaWb (5UL << 59)
+#define GITS_BASER_TYPE_SHIFT (56)
+#define GITS_BASER_TYPE_MASK (0x7)
+#define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
+#define GITS_BASER_ENTRY_SIZE_SHIFT (48)
+#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1)
+#define GITS_BASER_InnerShareable (1UL << 10)
+#define GITS_BASER_SHAREABILITY_SHIFT (10)
+#define GITS_BASER_SHAREABILITY_MASK (3UL << GITS_BASER_SHAREABILITY_SHIFT)
+#define GITS_BASER_PAGE_SIZE_SHIFT (8)
+#define GITS_BASER_PAGE_SIZE_4K (0UL << GITS_BASER_PAGE_SIZE_SHIFT)
+#define GITS_BASER_PAGE_SIZE_16K (1UL << GITS_BASER_PAGE_SIZE_SHIFT)
+#define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT)
+#define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT)
+#define GITS_BASER_TYPE_NONE 0
+#define GITS_BASER_TYPE_DEVICE 1
+#define GITS_BASER_TYPE_VCPU 2
+#define GITS_BASER_TYPE_CPU 3
+#define GITS_BASER_TYPE_COLLECTION 4
+#define GITS_BASER_TYPE_RESERVED5 5
+#define GITS_BASER_TYPE_RESERVED6 6
+#define GITS_BASER_TYPE_RESERVED7 7
+
+/*
+ * ITS commands
+ */
+#define GITS_CMD_MAPD 0x08
+#define GITS_CMD_MAPC 0x09
+#define GITS_CMD_MAPVI 0x0a
+#define GITS_CMD_MAPI 0x0b
+#define GITS_CMD_MOVI 0x01
+#define GITS_CMD_DISCARD 0x0f
+#define GITS_CMD_INV 0x0c
+#define GITS_CMD_MOVALL 0x0e
+#define GITS_CMD_INVALL 0x0d
+#define GITS_CMD_INT 0x03
+#define GITS_CMD_CLEAR 0x04
+#define GITS_CMD_SYNC 0x05
+
+#define LPI_PROP_ENABLED (1 << 0)
+#define LPI_PROP_GROUP1 (1 << 1)
+
+/*
+ * Collection structure - just an ID, and a redistributor address to
+ * ping. We use one per CPU as collection of interrupts assigned to this
+ * CPU.
+ */
+struct its_collection {
+ u64 target_address;
+ u16 col_id;
+};
+
+/* ITS command structure */
+typedef union {
+ u64 bits[4];
+ struct __packed {
+ uint8_t cmd;
+ uint8_t pad[7];
+ } hdr;
+ struct __packed {
+ u8 cmd;
+ u8 res1[3];
+ u32 devid;
+ u64 size:5;
+ u64 res2:59;
+ /* XXX: Though itt is 40 bit. Keep it 48 to avoid shift */
+ u64 res3:8;
+ u64 itt:40;
+ u64 res4:15;
+ u64 valid:1;
+ u64 res5;
+ } mapd;
+ struct __packed {
+ u8 cmd;
+ u8 res1[7];
+ u64 res2;
+ u16 col;
+ u32 ta;
+ u16 res3:15;
+ u16 valid:1;
+ u64 res4;
+ } mapc;
+ struct __packed {
+ u8 cmd;
+ u8 res1[3];
+ u32 devid;
+ u32 event;
+ u32 res2;
+ u16 col;
+ u8 res3[6];
+ u64 res4;
+ } mapi;
+ struct __packed {
+ u8 cmd;
+ u8 res1[3];
+ u32 devid;
+ u32 event;
+ u32 phy_id;
+ u16 col;
+ u8 res2[6];
+ u64 res3;
+ } mapvi;
+ struct __packed {
+ u8 cmd;
+ u8 res1[3];
+ u32 devid;
+ u32 event;
+ u32 res2;
+ u16 col;
+ u8 res3[6];
+ u64 res4;
+ } movi;
+ struct __packed {
+ u8 cmd;
+ u8 res1[3];
+ u32 devid;
+ u32 event;
+ u32 res2;
+ u64 res3;
+ u64 res4;
+ } discard;
+ struct __packed {
+ u8 cmd;
+ u8 res1[3];
+ u32 devid;
+ u32 event;
+ u32 res2;
+ u64 res3;
+ u64 res4;
+ } inv;
+ struct __packed {
+ u8 cmd;
+ u8 res1[7];
+ u64 res2;
+ u16 res3;
+ u32 ta1;
+ u16 res4;
+ u16 res5;
+ u32 ta2;
+ u16 res6;
+ } movall;
+ struct __packed {
+ u8 cmd;
+ u8 res1[7];
+ u64 res2;
+ u16 col;
+ u8 res3[6];
+ u64 res4;
+ } invall;
+ struct __packed {
+ u8 cmd;
+ u8 res1[3];
+ u32 devid;
+ u32 event;
+ u32 res2;
+ u64 res3;
+ u64 res4;
+ } int_cmd;
+ struct __packed {
+ u8 cmd;
+ u8 res1[3];
+ u32 devid;
+ u32 event;
+ u32 res2;
+ u64 res3;
+ u64 res4;
+ } clear;
+ struct __packed {
+ u8 cmd;
+ u8 res1[7];
+ u64 res2;
+ u16 res3;
+ u32 ta;
+ u16 res4;
+ u64 res5;
+ } sync;
+} its_cmd_block;
+
+struct event_lpi_map {
+ /* Physical LPI map */
+ unsigned long *lpi_map;
+ /* Collection map */
+ u16 *col_map;
+ /* First Physical LPI number assigned */
+ u32 lpi_base;
+ /* Number of ITES/Physical LPIs assigned */
+ u32 nr_lpis;
+};
+
+/*
+ * The ITS view of a device.
+ */
+struct its_device {
+ /* Physical ITS */
+ struct its_node *its;
+ /* Device ITT address */
+ paddr_t *itt_addr;
+ /* Device ITT size */
+ unsigned long itt_size;
+ /* LPI and event mapping */
+ struct event_lpi_map event_map;
+ /* Physical Device id */
+ u32 device_id;
+};
+
+int its_init(struct rdist_prop *rdists);
+int its_cpu_init(void);
+
+#endif /* __ASM_ARM_GIC_ITS_H__ */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index d343abf..e330fe3 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -161,6 +161,7 @@
DT_MATCH_COMPATIBLE("arm,gic-400")

#define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE("arm,gic-v3")
+#define DT_MATCH_GIC_ITS DT_MATCH_COMPATIBLE("arm,gic-v3-its")

#ifdef HAS_GICV3
/*
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index bf7b239..2c322da 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -48,6 +48,7 @@
/* Additional bits in GICD_TYPER defined by GICv3 */
#define GICD_TYPE_ID_BITS_SHIFT 19

+#define GICD_TYPER_LPIS_SUPPORTED (1U << 17)
#define GICD_CTLR_RWP (1UL << 31)
#define GICD_CTLR_ARE_NS (1U << 4)
#define GICD_CTLR_ENABLE_G1A (1U << 1)
@@ -59,11 +60,12 @@
#define GICR_WAKER_ProcessorSleep (1U << 1)
#define GICR_WAKER_ChildrenAsleep (1U << 2)

-#define GICD_PIDR2_ARCH_REV_MASK (0xf0)
+#define GIC_PIDR2_ARCH_REV_MASK (0xf0)
+#define GICD_PIDR2_ARCH_REV_MASK GIC_PIDR2_ARCH_REV_MASK
#define GICD_PIDR2_ARCH_REV_SHIFT (0x4)
#define GICD_PIDR2_ARCH_GICV3 (0x3)

-#define GICR_PIDR2_ARCH_REV_MASK GICD_PIDR2_ARCH_REV_MASK
+#define GICR_PIDR2_ARCH_REV_MASK GIC_PIDR2_ARCH_REV_MASK
#define GICR_PIDR2_ARCH_REV_SHIFT GICD_PIDR2_ARCH_REV_SHIFT
#define GICR_PIDR2_ARCH_GICV3 GICD_PIDR2_ARCH_GICV3

@@ -113,10 +115,24 @@
#define GICR_ICFGR1 (0x0C04)
#define GICR_NSACR (0x0E00)

+#define GICR_CTLR_ENABLE_LPIS (1UL << 0)
+#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff)
+
+#define GICR_PROPBASER_InnerShareable (1U << 10)
+#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10)
+#define GICR_PROPBASER_nC (1U << 7)
+#define GICR_PROPBASER_WaWb (5U << 7)
+#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
+#define GICR_PROPBASER_IDBITS_MASK (0x1f)
#define GICR_TYPER_PLPIS (1U << 0)
#define GICR_TYPER_VLPIS (1U << 1)
#define GICR_TYPER_LAST (1U << 4)

+#define GICR_PENDBASER_InnerShareable (1U << 10)
+#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10)
+#define GICR_PENDBASER_nC (1U << 7)
+#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
+
#define DEFAULT_PMR_VALUE 0xff

#define GICH_VMCR_EOI (1 << 9)
@@ -161,6 +177,28 @@ struct rdist_region {
void __iomem *map_base;
};

+/* Re-distributor per-cpu information */
+struct rdist {
+ /* CPU Re-distributor address */
+ void __iomem *rbase;
+ /* CPU LPI pending table */
+ void *pend_page;
+ /* CPU Re-distributor physical address */
+ paddr_t phys_base;
+};
+
+/* Common Re-distributor information */
+struct rdist_prop {
+ /* CPUs LPI configuration table */
+ void *prop_page;
+ /* Number of ID bits */
+ int id_bits;
+ /* Flags to store rdist attributes */
+ uint64_t flags;
+};
+
+DECLARE_PER_CPU(struct rdist, rdist);
+
#endif /* __ASM_ARM_GIC_V3_DEFS_H__ */

/*
--
1.7.9.5
Julien Grall
2015-08-31 15:41:31 UTC
Permalink
Hi Vijay,

This patch now looks good. A few comments below.

First, I've noticed that you moved again its_send_inv into patch #13. On
a previous version (v4) we asked you to keep all the code imported by
Linux in a single patch. You moved it correctly in v5 but then moved
again out in this version.

You could have avoid this move by splitting the patch #13 in 2 parts:
- part 1: introduce the hw_irq_controller for LPIs
- part 2: plumbing the hw_irq_controller

The part 1 would live before patch #11 which enable the ITS compilation.
Post by v***@gmail.com
The linux driver is based on 4.1 with below commit id
3ad2a5f57656a14d964b673a5a0e4ab0e583c870
I'm sure the commit ID should be changed as you also include
"591e5bec13f15feb13fc445b6c9c59954711c4ac".

Note that it's the only commit modifying drivers/irqchip/gic-v3-its.c
since the commit ID you mentioned above.

[..]
Post by v***@gmail.com
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
new file mode 100644
index 0000000..4ad8d8e
--- /dev/null
+++ b/xen/arch/arm/gic-v3-its.c
@@ -0,0 +1,1011 @@
[...]
Post by v***@gmail.com
+static void its_lpi_free(struct its_device *dev)
+{
+ int lpi;
+
+ spin_lock(&lpi_lock);
+
+ for ( lpi = dev->event_map.lpi_base;
+ lpi < (dev->event_map.lpi_base + dev->event_map.nr_lpis);
+ lpi += IRQS_PER_CHUNK )
The indentation was valid on the previous version. Why did you change it?
Post by v***@gmail.com
+ {
+ int chunk = its_lpi_to_chunk(lpi);
+
+ if (chunk > lpi_chunks)
+ its_err("Bad LPI chunk %d\n", chunk);
+ if ( test_bit(chunk, lpi_bitmap) )
+ clear_bit(chunk, lpi_bitmap);
+ }
+
+ spin_unlock(&lpi_lock);
+
+ xfree(dev->event_map.lpi_map);
+}
[...]
Post by v***@gmail.com
+static bool gic_rdists_supports_plpis(void)
+{
+ return !!(readl_relaxed(gic_data_rdist().rbase + GICR_TYPER) & GICR_TYPER_PLPIS);
The line should be less 80 characters. Please split it.
Post by v***@gmail.com
+}
+
+int its_cpu_init(void)
+{
+ if ( !list_empty(&its_nodes) )
+ {
+ if ( !gic_rdists_supports_plpis() )
+ {
+ its_info("CPU%d: LPIs not supported\n", smp_processor_id());
+ return -ENXIO;
+ }
+ its_cpu_init_lpis();
+ its_cpu_init_collection();
+ }
+
+ return 0;
+}
+
+int __init its_init(struct rdist_prop *rdists)
+{
+ struct dt_device_node *np = NULL;
+
+ static const struct dt_device_match its_device_ids[] __initconst =
+ {
+ DT_MATCH_GIC_ITS,
+ { /* sentinel */ },
+ };
+
+ for (np = dt_find_matching_node(NULL, its_device_ids); np;
+ np = dt_find_matching_node(np, its_device_ids))
Coding style:

for ( ... )

And the indentation of the second line is still wrong it should be

for ( np ...
np = dt_find... )
Post by v***@gmail.com
+ its_probe(np);
+
+ if ( list_empty(&its_nodes) )
+ {
+ its_warn("ITS: No ITS available, not enabling LPIs\n");
+ return -ENXIO;
+ }
+
+ gic_rdists = rdists;
+ its_alloc_lpi_tables();
+ its_lpi_init(rdists->id_bits);
+
+ return 0;
+}
Regards,
--
Julien Grall
Julien Grall
2015-09-03 17:02:12 UTC
Permalink
Post by v***@gmail.com
+struct its_device {
+ /* Physical ITS */
+ struct its_node *its;
+ /* Device ITT address */
+ paddr_t *itt_addr;
Just spotted this, why do you have a pointer to paddr_t?

You store a pointer to the base virtual address and not the physical
address of the ITT. So the name is also wrong.

I would keep what Linux does, i.e:

void *itt;
Post by v***@gmail.com
+ /* Device ITT size */
+ unsigned long itt_size;
+ /* LPI and event mapping */
+ struct event_lpi_map event_map;
+ /* Physical Device id */
+ u32 device_id;
+};
Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:36 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Export physical ITS information to virtual ITS driver

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Passed only one physical ITS info
- Passed all the values as parameters
- Initialize vITS only if physical ITS is available
---
xen/arch/arm/gic-v3-its.c | 11 +++++++++++
xen/arch/arm/vgic-v3-its.c | 28 ++++++++++++++++++++++++++++
xen/include/asm-arm/gic-its.h | 7 +++++++
3 files changed, 46 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 0865a93..77abbc6 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -94,6 +94,7 @@ static LIST_HEAD(its_nodes);
static DEFINE_SPINLOCK(its_lock);
static struct rdist_prop *gic_rdists;
static struct rb_root rb_its_dev;
+static struct gic_its_info its_data;
static DEFINE_SPINLOCK(rb_its_dev_lock);

#define gic_data_rdist() (this_cpu(rdist))
@@ -1312,6 +1313,8 @@ static int its_probe(struct dt_device_node *node)
its->phys_size = its_size;
typer = readl_relaxed(its_base + GITS_TYPER);
its->ite_size = ((typer >> 4) & 0xf) + 1;
+ its_data.eventid_bits = GITS_TYPER_IDBITS(typer);
+ its_data.dev_bits = GITS_TYPER_DEVBITS(typer);

its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ);
if ( !its->cmd_base )
@@ -1402,6 +1405,7 @@ int its_cpu_init(void)

int __init its_init(struct rdist_prop *rdists)
{
+ struct its_node *its;
struct dt_device_node *np = NULL;

static const struct dt_device_match its_device_ids[] __initconst =
@@ -1424,6 +1428,13 @@ int __init its_init(struct rdist_prop *rdists)
its_alloc_lpi_tables();
its_lpi_init(rdists->id_bits);

+ its = list_first_entry(&its_nodes, struct its_node, entry);
+ if ( !its )
+ return -ENOMEM;
+
+ vits_setup_hw(its_data.dev_bits, its_data.eventid_bits,
+ its->phys_base, its->phys_size);
+
return 0;
}

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index cef6139..53f2a27 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -68,6 +68,26 @@ static inline uint16_t vits_get_max_collections(struct domain *d)
return (d->max_vcpus + 1);
}

+static struct {
+ bool_t enabled;
+ uint32_t dev_bits;
+ uint32_t eventid_bits;
+ /* GITS physical base */
+ paddr_t phys_base;
+ /* GITS physical size */
+ unsigned long phys_size;
+} vits_hw;
+
+void vits_setup_hw(uint32_t dev_bits, uint32_t eventid_bits,
+ paddr_t phys_base, unsigned long phys_size)
+{
+ vits_hw.enabled = 1;
+ vits_hw.dev_bits = dev_bits;
+ vits_hw.eventid_bits = eventid_bits;
+ vits_hw.phys_base = phys_base;
+ vits_hw.phys_size = phys_size;
+}
+
int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
uint32_t size, bool_t set)
{
@@ -547,6 +567,14 @@ int vits_domain_init(struct domain *d)

ASSERT(is_hardware_domain(d));

+ if ( !vits_hw.enabled )
+ {
+ printk(XENLOG_G_ERR
+ "%"PRIu16": VITS is not supported on this platform.\n",
+ d->domain_id);
+ return -ENODEV;
+ }
+
d->arch.vgic.nr_lpis = nr_lpis;

d->arch.vgic.vits = xzalloc(struct vgic_its);
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 4327ba2..7077477 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -320,6 +320,11 @@ struct vitt {
uint32_t vlpi;
};

+struct gic_its_info {
+ uint32_t eventid_bits;
+ uint32_t dev_bits;
+};
+
void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
@@ -337,6 +342,8 @@ int vits_get_vitt_entry(struct domain *d, uint32_t devid,
uint32_t event, struct vitt *entry);
int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
struct vdevice_table *entry);
+void vits_setup_hw(uint32_t dev_bits, uint32_t eventid_bits,
+ paddr_t base, unsigned long size);

#endif /* __ASM_ARM_GIC_ITS_H__ */
/*
--
1.7.9.5
Julien Grall
2015-09-03 16:48:19 UTC
Permalink
Post by v***@gmail.com
Export physical ITS information to virtual ITS driver
---
v6: - Passed only one physical ITS info
- Passed all the values as parameters
- Initialize vITS only if physical ITS is available
---
xen/arch/arm/gic-v3-its.c | 11 +++++++++++
xen/arch/arm/vgic-v3-its.c | 28 ++++++++++++++++++++++++++++
xen/include/asm-arm/gic-its.h | 7 +++++++
3 files changed, 46 insertions(+)
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 0865a93..77abbc6 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
[...]
Post by v***@gmail.com
@@ -1402,6 +1405,7 @@ int its_cpu_init(void)
int __init its_init(struct rdist_prop *rdists)
{
+ struct its_node *its;
struct dt_device_node *np = NULL;
static const struct dt_device_match its_device_ids[] __initconst =
@@ -1424,6 +1428,13 @@ int __init its_init(struct rdist_prop *rdists)
its_alloc_lpi_tables();
its_lpi_init(rdists->id_bits);
+ its = list_first_entry(&its_nodes, struct its_node, entry);
+ if ( !its )
+ return -ENOMEM;
This check is not necessary, you already check is the its_nodes list is
not empty.
Post by v***@gmail.com
+
+ vits_setup_hw(its_data.dev_bits, its_data.eventid_bits,
+ its->phys_base, its->phys_size);
It would have been nice to have a comment explaining that we always
expose a single ITS to DOM0.
Post by v***@gmail.com
+
return 0;
}
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index cef6139..53f2a27 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -68,6 +68,26 @@ static inline uint16_t vits_get_max_collections(struct domain *d)
return (d->max_vcpus + 1);
}
+static struct {
+ bool_t enabled;
+ uint32_t dev_bits;
+ uint32_t eventid_bits;
Please have consistent name. I.e

eventID_bits
devID_bits

Also, those fields can be stored each on uint8_t (both are only 4 bits).
Post by v***@gmail.com
+ /* GITS physical base */
+ paddr_t phys_base;
+ /* GITS physical size */
+ unsigned long phys_size;
+} vits_hw;
+
+void vits_setup_hw(uint32_t dev_bits, uint32_t eventid_bits,
+ paddr_t phys_base, unsigned long phys_size)
+{
+ vits_hw.enabled = 1;
+ vits_hw.dev_bits = dev_bits;
+ vits_hw.eventid_bits = eventid_bits;
+ vits_hw.phys_base = phys_base;
+ vits_hw.phys_size = phys_size;
+}
+
int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
uint32_t size, bool_t set)
{
@@ -547,6 +567,14 @@ int vits_domain_init(struct domain *d)
ASSERT(is_hardware_domain(d));
+ if ( !vits_hw.enabled )
An ASSERT would have been enough given that this should never be called
when LPIs is not supported and ITS not enabled (see caller).
Post by v***@gmail.com
+ {
+ printk(XENLOG_G_ERR
+ "%"PRIu16": VITS is not supported on this platform.\n",
s/PRIu16/u/ to be consistent with the rest of Xen.
Post by v***@gmail.com
+ d->domain_id);
+ return -ENODEV;
+ }
+
d->arch.vgic.nr_lpis = nr_lpis;
d->arch.vgic.vits = xzalloc(struct vgic_its);
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 4327ba2..7077477 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -320,6 +320,11 @@ struct vitt {
uint32_t vlpi;
};
+struct gic_its_info {
+ uint32_t eventid_bits;
+ uint32_t dev_bits;
See my remark on the vits_hw.
Post by v***@gmail.com
+};
+
This is only used internally to gic-v3-its.c. So you could have directly
done

static struct
{
uint32_t eventid_bits;
uint32_t dev_bits;
} its_data;
Post by v***@gmail.com
void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
@@ -337,6 +342,8 @@ int vits_get_vitt_entry(struct domain *d, uint32_t devid,
uint32_t event, struct vitt *entry);
int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
struct vdevice_table *entry);
+void vits_setup_hw(uint32_t dev_bits, uint32_t eventid_bits,
+ paddr_t base, unsigned long size);
#endif /* __ASM_ARM_GIC_ITS_H__ */
/*
Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:18 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

dt_for_each_irq_map() returns error if no irq mapping is found.
With this patch, Ignore error and return success

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Change commit message
---
xen/common/device_tree.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index 323c3be..18cdb6f 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -1081,11 +1081,11 @@ int dt_for_each_irq_map(const struct dt_device_node *dev,

/* Now look for an interrupt-map */
imap = dt_get_property(dev, "interrupt-map", &imaplen);
- /* No interrupt map, check for an interrupt parent */
+ /* No interrupt-map found. Ignore */
if ( imap == NULL )
{
dt_dprintk(" -> no map, ignoring\n");
- goto fail;
+ return 0;
}
imaplen /= sizeof(u32);
--
1.7.9.5
Julien Grall
2015-08-31 14:20:17 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
dt_for_each_irq_map() returns error if no irq mapping is found.
With this patch, Ignore error and return success
NIT: s/Ignore/ignore/
I think this could go in Xen 4.6 as it's a bug fix:

Reviewed-by: Julien Grall <***@citrix.com>

Regards,
--
Julien Grall
Wei Liu
2015-09-02 15:30:19 UTC
Permalink
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
dt_for_each_irq_map() returns error if no irq mapping is found.
With this patch, Ignore error and return success
NIT: s/Ignore/ignore/
I replied to v5, forgetting I had a v6 in my hand too. I also forgot to CC
Wei. Lets try again here...
Wei -- I think this fix would be good to have for 4.6. It is not an error
to process a zero-length (==non-existent) array I think.
I think the title should be s/with/without/, Julien was that what you meant
when you suggested it?
Ian.
Julien Grall
2015-09-02 15:45:02 UTC
Permalink
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
dt_for_each_irq_map() returns error if no irq mapping is found.
With this patch, Ignore error and return success
NIT: s/Ignore/ignore/
I replied to v5, forgetting I had a v6 in my hand too. I also forgot to CC
Wei. Lets try again here...
Wei -- I think this fix would be good to have for 4.6. It is not an error
to process a zero-length (==non-existent) array I think.
I think the title should be s/with/without/, Julien was that what you meant
when you suggested it?
Yes.

Regards,
--
Julien Grall
Ian Campbell
2015-09-02 15:52:28 UTC
Permalink
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
dt_for_each_irq_map() returns error if no irq mapping is found.
With this patch, Ignore error and return success
NIT: s/Ignore/ignore/
I replied to v5, forgetting I had a v6 in my hand too. I also forgot to CC
Wei. Lets try again here...
Wei -- I think this fix would be good to have for 4.6. It is not an error
to process a zero-length (==non-existent) array I think.
I think the title should be s/with/without/, Julien was that what you meant
when you suggested it?
Yes.
I will adjust on commit (tomorrow since I'm about to go home).
Ian Campbell
2015-09-04 14:41:00 UTC
Permalink
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
dt_for_each_irq_map() returns error if no irq mapping is found.
With this patch, Ignore error and return success
NIT: s/Ignore/ignore/
I replied to v5, forgetting I had a v6 in my hand too. I also forgot to CC
Wei. Lets try again here...
Wei -- I think this fix would be good to have for 4.6. It is not an error
to process a zero-length (==non-existent) array I think.
I think the title should be s/with/without/, Julien was that what you meant
when you suggested it?
Yes.
Applied with that changed.
v***@gmail.com
2015-08-31 11:06:29 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Move vgic locking inside get_irq_priority callback.
LPIs does not have vgic lock for reading LPI priority.
So make generic vgic code cleaner.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/vgic-v2.c | 4 +++-
xen/arch/arm/vgic-v3.c | 4 +++-
xen/arch/arm/vgic.c | 3 ---
3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index 524787b..600d27e 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -519,11 +519,13 @@ static struct vcpu *vgic_v2_get_target_vcpu(struct vcpu *v, unsigned int irq)
static int vgic_v2_get_irq_priority(struct vcpu *v, unsigned int irq)
{
int priority;
+ unsigned long flags;
struct vgic_irq_rank *rank = vgic_rank_irq(v, irq);

- ASSERT(spin_is_locked(&rank->lock));
+ vgic_lock_rank(v, rank, flags);
priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8,
irq, DABT_WORD)], 0, irq & 0x3);
+ vgic_unlock_rank(v, rank, flags);

return priority;
}
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index f161248..863648c 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1096,11 +1096,13 @@ static const struct mmio_handler_ops vgic_distr_mmio_handler = {
static int vgic_v3_get_irq_priority(struct vcpu *v, unsigned int irq)
{
int priority;
+ unsigned long flags;
struct vgic_irq_rank *rank = vgic_rank_irq(v, irq);

- ASSERT(spin_is_locked(&rank->lock));
+ vgic_lock_rank(v, rank, flags);
priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8,
irq, DABT_WORD)], 0, irq & 0x3);
+ vgic_unlock_rank(v, rank, flags);

return priority;
}
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 01c1867..e28c30d 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -407,14 +407,11 @@ void vgic_clear_pending_irqs(struct vcpu *v)
void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
{
uint8_t priority;
- struct vgic_irq_rank *rank = vgic_rank_irq(v, virq);
struct pending_irq *iter, *n = irq_to_pending(v, virq);
unsigned long flags;
bool_t running;

- vgic_lock_rank(v, rank, flags);
priority = v->domain->arch.vgic.handler->get_irq_priority(v, virq);
- vgic_unlock_rank(v, rank, flags);

spin_lock_irqsave(&v->arch.vgic.lock, flags);
--
1.7.9.5
Julien Grall
2015-08-31 16:34:37 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
Move vgic locking inside get_irq_priority callback.
LPIs does not have vgic lock for reading LPI priority.
The commit message is wrong. We have to take the rank lock when reading
the IRQ priority not the vGIC lock.

The latter still exists for LPIs.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:30 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Implements hw_irq_controller api's required
to handle LPI's.

Changed callbacks gic_host_irq_type and gic_guest_irq_type
to gic_get_host_irq_type and gic_get_guest_irq_type
in gic_hw_operations, which returns
hw_irq_controller based on irq type (SPI or LPI).

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
CC: Zoltan Kiss <***@huawei.com>
---
v6: - Moved this patch #15 in v5 to patch #9
- Introduce inv command
- Moved msi_desc helper functions to separate
"xen/arm: ITS: Introduce msi_desc for LPIs"
- Exported LPI hw_irq_controller structure and removed
helper function to access.
v5: - Fixed review comments
- Exposed gicv3_[host|guest]_irq_end and hook to its
v4: - Implement separate hw_irq_controller for LPIs
- Drop setting LPI affinity
- virq and vid are moved under union
- Introduced inv command handling
- its_device is stored in irq_desc
---
xen/arch/arm/gic-hip04.c | 14 +++-
xen/arch/arm/gic-v2.c | 14 +++-
xen/arch/arm/gic-v3-its.c | 133 +++++++++++++++++++++++++++++++++++++
xen/arch/arm/gic-v3.c | 25 ++++++-
xen/arch/arm/gic.c | 14 +++-
xen/include/asm-arm/gic-its.h | 1 +
xen/include/asm-arm/gic.h | 4 +-
xen/include/asm-arm/gic_v3_defs.h | 2 +
8 files changed, 196 insertions(+), 11 deletions(-)

diff --git a/xen/arch/arm/gic-hip04.c b/xen/arch/arm/gic-hip04.c
index b5811e6..98fdeee 100644
--- a/xen/arch/arm/gic-hip04.c
+++ b/xen/arch/arm/gic-hip04.c
@@ -630,6 +630,16 @@ static hw_irq_controller hip04gic_guest_irq_type = {
.set_affinity = hip04gic_irq_set_affinity,
};

+static hw_irq_controller *hip04gic_get_host_irq_type(unsigned int irq)
+{
+ return &hip04gic_host_irq_type;
+}
+
+static hw_irq_controller *hip04gic_get_guest_irq_type(unsigned int irq)
+{
+ return &hip04gic_guest_irq_type;
+}
+
static int __init hip04gic_init(void)
{
int res;
@@ -712,8 +722,8 @@ const static struct gic_hw_operations hip04gic_ops = {
.save_state = hip04gic_save_state,
.restore_state = hip04gic_restore_state,
.dump_state = hip04gic_dump_state,
- .gic_host_irq_type = &hip04gic_host_irq_type,
- .gic_guest_irq_type = &hip04gic_guest_irq_type,
+ .gic_get_host_irq_type = hip04gic_get_host_irq_type,
+ .gic_get_guest_irq_type = hip04gic_get_guest_irq_type,
.eoi_irq = hip04gic_eoi_irq,
.deactivate_irq = hip04gic_dir_irq,
.read_irq = hip04gic_read_irq,
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 364343d..fe02334 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -616,6 +616,16 @@ static hw_irq_controller gicv2_guest_irq_type = {
.set_affinity = gicv2_irq_set_affinity,
};

+static hw_irq_controller *gicv2_get_host_irq_type(unsigned int irq)
+{
+ return &gicv2_host_irq_type;
+}
+
+static hw_irq_controller *gicv2_get_guest_irq_type(unsigned int irq)
+{
+ return &gicv2_guest_irq_type;
+}
+
static int __init gicv2_init(void)
{
int res;
@@ -698,8 +708,8 @@ const static struct gic_hw_operations gicv2_ops = {
.save_state = gicv2_save_state,
.restore_state = gicv2_restore_state,
.dump_state = gicv2_dump_state,
- .gic_host_irq_type = &gicv2_host_irq_type,
- .gic_guest_irq_type = &gicv2_guest_irq_type,
+ .gic_get_host_irq_type = gicv2_get_host_irq_type,
+ .gic_get_guest_irq_type = gicv2_get_guest_irq_type,
.eoi_irq = gicv2_eoi_irq,
.deactivate_irq = gicv2_dir_irq,
.read_irq = gicv2_read_irq,
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index f14c0f4..0865a93 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -349,6 +349,19 @@ post:
its_wait_for_range_completion(its, cmd, next_cmd);
}

+static void its_send_inv(struct its_device *dev, u32 event)
+{
+ its_cmd_block cmd;
+ struct its_collection *col = dev_event_to_col(dev, event);
+
+ memset(&cmd, 0x0, sizeof(its_cmd_block));
+ cmd.inv.cmd = GITS_CMD_INV;
+ cmd.inv.devid = dev->device_id;
+ cmd.inv.event = event;
+
+ its_send_single_command(dev->its, &cmd, col);
+}
+
static void its_send_mapd(struct its_device *dev, int valid)
{
its_cmd_block cmd;
@@ -425,6 +438,126 @@ static void its_send_discard(struct its_device *dev, u32 event)
its_send_single_command(dev->its, &cmd, col);
}

+static void its_flush_and_invalidate_prop(struct irq_desc *desc, u8 *cfg)
+{
+ struct its_device *its_dev = irqdesc_get_its_device(desc);
+ u32 vid = irqdesc_get_lpi_event(desc);
+
+ ASSERT(vid < its_dev->event_map.nr_lpis);
+
+ /*
+ * Make the above write visible to the redistributors.
+ * And yes, we're flushing exactly: One. Single. Byte.
+ * Humpf...
+ */
+ if ( gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING )
+ clean_and_invalidate_dcache_va_range(cfg, sizeof(*cfg));
+ else
+ dsb(ishst);
+
+ its_send_inv(its_dev, vid);
+}
+
+static void its_set_lpi_state(struct irq_desc *desc, int enable)
+{
+ u8 *cfg;
+
+ ASSERT(spin_is_locked(&its_lock));
+
+ cfg = gic_rdists->prop_page + desc->irq - FIRST_GIC_LPI;
+ if ( enable )
+ *cfg |= LPI_PROP_ENABLED;
+ else
+ *cfg &= ~LPI_PROP_ENABLED;
+
+ its_flush_and_invalidate_prop(desc, cfg);
+}
+
+static void its_irq_enable(struct irq_desc *desc)
+{
+ unsigned long flags;
+
+ ASSERT(spin_is_locked(&desc->lock));
+
+ spin_lock_irqsave(&its_lock, flags);
+ clear_bit(_IRQ_DISABLED, &desc->status);
+ dsb(sy);
+ its_set_lpi_state(desc, 1);
+ spin_unlock_irqrestore(&its_lock, flags);
+}
+
+static void its_irq_disable(struct irq_desc *desc)
+{
+ unsigned long flags;
+
+ ASSERT(spin_is_locked(&desc->lock));
+
+ spin_lock_irqsave(&its_lock, flags);
+ its_set_lpi_state(desc, 0);
+ set_bit(_IRQ_DISABLED, &desc->status);
+ spin_unlock_irqrestore(&its_lock, flags);
+}
+
+static unsigned int its_irq_startup(struct irq_desc *desc)
+{
+ its_irq_enable(desc);
+
+ return 0;
+}
+
+static void its_irq_shutdown(struct irq_desc *desc)
+{
+ its_irq_disable(desc);
+}
+
+static void its_irq_ack(struct irq_desc *desc)
+{
+ /* No ACK -- reading IAR has done this for us */
+}
+
+static void its_host_irq_end(struct irq_desc *desc)
+{
+ /* Lower the priority */
+ gicv3_eoi_irq(desc);
+ /* LPIs does not have active state. Do not deactivate */
+}
+
+static void its_guest_irq_end(struct irq_desc *desc)
+{
+ gicv3_eoi_irq(desc);
+}
+
+static void its_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask)
+{
+ /*TODO: Yet to support */
+ printk(XENLOG_G_WARNING
+ "%pv: ITS: Setting Affinity of LPI is not supported\n", current);
+
+ return;
+}
+
+const hw_irq_controller its_host_lpi_type = {
+ .typename = "gic-its",
+ .startup = its_irq_startup,
+ .shutdown = its_irq_shutdown,
+ .enable = its_irq_enable,
+ .disable = its_irq_disable,
+ .ack = its_irq_ack,
+ .end = its_host_irq_end,
+ .set_affinity = its_irq_set_affinity,
+};
+
+const hw_irq_controller its_guest_lpi_type = {
+ .typename = "gic-its",
+ .startup = its_irq_startup,
+ .shutdown = its_irq_shutdown,
+ .enable = its_irq_enable,
+ .disable = its_irq_disable,
+ .ack = its_irq_ack,
+ .end = its_guest_irq_end,
+ .set_affinity = its_irq_set_affinity,
+};
+
/*
* How we allocate LPIs:
*
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index e90e0cc..c3b1a7c 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -40,6 +40,7 @@
#include <asm/device.h>
#include <asm/gic.h>
#include <asm/gic_v3_defs.h>
+#include <asm/gic-its.h>
#include <asm/cpufeature.h>

/* Global state */
@@ -54,6 +55,8 @@ static struct {
} gicv3;

static struct gic_info gicv3_info;
+extern const hw_irq_controller its_host_lpi_type;
+extern const hw_irq_controller its_guest_lpi_type;

/* per-cpu re-distributor base */
DEFINE_PER_CPU(struct rdist, rdist);
@@ -440,7 +443,7 @@ static void gicv3_mask_irq(struct irq_desc *irqd)
gicv3_poke_irq(irqd, GICD_ICENABLER);
}

-static void gicv3_eoi_irq(struct irq_desc *irqd)
+void gicv3_eoi_irq(struct irq_desc *irqd)
{
/* Lower the priority */
WRITE_SYSREG32(irqd->irq, ICC_EOIR1_EL1);
@@ -1136,6 +1139,22 @@ static const hw_irq_controller gicv3_guest_irq_type = {
.set_affinity = gicv3_irq_set_affinity,
};

+static hw_irq_controller *gicv3_get_host_irq_type(unsigned int irq)
+{
+ if ( gic_is_lpi(irq) )
+ return &its_host_lpi_type;
+
+ return &gicv3_host_irq_type;
+}
+
+static hw_irq_controller *gicv3_get_guest_irq_type(unsigned int irq)
+{
+ if ( gic_is_lpi(irq) )
+ return &its_guest_lpi_type;
+
+ return &gicv3_guest_irq_type;
+}
+
static int __init cmp_rdist(const void *a, const void *b)
{
const struct rdist_region *l = a, *r = a;
@@ -1295,8 +1314,8 @@ static const struct gic_hw_operations gicv3_ops = {
.save_state = gicv3_save_state,
.restore_state = gicv3_restore_state,
.dump_state = gicv3_dump_state,
- .gic_host_irq_type = &gicv3_host_irq_type,
- .gic_guest_irq_type = &gicv3_guest_irq_type,
+ .gic_get_host_irq_type = gicv3_get_host_irq_type,
+ .gic_get_guest_irq_type = gicv3_get_guest_irq_type,
.eoi_irq = gicv3_eoi_irq,
.deactivate_irq = gicv3_dir_irq,
.read_irq = gicv3_read_irq,
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 2199963..16d43ec 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -103,6 +103,16 @@ void gic_restore_state(struct vcpu *v)
gic_restore_pending_irqs(v);
}

+static inline hw_irq_controller *get_host_hw_irq_controller(unsigned int irq)
+{
+ return gic_hw_ops->gic_get_host_irq_type(irq);
+}
+
+static inline hw_irq_controller *get_guest_hw_irq_controller(unsigned int irq)
+{
+ return gic_hw_ops->gic_get_guest_irq_type(irq);
+}
+
/*
* needs to be called with a valid cpu_mask, ie each cpu in the mask has
* already called gic_cpu_init
@@ -127,7 +137,7 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
ASSERT(test_bit(_IRQ_DISABLED, &desc->status));
ASSERT(spin_is_locked(&desc->lock));

- desc->handler = gic_hw_ops->gic_host_irq_type;
+ desc->handler = get_host_hw_irq_controller(desc->irq);

gic_set_irq_properties(desc, cpu_mask, priority);
}
@@ -158,7 +168,7 @@ int gic_route_irq_to_guest(struct domain *d, unsigned int virq,
test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) )
goto out;

- desc->handler = gic_hw_ops->gic_guest_irq_type;
+ desc->handler = get_guest_hw_irq_controller(desc->irq);
set_bit(_IRQ_GUEST, &desc->status);

gic_set_irq_properties(desc, cpumask_of(v_target->processor), priority);
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 3599c76..7a46e21 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -279,6 +279,7 @@ void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
+bool_t is_valid_collection(struct domain *d, uint32_t col);
int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index d39e1b3..6ece7cc 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -317,10 +317,10 @@ struct gic_hw_operations {
void (*dump_state)(const struct vcpu *);

/* hw_irq_controller to enable/disable/eoi host irq */
- hw_irq_controller *gic_host_irq_type;
+ const hw_irq_controller *(*gic_get_host_irq_type)(unsigned int irq);

/* hw_irq_controller to enable/disable/eoi guest irq */
- hw_irq_controller *gic_guest_irq_type;
+ const hw_irq_controller *(*gic_get_guest_irq_type)(unsigned int irq);

/* End of Interrupt */
void (*eoi_irq)(struct irq_desc *irqd);
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index 1153509..d950a1f 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -200,6 +200,8 @@ struct rdist_prop {

DECLARE_PER_CPU(struct rdist, rdist);

+void gicv3_eoi_irq(struct irq_desc *irqd);
+
#endif /* __ASM_ARM_GIC_V3_DEFS_H__ */

/*
--
1.7.9.5
Julien Grall
2015-08-31 17:53:48 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
Implements hw_irq_controller api's required
to handle LPI's.
Changed callbacks gic_host_irq_type and gic_guest_irq_type
s/Changed/Change the/
Post by v***@gmail.com
to gic_get_host_irq_type and gic_get_guest_irq_type
in gic_hw_operations, which returns
hw_irq_controller based on irq type (SPI or LPI).
---
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index f14c0f4..0865a93 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
its_wait_for_range_completion(its, cmd, next_cmd);
}
+static void its_send_inv(struct its_device *dev, u32 event)
See my point of view of about this function living here in my answer to
patch #6.

[...]
Post by v***@gmail.com
+static void its_host_irq_end(struct irq_desc *desc)
+{
+ /* Lower the priority */
+ gicv3_eoi_irq(desc);
+ /* LPIs does not have active state. Do not deactivate */
+}
+
+static void its_guest_irq_end(struct irq_desc *desc)
+{
+ gicv3_eoi_irq(desc);
+}
+
+static void its_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask)
+{
+ /*TODO: Yet to support */
+ printk(XENLOG_G_WARNING
+ "%pv: ITS: Setting Affinity of LPI is not supported\n", current);
Printing the current vCPU is hazardous, this function can be called at
any time and the current may not be meaningful.
Post by v***@gmail.com
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index e90e0cc..c3b1a7c 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -40,6 +40,7 @@
#include <asm/device.h>
#include <asm/gic.h>
#include <asm/gic_v3_defs.h>
+#include <asm/gic-its.h>
#include <asm/cpufeature.h>
/* Global state */
@@ -54,6 +55,8 @@ static struct {
} gicv3;
static struct gic_info gicv3_info;
+extern const hw_irq_controller its_host_lpi_type;
+extern const hw_irq_controller its_guest_lpi_type;
You should define the variable in gic-its.h in order to let the compiler
check that we are using the same as the declaration.
Post by v***@gmail.com
/* per-cpu re-distributor base */
DEFINE_PER_CPU(struct rdist, rdist);
[...]
Post by v***@gmail.com
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 3599c76..7a46e21 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -279,6 +279,7 @@ void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
+bool_t is_valid_collection(struct domain *d, uint32_t col);
Where does it come from? I don't see any usage nor implementation of it
within the patch.
Post by v***@gmail.com
int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index d39e1b3..6ece7cc 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -317,10 +317,10 @@ struct gic_hw_operations {
void (*dump_state)(const struct vcpu *);
/* hw_irq_controller to enable/disable/eoi host irq */
- hw_irq_controller *gic_host_irq_type;
+ const hw_irq_controller *(*gic_get_host_irq_type)(unsigned int irq);
/* hw_irq_controller to enable/disable/eoi guest irq */
- hw_irq_controller *gic_guest_irq_type;
+ const hw_irq_controller *(*gic_get_guest_irq_type)(unsigned int irq);
Actually the const was already embedded in hw_irq_controller (see the
typedef in xen/include/xen/irq.h). Sorry for the inconvenience.
Post by v***@gmail.com
/* End of Interrupt */
void (*eoi_irq)(struct irq_desc *irqd);
Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:37 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

gic_nr_event_ids() helper to read number of event IDs that
ITS hardware supports.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/gic-v3-its.c | 7 +++++++
xen/arch/arm/gic-v3.c | 3 +++
xen/arch/arm/gic.c | 5 +++++
xen/include/asm-arm/gic-its.h | 1 +
xen/include/asm-arm/gic.h | 4 ++++
5 files changed, 20 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 77abbc6..f41ec83 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -138,6 +138,11 @@ void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev)
irq_get_msi_desc(desc)->dev = dev;
}

+u32 its_get_nr_event_ids(void)
+{
+ return (1 << its_data.eventid_bits);
+}
+
static struct its_collection *dev_event_to_col(struct its_device *dev,
u32 event)
{
@@ -861,6 +866,8 @@ int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid)

for ( i = 0; i < pdev->event_map.nr_lpis; i++ )
{
+ ASSERT(i < gic_nr_event_ids());
+
plpi = its_get_plpi(pdev, i);
/* TODO: Route lpi */
}
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index bb2c531..538f9f4 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1315,7 +1315,10 @@ static int __init gicv3_init(void)
* ITS dt node is available
*/
if ( !its_init(&gicv3.rdist_data) )
+ {
gicv3_info.lpi_supported = 1;
+ gicv3_info.nr_event_ids = its_get_nr_event_ids();
+ }
else
gicv3_info.lpi_supported = 0;
}
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 555ad3c..2f23a14 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -81,6 +81,11 @@ bool_t gic_lpi_supported(void)
return gic_hw_ops->info->lpi_supported;
}

+unsigned int gic_nr_event_ids(void)
+{
+ return gic_hw_ops->info->nr_event_ids;
+}
+
void gic_save_state(struct vcpu *v)
{
ASSERT(!local_irq_is_enabled());
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 7077477..a3d21f7 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -330,6 +330,7 @@ unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
bool_t is_valid_collection(struct domain *d, uint32_t col);
+unsigned int its_get_nr_event_ids(void);
int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 15c76d0..2b26e28 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -283,6 +283,8 @@ extern void gic_dump_info(struct vcpu *v);

/* Number of interrupt lines */
extern unsigned int gic_number_lines(void);
+/* Number of event ids supported */
+extern unsigned int gic_nr_event_ids(void);
/* LPI support info */
bool_t gic_lpi_supported(void);

@@ -304,6 +306,8 @@ struct gic_info {
const struct dt_device_node *node;
/* Number of IRQ ID bits supported */
uint32_t nr_id_bits;
+ /* Number of Event IDs supported */
+ uint32_t nr_event_ids;
/* LPIs are support information */
bool_t lpi_supported;
};
--
1.7.9.5
Julien Grall
2015-09-03 17:51:00 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
gic_nr_event_ids() helper to read number of event IDs that
ITS hardware supports.
AFAICT, this new helper is only used for an ASSERT which live in
gic-v3-its.c.

If that's right, I would prefer to see directly the use of
its_data.eventid_bits (which lives within the same file) in the function
and drop this patch.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:24 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Helper functions to manage its devices using RB-tree
are introduced in physical ITS driver.

This is global list of all the devices.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
Acked-by: Ian Campbell <***@citrix.com>
Reviewed-by: Julien Grall <***@citrix.com>
---
v5: - Added assert on spinlock
v4: - Remove passing of root node as parameter
- Declare prototype in header file
- Rename find_its_device to its_find_device
---
xen/arch/arm/gic-v3-its.c | 53 +++++++++++++++++++++++++++++++++++++++++
xen/include/asm-arm/gic-its.h | 3 +++
2 files changed, 56 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 4ad8d8e..88cc89d 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -93,6 +93,8 @@ struct its_node {
static LIST_HEAD(its_nodes);
static DEFINE_SPINLOCK(its_lock);
static struct rdist_prop *gic_rdists;
+static struct rb_root rb_its_dev;
+static DEFINE_SPINLOCK(rb_its_dev_lock);

#define gic_data_rdist() (this_cpu(rdist))

@@ -115,6 +117,55 @@ static struct its_collection *dev_event_to_col(struct its_device *dev,
return its->collections + dev->event_map.col_map[event];
}

+/* RB-tree helpers for its_device */
+static struct its_device *its_find_device(u32 devid)
+{
+ struct rb_node *node = rb_its_dev.rb_node;
+
+ ASSERT(spin_is_locked(&rb_its_dev_lock));
+ while ( node )
+ {
+ struct its_device *dev;
+
+ dev = container_of(node, struct its_device, node);
+ if ( devid < dev->device_id )
+ node = node->rb_left;
+ else if ( devid > dev->device_id )
+ node = node->rb_right;
+ else
+ return dev;
+ }
+
+ return NULL;
+}
+
+static int its_insert_device(struct its_device *dev)
+{
+ struct rb_node **new, *parent;
+
+ ASSERT(spin_is_locked(&rb_its_dev_lock));
+ new = &rb_its_dev.rb_node;
+ parent = NULL;
+ while ( *new )
+ {
+ struct its_device *this;
+
+ this = container_of(*new, struct its_device, node);
+ parent = *new;
+ if ( dev->device_id < this->device_id )
+ new = &((*new)->rb_left);
+ else if ( dev->device_id > this->device_id )
+ new = &((*new)->rb_right);
+ else
+ return -EEXIST;
+ }
+
+ rb_link_node(&dev->node, parent, new);
+ rb_insert_color(&dev->node, &rb_its_dev);
+
+ return 0;
+}
+
#define ITS_CMD_QUEUE_SZ SZ_64K
#define ITS_CMD_QUEUE_NR_ENTRIES (ITS_CMD_QUEUE_SZ / sizeof(its_cmd_block))

@@ -939,6 +990,8 @@ static int its_probe(struct dt_device_node *node)
list_add(&its->entry, &its_nodes);
spin_unlock(&its_lock);

+ rb_its_dev = RB_ROOT;
+
return 0;

out_free_tables:
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 259b0fe..70e7f54 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -19,6 +19,7 @@
#define __ASM_ARM_GIC_ITS_H__

#include <asm/gic_v3_defs.h>
+#include <xen/rbtree.h>

/*
* ITS registers, offsets from ITS_base
@@ -266,6 +267,8 @@ struct its_device {
struct event_lpi_map event_map;
/* Physical Device id */
u32 device_id;
+ /* RB-tree entry */
+ struct rb_node node;
};

int its_init(struct rdist_prop *rdists);
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:22 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

NR_IRQS define signifies number of SGIs, PPIs and SPIs.
With introduction of LPIs, NR_IRQs is renamed to NR_LINE_IRQs.
Similarly vgic_num_irqs() is renamed as vgic_num_line_irqs().

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/gic.c | 2 +-
xen/arch/arm/irq.c | 10 +++++-----
xen/arch/arm/vgic-v3.c | 2 +-
xen/arch/arm/vgic.c | 10 +++++-----
xen/include/asm-arm/irq.h | 9 +++++----
xen/include/asm-arm/vgic.h | 2 +-
6 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 1757193..758678d 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -140,7 +140,7 @@ int gic_route_irq_to_guest(struct domain *d, unsigned int virq,
ASSERT(spin_is_locked(&desc->lock));
/* Caller has already checked that the IRQ is an SPI */
ASSERT(virq >= 32);
- ASSERT(virq < vgic_num_irqs(d));
+ ASSERT(virq < vgic_num_line_irqs(d));

vgic_lock_rank(v_target, rank, flags);

diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 1f38605..d8080c7 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -55,7 +55,7 @@ hw_irq_controller no_irq_type = {
.end = end_none
};

-static irq_desc_t irq_desc[NR_IRQS];
+static irq_desc_t irq_desc[NR_LINE_IRQS];
static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);

irq_desc_t *__irq_to_desc(int irq)
@@ -75,7 +75,7 @@ static int __init init_irq_data(void)
{
int irq;

- for (irq = NR_LOCAL_IRQS; irq < NR_IRQS; irq++) {
+ for (irq = NR_LOCAL_IRQS; irq < NR_LINE_IRQS; irq++) {
struct irq_desc *desc = irq_to_desc(irq);
init_one_irq_desc(desc);
desc->irq = irq;
@@ -407,11 +407,11 @@ int route_irq_to_guest(struct domain *d, unsigned int virq,
unsigned long flags;
int retval = 0;

- if ( virq >= vgic_num_irqs(d) )
+ if ( virq >= vgic_num_line_irqs(d) )
{
printk(XENLOG_G_ERR
"the vIRQ number %u is too high for domain %u (max = %u)\n",
- irq, d->domain_id, vgic_num_irqs(d));
+ irq, d->domain_id, vgic_num_line_irqs(d));
return -EINVAL;
}

@@ -523,7 +523,7 @@ int release_guest_irq(struct domain *d, unsigned int virq)
int ret;

/* Only SPIs are supported */
- if ( virq < NR_LOCAL_IRQS || virq >= vgic_num_irqs(d) )
+ if ( virq < NR_LOCAL_IRQS || virq >= vgic_num_line_irqs(d) )
return -EINVAL;

p = spi_to_pending(d, virq);
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index daa510a..f161248 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -721,7 +721,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
* Number of interrupt identifier bits supported by the GIC
* Stream Protocol Interface
*/
- unsigned int irq_bits = get_count_order(vgic_num_irqs(v->domain));
+ unsigned int irq_bits = get_count_order(vgic_num_line_irqs(v->domain));
/*
* Number of processors that may be used as interrupt targets when ARE
* bit is zero. The maximum is 8.
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index a6835a8..01c1867 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -122,7 +122,7 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
return ret;

d->arch.vgic.allocated_irqs =
- xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d)));
+ xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_line_irqs(d)));
if ( !d->arch.vgic.allocated_irqs )
return -ENOMEM;

@@ -254,7 +254,7 @@ void arch_move_irqs(struct vcpu *v)
struct vcpu *v_target;
int i;

- for ( i = 32; i < vgic_num_irqs(d); i++ )
+ for ( i = 32; i < vgic_num_line_irqs(d); i++ )
{
v_target = vgic_get_target_vcpu(v, i);
p = irq_to_pending(v_target, i);
@@ -465,7 +465,7 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq)
struct vcpu *v;

/* the IRQ needs to be an SPI */
- ASSERT(virq >= 32 && virq <= vgic_num_irqs(d));
+ ASSERT(virq >= 32 && virq <= vgic_num_line_irqs(d));

v = vgic_get_target_vcpu(d->vcpu[0], virq);
vgic_vcpu_inject_irq(v, virq);
@@ -487,7 +487,7 @@ int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)

bool_t vgic_reserve_virq(struct domain *d, unsigned int virq)
{
- if ( virq >= vgic_num_irqs(d) )
+ if ( virq >= vgic_num_line_irqs(d) )
return 0;

return !test_and_set_bit(virq, d->arch.vgic.allocated_irqs);
@@ -507,7 +507,7 @@ int vgic_allocate_virq(struct domain *d, bool_t spi)
else
{
first = 32;
- end = vgic_num_irqs(d);
+ end = vgic_num_line_irqs(d);
}

/*
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index f33c331..cbdc1ab 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -19,11 +19,12 @@ struct arch_irq_desc {
};

#define NR_LOCAL_IRQS 32
-#define NR_IRQS 1024
+/* Number of SGIs+PPIs+SPIs */
+#define NR_LINE_IRQS 1024

-#define nr_irqs NR_IRQS
-#define nr_static_irqs NR_IRQS
-#define arch_hwdom_irqs(domid) NR_IRQS
+#define nr_irqs NR_LINE_IRQS
+#define nr_static_irqs NR_LINE_IRQS
+#define arch_hwdom_irqs(domid) NR_LINE_IRQS

struct irq_desc;
struct irqaction;
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 62d24b6..659d919 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -307,7 +307,7 @@ enum gic_sgi_mode;
*/
#define REG_RANK_INDEX(b, n, s) ((((n) >> s) & ((b)-1)) % 32)

-#define vgic_num_irqs(d) ((d)->arch.vgic.nr_spis + 32)
+#define vgic_num_line_irqs(d) ((d)->arch.vgic.nr_spis + 32)

extern int domain_vgic_init(struct domain *d, unsigned int nr_spis);
extern void domain_vgic_free(struct domain *d);
--
1.7.9.5
Julien Grall
2015-08-31 14:40:05 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
NR_IRQS define signifies number of SGIs, PPIs and SPIs.
I don' think signifies is the right word here. And I would mention that
SGIs/PPIs/SPIs are an IRQ lines in order to make clear why we change the
name. I.e:

"NR_IRQS represents the number of lines (i.e SGIs, PPIs and SPIs)".
Post by v***@gmail.com
With introduction of LPIs, NR_IRQs is renamed to NR_LINE_IRQs.
^ the
Post by v***@gmail.com
Similarly vgic_num_irqs() is renamed as vgic_num_line_irqs().
The proper name is "interrupt line" or "irq line" but not "line irq"
which doesn't make sense.

So I would prefer to see NR_IRQ_LINES or NR_ITLINES. Note that the
latter is the best given that it's the name used within the spec.
Post by v***@gmail.com
---
[...]
Post by v***@gmail.com
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index f33c331..cbdc1ab 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -19,11 +19,12 @@ struct arch_irq_desc {
};
#define NR_LOCAL_IRQS 32
-#define NR_IRQS 1024
+/* Number of SGIs+PPIs+SPIs */
Space before and after each '+'
Post by v***@gmail.com
+#define NR_LINE_IRQS 1024
-#define nr_irqs NR_IRQS
-#define nr_static_irqs NR_IRQS
-#define arch_hwdom_irqs(domid) NR_IRQS
+#define nr_irqs NR_LINE_IRQS
+#define nr_static_irqs NR_LINE_IRQS
+#define arch_hwdom_irqs(domid) NR_LINE_IRQS
Regards,
--
Julien Grall
Ian Campbell
2015-09-09 13:08:08 UTC
Permalink
[...]
Post by v***@gmail.com
+#define nr_irqs NR_LINE_IRQS
+#define nr_static_irqs NR_LINE_IRQS
+#define arch_hwdom_irqs(domid) NR_LINE_IRQS
An aside: While looking at this patch I realised that all of these are used
by common code solely in relation to d->nr_pirqs. Since we don't have pirqs
on ARM really that field ought to be 0 (or even non-existent) and all of
these should then go away.

(Actually nr_irqs is used in flask, but the above is true for the rest for
sure).

Nothing to do with this patch and no action for you to take Vijay.


Ian.
Julien Grall
2015-09-09 13:23:55 UTC
Permalink
Post by Ian Campbell
[...]
Post by v***@gmail.com
+#define nr_irqs NR_LINE_IRQS
+#define nr_static_irqs NR_LINE_IRQS
+#define arch_hwdom_irqs(domid) NR_LINE_IRQS
An aside: While looking at this patch I realised that all of these are used
by common code solely in relation to d->nr_pirqs. Since we don't have pirqs
on ARM really that field ought to be 0 (or even non-existent) and all of
these should then go away.
nr_pirqs is used in DOMCTL_irq_permission to know the last IRQ number
suported. It's working correctly domain_pirq_to_irq is an identity mapping.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:19 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

bitmap_find_next_zero_area helper function will be used
by physical ITS driver. This is imported from linux 4.2

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
Acked-by: Jan Beulich <***@suse.com>
CC: Ian Campbell <***@citrix.com>
CC: Ian Jackson <***@eu.citrix.com>
CC: Jan Beulich <***@suse.com>
CC: Keir Fraser <***@xen.org>
CC: Tim Deegan <***@xen.org>
---
v5: Ported from Linux 4.2.
Added bitmap_find_next_zero_area_off().
v4: Removed spaces and added tabs
Moved ALIGN macro to lib.h
v3: Moved changes to xen/common/bitmap.c and
xen/include/xen/bitmap.h
---
xen/common/bitmap.c | 39 +++++++++++++++++++++++++++++++++++++++
xen/include/xen/bitmap.h | 16 ++++++++++++++++
xen/include/xen/lib.h | 2 ++
3 files changed, 57 insertions(+)

diff --git a/xen/common/bitmap.c b/xen/common/bitmap.c
index 61d1ea4..ad665d1 100644
--- a/xen/common/bitmap.c
+++ b/xen/common/bitmap.c
@@ -489,6 +489,45 @@ int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
}
EXPORT_SYMBOL(bitmap_allocate_region);

+/*
+ * bitmap_find_next_zero_area_off - find a contiguous aligned zero area
+ * @map: The address to base the search on
+ * @size: The bitmap size in bits
+ * @start: The bitnumber to start searching at
+ * @nr: The number of zeroed bits we're looking for
+ * @align_mask: Alignment mask for zero area
+ * @align_offset: Alignment offset for zero area.
+ *
+ * The @align_mask should be one less than a power of 2; the effect is that
+ * the bit offset of all zero areas this function finds plus @align_offset
+ * is multiple of that power of 2.
+ */
+unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
+ unsigned long size,
+ unsigned long start,
+ unsigned int nr,
+ unsigned long align_mask,
+ unsigned long align_offset)
+{
+ unsigned long index, end, i;
+again:
+ index = find_next_zero_bit(map, size, start);
+
+ /* Align allocation */
+ index = ALIGN_MASK(index + align_offset, align_mask) - align_offset;
+
+ end = index + nr;
+ if (end > size)
+ return end;
+ i = find_next_bit(map, end, index);
+ if (i < end) {
+ start = i + 1;
+ goto again;
+ }
+ return index;
+}
+EXPORT_SYMBOL(bitmap_find_next_zero_area_off)
+
#ifdef __BIG_ENDIAN

void bitmap_long_to_byte(uint8_t *bp, const unsigned long *lp, int nbits)
diff --git a/xen/include/xen/bitmap.h b/xen/include/xen/bitmap.h
index e2a3686..161f990 100644
--- a/xen/include/xen/bitmap.h
+++ b/xen/include/xen/bitmap.h
@@ -101,6 +101,22 @@ extern int bitmap_scnlistprintf(char *buf, unsigned int len,
extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order);
extern void bitmap_release_region(unsigned long *bitmap, int pos, int order);
extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order);
+extern unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
+ unsigned long size,
+ unsigned long start,
+ unsigned int nr,
+ unsigned long align_mask,
+ unsigned long align_offset);
+
+static inline unsigned long bitmap_find_next_zero_area(unsigned long *map,
+ unsigned long size,
+ unsigned long start,
+ unsigned int nr,
+ unsigned long align_mask)
+{
+ return bitmap_find_next_zero_area_off(map, size, start, nr,
+ align_mask, 0);
+}

#define BITMAP_LAST_WORD_MASK(nbits) \
( \
diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h
index 4258912..e7d9d95 100644
--- a/xen/include/xen/lib.h
+++ b/xen/include/xen/lib.h
@@ -55,6 +55,8 @@

#define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1))

+#define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
#define reserve_bootmem(_p,_l) ((void)0)

struct domain;
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:31 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Initialize physical ITS if HW supports LPIs.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
CC: Zoltan Kiss <***@huawei.com>
---

v6: - Updated lpi_supported gic_info member for GICv2 and GICv3
- Introduced helper gic_lpi_supported() and exported
v5: - Made check of its dt node availability before
setting lpi_supported flag
---
xen/arch/arm/gic-hip04.c | 2 ++
xen/arch/arm/gic-v2.c | 2 ++
xen/arch/arm/gic-v3.c | 23 +++++++++++++++++++++++
xen/arch/arm/gic.c | 5 +++++
xen/include/asm-arm/gic.h | 4 ++++
5 files changed, 36 insertions(+)

diff --git a/xen/arch/arm/gic-hip04.c b/xen/arch/arm/gic-hip04.c
index 98fdeee..b34db20 100644
--- a/xen/arch/arm/gic-hip04.c
+++ b/xen/arch/arm/gic-hip04.c
@@ -710,6 +710,8 @@ static int __init hip04gic_init(void)
hip04gic_cpu_init();
hip04gic_hyp_init();

+ gicv2_info.lpi_supported = 0;
+
spin_unlock(&gicv2.lock);

return 0;
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index fe02334..a9cd19c 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -696,6 +696,8 @@ static int __init gicv2_init(void)
gicv2_cpu_init();
gicv2_hyp_init();

+ gicv2_info.lpi_supported = 0;
+
spin_unlock(&gicv2.lock);

return 0;
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index c3b1a7c..bb2c531 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -684,6 +684,11 @@ static int __init gicv3_populate_rdist(void)
return -ENODEV;
}

+static int gicv3_dist_supports_lpis(void)
+{
+ return readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_LPIS_SUPPORTED;
+}
+
static int __cpuinit gicv3_cpu_init(void)
{
int i;
@@ -696,6 +701,10 @@ static int __cpuinit gicv3_cpu_init(void)
if ( gicv3_enable_redist() )
return -ENODEV;

+ /* Give LPIs a spin */
+ if ( gicv3_info.lpi_supported )
+ its_cpu_init();
+
/* Set priority on PPI and SGI interrupts */
priority = (GIC_PRI_IPI << 24 | GIC_PRI_IPI << 16 | GIC_PRI_IPI << 8 |
GIC_PRI_IPI);
@@ -1299,6 +1308,20 @@ static int __init gicv3_init(void)

spin_lock(&gicv3.lock);

+ if ( gicv3_dist_supports_lpis() )
+ {
+ /*
+ * LPI support is enabled only if HW supports it and
+ * ITS dt node is available
+ */
+ if ( !its_init(&gicv3.rdist_data) )
+ gicv3_info.lpi_supported = 1;
+ else
+ gicv3_info.lpi_supported = 0;
+ }
+ else
+ gicv3_info.lpi_supported = 0;
+
gicv3_dist_init();
res = gicv3_cpu_init();
gicv3_hyp_init();
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 16d43ec..555ad3c 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -76,6 +76,11 @@ unsigned int gic_number_lines(void)
return gic_hw_ops->info->nr_lines;
}

+bool_t gic_lpi_supported(void)
+{
+ return gic_hw_ops->info->lpi_supported;
+}
+
void gic_save_state(struct vcpu *v)
{
ASSERT(!local_irq_is_enabled());
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 6ece7cc..15c76d0 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -283,6 +283,8 @@ extern void gic_dump_info(struct vcpu *v);

/* Number of interrupt lines */
extern unsigned int gic_number_lines(void);
+/* LPI support info */
+bool_t gic_lpi_supported(void);

/* IRQ translation function for the device tree */
int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
@@ -302,6 +304,8 @@ struct gic_info {
const struct dt_device_node *node;
/* Number of IRQ ID bits supported */
uint32_t nr_id_bits;
+ /* LPIs are support information */
+ bool_t lpi_supported;
};

struct gic_hw_operations {
--
1.7.9.5
Julien Grall
2015-08-31 18:35:56 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 6ece7cc..15c76d0 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -283,6 +283,8 @@ extern void gic_dump_info(struct vcpu *v);
/* Number of interrupt lines */
extern unsigned int gic_number_lines(void);
+/* LPI support info */
+bool_t gic_lpi_supported(void);
I looked to all the usage of gic_lpi_supported in the code and none of
them require a new function in the common framework:

- patch #22: you should add a parameter to vgic_v3_setup_hw in order to
know whether LPIs and/or ITS is supported.
- patch #30: the call of gic_lpi_supported should go in the GICv3
implementation of the callback.

So I would be in favor to drop it rather introducing yet another field.

Note, that I will comment further on both patches in each of them.
Post by v***@gmail.com
/* IRQ translation function for the device tree */
int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
@@ -302,6 +304,8 @@ struct gic_info {
const struct dt_device_node *node;
/* Number of IRQ ID bits supported */
uint32_t nr_id_bits;
+ /* LPIs are support information */
+ bool_t lpi_supported;
};
struct gic_hw_operations {
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:40 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Add support to read 32-bit access to GICR_TYPER register

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/vgic-v3.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 771bfd1..4caac5e 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -122,6 +122,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
*r = vgic_reg32_read(GICV3_GICR_IIDR_VAL, info);
return 1;
case GICR_TYPER:
+ case GICR_TYPER + 4:
{
uint64_t typer, aff;

@@ -136,7 +137,10 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST )
typer |= GICR_TYPER_LAST;

- *r = vgic_reg64_read(typer, info);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(typer, info);
+ else
+ *r = vgic_reg32_read(typer, info);

return 1;
}
--
1.7.9.5
Julien Grall
2015-08-31 16:06:16 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
Add support to read 32-bit access to GICR_TYPER register
---
xen/arch/arm/vgic-v3.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 771bfd1..4caac5e 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -122,6 +122,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
*r = vgic_reg32_read(GICV3_GICR_IIDR_VAL, info);
return 1;
While I understand this...
Post by v***@gmail.com
{
uint64_t typer, aff;
@@ -136,7 +137,10 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST )
typer |= GICR_TYPER_LAST;
- *r = vgic_reg64_read(typer, info);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(typer, info);
+ else
+ *r = vgic_reg32_read(typer, info);
can you explain why this is necessary? The goal of vgic_reg64_read is to
handle all access size to 64bit register.
The vgic_reg32_read will only handle access on 32bit and therefore it
won't be possible to access to the most significant word.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:27 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Helper function gic_is_lpi() is used to find
if irq is lpi or not. For GICv2 platforms this function
returns number of IRQ id bits which holds only number of line irqs.
For GICv3 platform it read id_bits from GICD_TYPER

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
CC: Zoltan Kiss <***@huawei.com>
---
v6: - Added gic_info.nr_id_bits to hold number of SPI/LPIs
supported
- Dropped is_lpi() callback
---
xen/arch/arm/gic-hip04.c | 3 ++-
xen/arch/arm/gic-v2.c | 3 ++-
xen/arch/arm/gic-v3.c | 6 ++++++
xen/arch/arm/gic.c | 9 +++++++++
xen/include/asm-arm/gic.h | 4 ++++
xen/include/asm-arm/gic_v3_defs.h | 3 ++-
6 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/gic-hip04.c b/xen/arch/arm/gic-hip04.c
index c5ed545..b5811e6 100644
--- a/xen/arch/arm/gic-hip04.c
+++ b/xen/arch/arm/gic-hip04.c
@@ -301,7 +301,8 @@ static void __init hip04gic_dist_init(void)

/* Only 1020 interrupts are supported */
gicv2_info.nr_lines = min(1020U, nr_lines);
-
+ /* Number of IRQ ids supported */
+ gicv2_info.nr_id_bits = get_count_order(gicv2_info.nr_lines);
/* Turn on the distributor */
writel_gicd(GICD_CTL_ENABLE, GICD_CTLR);
}
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 596126d..364343d 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -291,7 +291,8 @@ static void __init gicv2_dist_init(void)

/* Only 1020 interrupts are supported */
gicv2_info.nr_lines = min(1020U, nr_lines);
-
+ /* Number of IRQ ids supported */
+ gicv2_info.nr_id_bits = get_count_order(gicv2_info.nr_lines);
/* Turn on the distributor */
writel_gicd(GICD_CTL_ENABLE, GICD_CTLR);
}
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 5076706..e90e0cc 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1270,6 +1270,12 @@ static int __init gicv3_init(void)
gicv3.rdist_stride);
gicv3_init_v2(node, dbase);

+ reg = readl_relaxed(GICD + GICD_TYPER);
+
+ gicv3.rdist_data.id_bits = ((reg >> GICD_TYPE_ID_BITS_SHIFT) &
+ GICD_TYPE_ID_BITS_MASK) + 1;
+ gicv3_info.nr_id_bits = gicv3.rdist_data.id_bits;
+
spin_lock_init(&gicv3.lock);

spin_lock(&gicv3.lock);
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 758678d..2199963 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -62,6 +62,15 @@ enum gic_version gic_hw_version(void)
return gic_hw_ops->info->hw_version;
}

+#ifdef HAS_GICV3
+bool_t gic_is_lpi(unsigned int irq)
+{
+ return (irq >= FIRST_GIC_LPI && irq < (1 << gic_hw_ops->info->nr_id_bits));
+}
+#else
+bool_t gic_is_lpi(unsigned int irq) { return 0; }
+#endif
+
unsigned int gic_number_lines(void)
{
return gic_hw_ops->info->nr_lines;
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index e330fe3..d39e1b3 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -20,6 +20,7 @@

#define NR_GIC_LOCAL_IRQS NR_LOCAL_IRQS
#define NR_GIC_SGI 16
+#define FIRST_GIC_LPI 8192
#define MAX_RDIST_COUNT 4

#define GICD_CTLR (0x000)
@@ -299,6 +300,8 @@ struct gic_info {
unsigned int maintenance_irq;
/* Pointer to the device tree node representing the interrupt controller */
const struct dt_device_node *node;
+ /* Number of IRQ ID bits supported */
+ uint32_t nr_id_bits;
};

struct gic_hw_operations {
@@ -359,6 +362,7 @@ void register_gic_ops(const struct gic_hw_operations *ops);
int gic_make_hwdom_dt_node(const struct domain *d,
const struct dt_device_node *node,
void *fdt);
+bool_t gic_is_lpi(unsigned int irq);

#endif /* __ASSEMBLY__ */
#endif
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index 2c322da..1153509 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -46,7 +46,8 @@
#define GICC_SRE_EL2_ENEL1 (1UL << 3)

/* Additional bits in GICD_TYPER defined by GICv3 */
-#define GICD_TYPE_ID_BITS_SHIFT 19
+#define GICD_TYPE_ID_BITS_SHIFT 19
+#define GICD_TYPE_ID_BITS_MASK 0x1f

#define GICD_TYPER_LPIS_SUPPORTED (1U << 17)
#define GICD_CTLR_RWP (1UL << 31)
--
1.7.9.5
Julien Grall
2015-08-31 16:49:22 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 758678d..2199963 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -62,6 +62,15 @@ enum gic_version gic_hw_version(void)
return gic_hw_ops->info->hw_version;
}
+#ifdef HAS_GICV3
+bool_t gic_is_lpi(unsigned int irq)
+{
+ return (irq >= FIRST_GIC_LPI && irq < (1 << gic_hw_ops->info->nr_id_bits));
It would make more sense to calculate the number of ID supported at boot
time rather than re-calculate everytime this function is called (i.e
very often).
Post by v***@gmail.com
+}
+#else
+bool_t gic_is_lpi(unsigned int irq) { return 0; }
+#endif
I though I'd already say it on a previous version. I would like to avoid
seen any #ifdef HAS_GICV3 in the generic code include interrupt framework.

In this case, I don't see much the benefit to do a specific case for
platform not using GICv3 (i.e ARM32).

Regards,
--
Julien Grall
Vijay Kilari
2015-09-01 09:02:31 UTC
Permalink
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 758678d..2199963 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -62,6 +62,15 @@ enum gic_version gic_hw_version(void)
return gic_hw_ops->info->hw_version;
}
+#ifdef HAS_GICV3
+bool_t gic_is_lpi(unsigned int irq)
+{
+ return (irq >= FIRST_GIC_LPI && irq < (1 <<
gic_hw_ops->info->nr_id_bits));
It would make more sense to calculate the number of ID supported at boot
time rather than re-calculate everytime this function is called (i.e very
often).
Post by v***@gmail.com
+}
+#else
+bool_t gic_is_lpi(unsigned int irq) { return 0; }
+#endif
I though I'd already say it on a previous version. I would like to avoid
seen any #ifdef HAS_GICV3 in the generic code include interrupt framework.
In this case, I don't see much the benefit to do a specific case for
platform not using GICv3 (i.e ARM32).
You mean, let gic_is_lpi() implemented for both ARM64/32 and let this
function fail
always for ARM32?

Other option is to implement callback to hw drivers (gicv3 and gicv2).
But overhead of callback
should also be considered
Julien Grall
2015-09-01 11:40:12 UTC
Permalink
Post by Vijay Kilari
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 758678d..2199963 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -62,6 +62,15 @@ enum gic_version gic_hw_version(void)
return gic_hw_ops->info->hw_version;
}
+#ifdef HAS_GICV3
+bool_t gic_is_lpi(unsigned int irq)
+{
+ return (irq >= FIRST_GIC_LPI && irq < (1 <<
gic_hw_ops->info->nr_id_bits));
It would make more sense to calculate the number of ID supported at boot
time rather than re-calculate everytime this function is called (i.e very
often).
Post by v***@gmail.com
+}
+#else
+bool_t gic_is_lpi(unsigned int irq) { return 0; }
+#endif
I though I'd already say it on a previous version. I would like to avoid
seen any #ifdef HAS_GICV3 in the generic code include interrupt framework.
In this case, I don't see much the benefit to do a specific case for
platform not using GICv3 (i.e ARM32).
You mean, let gic_is_lpi() implemented for both ARM64/32 and let this
function fail
always for ARM32?
Yes. You already implement it as always fail but with #ifdef. Although I
don't think this is worth to do as it's more difficult to maintain.
Post by Vijay Kilari
Other option is to implement callback to hw drivers (gicv3 and gicv2).
But overhead of callback
should also be considered
It was the implementation you suggested on v5. And I wasn't not in favor
about it.

BTW, I suggested to create a field nr_lpis but you decided to store the
number of bits supported. Why?

Regards,
--
Julien Grall
Vijay Kilari
2015-09-01 11:56:53 UTC
Permalink
Post by Julien Grall
Post by Vijay Kilari
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 758678d..2199963 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -62,6 +62,15 @@ enum gic_version gic_hw_version(void)
return gic_hw_ops->info->hw_version;
}
+#ifdef HAS_GICV3
+bool_t gic_is_lpi(unsigned int irq)
+{
+ return (irq >= FIRST_GIC_LPI && irq < (1 <<
gic_hw_ops->info->nr_id_bits));
It would make more sense to calculate the number of ID supported at boot
time rather than re-calculate everytime this function is called (i.e very
often).
Post by v***@gmail.com
+}
+#else
+bool_t gic_is_lpi(unsigned int irq) { return 0; }
+#endif
I though I'd already say it on a previous version. I would like to avoid
seen any #ifdef HAS_GICV3 in the generic code include interrupt framework.
In this case, I don't see much the benefit to do a specific case for
platform not using GICv3 (i.e ARM32).
You mean, let gic_is_lpi() implemented for both ARM64/32 and let this
function fail
always for ARM32?
Yes. You already implement it as always fail but with #ifdef. Although I
don't think this is worth to do as it's more difficult to maintain.
Post by Vijay Kilari
Other option is to implement callback to hw drivers (gicv3 and gicv2).
But overhead of callback
should also be considered
It was the implementation you suggested on v5. And I wasn't not in favor
about it.
BTW, I suggested to create a field nr_lpis but you decided to store the
number of bits supported. Why?
I have nr_lpis field in vgic structure (patch #17). But it just tells
how LPIs are supported
for a domain.
Where as nr_id_bits shows total number of lpis that hw supports.
Julien Grall
2015-09-01 13:02:25 UTC
Permalink
Post by Vijay Kilari
Post by Julien Grall
BTW, I suggested to create a field nr_lpis but you decided to store the
number of bits supported. Why?
I have nr_lpis field in vgic structure (patch #17). But it just tells
how LPIs are supported
for a domain.
Why are you speaking about vgic structure? I'm only suggesting to
replace you nr_id_bits by nr_lpis in the hw GIC. AFAICT, there is
nothing to prevent having 2 field using the same name on 2 differents
structure...
Post by Vijay Kilari
Where as nr_id_bits shows total number of lpis that hw supports.
No nr_id_bits shows the total number of interrupt not LPIs. The total
number of LPIs is (1 << nr_id_bits) - 8092. Although (1 << nr_id_bits)
gives you the last LPI interrupt ID supported.

Anyway, as I said earlier, re-calculating the last LPI interrupt ID
everytime based on the shift is time consuming. You should optimize for
the common case rather than using copy the raw value (i.e ID bits) from
the HW directly.

Maybe the name "max_lpi_id" would make more sense to you for a name?

Regards,
--
Julien Grall
Vijay Kilari
2015-09-03 06:32:47 UTC
Permalink
Post by Julien Grall
Post by Vijay Kilari
Post by Julien Grall
BTW, I suggested to create a field nr_lpis but you decided to store the
number of bits supported. Why?
I have nr_lpis field in vgic structure (patch #17). But it just tells
how LPIs are supported
for a domain.
Why are you speaking about vgic structure? I'm only suggesting to
replace you nr_id_bits by nr_lpis in the hw GIC. AFAICT, there is
nothing to prevent having 2 field using the same name on 2 differents
structure...
Post by Vijay Kilari
Where as nr_id_bits shows total number of lpis that hw supports.
No nr_id_bits shows the total number of interrupt not LPIs. The total
number of LPIs is (1 << nr_id_bits) - 8092. Although (1 << nr_id_bits)
gives you the last LPI interrupt ID supported.
Anyway, as I said earlier, re-calculating the last LPI interrupt ID
everytime based on the shift is time consuming. You should optimize for
the common case rather than using copy the raw value (i.e ID bits) from
the HW directly.
Maybe the name "max_lpi_id" would make more sense to you for a name?
Instead of storing max_lpi_id which is ( 1 << nr_id_bits) - 8192, I prefer
to rename nr_id_bits as nr_irq_ids which can be initialized to (1 << nr_id_bits)
for gicv3 and gicv2_info.nr_lines for gicv2.

and gic_is_lpi() as below will work both gicv2 and gicv3.

bool_t gic_is_lpi(unsigned int irq)
{
return (irq >= FIRST_GIC_LPI && irq < gic_hw_ops->info->nr_irq_ids);
}

Regards
Vijay
Julien Grall
2015-09-03 09:48:14 UTC
Permalink
Hi,
Post by Vijay Kilari
Post by Julien Grall
Post by Vijay Kilari
Post by Julien Grall
BTW, I suggested to create a field nr_lpis but you decided to store the
number of bits supported. Why?
I have nr_lpis field in vgic structure (patch #17). But it just tells
how LPIs are supported
for a domain.
Why are you speaking about vgic structure? I'm only suggesting to
replace you nr_id_bits by nr_lpis in the hw GIC. AFAICT, there is
nothing to prevent having 2 field using the same name on 2 differents
structure...
Post by Vijay Kilari
Where as nr_id_bits shows total number of lpis that hw supports.
No nr_id_bits shows the total number of interrupt not LPIs. The total
number of LPIs is (1 << nr_id_bits) - 8092. Although (1 << nr_id_bits)
gives you the last LPI interrupt ID supported.
Anyway, as I said earlier, re-calculating the last LPI interrupt ID
everytime based on the shift is time consuming. You should optimize for
the common case rather than using copy the raw value (i.e ID bits) from
the HW directly.
Maybe the name "max_lpi_id" would make more sense to you for a name?
Instead of storing max_lpi_id which is ( 1 << nr_id_bits) - 8192, I prefer
to rename nr_id_bits as nr_irq_ids which can be initialized to (1 << nr_id_bits)
for gicv3 and gicv2_info.nr_lines for gicv2.
I'm fine with that.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:20 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

log2 helper apis are ported from linux from
commit 13c07b0286d340275f2d97adf085cecda37ede37
(linux/log2.h: Fix rounddown_pow_of_two(1))
Changes made for xen are:
- Only required functionality is retained
- Replace fls_long with flsl

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
CC: Ian Campbell <***@citrix.com>
CC: Ian Jackson <***@eu.citrix.com>
CC: Jan Beulich <***@suse.com>
CC: Keir Fraser <***@xen.org>
CC: Tim Deegan <***@xen.org>
---
v4: - Only retained required functionality
- Replaced fls_long with flsl
- Removed fls_long implementation in bitops.h in v3 version
---
xen/include/xen/log2.h | 167 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 167 insertions(+)

diff --git a/xen/include/xen/log2.h b/xen/include/xen/log2.h
new file mode 100644
index 0000000..86bd861
--- /dev/null
+++ b/xen/include/xen/log2.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (***@redhat.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.
+ */
+
+#ifndef _XEN_LOG2_H
+#define _XEN_LOG2_H
+
+#include <xen/types.h>
+#include <xen/bitops.h>
+
+/*
+ * deal with unrepresentable constant logarithms
+ */
+extern __attribute__((const))
+int ____ilog2_NaN(void);
+
+/*
+ * non-constant log of base 2 calculators
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ * more efficiently than using fls() and fls64()
+ * - the arch is not required to handle n==0 if implementing the fallback
+ */
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+ return fls(n) - 1;
+}
+
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+ return flsl(n) - 1;
+}
+
+/*
+ * round up to nearest power of two
+ */
+static inline __attribute__((const))
+unsigned long __roundup_pow_of_two(unsigned long n)
+{
+ return 1UL << flsl(n - 1);
+}
+
+/**
+ * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
+ * @n - parameter
+ *
+ * constant-capable log of base 2 calculation
+ * - this can be used to initialise global variables from constant data, hence
+ * the massive ternary operator construction
+ *
+ * selects the appropriately-sized optimised version depending on sizeof(n)
+ */
+#define ilog2(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (n) < 1 ? ____ilog2_NaN() : \
+ (n) & (1ULL << 63) ? 63 : \
+ (n) & (1ULL << 62) ? 62 : \
+ (n) & (1ULL << 61) ? 61 : \
+ (n) & (1ULL << 60) ? 60 : \
+ (n) & (1ULL << 59) ? 59 : \
+ (n) & (1ULL << 58) ? 58 : \
+ (n) & (1ULL << 57) ? 57 : \
+ (n) & (1ULL << 56) ? 56 : \
+ (n) & (1ULL << 55) ? 55 : \
+ (n) & (1ULL << 54) ? 54 : \
+ (n) & (1ULL << 53) ? 53 : \
+ (n) & (1ULL << 52) ? 52 : \
+ (n) & (1ULL << 51) ? 51 : \
+ (n) & (1ULL << 50) ? 50 : \
+ (n) & (1ULL << 49) ? 49 : \
+ (n) & (1ULL << 48) ? 48 : \
+ (n) & (1ULL << 47) ? 47 : \
+ (n) & (1ULL << 46) ? 46 : \
+ (n) & (1ULL << 45) ? 45 : \
+ (n) & (1ULL << 44) ? 44 : \
+ (n) & (1ULL << 43) ? 43 : \
+ (n) & (1ULL << 42) ? 42 : \
+ (n) & (1ULL << 41) ? 41 : \
+ (n) & (1ULL << 40) ? 40 : \
+ (n) & (1ULL << 39) ? 39 : \
+ (n) & (1ULL << 38) ? 38 : \
+ (n) & (1ULL << 37) ? 37 : \
+ (n) & (1ULL << 36) ? 36 : \
+ (n) & (1ULL << 35) ? 35 : \
+ (n) & (1ULL << 34) ? 34 : \
+ (n) & (1ULL << 33) ? 33 : \
+ (n) & (1ULL << 32) ? 32 : \
+ (n) & (1ULL << 31) ? 31 : \
+ (n) & (1ULL << 30) ? 30 : \
+ (n) & (1ULL << 29) ? 29 : \
+ (n) & (1ULL << 28) ? 28 : \
+ (n) & (1ULL << 27) ? 27 : \
+ (n) & (1ULL << 26) ? 26 : \
+ (n) & (1ULL << 25) ? 25 : \
+ (n) & (1ULL << 24) ? 24 : \
+ (n) & (1ULL << 23) ? 23 : \
+ (n) & (1ULL << 22) ? 22 : \
+ (n) & (1ULL << 21) ? 21 : \
+ (n) & (1ULL << 20) ? 20 : \
+ (n) & (1ULL << 19) ? 19 : \
+ (n) & (1ULL << 18) ? 18 : \
+ (n) & (1ULL << 17) ? 17 : \
+ (n) & (1ULL << 16) ? 16 : \
+ (n) & (1ULL << 15) ? 15 : \
+ (n) & (1ULL << 14) ? 14 : \
+ (n) & (1ULL << 13) ? 13 : \
+ (n) & (1ULL << 12) ? 12 : \
+ (n) & (1ULL << 11) ? 11 : \
+ (n) & (1ULL << 10) ? 10 : \
+ (n) & (1ULL << 9) ? 9 : \
+ (n) & (1ULL << 8) ? 8 : \
+ (n) & (1ULL << 7) ? 7 : \
+ (n) & (1ULL << 6) ? 6 : \
+ (n) & (1ULL << 5) ? 5 : \
+ (n) & (1ULL << 4) ? 4 : \
+ (n) & (1ULL << 3) ? 3 : \
+ (n) & (1ULL << 2) ? 2 : \
+ (n) & (1ULL << 1) ? 1 : \
+ (n) & (1ULL << 0) ? 0 : \
+ ____ilog2_NaN() \
+ ) : \
+ (sizeof(n) <= 4) ? \
+ __ilog2_u32(n) : \
+ __ilog2_u64(n) \
+ )
+
+/**
+ * roundup_pow_of_two - round the given value up to nearest power of two
+ * @n - parameter
+ *
+ * round the given value up to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define roundup_pow_of_two(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (n == 1) ? 1 : \
+ (1UL << (ilog2((n) - 1) + 1)) \
+ ) : \
+ __roundup_pow_of_two(n) \
+ )
+
+/**
+ * order_base_2 - calculate the (rounded up) base 2 order of the argument
+ * @n: parameter
+ *
+ * The first few values calculated by this routine:
+ * ob2(0) = 0
+ * ob2(1) = 0
+ * ob2(2) = 1
+ * ob2(3) = 2
+ * ob2(4) = 2
+ * ob2(5) = 3
+ * ... and so on.
+ */
+
+#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+#endif /* _XEN_LOG2_H */
--
1.7.9.5
Jan Beulich
2015-08-31 11:21:14 UTC
Permalink
Post by v***@gmail.com
log2 helper apis are ported from linux from
commit 13c07b0286d340275f2d97adf085cecda37ede37
(linux/log2.h: Fix rounddown_pow_of_two(1))
- Only required functionality is retained
- Replace fls_long with flsl
Acked-by: Jan Beulich <***@suse.com>
v***@gmail.com
2015-08-31 11:06:32 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

This patch introduces virtual ITS driver with following
functionality
- Introduces helper functions to manage device table and
ITT table in guest memory
- Helper function to handle virtual ITS devices assigned
to domain

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Exported vits_access_guest_memory() api
v5: - Removed RB tree that manages vitual ITS devices
v4: - Rename functions {find,remove,insert}_vits_* to
vits_{find,remove,insert}.
- Add common helper function to map and read/write dt
or vitt table entry.
- Removed unused code
---
xen/arch/arm/vgic-v3-its.c | 162 +++++++++++++++++++++++++++++++++++++++++
xen/include/asm-arm/domain.h | 2 +
xen/include/asm-arm/gic-its.h | 38 ++++++++++
3 files changed, 202 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
new file mode 100644
index 0000000..14c38b3
--- /dev/null
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 Cavium Inc.
+ * Vijaya Kumar K <***@caviumnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 <xen/bitops.h>
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/irq.h>
+#include <xen/list.h>
+#include <xen/sched.h>
+#include <xen/sizes.h>
+#include <xen/domain_page.h>
+#include <asm/device.h>
+#include <asm/mmio.h>
+#include <asm/io.h>
+#include <asm/gic_v3_defs.h>
+#include <asm/gic.h>
+#include <asm/vgic.h>
+#include <asm/gic-its.h>
+#include <xen/log2.h>
+
+int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
+ uint32_t size, bool_t set)
+{
+ struct page_info *page;
+ uint64_t offset;
+ p2m_type_t p2mt;
+ void *p;
+
+ page = get_page_from_gfn(d, paddr_to_pfn(entry), &p2mt, P2M_ALLOC);
+ if ( !page )
+ {
+ printk(XENLOG_G_ERR "d%"PRIu16": vITS: Failed to get table entry\n",
+ d->domain_id);
+ return -EINVAL;
+ }
+
+ if ( !p2m_is_ram(p2mt) )
+ {
+ put_page(page);
+ printk(XENLOG_G_ERR "d%"PRIu16": vITS: with wrong attributes\n",
+ d->domain_id);
+ return -EINVAL;
+ }
+
+ p = __map_domain_page(page);
+ /* Offset within the mapped page */
+ offset = entry & ~PAGE_MASK;
+
+ if ( set )
+ memcpy(p + offset, addr, size);
+ else
+ memcpy(addr, p + offset, size);
+
+ unmap_domain_page(p);
+ put_page(page);
+
+ return 0;
+}
+
+/* ITS device table helper functions */
+static int vits_vdevice_entry(struct domain *d, uint32_t dev_id,
+ struct vdevice_table *entry, bool_t set)
+{
+ uint64_t offset;
+ paddr_t dt_entry;
+ const struct vgic_its *vits = d->arch.vgic.vits;
+
+ BUILD_BUG_ON(sizeof(struct vdevice_table) != 16);
+
+ offset = dev_id * sizeof(struct vdevice_table);
+ if ( offset > vits->dt_size )
+ {
+ printk(XENLOG_G_ERR
+ "d%"PRIu16":vITS:Out of range off 0x%"PRIx64" id 0x%"PRIx32"\n",
+ d->domain_id, offset, dev_id);
+ return -EINVAL;
+ }
+
+ dt_entry = vits->dt_ipa + offset;
+
+ return vits_access_guest_table(d, dt_entry, entry,
+ sizeof(struct vdevice_table), set);
+}
+
+static int vits_set_vdevice_entry(struct domain *d, uint32_t devid,
+ struct vdevice_table *entry)
+{
+ return vits_vdevice_entry(d, devid, entry, 1);
+}
+
+int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
+ struct vdevice_table *entry)
+{
+ return vits_vdevice_entry(d, devid, entry, 0);
+}
+
+static int vits_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry, bool_t set)
+{
+ struct vdevice_table dt_entry;
+ paddr_t vitt_entry;
+ uint64_t offset;
+
+ BUILD_BUG_ON(sizeof(struct vitt) != 8);
+
+ if ( vits_get_vdevice_entry(d, devid, &dt_entry) )
+ {
+ printk(XENLOG_G_ERR
+ "d%"PRIu16": vITS: Fail to get vdevice for vdevid 0x%"PRIx32"\n",
+ d->domain_id, devid);
+ return -EINVAL;
+ }
+
+ /* dt_entry has been validated in vits_get_vdevice_entry */
+ offset = event * sizeof(struct vitt);
+ if ( offset > dt_entry.vitt_size )
+ {
+ printk(XENLOG_G_ERR "d%"PRIu16": vITS: ITT out of range\n",
+ d->domain_id);
+ return -EINVAL;
+ }
+
+ vitt_entry = dt_entry.vitt_ipa + offset;
+
+ return vits_access_guest_table(d, vitt_entry, entry,
+ sizeof(struct vitt), set);
+}
+
+static int vits_set_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry)
+{
+ return vits_vitt_entry(d, devid, event, entry, 1);
+}
+
+int vits_get_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry)
+{
+ return vits_vitt_entry(d, devid, event, entry, 0);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 56aa208..986a4d6 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -104,6 +104,8 @@ struct arch_domain
paddr_t dbase; /* Distributor base address */
paddr_t cbase; /* CPU base address */
#ifdef HAS_GICV3
+ /* Virtual ITS */
+ struct vgic_its *vits;
/* GIC V3 addressing */
/* List of contiguous occupied by the redistributors */
struct vgic_rdist_region {
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 7a46e21..42f6551 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -116,6 +116,17 @@ struct its_collection {
u16 col_id;
};

+/*
+ * Per domain virtual ITS structure.
+ */
+struct vgic_its
+{
+ /* vITT device table ipa */
+ paddr_t dt_ipa;
+ /* vITT device table size */
+ uint64_t dt_size;
+};
+
/* ITS command structure */
typedef union {
u64 bits[4];
@@ -275,6 +286,27 @@ struct its_device {
struct rb_node node;
};

+/*
+ * struct vdevice_table and struct vitt are typically stored in memory
+ * which has been provided by the guest out of its own address space
+ * and which remains accessible to the guest.
+ *
+ * Therefore great care _must_ be taken when accessing an entry in
+ * either table to validate the sanity of any values which are used.
+ */
+struct vdevice_table {
+ uint64_t vitt_ipa;
+ uint32_t vitt_size;
+ uint32_t padding;
+};
+
+struct vitt {
+ uint16_t valid:1;
+ uint16_t pad:15;
+ uint16_t vcollection;
+ uint32_t vlpi;
+};
+
void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
@@ -284,6 +316,12 @@ int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
+int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
+ uint32_t size, bool_t set);
+int vits_get_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry);
+int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
+ struct vdevice_table *entry);

#endif /* __ASM_ARM_GIC_ITS_H__ */
/*
--
1.7.9.5
Julien Grall
2015-09-02 17:20:30 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
This patch introduces virtual ITS driver with following
functionality
- Introduces helper functions to manage device table and
ITT table in guest memory
- Helper function to handle virtual ITS devices assigned
to domain
---
v6: - Exported vits_access_guest_memory() api
This is exported because the GICR emulation has to use it, right?

If so, there is a slight problem. The function is misnamed and gives the
impression that the GICv3 property table has to use the vITS. This is
not true. The vITS makes usage of the GICv3 and not the invert.

I would prefer to see this function either in vgic-v3.c or vgic.c.
Overall, this function is generic enough to be in the common framework.

Of course you would need to rename the function ;).
Post by v***@gmail.com
v5: - Removed RB tree that manages vitual ITS devices
v4: - Rename functions {find,remove,insert}_vits_* to
vits_{find,remove,insert}.
- Add common helper function to map and read/write dt
or vitt table entry.
- Removed unused code
---
xen/arch/arm/vgic-v3-its.c | 162 +++++++++++++++++++++++++++++++++++++++++
xen/include/asm-arm/domain.h | 2 +
xen/include/asm-arm/gic-its.h | 38 ++++++++++
3 files changed, 202 insertions(+)
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
[...]
Post by v***@gmail.com
+/* ITS device table helper functions */
+static int vits_vdevice_entry(struct domain *d, uint32_t dev_id,
+ struct vdevice_table *entry, bool_t set)
+{
+ uint64_t offset;
+ paddr_t dt_entry;
+ const struct vgic_its *vits = d->arch.vgic.vits;
+
+ BUILD_BUG_ON(sizeof(struct vdevice_table) != 16);
+
+ offset = dev_id * sizeof(struct vdevice_table);
+ if ( offset > vits->dt_size )
+ {
+ printk(XENLOG_G_ERR
+ "d%"PRIu16":vITS:Out of range off 0x%"PRIx64" id 0x%"PRIx32"\n",
NIT: Please use the same format everywhere. I.e space after colon. For
instance:

"d%"PRIu16": vITS: My msg"
Post by v***@gmail.com
+ d->domain_id, offset, dev_id);
+ return -EINVAL;
+ }
+
+ dt_entry = vits->dt_ipa + offset;
+
+ return vits_access_guest_table(d, dt_entry, entry,
+ sizeof(struct vdevice_table), set);
+}
+
+static int vits_set_vdevice_entry(struct domain *d, uint32_t devid,
+ struct vdevice_table *entry)
+{
+ return vits_vdevice_entry(d, devid, entry, 1);
+}
+
+int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
+ struct vdevice_table *entry)
+{
+ return vits_vdevice_entry(d, devid, entry, 0);
+}
+
+static int vits_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry, bool_t set)
+{
+ struct vdevice_table dt_entry;
+ paddr_t vitt_entry;
+ uint64_t offset;
+
+ BUILD_BUG_ON(sizeof(struct vitt) != 8);
+
+ if ( vits_get_vdevice_entry(d, devid, &dt_entry) )
+ {
+ printk(XENLOG_G_ERR
+ "d%"PRIu16": vITS: Fail to get vdevice for vdevid 0x%"PRIx32"\n",
NIT: this is technically too long and would have been avoid by using %d
rather than PRIu16 for the domain ID.

FIY, as Ian said on the previous version, we commonly use %d when we
have to print the domain ID.
Post by v***@gmail.com
+ d->domain_id, devid);
+ return -EINVAL;
+ }
+
+ /* dt_entry has been validated in vits_get_vdevice_entry */
+ offset = event * sizeof(struct vitt);
+ if ( offset > dt_entry.vitt_size )
+ {
+ printk(XENLOG_G_ERR "d%"PRIu16": vITS: ITT out of range\n",
+ d->domain_id);
+ return -EINVAL;
+ }
+
+ vitt_entry = dt_entry.vitt_ipa + offset;
+
+ return vits_access_guest_table(d, vitt_entry, entry,
+ sizeof(struct vitt), set);
+}
+
+static int vits_set_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry)
+{
+ return vits_vitt_entry(d, devid, event, entry, 1);
+}
+
+int vits_get_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry)
+{
+ return vits_vitt_entry(d, devid, event, entry, 0);
+}
+
+/*
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ */
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 56aa208..986a4d6 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -104,6 +104,8 @@ struct arch_domain
paddr_t dbase; /* Distributor base address */
paddr_t cbase; /* CPU base address */
#ifdef HAS_GICV3
+ /* Virtual ITS */
+ struct vgic_its *vits;
NIT: I would have prefer to see the addition of this field at the end of
the vgic structure. We don't usually add a field in the middle of a
structure unless there is a good reason.
Post by v***@gmail.com
/* GIC V3 addressing */
/* List of contiguous occupied by the redistributors */
struct vgic_rdist_region {
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 7a46e21..42f6551 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -116,6 +116,17 @@ struct its_collection {
u16 col_id;
};
+/*
+ * Per domain virtual ITS structure.
+ */
+struct vgic_its
+{
+ /* vITT device table ipa */
+ paddr_t dt_ipa;
+ /* vITT device table size */
+ uint64_t dt_size;
+};
+
/* ITS command structure */
typedef union {
u64 bits[4];
@@ -275,6 +286,27 @@ struct its_device {
struct rb_node node;
};
+/*
+ * struct vdevice_table and struct vitt are typically stored in memory
+ * which has been provided by the guest out of its own address space
+ * and which remains accessible to the guest.
+ *
+ * Therefore great care _must_ be taken when accessing an entry in
+ * either table to validate the sanity of any values which are used.
+ */
+struct vdevice_table {
+ uint64_t vitt_ipa;
+ uint32_t vitt_size;
+ uint32_t padding;
+};
+
+struct vitt {
+ uint16_t valid:1;
+ uint16_t pad:15;
+ uint16_t vcollection;
+ uint32_t vlpi;
+};
+
Can you put all the definition of the vITS in a single place rather than
putting them in random place within the header? It would make easier to
read the header latter.

A better solution would be to move the vits structure/function in a new
header.
Post by v***@gmail.com
void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
@@ -284,6 +316,12 @@ int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
+int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
+ uint32_t size, bool_t set);
+int vits_get_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry);
+int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
+ struct vdevice_table *entry);
#endif /* __ASM_ARM_GIC_ITS_H__ */
/*
Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:25 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Define msi_desc structure for arm and introduce
helper functions to access msi_desc member variables.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/gic-v3-its.c | 28 ++++++++++++++++++++++++++++
xen/arch/arm/irq.c | 12 ++++++++++++
xen/include/asm-arm/gic-its.h | 4 ++++
xen/include/asm-arm/irq.h | 9 +++++++++
4 files changed, 53 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 88cc89d..e70c21a 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -109,6 +109,34 @@ static void dump_cmd(const its_cmd_block *cmd)
static void dump_cmd(const its_cmd_block *cmd) { }
#endif

+void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ irq_get_msi_desc(desc)->eventID = id;
+}
+
+unsigned int irqdesc_get_lpi_event(struct irq_desc *desc)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ return irq_get_msi_desc(desc)->eventID;
+}
+
+struct its_device *irqdesc_get_its_device(struct irq_desc *desc)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ return irq_get_msi_desc(desc)->dev;
+}
+
+void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ irq_get_msi_desc(desc)->dev = dev;
+}
+
static struct its_collection *dev_event_to_col(struct its_device *dev,
u32 event)
{
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index d8080c7..24c4f24 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -143,6 +143,18 @@ static inline struct domain *irq_get_domain(struct irq_desc *desc)
return irq_get_guest_info(desc)->d;
}

+void irq_set_msi_desc(struct irq_desc *desc, struct msi_desc *msi)
+{
+ desc->msi_desc = msi;
+}
+
+struct msi_desc *irq_get_msi_desc(struct irq_desc *desc)
+{
+ ASSERT(desc->msi_desc != NULL);
+
+ return desc->msi_desc;
+}
+
void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask)
{
if ( desc != NULL )
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 70e7f54..25c2176 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -271,6 +271,10 @@ struct its_device {
struct rb_node node;
};

+void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
+unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
+struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
+void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);

diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index cbdc1ab..bddd1ea 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -18,6 +18,13 @@ struct arch_irq_desc {
unsigned int type;
};

+struct msi_desc {
+#ifdef HAS_GICV3
+ unsigned int eventID;
+ struct its_device *dev;
+#endif
+};
+
#define NR_LOCAL_IRQS 32
/* Number of SGIs+PPIs+SPIs */
#define NR_LINE_IRQS 1024
@@ -56,6 +63,8 @@ int irq_set_spi_type(unsigned int spi, unsigned int type);
int platform_get_irq(const struct dt_device_node *device, int index);

void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
+void irq_set_msi_desc(struct irq_desc *desc, struct msi_desc *msi);
+struct msi_desc *irq_get_msi_desc(struct irq_desc *desc);

#endif /* _ASM_HW_IRQ_H */
/*
--
1.7.9.5
Julien Grall
2015-08-31 16:20:45 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
Define msi_desc structure for arm and introduce
helper functions to access msi_desc member variables.
IHMO none of those helpers are useful in the code given you are only
using in an handful number of places and they can't be optimized out.

Most of the time, you will have 2-3 times within the same function the
msi_desc. So it means 6 functions call rather than directly access the
msi_desc from the irq_desc.

Although, I guess we could rework later, so for now:

Reviewed-by: Julien Grall <***@citrix.com>

Regards,
--
Julien Grall
Ian Campbell
2015-09-09 13:16:27 UTC
Permalink
Post by v***@gmail.com
Define msi_desc structure for arm and introduce
helper functions to access msi_desc member variables.
---
xen/arch/arm/gic-v3-its.c | 28 ++++++++++++++++++++++++++++
xen/arch/arm/irq.c | 12 ++++++++++++
xen/include/asm-arm/gic-its.h | 4 ++++
xen/include/asm-arm/irq.h | 9 +++++++++
4 files changed, 53 insertions(+)
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 88cc89d..e70c21a 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -109,6 +109,34 @@ static void dump_cmd(const its_cmd_block *cmd)
static void dump_cmd(const its_cmd_block *cmd) { }
#endif
+void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id)
LPIs are logically part of the GIC, not the ITS, so I think all four of
these belong at least in a gic (without -its) .c file if not in irq.c.

Or is there a reason for them to live here?
Post by v***@gmail.com
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ irq_get_msi_desc(desc)->eventID = id;
+}
+
+unsigned int irqdesc_get_lpi_event(struct irq_desc *desc)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ return irq_get_msi_desc(desc)->eventID;
+}
+
+struct its_device *irqdesc_get_its_device(struct irq_desc *desc)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ return irq_get_msi_desc(desc)->dev;
+}
+
+void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ irq_get_msi_desc(desc)->dev = dev;
+}
+
static struct its_collection *dev_event_to_col(struct its_device *dev,
u32 event)
{
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index d8080c7..24c4f24 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -143,6 +143,18 @@ static inline struct domain *irq_get_domain(struct irq_desc *desc)
return irq_get_guest_info(desc)->d;
}
+void irq_set_msi_desc(struct irq_desc *desc, struct msi_desc *msi)
+{
+ desc->msi_desc = msi;
+}
+
+struct msi_desc *irq_get_msi_desc(struct irq_desc *desc)
+{
+ ASSERT(desc->msi_desc != NULL);
+
+ return desc->msi_desc;
+}
+
void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask)
{
if ( desc != NULL )
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic
-its.h
index 70e7f54..25c2176 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -271,6 +271,10 @@ struct its_device {
struct rb_node node;
};
+void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
+unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
+struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
+void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index cbdc1ab..bddd1ea 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -18,6 +18,13 @@ struct arch_irq_desc {
unsigned int type;
};
+struct msi_desc {
+#ifdef HAS_GICV3
+ unsigned int eventID;
+ struct its_device *dev;
+#endif
+};
+
#define NR_LOCAL_IRQS 32
/* Number of SGIs+PPIs+SPIs */
#define NR_LINE_IRQS 1024
@@ -56,6 +63,8 @@ int irq_set_spi_type(unsigned int spi, unsigned int type);
int platform_get_irq(const struct dt_device_node *device, int index);
void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
+void irq_set_msi_desc(struct irq_desc *desc, struct msi_desc *msi);
+struct msi_desc *irq_get_msi_desc(struct irq_desc *desc);
#endif /* _ASM_HW_IRQ_H */
/*
Julien Grall
2015-09-09 13:28:15 UTC
Permalink
Post by Ian Campbell
Post by v***@gmail.com
Define msi_desc structure for arm and introduce
helper functions to access msi_desc member variables.
---
xen/arch/arm/gic-v3-its.c | 28 ++++++++++++++++++++++++++++
xen/arch/arm/irq.c | 12 ++++++++++++
xen/include/asm-arm/gic-its.h | 4 ++++
xen/include/asm-arm/irq.h | 9 +++++++++
4 files changed, 53 insertions(+)
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 88cc89d..e70c21a 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -109,6 +109,34 @@ static void dump_cmd(const its_cmd_block *cmd)
static void dump_cmd(const its_cmd_block *cmd) { }
#endif
+void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id)
LPIs are logically part of the GIC, not the ITS, so I think all four of
these belong at least in a gic (without -its) .c file if not in irq.c.
Or is there a reason for them to live here?
Putting those helpers in irq.c will require some #ifdery in order to not
compile when GICV3 is not built. I'd like to avoid any #ifdef in the
common code for ITS specific code (see irqdesc_set_its_device).

Although, as I said in a previous mail, those helpers are pointless as
they are only used a couple of time and always in a batch. So we should
result to fetch MSI everytime we'd like to access a field.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:33 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Add Virtual ITS command processing support to Virtual ITS driver

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Updated printk to use correct PRI*
- Moved vits_get_max_collection and is_valid_collection
helper to this patch
- Added vits_domain_free()
- Few more review comments
v5: - Rename vgic_its_*() to vits_*()
v4: - Use helper function to read from command queue
- Add MOVALL
- Removed check for entry in device in domain RB-tree
---
xen/arch/arm/vgic-v3-its.c | 420 +++++++++++++++++++++++++++++++++++++++++
xen/include/asm-arm/gic-its.h | 15 ++
2 files changed, 435 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 14c38b3..fabbad0 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -30,8 +30,44 @@
#include <asm/gic.h>
#include <asm/vgic.h>
#include <asm/gic-its.h>
+#include <asm/atomic.h>
#include <xen/log2.h>

+//#define DEBUG_ITS
+
+#ifdef DEBUG_ITS
+# define DPRINTK(fmt, args...) dprintk(XENLOG_DEBUG, fmt, ##args)
+#else
+# define DPRINTK(fmt, args...) do {} while ( 0 )
+#endif
+
+#ifdef DEBUG_ITS
+static void dump_cmd(const its_cmd_block *cmd)
+{
+ printk("VITS:CMD[0] = 0x%lx CMD[1] = 0x%lx CMD[2] = 0x%lx CMD[3] = 0x%lx\n",
+ cmd->bits[0], cmd->bits[1], cmd->bits[2], cmd->bits[3]);
+}
+#else
+static void dump_cmd(const its_cmd_block *cmd) { }
+#endif
+
+bool_t is_valid_collection(struct domain *d, uint32_t col)
+{
+ return (col <= (d->max_vcpus + 1));
+}
+
+static inline uint16_t vits_get_max_collections(struct domain *d)
+{
+ /*
+ * ITS only supports upto 256 collections without
+ * provisioning external memory. As per vITS design, number of
+ * vCPUS should not exceed max number of collections.
+ */
+ ASSERT(d->max_vcpus < 256);
+
+ return (d->max_vcpus + 1);
+}
+
int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
uint32_t size, bool_t set)
{
@@ -152,6 +188,390 @@ int vits_get_vitt_entry(struct domain *d, uint32_t devid,
return vits_vitt_entry(d, devid, event, entry, 0);
}

+static int vits_process_sync(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ /* Ignored */
+ DPRINTK("%pv: vITS: SYNC: ta 0x%"PRIx32" \n", v, virt_cmd->sync.ta);
+
+ return 0;
+}
+
+static int vits_process_mapvi(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ struct vitt entry;
+ struct domain *d = v->domain;
+ uint16_t vcol_id;
+ uint8_t cmd;
+ uint32_t vid, dev_id, event;
+
+ vcol_id = virt_cmd->mapvi.col;
+ vid = virt_cmd->mapvi.phy_id;
+ cmd = virt_cmd->mapvi.cmd;
+ dev_id = virt_cmd->mapvi.devid;
+
+ DPRINTK("%pv: vITS: MAPVI: dev 0x%"PRIx32" vcol %"PRIu16" vid %"PRIu32"\n",
+ v, dev_id, vcol_id, vid);
+
+ entry.valid = true;
+ entry.vcollection = vcol_id;
+ entry.vlpi = vid;
+
+ if ( cmd == GITS_CMD_MAPI )
+ vits_set_vitt_entry(d, dev_id, vid, &entry);
+ else
+ {
+ event = virt_cmd->mapvi.event;
+ vits_set_vitt_entry(d, dev_id, event, &entry);
+ }
+
+ return 0;
+}
+
+static int vits_process_movi(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ struct vitt entry;
+ struct domain *d = v->domain;
+ uint32_t dev_id, event;
+ uint16_t vcol_id;
+
+ vcol_id = virt_cmd->movi.col;
+ event = virt_cmd->movi.event;
+ dev_id = virt_cmd->movi.devid;
+
+ DPRINTK("%pv vITS: MOVI: dev_id 0x%"PRIx32" vcol %"PRIu16" event %"PRIu32"\n",
+ v, dev_id, vcol_id, event);
+
+ if ( vits_get_vitt_entry(d, dev_id, event, &entry) )
+ return -EINVAL;
+
+ entry.vcollection = vcol_id;
+
+ if ( vits_set_vitt_entry(d, dev_id, event, &entry) )
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vits_process_movall(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ /* Ignored */
+ DPRINTK("%pv: vITS: MOVALL: ta1 0x%"PRIx32" ta2 0x%"PRIx32" \n",
+ v, virt_cmd->movall.ta1, virt_cmd->movall.ta2);
+
+ return 0;
+}
+
+static int vits_process_discard(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ struct vitt entry;
+ struct domain *d = v->domain;
+ uint32_t event, dev_id;
+
+ event = virt_cmd->discard.event;
+ dev_id = virt_cmd->discard.devid;
+
+ DPRINTK("%pv vITS: DISCARD: dev_id 0x%"PRIx32" id %"PRIu32"\n",
+ v, virt_cmd->discard.devid, event);
+
+ if ( vits_get_vitt_entry(d, dev_id, event, &entry) )
+ return -EINVAL;
+
+ entry.valid = false;
+
+ if ( vits_set_vitt_entry(d, dev_id, event, &entry) )
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vits_process_inv(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ /* Ignored */
+ DPRINTK("%pv vITS: INV: dev_id 0x%"PRIx32" id %"PRIu32"\n",
+ v, virt_cmd->inv.devid, virt_cmd->inv.event);
+
+ return 0;
+}
+
+static int vits_process_clear(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ /* Ignored */
+ DPRINTK("%pv: vITS: CLEAR: dev_id 0x%"PRIx32" id %"PRIu32"\n",
+ v, virt_cmd->clear.devid, virt_cmd->clear.event);
+
+ return 0;
+}
+
+static int vits_process_invall(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ /* Ignored */
+ DPRINTK("%pv: vITS: INVALL: vCID %"PRIu16"\n", v, virt_cmd->invall.col);
+
+ return 0;
+}
+
+static int vits_process_int(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ uint32_t event, dev_id ;
+
+ event = virt_cmd->int_cmd.cmd;
+ dev_id = virt_cmd->int_cmd.devid;
+
+ DPRINTK("%pv: vITS: INT: Device 0x%"PRIx32" id %"PRIu32"\n",
+ v, dev_id, event);
+
+ /* TODO: Inject LPI */
+
+ return 0;
+}
+
+static int vits_add_device(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ struct domain *d = v->domain;
+ struct vdevice_table dt_entry;
+ uint32_t dev_id = virt_cmd->mapd.devid;
+
+ DPRINTK("%pv: vITS:Add dev 0x%"PRIx32" ipa = 0x%"PRIx64" size %"PRIu32"\n",
+ v, dev_id, (u64)virt_cmd->mapd.itt << MAPC_ITT_IPA_SHIFT,
+ virt_cmd->mapd.size);
+
+ if ( virt_cmd->mapd.valid )
+ {
+ /* itt field is 40 bit. extract 48 bit address by shifting */
+ dt_entry.vitt_ipa = virt_cmd->mapd.itt << MAPC_ITT_IPA_SHIFT;
+ dt_entry.vitt_size = (1 << (virt_cmd->mapd.size + 1)) *
+ sizeof(struct vitt);
+ }
+ else
+ {
+ dt_entry.vitt_ipa = INVALID_PADDR;
+ dt_entry.vitt_size = 0;
+ }
+
+ if ( vits_set_vdevice_entry(d, dev_id, &dt_entry) )
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vits_process_mapc(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ uint16_t vcol_id;
+ uint64_t vta = 0;
+
+ vcol_id = virt_cmd->mapc.col;
+ vta = virt_cmd->mapc.ta;
+
+ DPRINTK("%pv: vITS: MAPC: vCID %"PRIu16" vTA 0x%"PRIx64" valid %"PRIu8"\n",
+ v, vcol_id, vta, virt_cmd->mapc.valid);
+
+ if ( !is_valid_collection(v->domain, vcol_id) )
+ return -EINVAL;
+
+ if ( virt_cmd->mapc.valid )
+ {
+ if ( vta > v->domain->max_vcpus )
+ return -EINVAL;
+ vits->collections[vcol_id].target_address = vta;
+ }
+ else
+ vits->collections[vcol_id].target_address = INVALID_PADDR;
+
+ return 0;
+}
+
+#ifdef DEBUG_ITS
+char *cmd_str[] = {
+ [GITS_CMD_MOVI] = "MOVI",
+ [GITS_CMD_INT] = "INT",
+ [GITS_CMD_CLEAR] = "CLEAR",
+ [GITS_CMD_SYNC] = "SYNC",
+ [GITS_CMD_MAPD] = "MAPD",
+ [GITS_CMD_MAPC] = "MAPC",
+ [GITS_CMD_MAPVI] = "MAPVI",
+ [GITS_CMD_MAPI] = "MAPI",
+ [GITS_CMD_INV] = "INV",
+ [GITS_CMD_INVALL] = "INVALL",
+ [GITS_CMD_MOVALL] = "MOVALL",
+ [GITS_CMD_DISCARD] = "DISCARD",
+ };
+#endif
+
+static int vits_parse_its_command(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ uint8_t cmd = virt_cmd->hdr.cmd;
+ int ret;
+
+ DPRINTK("%pv: vITS: Received cmd %s (0x%"PRIx8")\n", v, cmd_str[cmd], cmd);
+ dump_cmd(virt_cmd);
+
+ switch ( cmd )
+ {
+ case GITS_CMD_MAPD:
+ ret = vits_add_device(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_MAPC:
+ ret = vits_process_mapc(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_MAPI:
+ /* MAPI is same as MAPVI */
+ case GITS_CMD_MAPVI:
+ ret = vits_process_mapvi(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_MOVI:
+ ret = vits_process_movi(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_MOVALL:
+ ret = vits_process_movall(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_DISCARD:
+ ret = vits_process_discard(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_INV:
+ ret = vits_process_inv(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_INVALL:
+ ret = vits_process_invall(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_INT:
+ ret = vits_process_int(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_CLEAR:
+ ret = vits_process_clear(v, vits, virt_cmd);
+ break;
+ case GITS_CMD_SYNC:
+ ret = vits_process_sync(v, vits, virt_cmd);
+ break;
+ default:
+ dprintk(XENLOG_G_ERR, "%pv: vITS: Unhandled command cmd %"PRIu8"\n",
+ v, cmd);
+ return 1;
+ }
+
+ if ( ret )
+ {
+ dprintk(XENLOG_G_ERR, "%pv: vITS: Failed to handle cmd %"PRIu8"\n",
+ v, cmd);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int vits_read_virt_cmd(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ paddr_t maddr;
+ struct domain *d = v->domain;
+ int ret;
+
+ ASSERT(spin_is_locked(&vits->lock));
+
+ if ( !(vits->cmd_base & GITS_CBASER_VALID) )
+ {
+ dprintk(XENLOG_G_ERR, "%pv: vITS: Invalid CBASER\n", v);
+ return 0;
+ }
+
+ /* Map only the page that is required */
+ maddr = (vits->cmd_base & GITS_CBASER_PA_MASK) +
+ atomic_read(&vits->cmd_read);
+
+ DPRINTK("%pv: vITS: Mapping CMD Q maddr 0x%"PRIx64" read 0x%"PRIx32"\n",
+ v, maddr, atomic_read(&vits->cmd_read));
+
+ ret = vits_access_guest_table(d, maddr, (void *)virt_cmd,
+ sizeof(its_cmd_block), 0);
+ if ( ret )
+ {
+ dprintk(XENLOG_G_ERR,
+ "%pv: vITS: Failed to get command page @page 0x%"PRIx32"\n",
+ v, atomic_read(&vits->cmd_read));
+ return -EINVAL;
+ }
+
+ /* No command queue is created by vits to check on Q full */
+ atomic_add(sizeof(its_cmd_block), &vits->cmd_read);
+ if ( atomic_read(&vits->cmd_read) == vits->cmd_qsize )
+ {
+ DPRINTK("%pv: vITS: Reset read @ 0x%"PRIx32" qsize 0x%"PRIx64"\n",
+ v, atomic_read(&vits->cmd_read), vits->cmd_qsize);
+
+ atomic_set(&vits->cmd_read, 0);
+ }
+
+ return 0;
+}
+
+int vits_process_cmd(struct vcpu *v, struct vgic_its *vits)
+{
+ its_cmd_block virt_cmd;
+
+ ASSERT(spin_is_locked(&vits->lock));
+
+ do {
+ if ( vits_read_virt_cmd(v, vits, &virt_cmd) )
+ goto err;
+ if ( vits_parse_its_command(v, vits, &virt_cmd) )
+ goto err;
+ } while ( vits->cmd_write != atomic_read(&vits->cmd_read) );
+
+ DPRINTK("%pv: vITS: read @ 0x%"PRIx32" write @ 0x%"PRIx64"\n",
+ v, atomic_read(&vits->cmd_read),
+ vits->cmd_write);
+
+ return 1;
+err:
+ dprintk(XENLOG_G_ERR, "%pv: vITS: Failed to process guest cmd\n", v);
+ domain_crash_synchronous();
+
+ return 0;
+}
+
+int vits_domain_init(struct domain *d)
+{
+ struct vgic_its *vits;
+ int i;
+
+ ASSERT(is_hardware_domain(d));
+
+ d->arch.vgic.vits = xzalloc(struct vgic_its);
+ if ( !d->arch.vgic.vits )
+ return -ENOMEM;
+
+ vits = d->arch.vgic.vits;
+
+ spin_lock_init(&vits->lock);
+
+ vits->collections = xzalloc_array(struct its_collection,
+ vits_get_max_collections(d));
+ if ( !vits->collections )
+ return -ENOMEM;
+
+ for ( i = 0; i < vits_get_max_collections(d); i++ )
+ vits->collections[i].target_address = ~0UL;
+
+ return 0;
+}
+
+void vits_domain_free(struct domain *d)
+{
+ xfree(d->arch.vgic.vits->collections);
+ xfree(d->arch.vgic.vits);
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 42f6551..4327ba2 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -21,6 +21,7 @@
#include <asm/gic_v3_defs.h>
#include <xen/rbtree.h>

+#define MAPC_ITT_IPA_SHIFT 8
/*
* ITS registers, offsets from ITS_base
*/
@@ -59,6 +60,7 @@
#define GITS_CBASER_InnerShareable (1UL << 10)
#define GITS_CBASER_SHAREABILITY_MASK (3UL << 10)
#define GITS_CBASER_CACHEABILITY_MASK (7UL << 59)
+#define GITS_CBASER_PA_MASK (0xfffffffff000UL)

#define GITS_BASER_NR_REGS 8

@@ -121,10 +123,21 @@ struct its_collection {
*/
struct vgic_its
{
+ spinlock_t lock;
+ /* Command queue base */
+ paddr_t cmd_base;
+ /* Command queue write pointer */
+ paddr_t cmd_write;
+ /* Command queue read pointer */
+ atomic_t cmd_read;
+ /* Command queue size */
+ unsigned long cmd_qsize;
/* vITT device table ipa */
paddr_t dt_ipa;
/* vITT device table size */
uint64_t dt_size;
+ /* collections mapped */
+ struct its_collection *collections;
};

/* ITS command structure */
@@ -318,6 +331,8 @@ int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
uint32_t size, bool_t set);
+int vits_domain_init(struct domain *d);
+void vits_domain_free(struct domain *d);
int vits_get_vitt_entry(struct domain *d, uint32_t devid,
uint32_t event, struct vitt *entry);
int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
--
1.7.9.5
Julien Grall
2015-09-03 15:07:09 UTC
Permalink
Hi Vijay,

This patch looks good to me. Mostly coding style comment and question
about your code/comments. See below.
Post by v***@gmail.com
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 14c38b3..fabbad0 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
[...]
Post by v***@gmail.com
+bool_t is_valid_collection(struct domain *d, uint32_t col)
You should have define the prototype of is_valid_collection within this
patch rather than in patch #13.
Post by v***@gmail.com
+{
+ return (col <= (d->max_vcpus + 1));
col <= (vtis_get_max_collections(d)) to avoid hardcoding the number of
collection in multiple place.
Post by v***@gmail.com
+}
+
+static inline uint16_t vits_get_max_collections(struct domain *d)
+{
+ /*
+ * ITS only supports upto 256 collections without
up to
Post by v***@gmail.com
+ * provisioning external memory. As per vITS design, number of
+ * vCPUS should not exceed max number of collections.
+ */
+ ASSERT(d->max_vcpus < 256);
The problem with ASSERT is it's disappearing with non-debug build. Do
you ensure somewhere that it's never possible to create a domain with
more than 256 CPUs when vITS is in use?

Otherwise, bad things would happen if we are trying to create a guest
with more than 256 vCPUs.
Post by v***@gmail.com
+
+ return (d->max_vcpus + 1);
As said on v5, please add a comment to explain why d->max_vcpus + 1. It
could be a reference to the public spec...
Post by v***@gmail.com
+}
+
[...]
Post by v***@gmail.com
+static int vits_process_int(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ uint32_t event, dev_id ;
Spurious space after dev_id.
Post by v***@gmail.com
+
+ event = virt_cmd->int_cmd.cmd;
+ dev_id = virt_cmd->int_cmd.devid;
+
+ DPRINTK("%pv: vITS: INT: Device 0x%"PRIx32" id %"PRIu32"\n",
+ v, dev_id, event);
+
+ /* TODO: Inject LPI */
+
+ return 0;
+}
[...]
Post by v***@gmail.com
+static int vits_process_mapc(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ uint16_t vcol_id;
+ uint64_t vta = 0;
Setting vta to 0 is not necessary as you override the value 2 lines below.

Note that you could have directly assign the value in the declaration of
the variables. It would have drop 2 lines.
Post by v***@gmail.com
+
+ vcol_id = virt_cmd->mapc.col;
+ vta = virt_cmd->mapc.ta;
+
+ DPRINTK("%pv: vITS: MAPC: vCID %"PRIu16" vTA 0x%"PRIx64" valid %"PRIu8"\n",
+ v, vcol_id, vta, virt_cmd->mapc.valid);
+
+ if ( !is_valid_collection(v->domain, vcol_id) )
+ return -EINVAL;
+
+ if ( virt_cmd->mapc.valid )
+ {
+ if ( vta > v->domain->max_vcpus )
+ return -EINVAL;
+ vits->collections[vcol_id].target_address = vta;
+ }
+ else
+ vits->collections[vcol_id].target_address = INVALID_PADDR;
+
+ return 0;
+}
[...]
Post by v***@gmail.com
+static int vits_read_virt_cmd(struct vcpu *v, struct vgic_its *vits,
+ its_cmd_block *virt_cmd)
+{
+ paddr_t maddr;
+ struct domain *d = v->domain;
+ int ret;
+
+ ASSERT(spin_is_locked(&vits->lock));
+
+ if ( !(vits->cmd_base & GITS_CBASER_VALID) )
+ {
+ dprintk(XENLOG_G_ERR, "%pv: vITS: Invalid CBASER\n", v);
+ return 0;
+ }
+
+ /* Map only the page that is required */
IHMO the "CMD Q can be more than 1 page" was valid and useful. Sorry if
I wasn't enough clear that I wanted the typo fixed on the second sentence.
Post by v***@gmail.com
+ maddr = (vits->cmd_base & GITS_CBASER_PA_MASK) +
+ atomic_read(&vits->cmd_read);
+
+ DPRINTK("%pv: vITS: Mapping CMD Q maddr 0x%"PRIx64" read 0x%"PRIx32"\n",
+ v, maddr, atomic_read(&vits->cmd_read));
+
+ ret = vits_access_guest_table(d, maddr, (void *)virt_cmd,
+ sizeof(its_cmd_block), 0);
+ if ( ret )
+ {
+ dprintk(XENLOG_G_ERR,
+ v, atomic_read(&vits->cmd_read));
+ return -EINVAL;
+ }
+
+ /* No command queue is created by vits to check on Q full */
I don't understand this comment. What do you mean?
Post by v***@gmail.com
+ atomic_add(sizeof(its_cmd_block), &vits->cmd_read);
+ if ( atomic_read(&vits->cmd_read) == vits->cmd_qsize )
+ {
+ v, atomic_read(&vits->cmd_read), vits->cmd_qsize);
+
+ atomic_set(&vits->cmd_read, 0);
+ }
+
+ return 0;
+}
[...]
Post by v***@gmail.com
+int vits_domain_init(struct domain *d)
+{
+ struct vgic_its *vits;
+ int i;
+
+ ASSERT(is_hardware_domain(d));
+
+ d->arch.vgic.vits = xzalloc(struct vgic_its);
+ if ( !d->arch.vgic.vits )
+ return -ENOMEM;
+
+ vits = d->arch.vgic.vits;
+
+ spin_lock_init(&vits->lock);
+
+ vits->collections = xzalloc_array(struct its_collection,
+ vits_get_max_collections(d));
+ if ( !vits->collections )
+ return -ENOMEM;
+
+ for ( i = 0; i < vits_get_max_collections(d); i++ )
+ vits->collections[i].target_address = ~0UL;
You are using 2 different values for the invalid address: ~0UL and
INVALID_PADDR.

They are not defined the same way and even though they may give the same
result for target_address by luck you should always use the same
definition everywhere.

I would prefer to see INVALID_PADDR even though a define
VITS_TARGET_INVALID (or similar) would have been nice. Although, I'm
fine if you don't add the define.
Post by v***@gmail.com
+
+ return 0;
+}
[...]
Post by v***@gmail.com
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 42f6551..4327ba2 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -21,6 +21,7 @@
#include <asm/gic_v3_defs.h>
#include <xen/rbtree.h>
+#define MAPC_ITT_IPA_SHIFT 8
I would much prefer to see this define with the definition of the
command structure.
Post by v***@gmail.com
/*
* ITS registers, offsets from ITS_base
*/
@@ -59,6 +60,7 @@
#define GITS_CBASER_InnerShareable (1UL << 10)
#define GITS_CBASER_SHAREABILITY_MASK (3UL << 10)
#define GITS_CBASER_CACHEABILITY_MASK (7UL << 59)
+#define GITS_CBASER_PA_MASK (0xfffffffff000UL)
#define GITS_BASER_NR_REGS 8
Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:39 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Introduce vgic_is_lpi_supported() helper function
to know virtual ITS availability for a domain

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/vgic-v2.c | 5 +++++
xen/arch/arm/vgic-v3.c | 6 ++++++
xen/arch/arm/vgic.c | 5 +++++
xen/include/asm-arm/vgic.h | 7 +++++++
4 files changed, 23 insertions(+)

diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index 600d27e..15ec809 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -32,6 +32,8 @@
#include <asm/platform.h>
#include <asm/vgic.h>

+static struct vgic_info vgic_v2_info;
+
static struct {
bool_t enabled;
/* Distributor interface address */
@@ -594,10 +596,13 @@ static int vgic_v2_domain_init(struct domain *d)
register_mmio_handler(d, &vgic_v2_distr_mmio_handler, d->arch.vgic.dbase,
PAGE_SIZE);

+ vgic_v2_info.its_enabled = 0;
+
return 0;
}

static const struct vgic_ops vgic_v2_ops = {
+ .info = &vgic_v2_info,
.vcpu_init = vgic_v2_vcpu_init,
.domain_init = vgic_v2_domain_init,
.get_irq_priority = vgic_v2_get_irq_priority,
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 863648c..771bfd1 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -49,6 +49,8 @@
*/
#define VGICD_CTLR_DEFAULT (GICD_CTLR_ARE_NS)

+static struct vgic_info vgic_v3_info;
+
static struct {
bool_t enabled;
/* Distributor interface address */
@@ -1247,10 +1249,14 @@ static int vgic_v3_domain_init(struct domain *d)

d->arch.vgic.ctlr = VGICD_CTLR_DEFAULT;

+ if ( is_hardware_domain(d) && gic_lpi_supported() )
+ vgic_v3_info.its_enabled = 1;
+
return 0;
}

static const struct vgic_ops v3_ops = {
+ .info = &vgic_v3_info,
.vcpu_init = vgic_v3_vcpu_init,
.domain_init = vgic_v3_domain_init,
.get_irq_priority = vgic_v3_get_irq_priority,
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 6b6bbce..d5e9251 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -61,6 +61,11 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq)
return vgic_get_rank(v, rank);
}

+bool_t vgic_is_lpi_supported(struct domain *d)
+{
+ return d->arch.vgic.handler->info->its_enabled;
+}
+
static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
{
INIT_LIST_HEAD(&p->inflight);
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 659d919..1c88300 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -110,7 +110,13 @@ static inline void sgi_target_init(struct sgi_target *sgi_target)
sgi_target->list = 0;
}

+struct vgic_info {
+ bool_t its_enabled;
+};
+
struct vgic_ops {
+ /* Hold vGIC information */
+ const struct vgic_info *info;
/* Initialize vGIC */
int (*vcpu_init)(struct vcpu *v);
/* Domain specific initialization of vGIC */
@@ -309,6 +315,7 @@ enum gic_sgi_mode;

#define vgic_num_line_irqs(d) ((d)->arch.vgic.nr_spis + 32)

+extern bool_t vgic_is_lpi_supported(struct domain *d);
extern int domain_vgic_init(struct domain *d, unsigned int nr_spis);
extern void domain_vgic_free(struct domain *d);
extern int vcpu_vgic_init(struct vcpu *v);
--
1.7.9.5
Julien Grall
2015-09-07 13:41:15 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 659d919..1c88300 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -110,7 +110,13 @@ static inline void sgi_target_init(struct sgi_target *sgi_target)
sgi_target->list = 0;
}
+struct vgic_info {
+ bool_t its_enabled;
+};
+
struct vgic_ops {
+ /* Hold vGIC information */
+ const struct vgic_info *info;
The vgic_ops are shared between all the domains so you will end up to
allow ITS on every domains.

Any domain specific value should go in the domain structure and not in
the vgic_ops.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:43 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Allocate dynamically pending_lpi descriptors for LPIs

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/vgic-v3-its.c | 9 +++++++++
xen/arch/arm/vgic.c | 20 +++++++++++++++++---
xen/include/asm-arm/domain.h | 3 +++
xen/include/asm-arm/vgic.h | 4 +++-
4 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 7c0375a..1d1fd64 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -908,6 +908,14 @@ int vits_domain_init(struct domain *d)

vits = d->arch.vgic.vits;

+ d->arch.vgic.pending_lpis = xzalloc_array(struct pending_irq,
+ d->arch.vgic.nr_lpis);
+ if ( d->arch.vgic.pending_lpis == NULL )
+ return -ENOMEM;
+
+ for ( i = 0; i < d->arch.vgic.nr_lpis; i++ )
+ vgic_init_pending_irq(&d->arch.vgic.pending_lpis[i], i + FIRST_GIC_LPI);
+
spin_lock_init(&vits->lock);
spin_lock_init(&vits->prop_lock);

@@ -937,6 +945,7 @@ void vits_domain_free(struct domain *d)
{
free_xenheap_pages(d->arch.vgic.vits->prop_page,
get_order_from_bytes(d->arch.vgic.vits->prop_size));
+ xfree(d->arch.vgic.pending_lpis);
xfree(d->arch.vgic.vits->collections);
xfree(d->arch.vgic.vits);
}
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index d5e9251..6e7ae9e 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -66,7 +66,13 @@ bool_t vgic_is_lpi_supported(struct domain *d)
return d->arch.vgic.handler->info->its_enabled;
}

-static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
+bool_t vgic_is_domain_lpi(struct domain *d, unsigned int lpi)
+{
+ return ((lpi >= FIRST_GIC_LPI) &&
+ (lpi < (d->arch.vgic.nr_lpis + FIRST_GIC_LPI)));
+}
+
+void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
{
INIT_LIST_HEAD(&p->inflight);
INIT_LIST_HEAD(&p->lr_queue);
@@ -392,13 +398,21 @@ int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int

struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
{
- struct pending_irq *n;
+ struct pending_irq *n = NULL;
/* Pending irqs allocation strategy: the first vgic.nr_spis irqs
- * are used for SPIs; the rests are used for per cpu irqs */
+ * are used for SPIs; the rests are used for per cpu irqs.
+ * For LPIs pending_irq structures are allocated separately */
if ( irq < 32 )
n = &v->arch.vgic.pending_irqs[irq];
+#ifdef HAS_GICV3
+ else if ( vgic_is_domain_lpi(v->domain, irq) )
+ n = &v->domain->arch.vgic.pending_lpis[irq - FIRST_GIC_LPI];
+#endif
else
n = &v->domain->arch.vgic.pending_irqs[irq - 32];
+
+ ASSERT(n != NULL);
+
return n;
}

diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index b48a1d9..f6ec403 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -103,6 +103,9 @@ struct arch_domain
* struct arch_vcpu.
*/
struct pending_irq *pending_irqs;
+#ifdef HAS_GICV3
+ struct pending_irq *pending_lpis;
+#endif
/* Base address for guest GIC */
paddr_t dbase; /* Distributor base address */
paddr_t cbase; /* CPU base address */
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 1c88300..e971cab 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -339,6 +339,7 @@ extern int vgic_to_sgi(struct vcpu *v, register_t sgir,
enum gic_sgi_mode irqmode, int virq,
const struct sgi_target *target);
extern void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq);
+extern void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq);

/* Reserve a specific guest vIRQ */
extern bool_t vgic_reserve_virq(struct domain *d, unsigned int virq);
@@ -371,7 +372,8 @@ void vgic_v3_setup_hw(paddr_t dbase,
const struct rdist_region *regions,
uint32_t rdist_stride);
#endif
-
+bool_t vgic_is_domain_lpi(struct domain *d, unsigned int lpi);
+
#endif /* __ASM_ARM_VGIC_H__ */

/*
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:38 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Emulate GITS* registers

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Removed unrelated code of this patch
- Used vgic_regN_{read,write}
v4: - Removed GICR register emulation
---
xen/arch/arm/vgic-v3-its.c | 337 ++++++++++++++++++++++++++++++++++++++++-
xen/include/asm-arm/gic-its.h | 16 ++
2 files changed, 352 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 53f2a27..c384ecf 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -35,6 +35,14 @@

//#define DEBUG_ITS

+/* GITS_PIDRn register values for ARM implementations */
+#define GITS_PIDR0_VAL (0x94)
+#define GITS_PIDR1_VAL (0xb4)
+#define GITS_PIDR2_VAL (0x3b)
+#define GITS_PIDR3_VAL (0x00)
+#define GITS_PIDR4_VAL (0x04)
+#define GITS_BASER_INIT_VAL ((1UL << GITS_BASER_TYPE_SHIFT) | \
+ (0x7UL << GITS_BASER_ENTRY_SIZE_SHIFT))
#ifdef DEBUG_ITS
# define DPRINTK(fmt, args...) dprintk(XENLOG_DEBUG, fmt, ##args)
#else
@@ -535,7 +543,7 @@ static int vits_read_virt_cmd(struct vcpu *v, struct vgic_its *vits,
return 0;
}

-int vits_process_cmd(struct vcpu *v, struct vgic_its *vits)
+static int vits_process_cmd(struct vcpu *v, struct vgic_its *vits)
{
its_cmd_block virt_cmd;

@@ -560,6 +568,322 @@ err:
return 0;
}

+static inline void vits_spin_lock(struct vgic_its *vits)
+{
+ spin_lock(&vits->lock);
+}
+
+static inline void vits_spin_unlock(struct vgic_its *vits)
+{
+ spin_unlock(&vits->lock);
+}
+
+static int vgic_v3_gits_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+ struct hsr_dabt dabt = info->dabt;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ register_t *r = select_user_reg(regs, dabt.reg);
+ uint64_t val = 0;
+ uint32_t gits_reg;
+
+ gits_reg = info->gpa - vits->gits_base;
+ DPRINTK("%pv: vITS: GITS_MMIO_READ offset 0x%"PRIx32"\n", v, gits_reg);
+
+ switch ( gits_reg )
+ {
+ case GITS_CTLR:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ vits_spin_lock(vits);
+ /*
+ * vITS is always quiescent, has no translations in progress and
+ * completed all operations. So set quescent by default.
+ */
+ *r = vgic_reg32_read((vits->ctrl | GITS_CTLR_QUIESCENT), info);
+ vits_spin_unlock(vits);
+ return 1;
+ case GITS_IIDR:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GICV3_GICD_IIDR_VAL, info);
+ return 1;
+ case GITS_TYPER:
+ case GITS_TYPER + 4:
+ /*
+ * GITS_TYPER.HCC = max_vcpus + 1 (max collection supported)
+ * GITS_TYPER.Devbits = HW supported Devbits size
+ * GITS_TYPER.IDbits = HW supported IDbits size
+ * GITS_TYPER.PTA = 0 (Target addresses are linear processor numbers)
+ * GITS_TYPER.ITTSize = Size of struct vitt
+ * GITS_TYPER.Physical = 1
+ */
+ if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+ val = ((vits_get_max_collections(v->domain) << GITS_TYPER_HCC_SHIFT ) |
+ ((vits_hw.dev_bits - 1) << GITS_TYPER_DEVBITS_SHIFT) |
+ ((vits_hw.eventid_bits - 1) << GITS_TYPER_IDBITS_SHIFT) |
+ ((sizeof(struct vitt) - 1) << GITS_TYPER_ITT_SIZE_SHIFT) |
+ GITS_TYPER_PHYSICAL_LPIS);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(val, info);
+ else
+ *r = vgic_reg32_read(val, info);
+ return 1;
+ case 0x0010 ... 0x007c:
+ case 0xc000 ... 0xffcc:
+ /* Implementation defined -- read ignored */
+ goto read_as_zero;
+ case GITS_CBASER:
+ case GITS_CBASER + 4:
+ /* Read supports only 32/64-bit access */
+ if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+ vits_spin_lock(vits);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(vits->cmd_base, info);
+ else
+ *r = vgic_reg32_read(vits->cmd_base, info);
+ vits_spin_unlock(vits);
+ return 1;
+ case GITS_CWRITER:
+ /* Read supports only 32/64-bit access */
+ vits_spin_lock(vits);
+ val = vits->cmd_write;
+ vits_spin_unlock(vits);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(val, info);
+ else if (dabt.size == DABT_WORD )
+ *r = vgic_reg32_read(val, info);
+ else
+ goto bad_width;
+ return 1;
+ case GITS_CWRITER + 4:
+ /* BITS[63:20] are RES0 */
+ goto read_as_zero_32;
+ case GITS_CREADR:
+ /* Read supports only 32/64-bit access */
+ val = atomic_read(&vits->cmd_read);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(val, info);
+ else if (dabt.size == DABT_WORD )
+ *r = vgic_reg32_read(val, info);
+ else
+ goto bad_width;
+ return 1;
+ case GITS_CREADR + 4:
+ /* BITS[63:20] are RES0 */
+ goto read_as_zero_32;
+ case 0x0098 ... 0x009c:
+ case 0x00a0 ... 0x00fc:
+ case 0x0140 ... 0xbffc:
+ /* Reserved -- read ignored */
+ goto read_as_zero;
+ case GITS_BASER0:
+ /* Supports only 64-bit access */
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ {
+ vits_spin_lock(vits);
+ *r = vgic_reg64_read(vits->baser0, info);
+ vits_spin_unlock(vits);
+ }
+ else
+ goto bad_width;
+ return 1;
+ case GITS_BASER1 ... GITS_BASERN:
+ goto read_as_zero;
+ case GITS_PIDR0:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR0_VAL, info);
+ return 1;
+ case GITS_PIDR1:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR1_VAL, info);
+ return 1;
+ case GITS_PIDR2:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR2_VAL, info);
+ return 1;
+ case GITS_PIDR3:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR3_VAL, info);
+ return 1;
+ case GITS_PIDR4:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR4_VAL, info);
+ return 1;
+ case GITS_PIDR5 ... GITS_PIDR7:
+ goto read_as_zero_32;
+ default:
+ dprintk(XENLOG_G_ERR,
+ "%pv: vITS: unhandled read r%"PRId32" offset 0x%#08"PRIx32"\n",
+ v, dabt.reg, gits_reg);
+ return 0;
+ }
+
+bad_width:
+ dprintk(XENLOG_G_ERR,
+ "%pv: vITS: bad read width %d r%"PRId32" offset 0x%#08"PRIx32"\n",
+ v, dabt.size, dabt.reg, gits_reg);
+ domain_crash_synchronous();
+ return 0;
+
+read_as_zero_32:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+read_as_zero:
+ *r = 0;
+ return 1;
+}
+
+/*
+ * GITS_BASER.Type[58:56], GITS_BASER.Entry_size[55:48]
+ * and GITS_BASER.Shareability[11:10] are read-only,
+ * Here we support only flat table. So GITS_BASER.Indirect[62]
+ * is RAZ/WI.
+ * Mask those fields while emulating GITS_BASER reg.
+ * TODO: Shareability is set to 0x0 (Reserved) which is fixed.
+ * Implementing fixed value for Shareability is deprecated.
+ */
+#define GITS_BASER_MASK (~((0x7UL << GITS_BASER_TYPE_SHIFT) | \
+ (0x1UL << GITS_BASER_INDIRECT_SHIFT) | \
+ (0xffUL << GITS_BASER_ENTRY_SIZE_SHIFT) | \
+ (0x3UL << GITS_BASER_SHAREABILITY_SHIFT)))
+
+static int vgic_v3_gits_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+ struct hsr_dabt dabt = info->dabt;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ register_t *r = select_user_reg(regs, dabt.reg);
+ int ret;
+ uint32_t gits_reg, sz, psz;
+ uint64_t val;
+
+ gits_reg = info->gpa - vits->gits_base;
+
+ DPRINTK("%pv: vITS: GITS_MMIO_WRITE offset 0x%"PRIx32"\n", v, gits_reg);
+ switch ( gits_reg )
+ {
+ case GITS_CTLR:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ vits_spin_lock(vits);
+ vgic_reg32_write(&vits->ctrl, (*r & GITS_CTLR_ENABLE), info);
+ vits_spin_unlock(vits);
+ return 1;
+ case GITS_IIDR:
+ /* RO -- write ignored */
+ goto write_ignore;
+ case GITS_TYPER:
+ case GITS_TYPER + 4:
+ /* RO -- write ignored */
+ goto write_ignore;
+ case 0x0010 ... 0x007c:
+ case 0xc000 ... 0xffcc:
+ /* Implementation defined -- write ignored */
+ goto write_ignore;
+ case GITS_CBASER:
+ /* XXX: support 32-bit access */
+ if ( dabt.size != DABT_DOUBLE_WORD )
+ goto bad_width;
+ vits_spin_lock(vits);
+ if ( vits->ctrl & GITS_CTLR_ENABLE )
+ {
+ /* RO -- write ignored */
+ vits_spin_unlock(vits);
+ goto write_ignore;
+ }
+ vgic_reg64_write(&vits->cmd_base, *r, info);
+ val = SZ_4K * ((*r & GITS_BASER_PAGES_MASK_VAL) + 1);
+ vgic_reg64_write(&vits->cmd_qsize, val, info);
+ if ( vits->cmd_base & GITS_BASER_VALID )
+ atomic_set(&vits->cmd_read, 0);
+ vits_spin_unlock(vits);
+ return 1;
+ case GITS_CWRITER:
+ if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+ vits_spin_lock(vits);
+ /* Only BITS[19:0] are writable */
+ vgic_reg64_write(&vits->cmd_write, (*r & 0xfffe0), info);
+ ret = 1;
+ /* CWRITER should be within the range */
+ if ( (vits->ctrl & GITS_CTLR_ENABLE) &&
+ (vits->cmd_write < (vits->cmd_qsize & 0xfffe0)) )
+ ret = vits_process_cmd(v, vits);
+ vits_spin_unlock(vits);
+ return ret;
+ case GITS_CWRITER + 4:
+ /* BITS[63:20] are RES0 */
+ goto write_ignore_32;
+ case GITS_CREADR:
+ /* RO -- write ignored */
+ goto write_ignore;
+ case 0x0098 ... 0x009c:
+ case 0x00a0 ... 0x00fc:
+ case 0x0140 ... 0xbffc:
+ /* Reserved -- write ignored */
+ goto write_ignore;
+ case GITS_BASER0:
+ /* Support only 64-bit access */
+ if ( dabt.size != DABT_DOUBLE_WORD )
+ goto bad_width;
+ vits_spin_lock(vits);
+ /* RO -- write ignored if GITS_CTLR.Enable = 1 */
+ if ( vits->ctrl & GITS_CTLR_ENABLE )
+ {
+ vits_spin_unlock(vits);
+ goto write_ignore_64;
+ }
+ val = vits->baser0 | (*r & GITS_BASER_MASK);
+ vgic_reg64_write(&vits->baser0, val, info);
+ val = vits->baser0 & GITS_BASER_PA_MASK;
+ vgic_reg64_write(&vits->dt_ipa, val, info);
+ psz = (vits->baser0 >> GITS_BASER_PAGE_SIZE_SHIFT) &
+ GITS_BASER_PAGE_SIZE_MASK_VAL;
+ if ( psz == GITS_BASER_PAGE_SIZE_4K_VAL )
+ sz = 4;
+ else if ( psz == GITS_BASER_PAGE_SIZE_16K_VAL )
+ sz = 16;
+ else
+ /* 0x11 and 0x10 are treated as 64K size */
+ sz = 64;
+
+ val = (vits->baser0 & GITS_BASER_PAGES_MASK_VAL)
+ * sz * SZ_1K;
+ vgic_reg64_write(&vits->dt_size, val, info);
+ vits_spin_unlock(vits);
+ return 1;
+ case GITS_BASER1 ... GITS_BASERN:
+ if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+ goto write_ignore;
+ case GITS_PIDR7 ... GITS_PIDR0:
+ /* R0 -- write ignored */
+ goto write_ignore_32;
+ default:
+ dprintk(XENLOG_G_ERR,
+ "%pv vITS: unhandled write r%"PRId32" offset 0x%#08"PRIx32"\n",
+ v, dabt.reg, gits_reg);
+ return 0;
+ }
+
+bad_width:
+ dprintk(XENLOG_G_ERR,
+ "%pv: vITS: bad write width %d r%"PRId32" offset 0x%#08"PRIx32"\n",
+ v, dabt.size, dabt.reg, gits_reg);
+ domain_crash_synchronous();
+ return 0;
+
+write_ignore_64:
+ if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+ return 1;
+write_ignore_32:
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ return 1;
+write_ignore:
+ return 1;
+}
+
+
+static const struct mmio_handler_ops vgic_gits_mmio_handler = {
+ .read_handler = vgic_v3_gits_mmio_read,
+ .write_handler = vgic_v3_gits_mmio_write,
+};
+
int vits_domain_init(struct domain *d)
{
struct vgic_its *vits;
@@ -593,6 +917,17 @@ int vits_domain_init(struct domain *d)
for ( i = 0; i < vits_get_max_collections(d); i++ )
vits->collections[i].target_address = ~0UL;

+ vits->baser0 = GITS_BASER_INIT_VAL;
+
+ /*
+ * Only one virtual ITS is provided to domain.
+ * Assign first physical ITS address to Dom0 virtual ITS.
+ */
+ vits->gits_base = vits_hw.phys_base;
+ vits->gits_size = vits_hw.phys_size;
+
+ register_mmio_handler(d, &vgic_gits_mmio_handler, vits->gits_base, SZ_64K);
+
return 0;
}

diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index a3d21f7..db1530e 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -53,6 +53,8 @@
#define GITS_TYPER_IDBITS(r) ((((r) >> GITS_TYPER_IDBITS_SHIFT) & 0x1f) + 1)
#define GITS_TYPER_PTA (1UL << 19)
#define GITS_TYPER_HCC_SHIFT (24)
+#define GITS_TYPER_PHYSICAL_LPIS (1UL)
+#define GITS_TYPER_ITT_SIZE_SHIFT (4)

#define GITS_CBASER_VALID (1UL << 63)
#define GITS_CBASER_nC (1UL << 59)
@@ -65,6 +67,7 @@
#define GITS_BASER_NR_REGS 8

#define GITS_BASER_VALID (1UL << 63)
+#define GITS_BASER_INDIRECT_SHIFT (62)
#define GITS_BASER_nC (1UL << 59)
#define GITS_BASER_WaWb (5UL << 59)
#define GITS_BASER_TYPE_SHIFT (56)
@@ -80,6 +83,10 @@
#define GITS_BASER_PAGE_SIZE_16K (1UL << GITS_BASER_PAGE_SIZE_SHIFT)
#define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT)
#define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT)
+#define GITS_BASER_PAGE_SIZE_4K_VAL (0)
+#define GITS_BASER_PAGE_SIZE_16K_VAL (1)
+#define GITS_BASER_PAGE_SIZE_MASK_VAL (0x3)
+#define GITS_BASER_PAGES_MASK_VAL (0xff)
#define GITS_BASER_TYPE_NONE 0
#define GITS_BASER_TYPE_DEVICE 1
#define GITS_BASER_TYPE_VCPU 2
@@ -88,6 +95,7 @@
#define GITS_BASER_TYPE_RESERVED5 5
#define GITS_BASER_TYPE_RESERVED6 6
#define GITS_BASER_TYPE_RESERVED7 7
+#define GITS_BASER_PA_MASK (0xfffffffff000UL)

/*
* ITS commands
@@ -124,6 +132,8 @@ struct its_collection {
struct vgic_its
{
spinlock_t lock;
+ /* Emulation of BASER0 */
+ paddr_t baser0;
/* Command queue base */
paddr_t cmd_base;
/* Command queue write pointer */
@@ -132,6 +142,12 @@ struct vgic_its
atomic_t cmd_read;
/* Command queue size */
unsigned long cmd_qsize;
+ /* ITS mmio physical base */
+ paddr_t gits_base;
+ /* ITS mmio physical size */
+ unsigned long gits_size;
+ /* GICR ctrl register */
+ uint32_t ctrl;
/* vITT device table ipa */
paddr_t dt_ipa;
/* vITT device table size */
--
1.7.9.5
Julien Grall
2015-09-07 13:14:16 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
Emulate GITS* registers
---
v6: - Removed unrelated code of this patch
- Used vgic_regN_{read,write}
v4: - Removed GICR register emulation
---
xen/arch/arm/vgic-v3-its.c | 337 ++++++++++++++++++++++++++++++++++++++++-
xen/include/asm-arm/gic-its.h | 16 ++
2 files changed, 352 insertions(+), 1 deletion(-)
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 53f2a27..c384ecf 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -35,6 +35,14 @@
//#define DEBUG_ITS
+/* GITS_PIDRn register values for ARM implementations */
+#define GITS_PIDR0_VAL (0x94)
+#define GITS_PIDR1_VAL (0xb4)
+#define GITS_PIDR2_VAL (0x3b)
+#define GITS_PIDR3_VAL (0x00)
+#define GITS_PIDR4_VAL (0x04)
+#define GITS_BASER_INIT_VAL ((1UL << GITS_BASER_TYPE_SHIFT) | \
+ (0x7UL << GITS_BASER_ENTRY_SIZE_SHIFT))
This value is only for BASER0 so GITS_BASER0_INIT_VAL

You also need to explain what means the different values. And please
don't hardcode the size of the Device Entry but the proper sizeof.
Post by v***@gmail.com
#ifdef DEBUG_ITS
# define DPRINTK(fmt, args...) dprintk(XENLOG_DEBUG, fmt, ##args)
#else
@@ -535,7 +543,7 @@ static int vits_read_virt_cmd(struct vcpu *v, struct vgic_its *vits,
return 0;
}
-int vits_process_cmd(struct vcpu *v, struct vgic_its *vits)
+static int vits_process_cmd(struct vcpu *v, struct vgic_its *vits)
You would have been able to keep the static when the patch has been
introduced if you have plumbed vgic-v3 for vITS support latter (i.e part
of #19 moved at the end).
Post by v***@gmail.com
{
its_cmd_block virt_cmd;
[...]
Post by v***@gmail.com
+static int vgic_v3_gits_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+ struct hsr_dabt dabt = info->dabt;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ register_t *r = select_user_reg(regs, dabt.reg);
+ uint64_t val = 0;
+ uint32_t gits_reg;
+
+ gits_reg = info->gpa - vits->gits_base;
+ DPRINTK("%pv: vITS: GITS_MMIO_READ offset 0x%"PRIx32"\n", v, gits_reg);
+
+ switch ( gits_reg )
+ {
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ vits_spin_lock(vits);
+ /*
+ * vITS is always quiescent, has no translations in progress and
+ * completed all operations. So set quescent by default.
s/quescent/quiescent/
Post by v***@gmail.com
+ */
+ *r = vgic_reg32_read((vits->ctrl | GITS_CTLR_QUIESCENT), info);
IHMO the Quiescent bit should be set at write time not read time. So we
can use it in the emulation if necessary.
Post by v***@gmail.com
+ vits_spin_unlock(vits);
+ return 1;
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GICV3_GICD_IIDR_VAL, info);
+ return 1;
+ /*
+ * GITS_TYPER.HCC = max_vcpus + 1 (max collection supported)
+ * GITS_TYPER.Devbits = HW supported Devbits size
+ * GITS_TYPER.IDbits = HW supported IDbits size
+ * GITS_TYPER.PTA = 0 (Target addresses are linear processor numbers)
+ * GITS_TYPER.ITTSize = Size of struct vitt
+ * GITS_TYPER.Physical = 1
+ */
+ if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+ val = ((vits_get_max_collections(v->domain) << GITS_TYPER_HCC_SHIFT ) |
+ ((vits_hw.dev_bits - 1) << GITS_TYPER_DEVBITS_SHIFT) |
+ ((vits_hw.eventid_bits - 1) << GITS_TYPER_IDBITS_SHIFT) |
+ ((sizeof(struct vitt) - 1) << GITS_TYPER_ITT_SIZE_SHIFT) |
+ GITS_TYPER_PHYSICAL_LPIS);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(val, info);
+ else
+ *r = vgic_reg32_read(val, info);
Can you explain why this is necessary? The goal of vgic_reg64_read is to
handle all access size to 64bit register.
The vgic_reg32_read will only handle access on 32bit and therefore it
won't be possible to access to the most significant word.
Post by v***@gmail.com
+ return 1;
+ /* Implementation defined -- read ignored */
+ goto read_as_zero;
+ /* Read supports only 32/64-bit access */
This comment is not necessary and is confusing as you call the helper now
Post by v***@gmail.com
+ if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+ vits_spin_lock(vits);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(vits->cmd_base, info);
+ else
+ *r = vgic_reg32_read(vits->cmd_base, info);
Same remark as before. I have to say that those helpers are commented
with: "N-bit register helpers". Isn't it clear enough that N correspond
to the size of the GIC register?
Post by v***@gmail.com
+ vits_spin_unlock(vits);
+ return 1;
+ /* Read supports only 32/64-bit access */
+ vits_spin_lock(vits);
+ val = vits->cmd_write;
+ vits_spin_unlock(vits);
The size *should* be checked before locking the vITS and read the register.

Unless you have a strong reason to do it, please use the same pattern
everywhere and don't reinvent a new one.
Post by v***@gmail.com
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(val, info);
+ else if (dabt.size == DABT_WORD )
+ *r = vgic_reg32_read(val, info);
+ else
+ goto bad_width;
+ return 1;
+ /* BITS[63:20] are RES0 */
NIT: s/BITS/Bits/
Post by v***@gmail.com
+ goto read_as_zero_32;
+ /* Read supports only 32/64-bit access */
+ val = atomic_read(&vits->cmd_read);
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ *r = vgic_reg64_read(val, info);
+ else if (dabt.size == DABT_WORD )
+ *r = vgic_reg32_read(val, info);
+ else
+ goto bad_width;
Ditto.
Post by v***@gmail.com
+ return 1;
+ /* BITS[63:20] are RES0 */
NIT: s/BITS/Bits/
Post by v***@gmail.com
+ goto read_as_zero_32;
+ /* Reserved -- read ignored */
+ goto read_as_zero;
+ /* Supports only 64-bit access */
The indentation is wrong and I don't see why you can't support 32-bit
with the helpers I've introduced...
Post by v***@gmail.com
+ if ( dabt.size == DABT_DOUBLE_WORD )
+ {
+ vits_spin_lock(vits);
+ *r = vgic_reg64_read(vits->baser0, info);
+ vits_spin_unlock(vits);
+ }
+ else
+ goto bad_width;
Please use the same pattern everywhere. I.e the bad case should be first
then the good case. This will dropped one layer of indentation and keep
all the emulation similar.

Actually, I did the same remark on v5... So if you think this is not the
right thing to do, please explain why and don't silently ignore the
comment...
Post by v***@gmail.com
+ return 1;
+ goto read_as_zero;
Those register as read as zero 64 bits...
Post by v***@gmail.com
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR0_VAL, info);
+ return 1;
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR1_VAL, info);
+ return 1;
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR2_VAL, info);
+ return 1;
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR3_VAL, info);
+ return 1;
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = vgic_reg32_read(GITS_PIDR4_VAL, info);
+ return 1;
+ goto read_as_zero_32;
+ dprintk(XENLOG_G_ERR,
+ "%pv: vITS: unhandled read r%"PRId32" offset 0x%#08"PRIx32"\n",
I forgot to answer to " dabt.reg is unsigned long : 5. In vgic-v3.c it
is printed using %d."

%d matches with 8bit, 16bit and 32bit. In this case, the field reg is
5bits so this should technically PRId8.

You need to use your common sense to use PRIdX when necessary. PRIdX
should be used in sync with uintX_t. There is only few cases where it's
not the case like the domain ID.

In this case, it's a bitfield and therefore not uintX_t. So there is no
point to use PRIdX. I would prefer to see %d here.
Post by v***@gmail.com
+ v, dabt.reg, gits_reg);
+ return 0;
+ }
+
+ dprintk(XENLOG_G_ERR,
+ "%pv: vITS: bad read width %d r%"PRId32" offset 0x%#08"PRIx32"\n",
Ditto.
Post by v***@gmail.com
+ v, dabt.size, dabt.reg, gits_reg);
+ domain_crash_synchronous();
+ return 0;
+
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ *r = 0;
+ return 1;
+}
+
+/*
+ * GITS_BASER.Type[58:56], GITS_BASER.Entry_size[55:48]
+ * and GITS_BASER.Shareability[11:10] are read-only,
+ * Here we support only flat table. So GITS_BASER.Indirect[62]
I would replace by: "Only flat table is supported ...."
Post by v***@gmail.com
+ * is RAZ/WI.
+ * Mask those fields while emulating GITS_BASER reg.
+ * TODO: Shareability is set to 0x0 (Reserved) which is fixed.
+ * Implementing fixed value for Shareability is deprecated.
This is not a TODO but a restriction here. A TODO would explain what we
have to do. I.e

TODO: Support shareability as fixed value is deprecated.
Post by v***@gmail.com
+ */
+#define GITS_BASER_MASK (~((0x7UL << GITS_BASER_TYPE_SHIFT) | \
+ (0x1UL << GITS_BASER_INDIRECT_SHIFT) | \
+ (0xffUL << GITS_BASER_ENTRY_SIZE_SHIFT) | \
+ (0x3UL << GITS_BASER_SHAREABILITY_SHIFT)))
+
+static int vgic_v3_gits_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+ struct hsr_dabt dabt = info->dabt;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ register_t *r = select_user_reg(regs, dabt.reg);
+ int ret;
+ uint32_t gits_reg, sz, psz;
+ uint64_t val;
+
+ gits_reg = info->gpa - vits->gits_base;
+
+ DPRINTK("%pv: vITS: GITS_MMIO_WRITE offset 0x%"PRIx32"\n", v, gits_reg);
+ switch ( gits_reg )
+ {
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ vits_spin_lock(vits);
+ vgic_reg32_write(&vits->ctrl, (*r & GITS_CTLR_ENABLE), info);
The Quiescent bit should be set here rather than in the read part.
Post by v***@gmail.com
+ vits_spin_unlock(vits);
+ return 1;
+ /* RO -- write ignored */
+ goto write_ignore;
+ /* RO -- write ignored */
+ goto write_ignore;
goto write_ignore_64;
Post by v***@gmail.com
+ /* Implementation defined -- write ignored */
+ goto write_ignore;
+ /* XXX: support 32-bit access */
What is missing to support 32-bit access? The helpers I've introduced
should done the job for you...
Post by v***@gmail.com
+ if ( dabt.size != DABT_DOUBLE_WORD )
+ goto bad_width;
+ vits_spin_lock(vits);
+ if ( vits->ctrl & GITS_CTLR_ENABLE )
+ {
+ /* RO -- write ignored */
+ vits_spin_unlock(vits);
+ goto write_ignore;
+ }
+ vgic_reg64_write(&vits->cmd_base, *r, info);
+ val = SZ_4K * ((*r & GITS_BASER_PAGES_MASK_VAL) + 1);
Please use vits->cmd_base rather than *r. So it will make free to
support 32bit.
Post by v***@gmail.com
+ vgic_reg64_write(&vits->cmd_qsize, val, info);
Why do you use vgic_reg64_write???? cmd_qsize is not at all a register
but not a field.

Also, according to the spec (see 8.19.2 IHI 0069A), this should be done
only when GITS_BASER_VALID is set.
Post by v***@gmail.com
+ if ( vits->cmd_base & GITS_BASER_VALID )
+ atomic_set(&vits->cmd_read, 0);
+ vits_spin_unlock(vits);
+ return 1;
+ if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+ vits_spin_lock(vits);
+ /* Only BITS[19:0] are writable */
s/BITS/Bits/
Post by v***@gmail.com
+ vgic_reg64_write(&vits->cmd_write, (*r & 0xfffe0), info);
Either your comment or the implementation is wrong. Your comment is
saying that only bits[19:0] is writable but you mask the first 5 bits.

After reading the spec (see 8.19.5 IHI 0069A), I would say that your
comment is wrong. So please fix it.
Post by v***@gmail.com
+ ret = 1;
+ /* CWRITER should be within the range */
The comment is misplaced.
Post by v***@gmail.com
+ if ( (vits->ctrl & GITS_CTLR_ENABLE) &&
+ (vits->cmd_write < (vits->cmd_qsize & 0xfffe0)) )
The mask is not necessary. As the size of the queue should always point
to the last offset.
Post by v***@gmail.com
+ ret = vits_process_cmd(v, vits);
+ vits_spin_unlock(vits);
+ return ret;
+ /* BITS[63:20] are RES0 */
Nit: s/BITS/Bits/
Post by v***@gmail.com
+ goto write_ignore_32;
+ /* RO -- write ignored */
+ goto write_ignore;
goto write_ignore_64;
Post by v***@gmail.com
+ /* Reserved -- write ignored */
+ goto write_ignore;
+ /* Support only 64-bit access */
What's the problem to support 32-bit access?
Post by v***@gmail.com
+ if ( dabt.size != DABT_DOUBLE_WORD )
+ goto bad_width;
+ vits_spin_lock(vits);
+ /* RO -- write ignored if GITS_CTLR.Enable = 1 */
Wrong indentation.
Post by v***@gmail.com
+ if ( vits->ctrl & GITS_CTLR_ENABLE )
+ {
+ vits_spin_unlock(vits);
+ goto write_ignore_64;
No need to re-check the size here. You can directly use write_ignore.
Post by v***@gmail.com
+ }
+ val = vits->baser0 | (*r & GITS_BASER_MASK);
+ vgic_reg64_write(&vits->baser0, val, info);
+ val = vits->baser0 & GITS_BASER_PA_MASK;
+ vgic_reg64_write(&vits->dt_ipa, val, info);
Again, vgic_regN_* must only be used for actual register not for access
any field in the vits structure...
Post by v***@gmail.com
+ psz = (vits->baser0 >> GITS_BASER_PAGE_SIZE_SHIFT) &
+ GITS_BASER_PAGE_SIZE_MASK_VAL;
+ if ( psz == GITS_BASER_PAGE_SIZE_4K_VAL )
+ sz = 4;
+ else if ( psz == GITS_BASER_PAGE_SIZE_16K_VAL )
+ sz = 16;
+ else
+ /* 0x11 and 0x10 are treated as 64K size */
+ sz = 64;
+
+ val = (vits->baser0 & GITS_BASER_PAGES_MASK_VAL)
+ * sz * SZ_1K;
+ vgic_reg64_write(&vits->dt_size, val, info);
Ditto
Post by v***@gmail.com
+ vits_spin_unlock(vits);
+ return 1;
+ if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+ goto write_ignore;
+ /* R0 -- write ignored */
+ goto write_ignore_32;
+ dprintk(XENLOG_G_ERR,
+ "%pv vITS: unhandled write r%"PRId32" offset 0x%#08"PRIx32"\n",
Same remark as before for PRId32.
Post by v***@gmail.com
+ v, dabt.reg, gits_reg);
+ return 0;
+ }
+
+ dprintk(XENLOG_G_ERR,
+ "%pv: vITS: bad write width %d r%"PRId32" offset 0x%#08"PRIx32"\n",
+ v, dabt.size, dabt.reg, gits_reg);
Ditto
Post by v***@gmail.com
+ domain_crash_synchronous();
+ return 0;
+
+ if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
A 64-bit register could be accessed using 32-bit and 64-bit. So you need
to use vgic_reg64_check_access here.
Post by v***@gmail.com
+ return 1;
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ return 1;
+ return 1;
+}
[...]
Post by v***@gmail.com
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index a3d21f7..db1530e 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
[...]
Post by v***@gmail.com
/*
* ITS commands
@@ -124,6 +132,8 @@ struct its_collection {
struct vgic_its
{
spinlock_t lock;
+ /* Emulation of BASER0 */
Please add a word to explain what is the usage of GITS_BASER0.
Post by v***@gmail.com
+ paddr_t baser0;
paddr_t should only be used for actual physical address. This is not the
case of baser0 as it's a 64-bit register.
Please use uint64_t here.
Post by v***@gmail.com
/* Command queue base */
paddr_t cmd_base;
/* Command queue write pointer */
@@ -132,6 +142,12 @@ struct vgic_its
atomic_t cmd_read;
/* Command queue size */
unsigned long cmd_qsize;
+ /* ITS mmio physical base */
+ paddr_t gits_base;
+ /* ITS mmio physical size */
+ unsigned long gits_size;
+ /* GICR ctrl register */
+ uint32_t ctrl;
Please put all the emulation register field in the same place. I.e put
baser0 and ctlr together.
Post by v***@gmail.com
/* vITT device table ipa */
paddr_t dt_ipa;
/* vITT device table size */
Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:41 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Emulate LPI related changes to GICR registers

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Moved LPI handling code to vgic-v3.c
- parse LPI property table on GICR_PROPBASER update
- use vgic_is_lpi_supported()
v5: - Handled all sizes access to LPI configuration table
- Rename vits_unmap_lpi_prop as vits_map_lpi_prop
v4: - Added LPI configuration table emulation
- Rename function inline with vits
- Copied guest lpi configuration table to xen
---
xen/arch/arm/vgic-v3-its.c | 4 +
xen/arch/arm/vgic-v3.c | 354 ++++++++++++++++++++++++++++++++++++-
xen/include/asm-arm/domain.h | 3 +
xen/include/asm-arm/gic-its.h | 9 +
xen/include/asm-arm/gic_v3_defs.h | 4 +
5 files changed, 366 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index c384ecf..7c0375a 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -28,6 +28,7 @@
#include <asm/io.h>
#include <asm/gic_v3_defs.h>
#include <asm/gic.h>
+#include <asm/gic-its.h>
#include <asm/vgic.h>
#include <asm/gic-its.h>
#include <asm/atomic.h>
@@ -908,6 +909,7 @@ int vits_domain_init(struct domain *d)
vits = d->arch.vgic.vits;

spin_lock_init(&vits->lock);
+ spin_lock_init(&vits->prop_lock);

vits->collections = xzalloc_array(struct its_collection,
vits_get_max_collections(d));
@@ -933,6 +935,8 @@ int vits_domain_init(struct domain *d)

void vits_domain_free(struct domain *d)
{
+ free_xenheap_pages(d->arch.vgic.vits->prop_page,
+ get_order_from_bytes(d->arch.vgic.vits->prop_size));
xfree(d->arch.vgic.vits->collections);
xfree(d->arch.vgic.vits);
}
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 4caac5e..dd7dc32 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -29,6 +29,8 @@
#include <asm/current.h>
#include <asm/mmio.h>
#include <asm/gic_v3_defs.h>
+#include <asm/gic.h>
+#include <asm/gic-its.h>
#include <asm/vgic.h>

/* GICD_PIDRn register values for ARM implementations */
@@ -105,18 +107,287 @@ static struct vcpu *vgic_v3_get_target_vcpu(struct vcpu *v, unsigned int irq)
return v_target;
}

+static void vits_disable_lpi(struct vcpu *v, uint32_t vlpi)
+{
+ struct pending_irq *p;
+ struct vcpu *v_target = v->domain->vcpu[0];
+
+ p = irq_to_pending(v_target, vlpi);
+ if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) )
+ {
+ clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+ gic_remove_from_queues(v_target, vlpi);
+ }
+}
+
+static void vits_enable_lpi(struct vcpu *v, uint32_t vlpi, uint8_t priority)
+{
+ struct pending_irq *p;
+ unsigned long flags;
+ struct vcpu *v_target = v->domain->vcpu[0];
+
+ /*
+ * We don't have vlpi to plpi mapping and hence we cannot
+ * have target on which corresponding vlpi is enabled.
+ * So for now we are always injecting vlpi on vcpu0.
+ * (See vgic_vcpu_inject_lpi() function) and so we get pending_irq
+ * structure on vcpu0.
+ * TODO: Get correct target vcpu
+ */
+ p = irq_to_pending(v_target, vlpi);
+
+ set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+
+ spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
+
+ if ( !list_empty(&p->inflight) &&
+ !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
+ gic_raise_guest_irq(v_target, vlpi, p->priority);
+
+ spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
+}
+
+static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+ uint32_t offset;
+ void *addr;
+ uint64_t val;
+ unsigned long flags;
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+ struct hsr_dabt dabt = info->dabt;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ register_t *r = select_user_reg(regs, dabt.reg);
+
+ offset = info->gpa - (vits->propbase & GICR_PROPBASER_PA_MASK);
+ if ( offset > vits->prop_size )
+ {
+ dprintk(XENLOG_G_ERR, "%pv: vITS: LPI property table out of range\n",
+ current);
+ return 1;
+ }
+
+ /* Neglect if not LPI. */
+ if ( offset < FIRST_GIC_LPI )
+ {
+ *r = 0;
+ return 1;
+ }
+
+ addr = (void *)((u8*)vits->prop_page + offset);
+ spin_lock_irqsave(&vits->prop_lock, flags);
+ switch (dabt.size)
+ {
+ case DABT_DOUBLE_WORD:
+ val = *((u64*)addr);
+ *r = val;
+ break;
+ case DABT_WORD:
+ val = *((u32*)addr);
+ *r = (u32)val;
+ break;
+ case DABT_HALF_WORD:
+ val = *((u16*)addr);
+ *r = (u16)val;
+ break;
+ default:
+ val = *((u8*)addr);
+ *r = (u8)val;
+ }
+ spin_unlock_irqrestore(&vits->prop_lock, flags);
+
+ return 1;
+}
+
+static void vgic_v3_gits_update_lpis_state(struct vcpu *v, uint32_t vid,
+ uint32_t size)
+{
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+ uint32_t i;
+ uint8_t cfg, *p;
+ bool_t enable;
+
+ p = ((u8*)vits->prop_page + vid);
+
+ for ( i = 0 ; i < size; i++ )
+ {
+ cfg = *p;
+ enable = cfg & LPI_PROP_ENABLED;
+
+ if ( !enable )
+ vits_enable_lpi(v, vid, (cfg & LPI_PRIORITY_MASK));
+ else
+ vits_disable_lpi(v, vid);
+
+ p++;
+ vid++;
+ }
+}
+
+static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+ uint32_t offset;
+ uint8_t cfg, *p, *val, i, iter;
+ bool_t enable;
+ unsigned long flags;
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+ struct hsr_dabt dabt = info->dabt;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ register_t *r = select_user_reg(regs, dabt.reg);
+
+ offset = info->gpa - (vits->propbase & GICR_PROPBASER_PA_MASK);
+ if ( offset > vits->prop_size )
+ {
+ dprintk(XENLOG_G_ERR, "%pv: vITS: LPI property table out of range\n",
+ current);
+ return 1;
+ }
+
+ /* Neglect if not LPI. */
+ if ( offset < FIRST_GIC_LPI )
+ return 1;
+
+ switch (dabt.size)
+ {
+ case DABT_DOUBLE_WORD:
+ iter = 8;
+ break;
+ case DABT_WORD:
+ iter = 4;
+ break;
+ case DABT_HALF_WORD:
+ iter = 2;
+ break;
+ default:
+ iter = 1;
+ }
+ spin_lock_irqsave(&vits->prop_lock, flags);
+
+ p = ((u8*)vits->prop_page + offset);
+ val = (u8*)r;
+
+ for ( i = 0 ; i < iter; i++ )
+ {
+ cfg = *p;
+ enable = (cfg & *val) & LPI_PROP_ENABLED;
+
+ if ( !enable )
+ vits_enable_lpi(v, offset, (*val & LPI_PRIORITY_MASK));
+ else
+ vits_disable_lpi(v, offset);
+
+ /* Update virtual prop page */
+ *p = (*val & 0xff);
+ val++;
+ p++;
+ offset++;
+ }
+
+ spin_unlock_irqrestore(&vits->prop_lock, flags);
+
+ return 1;
+}
+
+static const struct mmio_handler_ops vgic_gits_lpi_mmio_handler = {
+ .read_handler = vgic_v3_gits_lpi_mmio_read,
+ .write_handler = vgic_v3_gits_lpi_mmio_write,
+};
+
+static int vits_map_lpi_prop(struct vcpu *v)
+{
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+ paddr_t gaddr, addr;
+ unsigned long mfn, flags;
+ uint32_t lpi_size, id_bits;
+ int i;
+
+ gaddr = vits->propbase & GICR_PROPBASER_PA_MASK;
+ id_bits = ((vits->propbase & GICR_PROPBASER_IDBITS_MASK) + 1);
+
+ if ( id_bits > v->domain->arch.vgic.id_bits )
+ id_bits = v->domain->arch.vgic.id_bits;
+
+ lpi_size = 1UL << id_bits;
+ if ( lpi_size < FIRST_GIC_LPI )
+ {
+ dprintk(XENLOG_G_ERR,
+ "d%"PRIu16": vITS: LPI property table does not hold LPI config\n",
+ v->domain->domain_id);
+ return 0;
+ }
+
+ vits->prop_size = lpi_size;
+ /* Allocate Virtual LPI Property table */
+ /* TODO: To re-use guest property table? */
+ vits->prop_page = alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0);
+ if ( !vits->prop_page )
+ {
+ dprintk(XENLOG_G_ERR,
+ "d%"PRIu16": vITS: Fail to allocate LPI Prop page\n",
+ v->domain->domain_id);
+ return 0;
+ }
+
+ addr = gaddr;
+
+ /*
+ * LPIs start from 8192 index in LPI property table.
+ * So subtract 8192 from lpi_size.
+ */
+ spin_lock_irqsave(&vits->prop_lock, flags);
+ for ( i = 0; i < (lpi_size - FIRST_GIC_LPI) / PAGE_SIZE; i++ )
+ {
+ vits_access_guest_table(v->domain, addr,
+ (void *)(vits->prop_page + FIRST_GIC_LPI + (i * PAGE_SIZE)),
+ PAGE_SIZE, 0);
+
+ vgic_v3_gits_update_lpis_state(v, FIRST_GIC_LPI + (i * PAGE_SIZE),
+ PAGE_SIZE);
+ addr += PAGE_SIZE;
+ }
+ spin_unlock_irqrestore(&vits->prop_lock, flags);
+
+ /*
+ * Each re-distributor shares a common LPI configuration table
+ * So one set of mmio handlers to manage configuration table is enough
+ */
+ addr = gaddr;
+ for ( i = 0; i < lpi_size / PAGE_SIZE; i++ )
+ {
+ mfn = gmfn_to_mfn(v->domain, paddr_to_pfn(addr));
+ if ( unlikely(!mfn_valid(mfn)) )
+ {
+ dprintk(XENLOG_G_ERR,
+ "vITS: Invalid propbaser address for domain %"PRIu16"\n",
+ v->domain->domain_id);
+ return 0;
+ }
+ guest_physmap_remove_page(v->domain, paddr_to_pfn(addr), mfn, 0);
+ addr += PAGE_SIZE;
+ }
+
+ /* Register mmio handlers for this region */
+ register_mmio_handler(v->domain, &vgic_gits_lpi_mmio_handler,
+ gaddr, lpi_size);
+
+ return 1;
+}
+
static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
uint32_t gicr_reg)
{
struct hsr_dabt dabt = info->dabt;
struct cpu_user_regs *regs = guest_cpu_user_regs();
register_t *r = select_user_reg(regs, dabt.reg);
+ struct vgic_its *vits;

switch ( gicr_reg )
{
case GICR_CTLR:
- /* We have not implemented LPI's, read zero */
- goto read_as_zero_32;
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ vgic_lock(v);
+ *r = vgic_reg32_read(v->domain->arch.vgic.gicr_ctlr, info);
+ vgic_unlock(v);
+ return 1;
case GICR_IIDR:
if ( dabt.size != DABT_WORD ) goto bad_width;
*r = vgic_reg32_read(GICV3_GICR_IIDR_VAL, info);
@@ -137,6 +408,12 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST )
typer |= GICR_TYPER_LAST;

+ /* Set Physical LPIs support */
+ if ( vgic_is_lpi_supported(v->domain) )
+ typer |= GICR_TYPER_PLPIS;
+ /* GITS_TYPER.PTA is 0. Provide vcpu number as target address */
+ typer |= (v->vcpu_id << GICR_TYPER_PROCESSOR_SHIFT);
+
if ( dabt.size == DABT_DOUBLE_WORD )
*r = vgic_reg64_read(typer, info);
else
@@ -157,10 +434,29 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
/* WO. Read as zero */
goto read_as_zero_64;
case GICR_PROPBASER:
- /* LPI's not implemented */
+ if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+ if ( vgic_is_lpi_supported(v->domain) )
+ {
+ vits = v->domain->arch.vgic.vits;
+ vgic_lock(v);
+ *r = vgic_reg64_read(vits->propbase, info);
+ vgic_unlock(v);
+ return 1;
+ }
goto read_as_zero_64;
case GICR_PENDBASER:
- /* LPI's not implemented */
+ if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+ if ( vgic_is_lpi_supported(v->domain) )
+ {
+ uint64_t val;
+
+ vgic_lock(v);
+ val = vgic_reg64_read(v->arch.vgic.pendbase, info);
+ /* PTZ field is WO */
+ *r = val & ~GICR_PENDBASER_PTZ_MASK;
+ vgic_unlock(v);
+ return 1;
+ }
goto read_as_zero_64;
case GICR_INVLPIR:
/* WO. Read as zero */
@@ -235,7 +531,19 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
switch ( gicr_reg )
{
case GICR_CTLR:
- /* LPI's not implemented */
+ if ( dabt.size != DABT_WORD ) goto bad_width;
+ if ( vgic_is_lpi_supported(v->domain) )
+ {
+ /*
+ * Enable LPI's for ITS. Direct injection of LPI
+ * by writing to GICR_{SET,CLR}LPIR is not supported.
+ */
+ vgic_lock(v);
+ vgic_reg32_write(&v->domain->arch.vgic.gicr_ctlr,
+ (*r & GICR_CTLR_ENABLE_LPIS), info);
+ vgic_unlock(v);
+ return 1;
+ }
goto write_ignore_32;
case GICR_IIDR:
/* RO */
@@ -256,10 +564,37 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
/* LPI is not implemented */
goto write_ignore_64;
case GICR_PROPBASER:
- /* LPI is not implemented */
+ if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+ if ( vgic_is_lpi_supported(v->domain) )
+ {
+ vgic_lock(v);
+ /* LPI configuration tables are shared across cpus. Should be same */
+ /*
+ * Allow updating on propbase only once with below check.
+ * TODO: Manage change in property table.
+ */
+ if ( v->domain->arch.vgic.vits->propbase != 0 )
+ {
+ printk(XENLOG_G_WARNING
+ "%pv: vGICR: Updating LPI propbase is not allowed\n", v);
+ vgic_unlock(v);
+ return 1;
+ }
+ vgic_reg64_write(&v->domain->arch.vgic.vits->propbase, *r, info);
+ vgic_unlock(v);
+ return vits_map_lpi_prop(v);
+ }
goto write_ignore_64;
case GICR_PENDBASER:
- /* LPI is not implemented */
+ if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+ if ( vgic_is_lpi_supported(v->domain) )
+ {
+ /* Just hold pendbaser value for guest read */
+ vgic_lock(v);
+ vgic_reg64_write(&v->arch.vgic.pendbase, *r, info);
+ vgic_unlock(v);
+ return 1;
+ }
goto write_ignore_64;
case GICR_INVLPIR:
/* LPI is not implemented */
@@ -740,10 +1075,13 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
typer = ((ncpus - 1) << GICD_TYPE_CPUS_SHIFT |
DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32));

+ irq_bits = v->domain->arch.vgic.id_bits;
typer |= (irq_bits - 1) << GICD_TYPE_ID_BITS_SHIFT;

- *r = vgic_reg32_read(typer, info);
+ if ( vgic_is_lpi_supported(v->domain) )
+ typer |= GICD_TYPE_LPIS;

+ *r = vgic_reg32_read(typer, info);
return 1;
}
case GICD_STATUSR:
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 269e4bb..b48a1d9 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -109,6 +109,7 @@ struct arch_domain
#ifdef HAS_GICV3
/* Virtual ITS */
struct vgic_its *vits;
+ uint32_t gicr_ctlr;
/* GIC V3 addressing */
/* List of contiguous occupied by the redistributors */
struct vgic_rdist_region {
@@ -251,6 +252,8 @@ struct arch_vcpu

/* GICv3: redistributor base and flags for this vCPU */
paddr_t rdist_base;
+ /* GICv3-ITS: LPI pending table for this vCPU */
+ paddr_t pendbase;
#define VGIC_V3_RDIST_LAST (1 << 0) /* last vCPU of the rdist */
uint8_t flags;
} vgic;
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index db1530e..11f1cd9 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -115,6 +115,7 @@

#define LPI_PROP_ENABLED (1 << 0)
#define LPI_PROP_GROUP1 (1 << 1)
+#define LPI_PRIORITY_MASK (0xfc)

/*
* Collection structure - just an ID, and a redistributor address to
@@ -148,6 +149,14 @@ struct vgic_its
unsigned long gits_size;
/* GICR ctrl register */
uint32_t ctrl;
+ /* LPI propbase */
+ paddr_t propbase;
+ /* Virtual LPI property table */
+ void *prop_page;
+ /* Virtual LPI property size */
+ uint32_t prop_size;
+ /* spinlock to protect lpi property table */
+ spinlock_t prop_lock;
/* vITT device table ipa */
paddr_t dt_ipa;
/* vITT device table size */
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index d950a1f..44f59a3 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -48,6 +48,7 @@
/* Additional bits in GICD_TYPER defined by GICv3 */
#define GICD_TYPE_ID_BITS_SHIFT 19
#define GICD_TYPE_ID_BITS_MASK 0x1f
+#define GICD_TYPE_LPIS (0x1UL << 17)

#define GICD_TYPER_LPIS_SUPPORTED (1U << 17)
#define GICD_CTLR_RWP (1UL << 31)
@@ -125,14 +126,17 @@
#define GICR_PROPBASER_WaWb (5U << 7)
#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
#define GICR_PROPBASER_IDBITS_MASK (0x1f)
+#define GICR_PROPBASER_PA_MASK (0xfffffffff000UL)
#define GICR_TYPER_PLPIS (1U << 0)
#define GICR_TYPER_VLPIS (1U << 1)
#define GICR_TYPER_LAST (1U << 4)
+#define GICR_TYPER_PROCESSOR_SHIFT (8)

#define GICR_PENDBASER_InnerShareable (1U << 10)
#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10)
#define GICR_PENDBASER_nC (1U << 7)
#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
+#define GICR_PENDBASER_PTZ_MASK (1UL << 62)

#define DEFAULT_PMR_VALUE 0xff
--
1.7.9.5
Julien Grall
2015-09-07 14:20:24 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
+static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
[...]
Post by v***@gmail.com
+ /* Neglect if not LPI. */
+ if ( offset < FIRST_GIC_LPI )
+ {
+ *r = 0;
+ return 1;
+ }
[...]
Post by v***@gmail.com
+static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
[...]
Post by v***@gmail.com
+ /* Neglect if not LPI. */
+ if ( offset < FIRST_GIC_LPI )
+ return 1;
Based on the spec, those 2 checks are wrong and make impossible to use
LPIs. Please test this patch series before sending it on the ML.

Regards,
--
Julien Grall
Vijay Kilari
2015-09-07 15:26:05 UTC
Permalink
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
+static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
[...]
Post by v***@gmail.com
+ /* Neglect if not LPI. */
+ if ( offset < FIRST_GIC_LPI )
+ {
+ *r = 0;
+ return 1;
+ }
[...]
Post by v***@gmail.com
+static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
[...]
Post by v***@gmail.com
+ /* Neglect if not LPI. */
+ if ( offset < FIRST_GIC_LPI )
+ return 1;
Based on the spec, those 2 checks are wrong and make impossible to use
LPIs. Please test this patch series before sending it on the ML.
Why do you think so?.
Ian Campbell
2015-09-09 13:55:48 UTC
Permalink
Post by Vijay Kilari
Post by Julien Grall
Hi Vijay,
Post by v***@gmail.com
+static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
[...]
Post by v***@gmail.com
+ /* Neglect if not LPI. */
+ if ( offset < FIRST_GIC_LPI )
+ {
+ *r = 0;
+ return 1;
+ }
[...]
Post by v***@gmail.com
+static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
[...]
Post by v***@gmail.com
+ /* Neglect if not LPI. */
+ if ( offset < FIRST_GIC_LPI )
+ return 1;
Based on the spec, those 2 checks are wrong and make impossible to use
LPIs. Please test this patch series before sending it on the ML.
Why do you think so?.
Consider which LPI is the subject of the word at the address pointed to by
GICR_PROPBASER. I think it is LPI==0 (== IRQ 8192), whereas this code
suggests that you think the entry for LPI==0 is at offset 8192 in the prop
table, which I don't think is correct.

Ian.
Julien Grall
2015-09-09 16:11:17 UTC
Permalink
Post by Ian Campbell
Post by Vijay Kilari
Post by Julien Grall
Based on the spec, those 2 checks are wrong and make impossible to use
LPIs. Please test this patch series before sending it on the ML.
Why do you think so?.
Consider which LPI is the subject of the word at the address pointed to by
GICR_PROPBASER. I think it is LPI==0 (== IRQ 8192), whereas this code
suggests that you think the entry for LPI==0 is at offset 8192 in the prop
table, which I don't think is correct.
For the spec section: 6.1.2 in ARM IHI 0069A.

Regards,
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:45 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Call domain specific ITS initialization and introduce
callback in vgic for domain free

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Moved vits_domain_free() out of this patch
---
xen/arch/arm/vgic-v3.c | 12 +++++++++++-
xen/arch/arm/vgic.c | 3 +++
xen/include/asm-arm/vgic.h | 2 ++
3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index f69f323..03f2876 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1623,15 +1623,25 @@ static int vgic_v3_domain_init(struct domain *d)
d->arch.vgic.ctlr = VGICD_CTLR_DEFAULT;

if ( is_hardware_domain(d) && gic_lpi_supported() )
- vgic_v3_info.its_enabled = 1;
+ {
+ if ( !vits_domain_init(d) )
+ vgic_v3_info.its_enabled = 1;
+ }

return 0;
}

+void vgic_v3_domain_free(struct domain *d)
+{
+ if ( is_hardware_domain(d) && gic_lpi_supported() )
+ vits_domain_free(d);
+}
+
static const struct vgic_ops v3_ops = {
.info = &vgic_v3_info,
.vcpu_init = vgic_v3_vcpu_init,
.domain_init = vgic_v3_domain_init,
+ .domain_free = vgic_v3_domain_free,
.get_irq_priority = vgic_v3_get_irq_priority,
.get_target_vcpu = vgic_v3_get_target_vcpu,
.emulate_sysreg = vgic_v3_emulate_sysreg,
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index e7341f5..311c940 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -183,6 +183,9 @@ void domain_vgic_free(struct domain *d)
xfree(d->arch.vgic.shared_irqs);
xfree(d->arch.vgic.pending_irqs);
xfree(d->arch.vgic.allocated_irqs);
+
+ if ( d->arch.vgic.handler->domain_free )
+ d->arch.vgic.handler->domain_free(d);
}

int vcpu_vgic_init(struct vcpu *v)
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 71ce6c3..379e914 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -121,6 +121,8 @@ struct vgic_ops {
int (*vcpu_init)(struct vcpu *v);
/* Domain specific initialization of vGIC */
int (*domain_init)(struct domain *d);
+ /* Free domain specific resources */
+ void (*domain_free)(struct domain *d);
/* Get priority for a given irq stored in vgic structure */
int (*get_irq_priority)(struct vcpu *v, unsigned int irq);
/* Get the target vcpu for a given virq. The rank lock is already taken
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:47 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Parse host dt and generate ITS node for Dom0.
ITS node resides inside GIC node so when GIC node
is encountered look for ITS node.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Introduced get_its_phandle in gic_hw_ops
- Removed make_hwdom_its_dt_node callback in gic_hw_ops
- Renamed gic_get_msi_handle() as gic_update_msi_phandle()
- Renamed its_get_phandle to its_update_phandle()
- ITS node generation is wrapped inside GICv3
- Update msi-parent phandle only if msi-parent is ITS
and find its phandle on demand
v5: - Moved ITS dt node generation to ITS driver
v4: - Generate only one ITS node for Dom0
- Replace msi-parent references to single its phandle
---
xen/arch/arm/domain_build.c | 11 ++++
xen/arch/arm/gic-v3-its.c | 120 +++++++++++++++++++++++++++++++++++++++++
xen/arch/arm/gic-v3.c | 14 ++++-
xen/arch/arm/gic.c | 6 +++
xen/include/asm-arm/gic-its.h | 2 +
xen/include/asm-arm/gic.h | 3 ++
6 files changed, 155 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index a059de6..19cd40d 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -469,6 +469,17 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo,
continue;
}

+ /*
+ * Replace all msi-parent phandle references to single ITS node
+ * generated for Dom0
+ */
+ if ( dt_property_name_is_equal(prop, "msi-parent") )
+ {
+ DPRINT(" Set msi-parent with ITS phandle (if ITS available)\n");
+ gic_update_msi_phandle(kinfo->fdt, prop);
+ continue;
+ }
+
res = fdt_property(kinfo->fdt, prop->name, prop_data, prop_len);

xfree(new_data);
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index e825d1e..9787f81 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -27,6 +27,8 @@
#include <xen/sched.h>
#include <xen/errno.h>
#include <xen/delay.h>
+#include <xen/device_tree.h>
+#include <xen/libfdt/libfdt.h>
#include <xen/list.h>
#include <xen/sizes.h>
#include <xen/vmap.h>
@@ -1244,6 +1246,124 @@ static void its_cpu_init_collection(void)
spin_unlock(&its_lock);
}

+int its_make_dt_node(const struct domain *d, void *fdt)
+{
+ struct its_node *its;
+ const struct dt_device_node *node;
+ const void *compatible = NULL;
+ u32 len;
+ __be32 *new_cells, *tmp;
+ int res = 0;
+
+ /* Will pass only first ITS node info */
+ its = list_first_entry(&its_nodes, struct its_node, entry);
+ if ( !its )
+ {
+ dprintk(XENLOG_ERR, "ITS node not found\n");
+ return -FDT_ERR_XEN(ENOENT);
+ }
+
+ node = its->dt_node;
+
+ compatible = dt_get_property(node, "compatible", &len);
+ if ( !compatible )
+ {
+ dprintk(XENLOG_ERR, "Can't find compatible property for the its node\n");
+ return -FDT_ERR_XEN(ENOENT);
+ }
+
+ res = fdt_begin_node(fdt, "gic-its");
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "compatible", compatible, len);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "msi-controller", NULL, 0);
+ if ( res )
+ return res;
+
+ len = dt_cells_to_size(dt_n_addr_cells(node) + dt_n_size_cells(node));
+
+ new_cells = xzalloc_bytes(len);
+ if ( new_cells == NULL )
+ return -FDT_ERR_XEN(ENOMEM);
+ tmp = new_cells;
+
+ dt_set_range(&tmp, node, its->phys_base, its->phys_size);
+
+ res = fdt_property(fdt, "reg", new_cells, len);
+ xfree(new_cells);
+ if ( res )
+ return res;
+
+ if ( node->phandle )
+ {
+ res = fdt_property_cell(fdt, "phandle", node->phandle);
+ if ( res )
+ return res;
+ }
+
+ res = fdt_end_node(fdt);
+
+ return res;
+}
+
+static int its_find_compatible_phandle(fdt32_t msi_parent_phandle)
+{
+ struct its_node *its;
+ const struct dt_device_node *node;
+ fdt32_t phandle;
+
+ list_for_each_entry(its, &its_nodes, entry)
+ {
+ node = its->dt_node;
+
+ if ( node->phandle )
+ {
+ phandle = cpu_to_fdt32(node->phandle);
+ if ( phandle == msi_parent_phandle )
+ return 0;
+ }
+ }
+
+ return -FDT_ERR_XEN(ENOENT);
+}
+
+int its_update_phandle(void *fdt, const struct dt_property *prop)
+{
+ struct its_node *its;
+ const struct dt_device_node *node;
+ fdt32_t phandle, msi_parent_phandle;
+
+ memcpy(&msi_parent_phandle, prop->value, sizeof(msi_parent_phandle));
+
+ /* chech if msi-parent phandle is ITS */
+ if ( its_find_compatible_phandle(msi_parent_phandle) )
+ return -FDT_ERR_XEN(ENOENT);
+
+ /* Only first ITS node phandle is considered */
+ its = list_first_entry(&its_nodes, struct its_node, entry);
+ if ( !its )
+ {
+ dprintk(XENLOG_ERR, "ITS node not found\n");
+ return -FDT_ERR_XEN(ENOENT);
+ }
+
+ node = its->dt_node;
+
+ if ( node->phandle )
+ {
+ phandle = cpu_to_fdt32(node->phandle);
+ fdt_property(fdt, prop->name, (void *)&phandle, sizeof(phandle));
+
+ return 0;
+ }
+
+ return -FDT_ERR_XEN(ENOENT);
+}
+
static int its_force_quiescent(void __iomem *base)
{
u32 count = 1000000; /* 1s */
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 9260c6d..4389c6a 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1080,6 +1080,11 @@ static void gicv3_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask)
spin_unlock(&gicv3.lock);
}

+static int gicv3_update_its_phandle(void *fdt, const struct dt_property *prop)
+{
+ return its_update_phandle(fdt, prop);
+}
+
static int gicv3_make_hwdom_dt_node(const struct domain *d,
const struct dt_device_node *node,
void *fdt)
@@ -1101,6 +1106,10 @@ static int gicv3_make_hwdom_dt_node(const struct domain *d,
if ( res )
return res;

+ res = fdt_property(fdt, "ranges", NULL, 0);
+ if ( res )
+ return res;
+
res = fdt_property_cell(fdt, "redistributor-stride",
d->arch.vgic.rdist_stride);
if ( res )
@@ -1132,8 +1141,10 @@ static int gicv3_make_hwdom_dt_node(const struct domain *d,

res = fdt_property(fdt, "reg", new_cells, len);
xfree(new_cells);
+ if ( res )
+ return res;

- return res;
+ return its_make_dt_node(d, fdt);
}

static const hw_irq_controller gicv3_host_irq_type = {
@@ -1366,6 +1377,7 @@ static const struct gic_hw_operations gicv3_ops = {
.read_vmcr_priority = gicv3_read_vmcr_priority,
.read_apr = gicv3_read_apr,
.secondary_init = gicv3_secondary_cpu_init,
+ .update_its_phandle = gicv3_update_its_phandle,
.make_hwdom_dt_node = gicv3_make_hwdom_dt_node,
};

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index d91623a..2b5842e 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -758,6 +758,12 @@ void __cpuinit init_maintenance_interrupt(void)
"irq-maintenance", NULL);
}

+void gic_update_msi_phandle(void *fdt, const struct dt_property *prop)
+{
+ if ( gic_lpi_supported() )
+ gic_hw_ops->update_its_phandle(fdt, prop);
+}
+
int gic_make_hwdom_dt_node(const struct domain *d,
const struct dt_device_node *node,
void *fdt)
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 75a9c95..c620b17 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -356,6 +356,7 @@ struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
bool_t is_valid_collection(struct domain *d, uint32_t col);
unsigned int its_get_nr_event_ids(void);
+int its_make_dt_node(const struct domain *d, void *fdt);
int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
@@ -363,6 +364,7 @@ int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
void its_set_lpi_properties(struct irq_desc *desc,
const cpumask_t *cpu_mask,
unsigned int priority);
+int its_update_phandle(void *fdt, const struct dt_property *prop);
int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
uint32_t size, bool_t set);
int vits_domain_init(struct domain *d);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index abb8616..f620aff 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -151,6 +151,7 @@

#ifndef __ASSEMBLY__
#include <xen/device_tree.h>
+#include <xen/libfdt/libfdt.h>
#include <xen/irq.h>
#include <asm-arm/vgic.h>

@@ -369,6 +370,7 @@ struct gic_hw_operations {
int (*secondary_init)(void);
int (*make_hwdom_dt_node)(const struct domain *d,
const struct dt_device_node *node, void *fdt);
+ int (*update_its_phandle)(void *fdt, const struct dt_property *prop);
};

void register_gic_ops(const struct gic_hw_operations *ops);
@@ -376,6 +378,7 @@ int gic_make_hwdom_dt_node(const struct domain *d,
const struct dt_device_node *node,
void *fdt);
bool_t gic_is_lpi(unsigned int irq);
+void gic_update_msi_phandle(void *fdt, const struct dt_property *prop);

#endif /* __ASSEMBLY__ */
#endif
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:48 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

ITS initialization required for all PCI devices in
ThunderX platform are done by calling from specific
mapping function.

This patch can be reverted once XEN PCI passthrough
framework for arm64 is in available.

For now all the PCI devices are assigned to Dom0

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
Acked-by: Ian Campbell <***@citrix.com>
---
xen/arch/arm/platforms/Makefile | 1 +
xen/arch/arm/platforms/thunderx.c | 151 +++++++++++++++++++++++++++++++++++++
2 files changed, 152 insertions(+)

diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile
index e173fec..d9f98f9 100644
--- a/xen/arch/arm/platforms/Makefile
+++ b/xen/arch/arm/platforms/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_ARM_32) += sunxi.o
obj-$(CONFIG_ARM_32) += rcar2.o
obj-$(CONFIG_ARM_64) += seattle.o
obj-$(CONFIG_ARM_64) += xgene-storm.o
+obj-$(CONFIG_ARM_64) += thunderx.o
diff --git a/xen/arch/arm/platforms/thunderx.c b/xen/arch/arm/platforms/thunderx.c
new file mode 100644
index 0000000..7c335ba
--- /dev/null
+++ b/xen/arch/arm/platforms/thunderx.c
@@ -0,0 +1,151 @@
+/*
+ * xen/arch/arm/platforms/thunderx.c
+ *
+ * Cavium Thunder specific settings
+ *
+ * Vijaya Kumar K <***@caviumnetworks.com>
+ * Copyright (c) 2015 Cavium Inc.
+ *
+ * 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.
+ */
+
+#include <xen/config.h>
+#include <asm/platform.h>
+#include <asm/gic-its.h>
+
+struct pci_dev_list
+{
+ uint32_t seg;
+ uint32_t bus;
+ uint32_t dev;
+ uint32_t func;
+};
+
+#define NUM_DEVIDS 54
+
+static struct pci_dev_list bdf[NUM_DEVIDS] =
+{
+ {0, 0, 2, 0}, /* 1 */
+ {0, 0, 6, 0},
+ {0, 0, 7, 0},
+ {0, 0, 10, 0},
+ {0, 0, 11, 0},
+ {0, 1, 0, 0},
+ {0, 1, 0, 1},
+ {0, 1, 0, 5},
+ {0, 1, 1, 4},
+ {0, 1, 9, 0}, /* 10 */
+ {0, 1, 9, 1},
+ {0, 1, 9, 2},
+ {0, 1, 9, 3},
+ {0, 1, 9, 4},
+ {0, 1, 9, 5},
+ {0, 1, 10, 0},
+ {0, 1, 10, 1},
+ {0, 1, 10, 2},
+ {0, 1, 10, 3},
+ {0, 1, 14, 0}, /* 20 */
+ {0, 1, 14, 2},
+ {0, 1, 14, 4},
+ {0, 1, 16, 0},
+ {0, 1, 16, 1},
+ {0, 2, 0, 0},
+ {0, 3, 0, 0},
+ {0, 4, 0, 0},
+ {1, 0, 8, 0},
+ {1, 0, 9, 0},
+ {1, 0, 10, 0}, /* 30 */
+ {1, 0, 11, 0},
+ {2, 0, 1, 0},
+ {2, 0, 3, 0},
+ {2, 1, 0, 0},
+ {2, 1, 0, 1},
+ {2, 1, 0, 2},
+ {2, 1, 0, 3},
+ {2, 1, 0, 4},
+ {2, 1, 0, 5},
+ {2, 1, 0, 6}, /* 40 */
+ {2, 1, 0, 7},
+ {2, 1, 1, 0},
+ {2, 1, 1, 1},
+ {2, 1, 1, 2},
+ {2, 1, 1, 3},
+ {2, 1, 1, 4},
+ {2, 1, 1, 5},
+ {2, 1, 1, 6},
+ {2, 1, 1, 7},
+ {2, 1, 2, 0}, /* 50 */
+ {2, 1, 2, 1},
+ {2, 1, 2, 2},
+ {2, 1, 1, 7},
+ {3, 0, 1, 0}, /* 54 */
+};
+
+#define BDF_TO_DEVID(seg, bus, dev, func) (seg << 16 | bus << 8 | dev << 3| func)
+
+/* TODO: add and assign devices using PCI framework */
+static int thunderx_specific_mapping(struct domain *d)
+{
+ struct dt_device_node *dt_its;
+ uint32_t devid, i;
+ int res;
+
+ static const struct dt_device_match its_device_ids[] __initconst =
+ {
+ DT_MATCH_GIC_ITS,
+ { /* sentinel */ },
+ };
+
+ for (dt_its = dt_find_matching_node(NULL, its_device_ids); dt_its;
+ dt_its = dt_find_matching_node(dt_its, its_device_ids))
+ {
+ break;
+ }
+
+ if ( dt_its == NULL )
+ {
+ dprintk(XENLOG_ERR, "ThunderX: ITS node not found to add device\n");
+ return 0;
+ }
+
+ for ( i = 0; i < NUM_DEVIDS; i++ )
+ {
+ devid = BDF_TO_DEVID(bdf[i].seg, bdf[i].bus,bdf[i].dev, bdf[i].func);
+ res = its_add_device(devid, 32, dt_its);
+ if ( res )
+ return res;
+ res = its_assign_device(d, devid, devid);
+ if ( res )
+ return res;
+ }
+
+ return 0;
+}
+
+static const char * const thunderx_dt_compat[] __initconst =
+{
+ "cavium,thunder-88xx",
+ NULL
+};
+
+PLATFORM_START(thunderx, "THUNDERX")
+ .compatible = thunderx_dt_compat,
+ .specific_mapping = thunderx_specific_mapping,
+PLATFORM_END
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
1.7.9.5
Ian Campbell
2015-09-09 15:22:25 UTC
Permalink
Post by v***@gmail.com
[...]
+#define NUM_DEVIDS 54
+
+static struct pci_dev_list bdf[NUM_DEVIDS] =
FYI you could make this
static struct pci_dev_list bdf[] =

and use ARRAY_SIZE(bdf) in the loops. That would save you having to
manually keep NUM_DEVIDS up to date and avoid any possibility of
miscounting.
v***@gmail.com
2015-08-31 11:06:35 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Enable compilation of virtual ITS driver.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
xen/arch/arm/Makefile | 1 +
1 file changed, 1 insertion(+)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 4708716..cd10d42 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -33,6 +33,7 @@ obj-y += shutdown.o
obj-y += traps.o
obj-y += vgic.o vgic-v2.o
obj-$(CONFIG_ARM_64) += vgic-v3.o
+obj-$(CONFIG_ARM_64) += vgic-v3-its.o
obj-y += vtimer.o
obj-y += vuart.o
obj-y += hvm.o
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:46 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

ITS translation space contains GITS_TRANSLATER register
which is written by device to raise LPI. This space needs
to mapped to every domain address space for all physical
ITS available,so that device can access GITS_TRANSLATER
register using SMMU.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
Acked-by: Ian Campbell <***@citrix.com>
---
v6: - corrected typo in commit message
- Removed check for dom0
---
xen/arch/arm/vgic-v3-its.c | 35 ++++++++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 6334ca3..328c4db 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -885,6 +885,39 @@ static const struct mmio_handler_ops vgic_gits_mmio_handler = {
.write_handler = vgic_v3_gits_mmio_write,
};

+/*
+ * Map the 64K ITS translation space in guest.
+ * This is required purely for device smmu writes.
+*/
+
+static int vits_map_translation_space(struct domain *d)
+{
+ uint64_t addr, size;
+ int ret;
+
+ ASSERT(is_domain_direct_mapped(d));
+
+ addr = d->arch.vgic.vits->gits_base + SZ_64K;
+ size = SZ_64K;
+
+ /* Using 1:1 mapping to map translation space */
+ /* TODO: Handle DomU mapping */
+ ret = map_mmio_regions(d,
+ paddr_to_pfn(addr & PAGE_MASK),
+ DIV_ROUND_UP(size, PAGE_SIZE),
+ paddr_to_pfn(addr & PAGE_MASK));
+
+ if ( ret )
+ {
+ dprintk(XENLOG_G_ERR, "vITS: Unable to map to"
+ " 0x%"PRIx64" - 0x%"PRIx64" to dom%d\n",
+ addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1,
+ d->domain_id);
+ }
+
+ return ret;
+}
+
int vits_domain_init(struct domain *d)
{
struct vgic_its *vits;
@@ -938,7 +971,7 @@ int vits_domain_init(struct domain *d)

register_mmio_handler(d, &vgic_gits_mmio_handler, vits->gits_base, SZ_64K);

- return 0;
+ return vits_map_translation_space(d);
}

void vits_domain_free(struct domain *d)
--
1.7.9.5
Julien Grall
2015-08-31 19:07:26 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 6334ca3..328c4db 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -885,6 +885,39 @@ static const struct mmio_handler_ops vgic_gits_mmio_handler = {
.write_handler = vgic_v3_gits_mmio_write,
};
+/*
+ * Map the 64K ITS translation space in guest.
+ * This is required purely for device smmu writes.
+*/
+
+static int vits_map_translation_space(struct domain *d)
+{
+ uint64_t addr, size;
+ int ret;
+
+ ASSERT(is_domain_direct_mapped(d));
+
+ addr = d->arch.vgic.vits->gits_base + SZ_64K;
+ size = SZ_64K;
+
+ /* Using 1:1 mapping to map translation space */
+ /* TODO: Handle DomU mapping */
I would have expected a summary of the discussion we had on the previous
version of this patch [1] here.

This is in order to remember what needs to be done before we effectively
implement ITS support for guest.

Regards,

[1] http://lists.xen.org/archives/html/xen-devel/2015-08/msg01704.html
--
Julien Grall
v***@gmail.com
2015-08-31 11:06:44 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Allocate and initialize irq descriptor for LPIs and
route LPIs to guest

For LPIs deactivation is not required. Hence
GICH_LR.HW is not required to set.

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Moved ITS specific code from irq.c to vgic.c and
introduced vgic_vcpu_raise_lpi()
- Renamed gicv3_set_properties to gicv3_set_irq_properties
- Always Inject LPI to vcpu0
- Changed route_lpi_to_guest definition
---
xen/arch/arm/gic-v3-its.c | 17 ++++++-
xen/arch/arm/gic-v3.c | 16 ++++--
xen/arch/arm/gic.c | 32 +++++++++++-
xen/arch/arm/irq.c | 112 ++++++++++++++++++++++++++++++++++++++---
xen/arch/arm/vgic-v3-its.c | 2 +-
xen/arch/arm/vgic-v3.c | 41 +++++++++++++--
xen/arch/arm/vgic.c | 64 +++++++++++++++++++++++
xen/include/asm-arm/gic-its.h | 3 ++
xen/include/asm-arm/gic.h | 7 ++-
xen/include/asm-arm/irq.h | 2 +
xen/include/asm-arm/vgic.h | 3 ++
11 files changed, 278 insertions(+), 21 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index d9ec044..e825d1e 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -464,6 +464,21 @@ static void its_flush_and_invalidate_prop(struct irq_desc *desc, u8 *cfg)
its_send_inv(its_dev, vid);
}

+void its_set_lpi_properties(struct irq_desc *desc,
+ const cpumask_t *cpu_mask,
+ unsigned int priority)
+{
+ unsigned long flags;
+ u8 *cfg;
+
+ spin_lock_irqsave(&its_lock, flags);
+ cfg = gic_rdists->prop_page + desc->irq - FIRST_GIC_LPI;
+ *cfg = (*cfg & 3) | (priority & LPI_PRIORITY_MASK) ;
+
+ its_flush_and_invalidate_prop(desc, cfg);
+ spin_unlock_irqrestore(&its_lock, flags);
+}
+
static void its_set_lpi_state(struct irq_desc *desc, int enable)
{
u8 *cfg;
@@ -869,7 +884,7 @@ int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid)
ASSERT(i < gic_nr_event_ids());

plpi = its_get_plpi(pdev, i);
- /* TODO: Route lpi */
+ route_lpi_to_guest(d, plpi, "LPI");
}

return 0;
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 538f9f4..9260c6d 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -471,9 +471,9 @@ static inline uint64_t gicv3_mpidr_to_affinity(int cpu)
MPIDR_AFFINITY_LEVEL(mpidr, 0));
}

-static void gicv3_set_irq_properties(struct irq_desc *desc,
- const cpumask_t *cpu_mask,
- unsigned int priority)
+static void gicv3_set_line_properties(struct irq_desc *desc,
+ const cpumask_t *cpu_mask,
+ unsigned int priority)
{
uint32_t cfg, actual, edgebit;
uint64_t affinity;
@@ -532,6 +532,16 @@ static void gicv3_set_irq_properties(struct irq_desc *desc,
spin_unlock(&gicv3.lock);
}

+static void gicv3_set_irq_properties(struct irq_desc *desc,
+ const cpumask_t *cpu_mask,
+ unsigned int priority)
+{
+ if ( gic_is_lpi(desc->irq) )
+ its_set_lpi_properties(desc, cpu_mask, priority);
+ else
+ gicv3_set_line_properties(desc, cpu_mask, priority);
+}
+
static void __init gicv3_dist_init(void)
{
uint32_t type;
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 2f23a14..d91623a 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -71,11 +71,18 @@ bool_t gic_is_lpi(unsigned int irq)
bool_t gic_is_lpi(unsigned int irq) { return 0; }
#endif

+/* Returns number of PPIs/SGIs/SPIs supported */
unsigned int gic_number_lines(void)
{
return gic_hw_ops->info->nr_lines;
}

+/* Validates PPIs/SGIs/SPIs/LPIs supported */
+bool_t gic_is_valid_irq(unsigned int irq)
+{
+ return (irq < gic_hw_ops->info->nr_lines || gic_is_lpi(irq));
+}
+
bool_t gic_lpi_supported(void)
{
return gic_hw_ops->info->lpi_supported;
@@ -143,7 +150,8 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
unsigned int priority)
{
ASSERT(priority <= 0xff); /* Only 8 bits of priority */
- ASSERT(desc->irq < gic_number_lines());/* Can't route interrupts that don't exist */
+ /* Can't route interrupts that don't exist */
+ ASSERT(gic_is_valid_irq(desc->irq));
ASSERT(test_bit(_IRQ_DISABLED, &desc->status));
ASSERT(spin_is_locked(&desc->lock));

@@ -192,6 +200,26 @@ out:
return res;
}

+int gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc,
+ unsigned int priority)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ desc->handler = get_guest_hw_irq_controller(desc->irq);
+ set_bit(_IRQ_GUEST, &desc->status);
+
+ /* Set cpumask to current processor */
+ gic_set_irq_properties(desc, cpumask_of(smp_processor_id()), priority);
+
+ /*
+ * Enable LPI by default. Each pLPI is enabled and routed
+ * when device is assigned.
+ */
+ desc->handler->enable(desc);
+
+ return 0;
+}
+
/* This function only works with SPIs for now */
int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
struct irq_desc *desc)
@@ -672,7 +700,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
/* Reading IRQ will ACK it */
irq = gic_hw_ops->read_irq();

- if ( likely(irq >= 16 && irq < 1020) )
+ if ( likely((irq >= 16 && irq < 1020) || gic_is_lpi(irq)) )
{
local_irq_enable();
do_IRQ(regs, irq, is_fiq);
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 2a37521..7ba90d1 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -214,7 +214,7 @@ int request_irq(unsigned int irq, unsigned int irqflags,
* which interrupt is which (messes up the interrupt freeing
* logic etc).
*/
- if ( irq >= nr_irqs )
+ if ( !gic_is_valid_irq(irq) )
return -EINVAL;
if ( !handler )
return -EINVAL;
@@ -272,11 +272,16 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, int is_fiq)

set_bit(_IRQ_INPROGRESS, &desc->status);

- /*
- * The irq cannot be a PPI, we only support delivery of SPIs to
- * guests.
- */
- vgic_vcpu_inject_spi(info->d, info->virq);
+#ifdef HAS_GICV3
+ if ( gic_is_lpi(irq) )
+ vgic_vcpu_raise_lpi(info->d, desc);
+ else
+#endif
+ /*
+ * The irq cannot be a PPI, we only support delivery of SPIs to
+ * guests
+ */
+ vgic_vcpu_inject_spi(info->d, info->virq);
goto out_no_end;
}

@@ -361,6 +366,9 @@ void release_irq(unsigned int irq, const void *dev_id)
/* Wait to make sure it's not being used on another CPU */
do { smp_mb(); } while ( test_bit(_IRQ_INPROGRESS, &desc->status) );

+ if ( gic_is_lpi(irq) )
+ xfree(desc->msi_desc);
+
if ( action->free_on_release )
xfree(action);
}
@@ -442,9 +450,97 @@ err:

bool_t is_assignable_irq(unsigned int irq)
{
- /* For now, we can only route SPIs to the guest */
- return ((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines()));
+ /* For now, we can only route SPI/LPIs to the guest */
+ return (((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines())) ||
+ gic_is_lpi(irq));
+}
+
+#ifdef HAS_GICV3
+/*
+ * Route an LPI to a specific guest.
+ */
+int route_lpi_to_guest(struct domain *d, unsigned int plpi, const char *devname)
+{
+ struct irqaction *action;
+ struct irq_guest *info;
+ struct irq_desc *desc;
+ unsigned long flags;
+ int retval = 0;
+
+ if ( !gic_is_lpi(plpi) )
+ {
+ printk(XENLOG_G_ERR "Only LPI can be routed \n");
+ return -EINVAL;
+ }
+
+ action = xmalloc(struct irqaction);
+ if ( !action )
+ return -ENOMEM;
+
+ info = xmalloc(struct irq_guest);
+ if ( !info )
+ {
+ xfree(action);
+ return -ENOMEM;
+ }
+ info->d = d;
+
+ action->dev_id = info;
+ action->name = devname;
+ action->free_on_release = 1;
+
+ desc = irq_to_desc(plpi);
+ spin_lock_irqsave(&desc->lock, flags);
+
+ ASSERT(desc->msi_desc != NULL);
+
+ if ( desc->arch.type == DT_IRQ_TYPE_INVALID )
+ {
+ printk(XENLOG_G_ERR "LPI %u has not been configured\n", plpi);
+ retval = -EIO;
+ goto out;
+ }
+
+ /* If the IRQ is already used by same domain, do not setup again.*/
+ if ( desc->action != NULL )
+ {
+ struct domain *ad = irq_get_domain(desc);
+
+ if ( test_bit(_IRQ_GUEST, &desc->status) && d == ad )
+ {
+ printk(XENLOG_G_ERR
+ "d%u: LPI %u is already assigned to domain %u\n",
+ d->domain_id, plpi, d->domain_id);
+ retval = -EBUSY;
+ goto out;
+ }
+ }
+
+ retval = __setup_irq(desc, 0, action);
+ if ( retval )
+ goto out;
+
+ retval = gic_route_lpi_to_guest(d, desc, GIC_PRI_IRQ);
+
+ spin_unlock_irqrestore(&desc->lock, flags);
+
+ if ( retval )
+ {
+ release_irq(desc->irq, info);
+ goto free_info;
+ }
+
+ return 0;
+
+out:
+ spin_unlock_irqrestore(&desc->lock, flags);
+ xfree(action);
+free_info:
+ xfree(info);
+
+ return retval;
}
+#endif

/*
* Route an IRQ to a specific guest.
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 1d1fd64..6334ca3 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -358,7 +358,7 @@ static int vits_process_int(struct vcpu *v, struct vgic_its *vits,
DPRINTK("%pv: vITS: INT: Device 0x%"PRIx32" id %"PRIu32"\n",
v, dev_id, event);

- /* TODO: Inject LPI */
+ vgic_vcpu_inject_lpi(v->domain, dev_id, event);

return 0;
}
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index dd7dc32..f69f323 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1439,14 +1439,45 @@ static const struct mmio_handler_ops vgic_distr_mmio_handler = {

static int vgic_v3_get_irq_priority(struct vcpu *v, unsigned int irq)
{
- int priority;
+ int priority = 0;
unsigned long flags;
- struct vgic_irq_rank *rank = vgic_rank_irq(v, irq);
+ struct vgic_irq_rank *rank;

- vgic_lock_rank(v, rank, flags);
- priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8,
+ if ( !gic_is_lpi(irq) )
+ {
+ rank = vgic_rank_irq(v, irq);
+
+ vgic_lock_rank(v, rank, flags);
+ priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8,
irq, DABT_WORD)], 0, irq & 0x3);
- vgic_unlock_rank(v, rank, flags);
+ vgic_unlock_rank(v, rank, flags);
+ }
+ else if ( vgic_is_domain_lpi(v->domain, irq) )
+ {
+ struct vgic_its *vits = v->domain->arch.vgic.vits;
+
+ /*
+ * Guest can receive LPI before availability of LPI property table.
+ * Hence assert is wrong.
+ * TODO: Handle LPI which is valid and does not have LPI property
+ * table entry and remove below assert.
+ */
+ ASSERT(irq < vits->prop_size);
+
+ spin_lock_irqsave(&vits->prop_lock, flags);
+ /*
+ * LPI property table always starts from 0 and LPI information
+ * is availeble above 8192 index.
+ * So, We don't subtract FIRST_GIC_LPI from irq value.
+ */
+ priority = *((u8*)vits->prop_page + irq);
+ /*
+ * Bits[7:2] specify priority with bits[1:0] of priority
+ * is set to zero. Hence only mask bits[7:2]
+ */
+ priority &= LPI_PRIORITY_MASK;
+ spin_unlock_irqrestore(&vits->prop_lock, flags);
+ }

return priority;
}
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 6e7ae9e..e7341f5 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -30,6 +30,7 @@

#include <asm/mmio.h>
#include <asm/gic.h>
+#include <asm/gic-its.h>
#include <asm/vgic.h>

static inline struct vgic_irq_rank *vgic_get_rank(struct vcpu *v, int rank)
@@ -499,6 +500,69 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq)
vgic_vcpu_inject_irq(v, virq);
}

+#ifdef HAS_GICV3
+void vgic_vcpu_inject_lpi(struct domain *d, unsigned int vdevid,
+ unsigned int eventID)
+{
+ struct vdevice_table dt_entry;
+ struct vitt vitt_entry;
+ uint32_t col_id;
+
+ if ( vits_get_vdevice_entry(d, vdevid, &dt_entry) )
+ {
+ dprintk(XENLOG_WARNING,
+ "Failed to read dt entry for dev 0x%"PRIx32" ..dropping\n",
+ vdevid);
+ return;
+ }
+
+ if ( dt_entry.vitt_ipa == INVALID_PADDR )
+ {
+ dprintk(XENLOG_WARNING,
+ "Event %"PRId32" of dev 0x%"PRIx32" is invalid..dropping\n",
+ eventID, vdevid);
+ return;
+ }
+
+ if ( vits_get_vitt_entry(d, vdevid, eventID, &vitt_entry) )
+ {
+ dprintk(XENLOG_WARNING,
+ "Event %"PRId32" of dev 0x%"PRIx32" is invalid..dropping\n",
+ eventID, vdevid);
+ return;
+ }
+
+ col_id = vitt_entry.vcollection;
+
+ if ( !vitt_entry.valid || !is_valid_collection(d, col_id) ||
+ !vgic_is_domain_lpi(d, vitt_entry.vlpi) )
+ {
+ dprintk(XENLOG_WARNING,
+ "vlpi %"PRId32" for dev 0x%"PRIx32" is not valid..dropping\n",
+ vitt_entry.vlpi, vdevid);
+ return;
+ }
+
+ /*
+ * We don't have vlpi to plpi mapping and hence we cannot
+ * have target on which corresponding vlpi is enabled.
+ * So for now we are always injecting vlpi on vcpu0.
+ * (See vgic_vcpu_inject_lpi() function) and so we get pending_irq
+ * structure on vcpu0.
+ * TODO: Get correct target vcpu
+ */
+ vgic_vcpu_inject_irq(d->vcpu[0], vitt_entry.vlpi);
+}
+
+void vgic_vcpu_raise_lpi(struct domain *d, struct irq_desc *desc)
+{
+ struct its_device *dev = irqdesc_get_its_device(desc);
+ unsigned int eventID = irqdesc_get_lpi_event(desc);
+
+ vgic_vcpu_inject_lpi(d, dev->virt_device_id, eventID);
+}
+#endif
+
void arch_evtchn_inject(struct vcpu *v)
{
vgic_vcpu_inject_irq(v, v->domain->arch.evtchn_irq);
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 11f1cd9..75a9c95 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -360,6 +360,9 @@ int its_init(struct rdist_prop *rdists);
int its_cpu_init(void);
int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
+void its_set_lpi_properties(struct irq_desc *desc,
+ const cpumask_t *cpu_mask,
+ unsigned int priority);
int vits_access_guest_table(struct domain *d, paddr_t entry, void *addr,
uint32_t size, bool_t set);
int vits_domain_init(struct domain *d);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 2b26e28..abb8616 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -225,6 +225,9 @@ extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mas
extern int gic_route_irq_to_guest(struct domain *, unsigned int virq,
struct irq_desc *desc,
unsigned int priority);
+extern int gic_route_lpi_to_guest(struct domain *d,
+ struct irq_desc *desc,
+ unsigned int priority);

/* Remove an IRQ passthrough to a guest */
int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
@@ -281,8 +284,10 @@ extern void send_SGI_allbutself(enum gic_sgi sgi);
/* print useful debug info */
extern void gic_dump_info(struct vcpu *v);

-/* Number of interrupt lines */
+/* Number of interrupt lines (PPIs + SGIs + SPIs)*/
extern unsigned int gic_number_lines(void);
+/* Check if irq is valid */
+bool_t gic_is_valid_irq(unsigned int irq);
/* Number of event ids supported */
extern unsigned int gic_nr_event_ids(void);
/* LPI support info */
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 437f99b..cf13d88 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -52,6 +52,8 @@ bool_t is_assignable_irq(unsigned int irq);
void init_IRQ(void);
void init_secondary_IRQ(void);

+int route_lpi_to_guest(struct domain *d, unsigned int irq,
+ const char *devname);
int route_irq_to_guest(struct domain *d, unsigned int virq,
unsigned int irq, const char *devname);
int release_guest_irq(struct domain *d, unsigned int irq);
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index e971cab..71ce6c3 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -322,6 +322,9 @@ extern int vcpu_vgic_init(struct vcpu *v);
extern struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int irq);
extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq);
extern void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq);
+extern void vgic_vcpu_inject_lpi(struct domain *d, unsigned int devid,
+ unsigned int eventID);
+extern void vgic_vcpu_raise_lpi(struct domain *d, struct irq_desc *desc);
extern void vgic_clear_pending_irqs(struct vcpu *v);
extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq);
extern struct pending_irq *spi_to_pending(struct domain *d, unsigned int irq);
--
1.7.9.5
v***@gmail.com
2015-08-31 11:06:42 UTC
Permalink
From: Vijaya Kumar K <***@caviumnetworks.com>

Allocate dynamically irq descriptors for LPIs

Signed-off-by: Vijaya Kumar K <***@caviumnetworks.com>
---
v6: - Add separate patch for irq_pending structures
- renamed and moved is_domain_lpi to vgic
- Updated __irq_to_domain
---
xen/arch/arm/gic-v3-its.c | 4 ++++
xen/arch/arm/irq.c | 33 ++++++++++++++++++++++++++++++++-
xen/include/asm-arm/irq.h | 1 +
3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index f41ec83..d9ec044 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -1435,6 +1435,10 @@ int __init its_init(struct rdist_prop *rdists)
its_alloc_lpi_tables();
its_lpi_init(rdists->id_bits);

+ /* Allocate irq descriptors for LPIs */
+ if ( init_lpi() )
+ return -ENOMEM;
+
its = list_first_entry(&its_nodes, struct its_node, entry);
if ( !its )
return -ENOMEM;
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 93e9411..2a37521 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -31,6 +31,7 @@
static unsigned int local_irqs_type[NR_LOCAL_IRQS];
static DEFINE_SPINLOCK(local_irqs_type_lock);

+static irq_desc_t *irq_desc_lpi;
/* Number of LPI supported in XEN */
/*
* LPI number start from 8192. Minimum number of bits
@@ -70,7 +71,15 @@ static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);
irq_desc_t *__irq_to_desc(int irq)
{
if (irq < NR_LOCAL_IRQS) return &this_cpu(local_irq_desc)[irq];
- return &irq_desc[irq-NR_LOCAL_IRQS];
+ else if ( gic_is_lpi(irq) )
+ {
+ ASSERT(irq_desc_lpi != NULL);
+ return &irq_desc_lpi[irq - FIRST_GIC_LPI];
+ }
+ else
+ return &irq_desc[irq - NR_LOCAL_IRQS];
+
+ return NULL;
}

int __init arch_init_one_irq_desc(struct irq_desc *desc)
@@ -120,6 +129,28 @@ static int __cpuinit init_local_irq_data(void)
return 0;
}

+int init_lpi(void)
+{
+ struct irq_desc *desc;
+ unsigned int i;
+
+ /* Allocate LPI irq descriptors */
+ irq_desc_lpi = xzalloc_array(struct irq_desc, nr_lpis);
+ if ( !irq_desc_lpi )
+ return -ENOSPC;
+
+ for ( i = 0; i < nr_lpis; i++ )
+ {
+ desc = &irq_desc_lpi[i];
+ init_one_irq_desc(desc);
+ desc->irq = FIRST_GIC_LPI + i;
+ desc->arch.type = DT_IRQ_TYPE_EDGE_BOTH;
+ desc->action = NULL;
+ }
+
+ return 0;
+}
+
void __init init_IRQ(void)
{
int irq;
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index ff37234..437f99b 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -68,6 +68,7 @@ int platform_get_irq(const struct dt_device_node *device, int index);
void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
void irq_set_msi_desc(struct irq_desc *desc, struct msi_desc *msi);
struct msi_desc *irq_get_msi_desc(struct irq_desc *desc);
+int init_lpi(void);

#endif /* _ASM_HW_IRQ_H */
/*
--
1.7.9.5
Ian Campbell
2015-09-02 15:38:00 UTC
Permalink
Post by v***@gmail.com
- Rebased to latest staging branch.
- Compiled all the patches individually for both arm32 and arm64
- Split the patch "xen/arm: ITS: Allocate irq descriptors for LPIs" into two.
One for allocating LPI irq_desc and other patch for allocating pending_irq desc
for LPIs
- Following new patches are introduced
1) xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
2) xen/arm: ITS: Introduce msi_desc for LPIs
3) xen/arm: Move vgic locking inside get_irq_priority callback
4) xen/arm: ITS: Store LPIs allocated and IRQ ID bits per domain
5) xen/arm: ITS: Introduce helper to get number of event IDs
6) xen/arm: ITS: Add virtual ITS availability check helper
7) xen/arm: ITS: Add 32-bit access to GICR_TYPER)
8) xen/arm: ITS: Allocate pending_lpi descriptors for LPIs
- Based on below patch set
http://lists.xen.org/archives/html/xen-devel/2015-08/msg00168.html
1) Avoid making vits_process_cmd() static in later point of time
2) How to handle LPI that does not have LPI config table entry.
3) Enable/disable ITS to Dom0
http://article.gmane.org/gmane.comp.emulators.xen.devel/258198 doesn't seem
to be reflected here as either a change/new-patch or a Major TODO, and it
is pretty Major I think.

Ian.
Ian Campbell
2015-09-02 15:52:02 UTC
Permalink
Post by Ian Campbell
Post by v***@gmail.com
- Rebased to latest staging branch.
- Compiled all the patches individually for both arm32 and arm64
- Split the patch "xen/arm: ITS: Allocate irq descriptors for LPIs"
into
two.
One for allocating LPI irq_desc and other patch for allocating pending_irq desc
for LPIs
- Following new patches are introduced
1) xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
2) xen/arm: ITS: Introduce msi_desc for LPIs
3) xen/arm: Move vgic locking inside get_irq_priority callback
4) xen/arm: ITS: Store LPIs allocated and IRQ ID bits per domain
5) xen/arm: ITS: Introduce helper to get number of event IDs
6) xen/arm: ITS: Add virtual ITS availability check helper
7) xen/arm: ITS: Add 32-bit access to GICR_TYPER)
8) xen/arm: ITS: Allocate pending_lpi descriptors for LPIs
- Based on below patch set
http://lists.xen.org/archives/html/xen-devel/2015-08/msg00168.html
1) Avoid making vits_process_cmd() static in later point of time
2) How to handle LPI that does not have LPI config table entry.
3) Enable/disable ITS to Dom0
http://article.gmane.org/gmane.comp.emulators.xen.devel/258198 doesn't seem
to be reflected here as either a change/new-patch or a Major TODO, and it
is pretty Major I think.
I was reminded by Julien's response to patch #29 that this is only really a
problem once we are exposing the ITS to domU, and I concur with his request
for a big fat warning comment (the existing ASSERT I think is sufficient to
avoid runtime problems).

Ian.
Julien Grall
2015-09-03 16:45:58 UTC
Permalink
Hi Vijay,
Post by v***@gmail.com
This is based on DraftG version
http://xenbits.xen.org/people/ianc/vits/draftG.pdf
Following major features are supported
- GICv3 ITS support for arm64 platform
- Only Dom0 is supported. For DomU pci passthrough feature
is required.
Thank you for the repo.

FYI, you could have re-used the git repo you've used for v2 and create a
new branch called its-v6 ;). It's easier than creating a new repo for
every version.

Regards,
--
Julien Grall
Ian Campbell
2015-09-09 15:29:42 UTC
Permalink
Post by v***@gmail.com
1) Avoid making vits_process_cmd() static in later point of time
2) How to handle LPI that does not have LPI config table entry.
3) Enable/disable ITS to Dom0
I'm not quite sure what any of these 3 are, can you expand upon them
please.

Major TODOs I can think of (which may overlap those above which I don't
understand):

A. Ensuring that no aspect of the vITS is exposed to domains other than
dom0, so no mapping, no GICR registers relating to LPIs or ITS etc.
B. A bug fat warning in the code vits_map_translation_space about the
issues with exposing this to dom0.
C. The issue regarding what to do with physical LPIs which arrive before
the guest has mapped the corresponding event in the vits or which is
masked

Have I missed anything?

I think A and B are pretty straight forward to fix.

C I think is a bit thornier, and IIRC we do not currently have a plan for
how we can address this in a generic way. I think we might have some ideas
which work only for PCI devices (or maybe only PCI-e devices?).

Ian.
Post by v***@gmail.com
- Added following new patches
0001-xen-arm-Return-success-if-dt-node-does-not-have-irq-.patch
0004-xen-arm-Set-nr_cpu_ids-to-available-number-of-cpus.patch
0009-xen-arm-ITS-Export-ITS-info-to-Virtual-ITS.patch
0013-xen-arm-ITS-Implement-gic_is_lpi-helper-function.patch
- Split patch #12 into two patches #14 & #16
0014-xen-arm-ITS-Allocate-irq-descriptors-for-LPIs.patch
0016-xen-arm-ITS-Route-LPIs.patch
- Introduce new API to route LPI (route_lpi_to_guest() )
- Moved patch #8 in v4 as patch #19
- irq_descritors for LPIs are allocated dynamically
- Removed RB-tree for managing vitual its devices. Will be
introduced when pci-passthrough is implemented
- its_add_device() api now takes nr_ites and DT its node as parameters
- some function are kept as non-static when introduced in a patch for
compilation purpose and eventually made static when used.
- Tested compilation for arm32
- Patch for rate limiting of error message is removed.
- Patch #4 and #5 in v3 is merged
- Merged #13 and #16 as one patch
- hw_irq_controller is implemented for LPIs
- GITS and GICR emulation for LPIs in separate patches
- Removed build functions for ITS command in physical ITS driver
- Added new patch to add and assign devices from platform file
- Enable compilation of vits and pits driver in separate patch
- Replace msi-parent property in all pci dt nodes to single
ITS node generated by Xen for Dom0
xen/dt: Handle correctly node with interrupt-map in
dt_for_each_irq_map
xen/arm: Add bitmap_find_next_zero_area helper function
xen: Add log2 functionality
xen/arm: Set nr_cpu_ids to available number of cpus
xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
xen/arm: ITS: Port ITS driver to Xen
xen/arm: ITS: Add helper functions to manage its_devices
xen/arm: ITS: Introduce msi_desc for LPIs
xen/arm: ITS: Add APIs to add and assign device
xen/arm: ITS: Introduce gic_is_lpi helper function
xen/arm: ITS: Enable compilation of physical ITS driver
xen/arm: Move vgic locking inside get_irq_priority callback
xen/arm: ITS: implement hw_irq_controller for LPIs
xen/arm: ITS: Initialize physical ITS and export lpi support
xen/arm: ITS: Add virtual ITS driver
xen/arm: ITS: Add virtual ITS commands support
xen/arm: ITS: Store LPIs allocated and IRQ ID bits per domain
xen/arm: ITS: Enable virtual ITS driver
xen/arm: ITS: Export ITS info to Virtual ITS
xen/arm: ITS: Introduce helper to get number of event IDs
xen/arm: ITS: Add GITS registers emulation
xen/arm: ITS: Add virtual ITS availability check helper
xen/arm: ITS: Add 32-bit access to GICR_TYPER
xen/arm: ITS: Add GICR register emulation
xen/arm: ITS: Allocate irq descriptors for LPIs
xen/arm: ITS: Allocate pending_lpi descriptors for LPIs
xen/arm: ITS: Route LPIs
xen/arm: ITS: Add domain specific ITS initialization
xen/arm: ITS: Map ITS translation space
xen/arm: ITS: Generate ITS node for Dom0
xen/arm: ITS: Add pci devices in ThunderX
xen/arch/arm/Makefile | 2 +
xen/arch/arm/domain_build.c | 11 +
xen/arch/arm/gic-hip04.c | 19 +-
xen/arch/arm/gic-v2.c | 19 +-
xen/arch/arm/gic-v3-its.c | 1594
+++++++++++++++++++++++++++++++++++++
xen/arch/arm/gic-v3.c | 102 ++-
xen/arch/arm/gic.c | 73 +-
xen/arch/arm/irq.c | 176 +++-
xen/arch/arm/platforms/Makefile | 1 +
xen/arch/arm/platforms/thunderx.c | 151 ++++
xen/arch/arm/setup.c | 2 +
xen/arch/arm/vgic-v2.c | 9 +-
xen/arch/arm/vgic-v3-its.c | 993 +++++++++++++++++++++++
xen/arch/arm/vgic-v3.c | 419 +++++++++-
xen/arch/arm/vgic.c | 117 ++-
xen/common/bitmap.c | 39 +
xen/common/device_tree.c | 4 +-
xen/include/asm-arm/domain.h | 11 +
xen/include/asm-arm/gic-its.h | 387 +++++++++
xen/include/asm-arm/gic.h | 27 +-
xen/include/asm-arm/gic_v3_defs.h | 51 +-
xen/include/asm-arm/irq.h | 24 +-
xen/include/asm-arm/vgic.h | 18 +-
xen/include/xen/bitmap.h | 16 +
xen/include/xen/lib.h | 2 +
xen/include/xen/log2.h | 167 ++++
26 files changed, 4357 insertions(+), 77 deletions(-)
create mode 100644 xen/arch/arm/gic-v3-its.c
create mode 100644 xen/arch/arm/platforms/thunderx.c
create mode 100644 xen/arch/arm/vgic-v3-its.c
create mode 100644 xen/include/asm-arm/gic-its.h
create mode 100644 xen/include/xen/log2.h
Vijay Kilari
2015-09-14 11:00:38 UTC
Permalink
Post by Ian Campbell
Post by v***@gmail.com
1) Avoid making vits_process_cmd() static in later point of time
2) How to handle LPI that does not have LPI config table entry.
3) Enable/disable ITS to Dom0
I'm not quite sure what any of these 3 are, can you expand upon them
please.
Major TODOs I can think of (which may overlap those above which I don't
A. Ensuring that no aspect of the vITS is exposed to domains other than
dom0, so no mapping, no GICR registers relating to LPIs or ITS etc.
B. A bug fat warning in the code vits_map_translation_space about the
issues with exposing this to dom0.
C. The issue regarding what to do with physical LPIs which arrive before
the guest has mapped the corresponding event in the vits or which is
masked
Have I missed anything?
I think A and B are pretty straight forward to fix.
C I think is a bit thornier, and IIRC we do not currently have a plan for
how we can address this in a generic way. I think we might have some ideas
which work only for PCI devices (or maybe only PCI-e devices?).
Ian.
I will take care of A & B in next revision.

Is there any further comments on this series?. I have not received
any comments on last few patches (patch #25 to patch#30).
Post by Ian Campbell
Post by v***@gmail.com
- Added following new patches
0001-xen-arm-Return-success-if-dt-node-does-not-have-irq-.patch
0004-xen-arm-Set-nr_cpu_ids-to-available-number-of-cpus.patch
0009-xen-arm-ITS-Export-ITS-info-to-Virtual-ITS.patch
0013-xen-arm-ITS-Implement-gic_is_lpi-helper-function.patch
- Split patch #12 into two patches #14 & #16
0014-xen-arm-ITS-Allocate-irq-descriptors-for-LPIs.patch
0016-xen-arm-ITS-Route-LPIs.patch
- Introduce new API to route LPI (route_lpi_to_guest() )
- Moved patch #8 in v4 as patch #19
- irq_descritors for LPIs are allocated dynamically
- Removed RB-tree for managing vitual its devices. Will be
introduced when pci-passthrough is implemented
- its_add_device() api now takes nr_ites and DT its node as parameters
- some function are kept as non-static when introduced in a patch for
compilation purpose and eventually made static when used.
- Tested compilation for arm32
- Patch for rate limiting of error message is removed.
- Patch #4 and #5 in v3 is merged
- Merged #13 and #16 as one patch
- hw_irq_controller is implemented for LPIs
- GITS and GICR emulation for LPIs in separate patches
- Removed build functions for ITS command in physical ITS driver
- Added new patch to add and assign devices from platform file
- Enable compilation of vits and pits driver in separate patch
- Replace msi-parent property in all pci dt nodes to single
ITS node generated by Xen for Dom0
xen/dt: Handle correctly node with interrupt-map in
dt_for_each_irq_map
xen/arm: Add bitmap_find_next_zero_area helper function
xen: Add log2 functionality
xen/arm: Set nr_cpu_ids to available number of cpus
xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
xen/arm: ITS: Port ITS driver to Xen
xen/arm: ITS: Add helper functions to manage its_devices
xen/arm: ITS: Introduce msi_desc for LPIs
xen/arm: ITS: Add APIs to add and assign device
xen/arm: ITS: Introduce gic_is_lpi helper function
xen/arm: ITS: Enable compilation of physical ITS driver
xen/arm: Move vgic locking inside get_irq_priority callback
xen/arm: ITS: implement hw_irq_controller for LPIs
xen/arm: ITS: Initialize physical ITS and export lpi support
xen/arm: ITS: Add virtual ITS driver
xen/arm: ITS: Add virtual ITS commands support
xen/arm: ITS: Store LPIs allocated and IRQ ID bits per domain
xen/arm: ITS: Enable virtual ITS driver
xen/arm: ITS: Export ITS info to Virtual ITS
xen/arm: ITS: Introduce helper to get number of event IDs
xen/arm: ITS: Add GITS registers emulation
xen/arm: ITS: Add virtual ITS availability check helper
xen/arm: ITS: Add 32-bit access to GICR_TYPER
xen/arm: ITS: Add GICR register emulation
xen/arm: ITS: Allocate irq descriptors for LPIs
xen/arm: ITS: Allocate pending_lpi descriptors for LPIs
xen/arm: ITS: Route LPIs
xen/arm: ITS: Add domain specific ITS initialization
xen/arm: ITS: Map ITS translation space
xen/arm: ITS: Generate ITS node for Dom0
xen/arm: ITS: Add pci devices in ThunderX
xen/arch/arm/Makefile | 2 +
xen/arch/arm/domain_build.c | 11 +
xen/arch/arm/gic-hip04.c | 19 +-
xen/arch/arm/gic-v2.c | 19 +-
xen/arch/arm/gic-v3-its.c | 1594
+++++++++++++++++++++++++++++++++++++
xen/arch/arm/gic-v3.c | 102 ++-
xen/arch/arm/gic.c | 73 +-
xen/arch/arm/irq.c | 176 +++-
xen/arch/arm/platforms/Makefile | 1 +
xen/arch/arm/platforms/thunderx.c | 151 ++++
xen/arch/arm/setup.c | 2 +
xen/arch/arm/vgic-v2.c | 9 +-
xen/arch/arm/vgic-v3-its.c | 993 +++++++++++++++++++++++
xen/arch/arm/vgic-v3.c | 419 +++++++++-
xen/arch/arm/vgic.c | 117 ++-
xen/common/bitmap.c | 39 +
xen/common/device_tree.c | 4 +-
xen/include/asm-arm/domain.h | 11 +
xen/include/asm-arm/gic-its.h | 387 +++++++++
xen/include/asm-arm/gic.h | 27 +-
xen/include/asm-arm/gic_v3_defs.h | 51 +-
xen/include/asm-arm/irq.h | 24 +-
xen/include/asm-arm/vgic.h | 18 +-
xen/include/xen/bitmap.h | 16 +
xen/include/xen/lib.h | 2 +
xen/include/xen/log2.h | 167 ++++
26 files changed, 4357 insertions(+), 77 deletions(-)
create mode 100644 xen/arch/arm/gic-v3-its.c
create mode 100644 xen/arch/arm/platforms/thunderx.c
create mode 100644 xen/arch/arm/vgic-v3-its.c
create mode 100644 xen/include/asm-arm/gic-its.h
create mode 100644 xen/include/xen/log2.h
Julien Grall
2015-09-14 11:09:53 UTC
Permalink
Hi Vijay,
Post by Vijay Kilari
I will take care of A & B in next revision.
Is there any further comments on this series?. I have not received
any comments on last few patches (patch #25 to patch#30).
I haven't commented the rest of the series because I'm expecting to see
the remaining patches change after the comment related the LPI property
table in patch #24.

Actually, even in patch #24 I had some comments but I'm delaying them
until the main one is fixed.

Regards,
--
Julien Grall
Vijay Kilari
2015-09-14 13:04:31 UTC
Permalink
Post by Julien Grall
Hi Vijay,
Post by Vijay Kilari
I will take care of A & B in next revision.
Is there any further comments on this series?. I have not received
any comments on last few patches (patch #25 to patch#30).
I haven't commented the rest of the series because I'm expecting to see
the remaining patches change after the comment related the LPI property
table in patch #24.
Actually, even in patch #24 I had some comments but I'm delaying them
until the main one is fixed.
Ok. Expecting no further review on v6, I will send next revision.
Continue reading on narkive:
Loading...