[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 |