2005-08-19 03:31:00 +07:00
|
|
|
/*
|
2012-12-28 02:10:24 +07:00
|
|
|
* include/linux/irqchip/arm-gic.h
|
2005-08-19 03:31:00 +07:00
|
|
|
*
|
|
|
|
* Copyright (C) 2002 ARM Limited, All Rights Reserved.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-12-28 02:10:24 +07:00
|
|
|
#ifndef __LINUX_IRQCHIP_ARM_GIC_H
|
|
|
|
#define __LINUX_IRQCHIP_ARM_GIC_H
|
2005-08-19 03:31:00 +07:00
|
|
|
|
|
|
|
#define GIC_CPU_CTRL 0x00
|
|
|
|
#define GIC_CPU_PRIMASK 0x04
|
|
|
|
#define GIC_CPU_BINPOINT 0x08
|
|
|
|
#define GIC_CPU_INTACK 0x0c
|
|
|
|
#define GIC_CPU_EOI 0x10
|
|
|
|
#define GIC_CPU_RUNNINGPRI 0x14
|
|
|
|
#define GIC_CPU_HIGHPRI 0x18
|
2013-09-24 04:55:56 +07:00
|
|
|
#define GIC_CPU_ALIAS_BINPOINT 0x1c
|
|
|
|
#define GIC_CPU_ACTIVEPRIO 0xd0
|
|
|
|
#define GIC_CPU_IDENT 0xfc
|
2015-08-26 23:00:44 +07:00
|
|
|
#define GIC_CPU_DEACTIVATE 0x1000
|
2005-08-19 03:31:00 +07:00
|
|
|
|
2014-07-31 04:56:58 +07:00
|
|
|
#define GICC_ENABLE 0x1
|
|
|
|
#define GICC_INT_PRI_THRESHOLD 0xf0
|
2015-08-26 23:00:44 +07:00
|
|
|
|
2017-05-20 19:12:34 +07:00
|
|
|
#define GIC_CPU_CTRL_EnableGrp0_SHIFT 0
|
|
|
|
#define GIC_CPU_CTRL_EnableGrp0 (1 << GIC_CPU_CTRL_EnableGrp0_SHIFT)
|
|
|
|
#define GIC_CPU_CTRL_EnableGrp1_SHIFT 1
|
|
|
|
#define GIC_CPU_CTRL_EnableGrp1 (1 << GIC_CPU_CTRL_EnableGrp1_SHIFT)
|
|
|
|
#define GIC_CPU_CTRL_AckCtl_SHIFT 2
|
|
|
|
#define GIC_CPU_CTRL_AckCtl (1 << GIC_CPU_CTRL_AckCtl_SHIFT)
|
|
|
|
#define GIC_CPU_CTRL_FIQEn_SHIFT 3
|
|
|
|
#define GIC_CPU_CTRL_FIQEn (1 << GIC_CPU_CTRL_FIQEn_SHIFT)
|
|
|
|
#define GIC_CPU_CTRL_CBPR_SHIFT 4
|
|
|
|
#define GIC_CPU_CTRL_CBPR (1 << GIC_CPU_CTRL_CBPR_SHIFT)
|
|
|
|
#define GIC_CPU_CTRL_EOImodeNS_SHIFT 9
|
|
|
|
#define GIC_CPU_CTRL_EOImodeNS (1 << GIC_CPU_CTRL_EOImodeNS_SHIFT)
|
2015-08-26 23:00:44 +07:00
|
|
|
|
2014-05-11 15:05:58 +07:00
|
|
|
#define GICC_IAR_INT_ID_MASK 0x3ff
|
2014-07-31 04:56:58 +07:00
|
|
|
#define GICC_INT_SPURIOUS 1023
|
2014-07-31 04:56:59 +07:00
|
|
|
#define GICC_DIS_BYPASS_MASK 0x1e0
|
2014-05-11 15:05:58 +07:00
|
|
|
|
2005-08-19 03:31:00 +07:00
|
|
|
#define GIC_DIST_CTRL 0x000
|
|
|
|
#define GIC_DIST_CTR 0x004
|
2016-04-26 17:06:47 +07:00
|
|
|
#define GIC_DIST_IIDR 0x008
|
2013-01-24 01:18:03 +07:00
|
|
|
#define GIC_DIST_IGROUP 0x080
|
2005-08-19 03:31:00 +07:00
|
|
|
#define GIC_DIST_ENABLE_SET 0x100
|
|
|
|
#define GIC_DIST_ENABLE_CLEAR 0x180
|
|
|
|
#define GIC_DIST_PENDING_SET 0x200
|
|
|
|
#define GIC_DIST_PENDING_CLEAR 0x280
|
2013-01-24 01:18:03 +07:00
|
|
|
#define GIC_DIST_ACTIVE_SET 0x300
|
|
|
|
#define GIC_DIST_ACTIVE_CLEAR 0x380
|
2005-08-19 03:31:00 +07:00
|
|
|
#define GIC_DIST_PRI 0x400
|
|
|
|
#define GIC_DIST_TARGET 0x800
|
|
|
|
#define GIC_DIST_CONFIG 0xc00
|
|
|
|
#define GIC_DIST_SOFTINT 0xf00
|
2012-04-12 12:40:31 +07:00
|
|
|
#define GIC_DIST_SGI_PENDING_CLEAR 0xf10
|
|
|
|
#define GIC_DIST_SGI_PENDING_SET 0xf20
|
2005-08-19 03:31:00 +07:00
|
|
|
|
2014-07-31 04:56:58 +07:00
|
|
|
#define GICD_ENABLE 0x1
|
|
|
|
#define GICD_DISABLE 0x0
|
|
|
|
#define GICD_INT_ACTLOW_LVLTRIG 0x0
|
|
|
|
#define GICD_INT_EN_CLR_X32 0xffffffff
|
|
|
|
#define GICD_INT_EN_SET_SGI 0x0000ffff
|
|
|
|
#define GICD_INT_EN_CLR_PPI 0xffff0000
|
|
|
|
#define GICD_INT_DEF_PRI 0xa0
|
|
|
|
#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\
|
|
|
|
(GICD_INT_DEF_PRI << 16) |\
|
|
|
|
(GICD_INT_DEF_PRI << 8) |\
|
|
|
|
GICD_INT_DEF_PRI)
|
|
|
|
|
2018-07-16 20:06:18 +07:00
|
|
|
#define GICD_IIDR_IMPLEMENTER_SHIFT 0
|
|
|
|
#define GICD_IIDR_IMPLEMENTER_MASK (0xfff << GICD_IIDR_IMPLEMENTER_SHIFT)
|
|
|
|
#define GICD_IIDR_REVISION_SHIFT 12
|
|
|
|
#define GICD_IIDR_REVISION_MASK (0xf << GICD_IIDR_REVISION_SHIFT)
|
|
|
|
#define GICD_IIDR_VARIANT_SHIFT 16
|
|
|
|
#define GICD_IIDR_VARIANT_MASK (0xf << GICD_IIDR_VARIANT_SHIFT)
|
|
|
|
#define GICD_IIDR_PRODUCT_ID_SHIFT 24
|
|
|
|
#define GICD_IIDR_PRODUCT_ID_MASK (0xff << GICD_IIDR_PRODUCT_ID_SHIFT)
|
|
|
|
|
|
|
|
|
2013-01-22 07:36:11 +07:00
|
|
|
#define GICH_HCR 0x0
|
|
|
|
#define GICH_VTR 0x4
|
|
|
|
#define GICH_VMCR 0x8
|
|
|
|
#define GICH_MISR 0x10
|
|
|
|
#define GICH_EISR0 0x20
|
|
|
|
#define GICH_EISR1 0x24
|
|
|
|
#define GICH_ELRSR0 0x30
|
|
|
|
#define GICH_ELRSR1 0x34
|
|
|
|
#define GICH_APR 0xf0
|
|
|
|
#define GICH_LR0 0x100
|
|
|
|
|
|
|
|
#define GICH_HCR_EN (1 << 0)
|
|
|
|
#define GICH_HCR_UIE (1 << 1)
|
KVM: arm/arm64: vgic: Don't populate multiple LRs with the same vintid
The vgic code is trying to be clever when injecting GICv2 SGIs,
and will happily populate LRs with the same interrupt number if
they come from multiple vcpus (after all, they are distinct
interrupt sources).
Unfortunately, this is against the letter of the architecture,
and the GICv2 architecture spec says "Each valid interrupt stored
in the List registers must have a unique VirtualID for that
virtual CPU interface.". GICv3 has similar (although slightly
ambiguous) restrictions.
This results in guests locking up when using GICv2-on-GICv3, for
example. The obvious fix is to stop trying so hard, and inject
a single vcpu per SGI per guest entry. After all, pending SGIs
with multiple source vcpus are pretty rare, and are mostly seen
in scenario where the physical CPUs are severely overcomitted.
But as we now only inject a single instance of a multi-source SGI per
vcpu entry, we may delay those interrupts for longer than strictly
necessary, and run the risk of injecting lower priority interrupts
in the meantime.
In order to address this, we adopt a three stage strategy:
- If we encounter a multi-source SGI in the AP list while computing
its depth, we force the list to be sorted
- When populating the LRs, we prevent the injection of any interrupt
of lower priority than that of the first multi-source SGI we've
injected.
- Finally, the injection of a multi-source SGI triggers the request
of a maintenance interrupt when there will be no pending interrupt
in the LRs (HCR_NPIE).
At the point where the last pending interrupt in the LRs switches
from Pending to Active, the maintenance interrupt will be delivered,
allowing us to add the remaining SGIs using the same process.
Cc: stable@vger.kernel.org
Fixes: 0919e84c0fc1 ("KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework")
Acked-by: Christoffer Dall <cdall@kernel.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2018-03-07 04:48:01 +07:00
|
|
|
#define GICH_HCR_NPIE (1 << 3)
|
2013-01-22 07:36:11 +07:00
|
|
|
|
|
|
|
#define GICH_LR_VIRTUALID (0x3ff << 0)
|
|
|
|
#define GICH_LR_PHYSID_CPUID_SHIFT (10)
|
2015-06-08 21:37:26 +07:00
|
|
|
#define GICH_LR_PHYSID_CPUID (0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
|
2015-11-27 00:19:25 +07:00
|
|
|
#define GICH_LR_PRIORITY_SHIFT 23
|
2013-01-22 07:36:11 +07:00
|
|
|
#define GICH_LR_STATE (3 << 28)
|
|
|
|
#define GICH_LR_PENDING_BIT (1 << 28)
|
|
|
|
#define GICH_LR_ACTIVE_BIT (1 << 29)
|
|
|
|
#define GICH_LR_EOI (1 << 19)
|
2018-07-16 20:06:22 +07:00
|
|
|
#define GICH_LR_GROUP1 (1 << 30)
|
2015-06-08 21:37:26 +07:00
|
|
|
#define GICH_LR_HW (1 << 31)
|
2013-01-22 07:36:11 +07:00
|
|
|
|
2017-05-20 19:12:34 +07:00
|
|
|
#define GICH_VMCR_ENABLE_GRP0_SHIFT 0
|
|
|
|
#define GICH_VMCR_ENABLE_GRP0_MASK (1 << GICH_VMCR_ENABLE_GRP0_SHIFT)
|
|
|
|
#define GICH_VMCR_ENABLE_GRP1_SHIFT 1
|
|
|
|
#define GICH_VMCR_ENABLE_GRP1_MASK (1 << GICH_VMCR_ENABLE_GRP1_SHIFT)
|
|
|
|
#define GICH_VMCR_ACK_CTL_SHIFT 2
|
|
|
|
#define GICH_VMCR_ACK_CTL_MASK (1 << GICH_VMCR_ACK_CTL_SHIFT)
|
|
|
|
#define GICH_VMCR_FIQ_EN_SHIFT 3
|
|
|
|
#define GICH_VMCR_FIQ_EN_MASK (1 << GICH_VMCR_FIQ_EN_SHIFT)
|
|
|
|
#define GICH_VMCR_CBPR_SHIFT 4
|
|
|
|
#define GICH_VMCR_CBPR_MASK (1 << GICH_VMCR_CBPR_SHIFT)
|
|
|
|
#define GICH_VMCR_EOI_MODE_SHIFT 9
|
|
|
|
#define GICH_VMCR_EOI_MODE_MASK (1 << GICH_VMCR_EOI_MODE_SHIFT)
|
|
|
|
|
2013-09-24 04:55:56 +07:00
|
|
|
#define GICH_VMCR_PRIMASK_SHIFT 27
|
|
|
|
#define GICH_VMCR_PRIMASK_MASK (0x1f << GICH_VMCR_PRIMASK_SHIFT)
|
|
|
|
#define GICH_VMCR_BINPOINT_SHIFT 21
|
|
|
|
#define GICH_VMCR_BINPOINT_MASK (0x7 << GICH_VMCR_BINPOINT_SHIFT)
|
|
|
|
#define GICH_VMCR_ALIAS_BINPOINT_SHIFT 18
|
|
|
|
#define GICH_VMCR_ALIAS_BINPOINT_MASK (0x7 << GICH_VMCR_ALIAS_BINPOINT_SHIFT)
|
|
|
|
|
2013-01-22 07:36:11 +07:00
|
|
|
#define GICH_MISR_EOI (1 << 0)
|
|
|
|
#define GICH_MISR_U (1 << 1)
|
|
|
|
|
2017-03-22 04:05:22 +07:00
|
|
|
#define GICV_PMR_PRIORITY_SHIFT 3
|
|
|
|
#define GICV_PMR_PRIORITY_MASK (0x1f << GICV_PMR_PRIORITY_SHIFT)
|
|
|
|
|
2013-01-24 20:39:43 +07:00
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
|
2014-11-28 01:27:49 +07:00
|
|
|
#include <linux/irqdomain.h>
|
|
|
|
|
2011-09-29 09:25:31 +07:00
|
|
|
struct device_node;
|
2016-06-07 22:12:32 +07:00
|
|
|
struct gic_chip_data;
|
2011-09-29 09:25:31 +07:00
|
|
|
|
2007-02-15 01:14:56 +07:00
|
|
|
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
|
2015-07-31 15:44:12 +07:00
|
|
|
int gic_cpu_if_down(unsigned int gic_nr);
|
2016-06-07 22:12:32 +07:00
|
|
|
void gic_cpu_save(struct gic_chip_data *gic);
|
|
|
|
void gic_cpu_restore(struct gic_chip_data *gic);
|
|
|
|
void gic_dist_save(struct gic_chip_data *gic);
|
|
|
|
void gic_dist_restore(struct gic_chip_data *gic);
|
2011-07-16 08:49:47 +07:00
|
|
|
|
2015-10-24 05:15:52 +07:00
|
|
|
/*
|
|
|
|
* Subdrivers that need some preparatory work can initialize their
|
|
|
|
* chips and call this to register their GICs.
|
|
|
|
*/
|
|
|
|
int gic_of_init(struct device_node *node, struct device_node *parent);
|
|
|
|
|
irqchip/gic: Add platform driver for non-root GICs that require RPM
Add a platform driver to support non-root GICs that require runtime
power-management. Currently, only non-root GICs are supported because
the functions, smp_cross_call() and set_handle_irq(), that need to
be called for a root controller are located in the __init section and
so cannot be called by the platform driver.
The GIC platform driver re-uses many functions from the existing GIC
driver including some functions to save and restore the GIC context
during power transitions. The functions for saving and restoring the
GIC context are currently only defined if CONFIG_CPU_PM is enabled and
to ensure that these functions are always defined when the platform
driver is enabled, a dependency on CONFIG_ARM_GIC_PM (which selects the
platform driver) has been added.
In order to re-use the private GIC initialisation code, a new public
function, gic_of_init_child(), has been added which calls various
private functions to initialise the GIC. This is different from the
existing gic_of_init() because it only supports non-root GICs (ie. does
not call smp_cross_call() is set_handle_irq()) and is not located in
the __init section (so can be used by platform drivers). Furthermore,
gic_of_init_child() dynamically allocates memory for the GIC chip data
which is also different from gic_of_init().
There is no specific suspend handling for GICs registered as platform
devices. Non-wakeup interrupts will be disabled by the kernel during
late suspend, however, this alone will not power down the GIC if
interrupts have been requested and not freed. Therefore, requestors of
non-wakeup interrupts will need to free them on entering suspend in
order to power-down the GIC.
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2016-06-07 22:12:34 +07:00
|
|
|
/*
|
|
|
|
* Initialises and registers a non-root or child GIC chip. Memory for
|
|
|
|
* the gic_chip_data structure is dynamically allocated.
|
|
|
|
*/
|
|
|
|
int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq);
|
|
|
|
|
2015-10-24 05:15:52 +07:00
|
|
|
/*
|
|
|
|
* Legacy platforms not converted to DT yet must use this to init
|
|
|
|
* their GIC
|
|
|
|
*/
|
2015-10-13 18:51:39 +07:00
|
|
|
void gic_init(unsigned int nr, int start,
|
|
|
|
void __iomem *dist , void __iomem *cpu);
|
2011-11-12 23:09:49 +07:00
|
|
|
|
2015-12-10 23:55:30 +07:00
|
|
|
int gicv2m_init(struct fwnode_handle *parent_handle,
|
|
|
|
struct irq_domain *parent);
|
2014-11-26 01:47:22 +07:00
|
|
|
|
2012-11-29 06:48:19 +07:00
|
|
|
void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
|
2012-07-06 08:33:26 +07:00
|
|
|
int gic_get_cpu_id(unsigned int cpu);
|
2012-04-12 12:40:31 +07:00
|
|
|
void gic_migrate_target(unsigned int new_cpu_id);
|
2012-11-29 06:17:25 +07:00
|
|
|
unsigned long gic_get_sgir_physaddr(void);
|
2012-04-12 12:40:31 +07:00
|
|
|
|
2013-01-24 20:39:43 +07:00
|
|
|
#endif /* __ASSEMBLY */
|
2005-08-19 03:31:00 +07:00
|
|
|
#endif
|