On 2017-09-14 15:09, Ralf Ramsauer wrote:
> Hi Jan,
> 
> I just accidentally came across commit 05c1d67e0a79 ("arm: Remove cpuid
> from pending_irq") from last year.
> 
> Seems like there already has been a preparation for the feature I'm now
> reintroducing. Can you remember why you removed the code instead of
> providing the correct CPU ID?

>From reading my own commit log, it seems I didn't care to fix the
preexisting code, given that every user since then was happy with the
nop version.

Jan

> 
>   Ralf
> 
> On 09/13/2017 04:29 PM, Ralf Ramsauer wrote:
>> When receiving an SGI on a GICv2 system, the receiving CPU expects the
>> caller's CPU ID in the IAR. Jailhouse did not forward the caller's CPU
>> ID, so cells might erroneously assume that the calling CPU is (always)
>> CPU0.
>>
>> GICv3+ doesn't support this feature.
>>
>> Let's fix this in two steps:
>>   - expand irqchip_set_pending() by a u16 caller parameter that is only
>>     respected in case of SGIs
>>   - change the data type of pending_irqs from u16 to u32 to be able to
>>     encode the calling interface in the upper bits
>>
>> Signed-off-by: Ralf Ramsauer <[email protected]>
>> ---
>>  hypervisor/arch/arm-common/control.c             |  2 +-
>>  hypervisor/arch/arm-common/gic-v2.c              |  4 +++-
>>  hypervisor/arch/arm-common/include/asm/irqchip.h |  4 ++--
>>  hypervisor/arch/arm-common/irqchip.c             | 22 ++++++++++++++--------
>>  hypervisor/arch/arm-common/ivshmem.c             |  2 +-
>>  hypervisor/arch/arm/gic-v3.c                     |  5 ++++-
>>  hypervisor/arch/arm/include/asm/percpu.h         |  4 +++-
>>  hypervisor/arch/arm64/include/asm/percpu.h       |  4 +++-
>>  8 files changed, 31 insertions(+), 16 deletions(-)
>>
>> diff --git a/hypervisor/arch/arm-common/control.c 
>> b/hypervisor/arch/arm-common/control.c
>> index 4d3abd25..8aa39028 100644
>> --- a/hypervisor/arch/arm-common/control.c
>> +++ b/hypervisor/arch/arm-common/control.c
>> @@ -188,7 +188,7 @@ bool arch_handle_phys_irq(struct per_cpu *cpu_data, u32 
>> irqn,
>>      }
>>  
>>      cpu_data->stats[JAILHOUSE_CPU_STAT_VMEXITS_VIRQ] += count_event;
>> -    irqchip_set_pending(cpu_data, irqn);
>> +    irqchip_set_pending(cpu_data, irqn, -1);
>>  
>>      return false;
>>  }
>> diff --git a/hypervisor/arch/arm-common/gic-v2.c 
>> b/hypervisor/arch/arm-common/gic-v2.c
>> index 1aec2a2f..7255cd50 100644
>> --- a/hypervisor/arch/arm-common/gic-v2.c
>> +++ b/hypervisor/arch/arm-common/gic-v2.c
>> @@ -265,7 +265,7 @@ static int gic_send_sgi(struct sgi *sgi)
>>      return 0;
>>  }
>>  
>> -static int gic_inject_irq(struct per_cpu *cpu_data, u16 irq_id)
>> +static int gic_inject_irq(struct per_cpu *cpu_data, u16 irq_id, u16 caller)
>>  {
>>      int i;
>>      int first_free = -1;
>> @@ -298,6 +298,8 @@ static int gic_inject_irq(struct per_cpu *cpu_data, u16 
>> irq_id)
>>      if (!is_sgi(irq_id)) {
>>              lr |= GICH_LR_HW_BIT;
>>              lr |= (u32)irq_id << GICH_LR_PHYS_ID_SHIFT;
>> +    } else {
>> +            lr |= (caller & 0x7) << GICH_LR_CPUID_SHIFT;
>>      }
>>  
>>      gic_write_lr(first_free, lr);
>> diff --git a/hypervisor/arch/arm-common/include/asm/irqchip.h 
>> b/hypervisor/arch/arm-common/include/asm/irqchip.h
>> index 7cf5d704..5a4a3705 100644
>> --- a/hypervisor/arch/arm-common/include/asm/irqchip.h
>> +++ b/hypervisor/arch/arm-common/include/asm/irqchip.h
>> @@ -48,7 +48,7 @@ struct irqchip {
>>      int     (*send_sgi)(struct sgi *sgi);
>>      u32     (*read_iar_irqn)(void);
>>      void    (*eoi_irq)(u32 irqn, bool deactivate);
>> -    int     (*inject_irq)(struct per_cpu *cpu_data, u16 irq_id);
>> +    int     (*inject_irq)(struct per_cpu *cpu_data, u16 irq_id, u16 caller);
>>      void    (*enable_maint_irq)(bool enable);
>>      bool    (*has_pending_irqs)(void);
>>  
>> @@ -85,7 +85,7 @@ void irqchip_handle_irq(struct per_cpu *cpu_data);
>>  bool irqchip_has_pending_irqs(void);
>>  
>>  void irqchip_inject_pending(struct per_cpu *cpu_data);
>> -void irqchip_set_pending(struct per_cpu *cpu_data, u16 irq_id);
>> +void irqchip_set_pending(struct per_cpu *cpu_data, u16 irq_id, u16 caller);
>>  
>>  bool irqchip_irq_in_cell(struct cell *cell, unsigned int irq_id);
>>  
>> diff --git a/hypervisor/arch/arm-common/irqchip.c 
>> b/hypervisor/arch/arm-common/irqchip.c
>> index f0f84c92..5e8e28ba 100644
>> --- a/hypervisor/arch/arm-common/irqchip.c
>> +++ b/hypervisor/arch/arm-common/irqchip.c
>> @@ -106,10 +106,11 @@ void gic_handle_sgir_write(struct sgi *sgi)
>>      struct per_cpu *cpu_data = this_cpu_data();
>>      unsigned int cpu, target;
>>      u64 cluster;
>> +    const u16 caller = cpu_data->cpu_id;
>>  
>>      if (sgi->routing_mode == 2)
>>              /* Route to the caller itself */
>> -            irqchip_set_pending(cpu_data, sgi->id);
>> +            irqchip_set_pending(cpu_data, sgi->id, caller);
>>      else
>>              for_each_cpu(cpu, cpu_data->cell->cpu_set) {
>>                      if (sgi->routing_mode == 1) {
>> @@ -126,7 +127,7 @@ void gic_handle_sgir_write(struct sgi *sgi)
>>                                      continue;
>>                      }
>>  
>> -                    irqchip_set_pending(per_cpu(cpu), sgi->id);
>> +                    irqchip_set_pending(per_cpu(cpu), sgi->id, caller);
>>              }
>>  }
>>  
>> @@ -220,7 +221,7 @@ bool irqchip_has_pending_irqs(void)
>>      return irqchip.has_pending_irqs();
>>  }
>>  
>> -void irqchip_set_pending(struct per_cpu *cpu_data, u16 irq_id)
>> +void irqchip_set_pending(struct per_cpu *cpu_data, u16 irq_id, u16 caller)
>>  {
>>      bool local_injection = (this_cpu_data() == cpu_data);
>>      unsigned int new_tail;
>> @@ -233,7 +234,8 @@ void irqchip_set_pending(struct per_cpu *cpu_data, u16 
>> irq_id)
>>              return;
>>      }
>>  
>> -    if (local_injection && irqchip.inject_irq(cpu_data, irq_id) != -EBUSY)
>> +    if (local_injection &&
>> +        irqchip.inject_irq(cpu_data, irq_id, caller) != -EBUSY)
>>              return;
>>  
>>      spin_lock(&cpu_data->pending_irqs_lock);
>> @@ -242,7 +244,8 @@ void irqchip_set_pending(struct per_cpu *cpu_data, u16 
>> irq_id)
>>  
>>      /* Queue space available? */
>>      if (new_tail != cpu_data->pending_irqs_head) {
>> -            cpu_data->pending_irqs[cpu_data->pending_irqs_tail] = irq_id;
>> +            cpu_data->pending_irqs[cpu_data->pending_irqs_tail] =
>> +                    irq_id | (caller << 16);
>>              cpu_data->pending_irqs_tail = new_tail;
>>              /*
>>               * Make the change to pending_irqs_tail visible before the
>> @@ -272,12 +275,15 @@ void irqchip_set_pending(struct per_cpu *cpu_data, u16 
>> irq_id)
>>  
>>  void irqchip_inject_pending(struct per_cpu *cpu_data)
>>  {
>> -    u16 irq_id;
>> +    u32 pending;
>> +    u16 irq_id, caller;
>>  
>>      while (cpu_data->pending_irqs_head != cpu_data->pending_irqs_tail) {
>> -            irq_id = cpu_data->pending_irqs[cpu_data->pending_irqs_head];
>> +            pending = cpu_data->pending_irqs[cpu_data->pending_irqs_head];
>> +            irq_id = pending & 0xffff;
>> +            caller = (pending >> 16) & 0xffff;
>>  
>> -            if (irqchip.inject_irq(cpu_data, irq_id) == -EBUSY) {
>> +            if (irqchip.inject_irq(cpu_data, irq_id, caller) == -EBUSY) {
>>                      /*
>>                       * The list registers are full, trigger maintenance
>>                       * interrupt and leave.
>> diff --git a/hypervisor/arch/arm-common/ivshmem.c 
>> b/hypervisor/arch/arm-common/ivshmem.c
>> index 19d300d3..79b8eaf3 100644
>> --- a/hypervisor/arch/arm-common/ivshmem.c
>> +++ b/hypervisor/arch/arm-common/ivshmem.c
>> @@ -18,7 +18,7 @@ void arch_ivshmem_trigger_interrupt(struct 
>> ivshmem_endpoint *ive)
>>      unsigned int irq_id = ive->arch.irq_id;
>>  
>>      if (irq_id)
>> -            irqchip_set_pending(NULL, irq_id);
>> +            irqchip_set_pending(NULL, irq_id, -1);
>>  }
>>  
>>  int arch_ivshmem_update_msix(struct pci_device *device)
>> diff --git a/hypervisor/arch/arm/gic-v3.c b/hypervisor/arch/arm/gic-v3.c
>> index 9052caee..a331bcbf 100644
>> --- a/hypervisor/arch/arm/gic-v3.c
>> +++ b/hypervisor/arch/arm/gic-v3.c
>> @@ -460,7 +460,7 @@ static void gic_eoi_irq(u32 irq_id, bool deactivate)
>>              arm_write_sysreg(ICC_DIR_EL1, irq_id);
>>  }
>>  
>> -static int gic_inject_irq(struct per_cpu *cpu_data, u16 irq_id)
>> +static int gic_inject_irq(struct per_cpu *cpu_data, u16 irq_id, u16 caller)
>>  {
>>      int i;
>>      int free_lr = -1;
>> @@ -501,6 +501,9 @@ static int gic_inject_irq(struct per_cpu *cpu_data, u16 
>> irq_id)
>>      if (!is_sgi(irq_id)) {
>>              lr |= ICH_LR_HW_BIT;
>>              lr |= (u64)irq_id << ICH_LR_PHYS_ID_SHIFT;
>> +    } else {
>> +            /* For GICv2, we save the calling CPU ID in the list register
>> +             * in case of SGIs. GICv3 doesn't support this feature. */
>>      }
>>  
>>      gic_write_lr(free_lr, lr);
>> diff --git a/hypervisor/arch/arm/include/asm/percpu.h 
>> b/hypervisor/arch/arm/include/asm/percpu.h
>> index 14cf3e13..6bf0a582 100644
>> --- a/hypervisor/arch/arm/include/asm/percpu.h
>> +++ b/hypervisor/arch/arm/include/asm/percpu.h
>> @@ -43,7 +43,9 @@ struct per_cpu {
>>  
>>      /* synchronizes parallel insertions of SGIs into the pending ring */
>>      spinlock_t pending_irqs_lock;
>> -    u16 pending_irqs[MAX_PENDING_IRQS];
>> +    /* first 16 bits are for irqn, bits 16- describe the calling cpu
>> +     * interface */
>> +    u32 pending_irqs[MAX_PENDING_IRQS];
>>      unsigned int pending_irqs_head;
>>      /* removal from the ring happens lockless, thus tail is volatile */
>>      volatile unsigned int pending_irqs_tail;
>> diff --git a/hypervisor/arch/arm64/include/asm/percpu.h 
>> b/hypervisor/arch/arm64/include/asm/percpu.h
>> index e0ffa234..a6938a94 100644
>> --- a/hypervisor/arch/arm64/include/asm/percpu.h
>> +++ b/hypervisor/arch/arm64/include/asm/percpu.h
>> @@ -37,7 +37,9 @@ struct per_cpu {
>>  
>>      /* synchronizes parallel insertions of SGIs into the pending ring */
>>      spinlock_t pending_irqs_lock;
>> -    u16 pending_irqs[MAX_PENDING_IRQS];
>> +    /* first 16 bits are for irqn, bits 16- describe the calling cpu
>> +     * interface */
>> +    u32 pending_irqs[MAX_PENDING_IRQS];
>>      unsigned int pending_irqs_head;
>>      /* removal from the ring happens lockless, thus tail is volatile */
>>      volatile unsigned int pending_irqs_tail;
>>


-- 
Siemens AG, Corporate Technology, CT RDA ITP SES-DE
Corporate Competence Center Embedded Linux

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to