[PATCH v3 13/13] virt: arm: support hip04 gic
Marc Zyngier
marc.zyngier at arm.com
Tue Apr 22 05:15:51 PDT 2014
On Fri, Apr 18 2014 at 7:05:56 am BST, Haojian Zhuang <haojian.zhuang at linaro.org> wrote:
> In HiP04 SoC, the address of GICH_APR & GICH_LR0 registers are different
> from ARM standard SoC. So add the support of HiP04 SoC in VGIC.
Please explain the differences in the commit message.
> Signed-off-by: Haojian Zhuang <haojian.zhuang at linaro.org>
> ---
> arch/arm/kvm/interrupts_head.S | 23 +++++++++++++++++++----
> include/linux/irqchip/arm-gic.h | 3 +++
> virt/kvm/arm/vgic.c | 10 ++++++++--
> 3 files changed, 30 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
> index 76af9302..13e4144 100644
> --- a/arch/arm/kvm/interrupts_head.S
> +++ b/arch/arm/kvm/interrupts_head.S
> @@ -419,7 +419,9 @@ vcpu .req r0 @ vcpu pointer always in r0
> ldr r7, [r2, #GICH_EISR1]
> ldr r8, [r2, #GICH_ELRSR0]
> ldr r9, [r2, #GICH_ELRSR1]
> - ldr r10, [r2, #GICH_APR]
> + ldr r10, =gich_apr
> + ldr r10, [r10]
> + ldr r10, [r2, r10]
>
> str r3, [r11, #VGIC_CPU_HCR]
> str r4, [r11, #VGIC_CPU_VMCR]
> @@ -435,7 +437,9 @@ vcpu .req r0 @ vcpu pointer always in r0
> str r5, [r2, #GICH_HCR]
>
> /* Save list registers */
> - add r2, r2, #GICH_LR0
> + ldr r10, =gich_lr0
> + ldr r10, [r10]
> + add r2, r2, r10
> add r3, r11, #VGIC_CPU_LR
> ldr r4, [r11, #VGIC_CPU_NR_LR]
> 1: ldr r6, [r2], #4
> @@ -469,10 +473,14 @@ vcpu .req r0 @ vcpu pointer always in r0
>
> str r3, [r2, #GICH_HCR]
> str r4, [r2, #GICH_VMCR]
> - str r8, [r2, #GICH_APR]
> + ldr r6, =gich_apr
> + ldr r6, [r6]
> + str r8, [r2, r6]
>
> /* Restore list registers */
> - add r2, r2, #GICH_LR0
> + ldr r6, =gich_lr0
> + ldr r6, [r6]
> + add r2, r2, r6
> add r3, r11, #VGIC_CPU_LR
> ldr r4, [r11, #VGIC_CPU_NR_LR]
> 1: ldr r6, [r3], #4
So we get four extra memory accesses per world switch, just to find out
about the new fancy memory map. Let's just say that I'm not exactly
pleased.
How about encoding that in the field containing the number of LRs? the
distance between GICH_APR and GICH_LR0 is constant (0x10), so we only
need to encode the offset of GICH_APR. This way, we only have to read
one single word from memory. Not pretty, but I'm not really willing to
impact
> @@ -618,3 +626,10 @@ vcpu .req r0 @ vcpu pointer always in r0
> .macro load_vcpu
> mrc p15, 4, vcpu, c13, c0, 2 @ HTPIDR
> .endm
> +
> + .global gich_apr
> +gich_apr:
> + .long GICH_APR
> + .global gich_lr0
> +gich_lr0:
> + .long GICH_LR0
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 55933aa..653525b 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -49,6 +49,8 @@
> #define GICH_ELRSR1 0x34
> #define GICH_APR 0xf0
> #define GICH_LR0 0x100
> +#define HIP04_GICH_APR 0x70
> +#define HIP04_GICH_LR0 0x80
>
> #define GICH_HCR_EN (1 << 0)
> #define GICH_HCR_UIE (1 << 1)
> @@ -78,6 +80,7 @@
> struct device_node;
>
> extern struct irq_chip gic_arch_extn;
> +extern unsigned int gich_apr, gich_lr0;
>
> void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
> u32 offset, struct device_node *);
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 47b2983..010e491 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -1478,8 +1478,14 @@ int kvm_vgic_hyp_init(void)
>
> vgic_node = of_find_compatible_node(NULL, NULL, "arm,cortex-a15-gic");
> if (!vgic_node) {
> - kvm_err("error: no compatible vgic node in DT\n");
> - return -ENODEV;
> + vgic_node = of_find_compatible_node(NULL, NULL,
> + "hisilicon,hip04-gic");
> + if (!vgic_node) {
> + kvm_err("error: no compatible vgic node in DT\n");
> + return -ENODEV;
> + }
> + gich_apr = HIP04_GICH_APR;
> + gich_lr0 = HIP04_GICH_LR0;
Consider using of_find_matching_node_and_match instead, with a set of
flags for this particular case.
> }
>
> vgic_maint_irq = irq_of_parse_and_map(vgic_node, 0);
Thanks,
M.
--
Jazz is not dead. It just smells funny.
More information about the linux-arm-kernel
mailing list