|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 05/17] xen/arm: ITS: implement hw_irq_controller for LPIs
From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
Implements hw_irq_controller api's required
to handle LPI's
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
---
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-v3-its.c | 132 +++++++++++++++++++++++++++++++++++++
xen/arch/arm/gic-v3.c | 5 +-
xen/arch/arm/gic.c | 32 +++++++--
xen/arch/arm/irq.c | 40 ++++++++++-
xen/include/asm-arm/gic-its.h | 4 ++
xen/include/asm-arm/gic.h | 13 ++++
xen/include/asm-arm/gic_v3_defs.h | 1 +
xen/include/asm-arm/irq.h | 8 ++-
8 files changed, 227 insertions(+), 8 deletions(-)
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index b421a6f..b98d396 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -295,6 +295,19 @@ post:
its_wait_for_range_completion(its, cmd, next_cmd);
}
+static void its_send_inv(struct its_device *dev, struct its_collection *col,
+ u32 event_id)
+{
+ its_cmd_block cmd;
+
+ memset(&cmd, 0x0, sizeof(its_cmd_block));
+ cmd.inv.cmd = GITS_CMD_INV;
+ cmd.inv.devid = dev->device_id;
+ cmd.inv.event = event_id;
+
+ its_send_single_command(dev->its, &cmd, col);
+}
+
static void its_send_mapc(struct its_node *its, struct its_collection *col,
int valid)
{
@@ -320,6 +333,125 @@ static void its_send_invall(struct its_node *its, struct
its_collection *col)
its_send_single_command(its, &cmd, NULL);
}
+static void lpi_set_config(struct irq_desc *desc, int enable)
+{
+ u8 *cfg;
+ struct its_collection *col;
+ struct its_device *its_dev = get_irq_device(desc);
+ u16 col_id;
+ u32 vid = irq_to_vid(desc);
+
+ ASSERT(vid < its_dev->nr_lpis);
+
+ cfg = gic_rdists->prop_page + desc->irq - NR_GIC_LPI;
+ if ( enable )
+ *cfg |= LPI_PROP_ENABLED;
+ else
+ *cfg &= ~LPI_PROP_ENABLED;
+
+ /*
+ * 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);
+
+ /* Get collection id for this event id */
+ col_id = gic_get_irq_collection(desc->irq);
+ col = &its_dev->its->collections[col_id];
+ its_send_inv(its_dev, col, vid);
+}
+
+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);
+ lpi_set_config(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);
+ lpi_set_config(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);
+ /* Deactivate */
+ gicv3_dir_irq(desc);
+}
+
+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)
+{
+ return;
+}
+
+static 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,
+};
+
+static 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,
+};
+
+static const struct its_hw_operations its_ops = {
+ .lpi_host_irq_type = &its_host_lpi_type,
+ .lpi_guest_irq_type = &its_guest_lpi_type,
+};
+
/*
* How we allocate LPIs:
*
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index b5c59f6..904fe57 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>
struct rdist_region {
@@ -435,14 +436,14 @@ 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);
isb();
}
-static void gicv3_dir_irq(struct irq_desc *irqd)
+void gicv3_dir_irq(struct irq_desc *irqd)
{
/* Deactivate */
WRITE_SYSREG32(irqd->irq, ICC_DIR_EL1);
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index c41e82e..4f3801b 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -46,12 +46,18 @@ static DEFINE_PER_CPU(uint64_t, lr_mask);
static void gic_update_one_lr(struct vcpu *v, int i);
static const struct gic_hw_operations *gic_hw_ops;
+static const struct its_hw_operations *its_hw_ops;
void register_gic_ops(const struct gic_hw_operations *ops)
{
gic_hw_ops = ops;
}
+void register_its_ops(const struct its_hw_operations *ops)
+{
+ its_hw_ops = ops;
+}
+
static void clear_cpu_lr_mask(void)
{
this_cpu(lr_mask) = 0ULL;
@@ -94,6 +100,22 @@ 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)
+{
+ if ( is_lpi(irq) )
+ return its_hw_ops->lpi_host_irq_type;
+ else
+ return gic_hw_ops->gic_host_irq_type;
+}
+
+static inline hw_irq_controller *get_guest_hw_irq_controller(unsigned int irq)
+{
+ if ( is_lpi(irq) )
+ return its_hw_ops->lpi_guest_irq_type;
+ else
+ return gic_hw_ops->gic_guest_irq_type;
+}
+
/*
* needs to be called with a valid cpu_mask, ie each cpu in the mask has
* already called gic_cpu_init
@@ -104,7 +126,8 @@ static void gic_set_irq_properties(struct irq_desc *desc,
const cpumask_t *cpu_mask,
unsigned int priority)
{
- gic_hw_ops->set_irq_properties(desc, cpu_mask, priority);
+ if ( desc->irq < gic_number_lines() )
+ gic_hw_ops->set_irq_properties(desc, cpu_mask, priority);
}
/* Program the GIC to route an interrupt to the host (i.e. Xen)
@@ -114,11 +137,12 @@ 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(desc->irq < gic_number_lines() || is_lpi(desc->irq));
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);
}
@@ -149,7 +173,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/arch/arm/irq.c b/xen/arch/arm/irq.c
index 2dd43ee..ba8528a 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -35,7 +35,13 @@ static DEFINE_SPINLOCK(local_irqs_type_lock);
struct irq_guest
{
struct domain *d;
- unsigned int virq;
+ union
+ {
+ /* virq refer to virtual irq in case of spi */
+ unsigned int virq;
+ /* virq refer to event ID in case of lpi */
+ unsigned int vid;
+ };
};
static void ack_none(struct irq_desc *irq)
@@ -143,6 +149,38 @@ static inline struct domain *irq_get_domain(struct
irq_desc *desc)
return irq_get_guest_info(desc)->d;
}
+unsigned int irq_to_vid(struct irq_desc *desc)
+{
+ return irq_get_guest_info(desc)->vid;
+}
+
+unsigned int irq_to_virq(struct irq_desc *desc)
+{
+ return irq_get_guest_info(desc)->virq;
+}
+
+struct its_device *get_irq_device(struct irq_desc *desc)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ return desc->arch.dev;
+}
+
+void set_irq_device(struct irq_desc *desc, struct its_device *dev)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+ desc->arch.dev = dev;
+}
+
+u16 gic_get_irq_collection(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ ASSERT(spin_is_locked(&desc->lock));
+
+ return desc->arch.col_id;
+}
+
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 b5e09bd..e8d244f 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -161,6 +161,10 @@ typedef union {
* The ITS view of a device.
*/
struct its_device {
+ /* Physical ITS */
+ struct its_node *its;
+ /* Number of Physical LPIs assigned */
+ int nr_lpis;
/* Physical Device id */
u32 device_id;
/* RB-tree entry */
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index e9d5f36..44c2317 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -20,6 +20,9 @@
#define NR_GIC_LOCAL_IRQS NR_LOCAL_IRQS
#define NR_GIC_SGI 16
+#define FIRST_GIC_LPI 8192
+#define NR_GIC_LPI 4096
+#define MAX_LPI (FIRST_GIC_LPI + NR_GIC_LPI)
#define MAX_RDIST_COUNT 4
#define GICD_CTLR (0x000)
@@ -163,6 +166,7 @@
#define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE("arm,gic-v3")
#define DT_MATCH_GIC_ITS DT_MATCH_COMPATIBLE("arm,gic-v3-its")
+#define is_lpi(lpi) (lpi >= FIRST_GIC_LPI && lpi < MAX_LPI)
/*
* GICv3 registers that needs to be saved/restored
*/
@@ -279,6 +283,8 @@ extern void gic_dump_info(struct vcpu *v);
/* Number of interrupt lines */
extern unsigned int gic_number_lines(void);
+void gicv3_eoi_irq(struct irq_desc *irqd);
+void gicv3_dir_irq(struct irq_desc *irqd);
/* IRQ translation function for the device tree */
int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
unsigned int *out_hwirq, unsigned int *out_type);
@@ -353,7 +359,14 @@ struct gic_hw_operations {
const struct dt_device_node *node, void *fdt);
};
+struct its_hw_operations {
+ /* hw_irq_controller to enable/disable/eoi host lpi */
+ hw_irq_controller *lpi_host_irq_type;
+ /* hw_irq_controller to enable/disable/eoi guest lpi */
+ hw_irq_controller *lpi_guest_irq_type;
+};
void register_gic_ops(const struct gic_hw_operations *ops);
+void register_its_ops(const struct its_hw_operations *ops);
int gic_make_node(const struct domain *d,const struct dt_device_node *node,
void *fdt);
diff --git a/xen/include/asm-arm/gic_v3_defs.h
b/xen/include/asm-arm/gic_v3_defs.h
index 051a95e..0443ae7 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -169,6 +169,7 @@
#define ICH_SGI_IRQ_MASK 0xf
#define ICH_SGI_TARGETLIST_MASK 0xffff
#define LPI_PROP_GROUP1 (1 << 1)
+#define LPI_PROP_ENABLED (1 << 0)
/*
* ITS registers, offsets from ITS_base
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 34b492b..55e219f 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -17,6 +17,8 @@ struct arch_pirq
struct arch_irq_desc {
int eoi_cpu;
unsigned int type;
+ struct its_device *dev;
+ u16 col_id;
};
#define NR_LOCAL_IRQS 32
@@ -50,7 +52,11 @@ void arch_move_irqs(struct vcpu *v);
/* Set IRQ type for an SPI */
int irq_set_spi_type(unsigned int spi, unsigned int type);
-
+unsigned int irq_to_virq(struct irq_desc *desc);
+unsigned int irq_to_vid(struct irq_desc *desc);
+struct its_device *get_irq_device(struct irq_desc *desc);
+void set_irq_device(struct irq_desc *desc, struct its_device *dev);
+u16 gic_get_irq_collection(unsigned int irq);
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);
--
1.7.9.5
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |