intc/arm_gic: Implement virtualization extensions in gic_(activate_irq|drop_prio)

Implement virtualization extensions in gic_activate_irq() and
gic_drop_prio() and in gic_get_prio_from_apr_bits() called by
gic_drop_prio().

When the current CPU is a vCPU:
  - Use GIC_VIRT_MIN_BPR and GIC_VIRT_NR_APRS instead of their non-virt
  counterparts,
  - the vCPU APR is stored in the virtual interface, in h_apr.

Signed-off-by: Luc Michel <luc.michel@greensocs.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20180727095421.386-11-luc.michel@greensocs.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Luc Michel 2018-08-14 17:17:20 +01:00 committed by Peter Maydell
parent 86b350f0d0
commit a1d7b8d896

View File

@ -276,16 +276,23 @@ static void gic_activate_irq(GICState *s, int cpu, int irq)
* and update the running priority.
*/
int prio = gic_get_group_priority(s, cpu, irq);
int preemption_level = prio >> (GIC_MIN_BPR + 1);
int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR;
int preemption_level = prio >> (min_bpr + 1);
int regno = preemption_level / 32;
int bitno = preemption_level % 32;
uint32_t *papr = NULL;
if (gic_has_groups(s) && gic_test_group(s, irq, cpu)) {
s->nsapr[regno][cpu] |= (1 << bitno);
if (gic_is_vcpu(cpu)) {
assert(regno == 0);
papr = &s->h_apr[gic_get_vcpu_real_id(cpu)];
} else if (gic_has_groups(s) && gic_test_group(s, irq, cpu)) {
papr = &s->nsapr[regno][cpu];
} else {
s->apr[regno][cpu] |= (1 << bitno);
papr = &s->apr[regno][cpu];
}
*papr |= (1 << bitno);
s->running_priority[cpu] = prio;
gic_set_active(s, irq, cpu);
}
@ -296,6 +303,16 @@ static int gic_get_prio_from_apr_bits(GICState *s, int cpu)
* on the set bits in the Active Priority Registers.
*/
int i;
if (gic_is_vcpu(cpu)) {
uint32_t apr = s->h_apr[gic_get_vcpu_real_id(cpu)];
if (apr) {
return ctz32(apr) << (GIC_VIRT_MIN_BPR + 1);
} else {
return 0x100;
}
}
for (i = 0; i < GIC_NR_APRS; i++) {
uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu];
if (!apr) {
@ -324,6 +341,14 @@ static void gic_drop_prio(GICState *s, int cpu, int group)
* running priority will be wrong, so interrupts that should preempt
* might not do so, and interrupts that should not preempt might do so.
*/
if (gic_is_vcpu(cpu)) {
int rcpu = gic_get_vcpu_real_id(cpu);
if (s->h_apr[rcpu]) {
/* Clear lowest set bit */
s->h_apr[rcpu] &= s->h_apr[rcpu] - 1;
}
} else {
int i;
for (i = 0; i < GIC_NR_APRS; i++) {
@ -335,6 +360,7 @@ static void gic_drop_prio(GICState *s, int cpu, int group)
*papr &= *papr - 1;
break;
}
}
s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu);
}