[PATCH v3 13/13] virt: arm: support hip04 gic

Haojian Zhuang haojian.zhuang at linaro.org
Thu Apr 24 18:16:39 PDT 2014


On 22 April 2014 20:15, Marc Zyngier <marc.zyngier at arm.com> wrote:
> 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.
>
OK. I'll append it.

>> 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
>
Yes, it's better.

>
>> @@ -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.
>
OK. I'll use it.

Thanks
Haojian



More information about the linux-arm-kernel mailing list