hv: Bit Representation for IOAPIC RTE

As we enable Interrupt Remapping, bit positions in IOAPIC RTEs
have a different syntax for programming. ACRN should handle original
format for vIOAPIC as well IR representation for physical IOAPIC.
This patch adds bit granularity IOAPIC RTE.

Tracked-On: #2407
Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com>
This commit is contained in:
Sainath Grandhi 2019-01-26 01:33:02 -08:00 committed by wenlingz
parent 7d57eb056e
commit 6d5456a0df
8 changed files with 158 additions and 175 deletions

View File

@ -54,9 +54,9 @@ ptirq_lookup_entry_by_vpin(const struct acrn_vm *vm, uint32_t virt_pin, bool pic
return entry;
}
static uint64_t calculate_logical_dest_mask(uint64_t pdmask)
static uint32_t calculate_logical_dest_mask(uint64_t pdmask)
{
uint64_t dest_mask = 0UL;
uint32_t dest_mask = 0UL;
uint64_t pcpu_mask = pdmask;
uint16_t pcpu_id;
@ -72,8 +72,8 @@ static uint64_t calculate_logical_dest_mask(uint64_t pdmask)
static void ptirq_build_physical_msi(struct acrn_vm *vm, struct ptirq_msi_info *info,
uint32_t vector)
{
uint64_t vdmask, pdmask, dest_mask;
uint32_t dest, delmode;
uint64_t vdmask, pdmask;
uint32_t dest, delmode, dest_mask;
bool phys;
/* get physical destination cpu mask */
@ -114,8 +114,8 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
union source_id *virt_sid = &entry->virt_sid;
if (virt_sid->intx_id.src == PTDEV_VPIN_IOAPIC) {
uint64_t vdmask, pdmask, delmode, dest_mask, vector;
uint32_t dest;
uint64_t vdmask, pdmask;
uint32_t dest, delmode, dest_mask, vector;
union ioapic_rte virt_rte;
bool phys;
@ -123,7 +123,7 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
rte = virt_rte;
/* init polarity & pin state */
if ((rte.full & IOAPIC_RTE_INTPOL) != 0UL) {
if (rte.bits.intr_polarity == IOAPIC_RTE_INTPOL_ALO) {
if (entry->polarity == 0U) {
vioapic_set_irqline_nolock(vm, virt_sid->intx_id.pin, GSI_SET_HIGH);
}
@ -136,27 +136,27 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
}
/* physical destination cpu mask */
phys = ((virt_rte.full & IOAPIC_RTE_DESTMOD) == IOAPIC_RTE_DESTPHY);
dest = (uint32_t)(virt_rte.full >> IOAPIC_RTE_DEST_SHIFT);
phys = (virt_rte.bits.dest_mode == IOAPIC_RTE_DESTMODE_PHY);
dest = (uint32_t)virt_rte.bits.dest_field;
vlapic_calcdest(vm, &vdmask, dest, phys, false);
pdmask = vcpumask2pcpumask(vm, vdmask);
/* physical delivery mode */
delmode = virt_rte.full & IOAPIC_RTE_DELMOD;
if ((delmode != IOAPIC_RTE_DELFIXED) &&
(delmode != IOAPIC_RTE_DELLOPRI)) {
delmode = IOAPIC_RTE_DELLOPRI;
delmode = virt_rte.bits.delivery_mode;
if ((delmode != IOAPIC_RTE_DELMODE_FIXED) &&
(delmode != IOAPIC_RTE_DELMODE_LOPRI)) {
delmode = IOAPIC_RTE_DELMODE_LOPRI;
}
/* update physical delivery mode, dest mode(logical) & vector */
vector = (uint64_t)irq_to_vector(phys_irq);
rte.full &= ~(IOAPIC_RTE_DESTMOD | IOAPIC_RTE_DELMOD | IOAPIC_RTE_INTVEC);
rte.full |= IOAPIC_RTE_DESTLOG | delmode | vector;
vector = irq_to_vector(phys_irq);
rte.bits.dest_mode = IOAPIC_RTE_DESTMODE_LOGICAL;
rte.bits.delivery_mode = delmode;
rte.bits.vector = vector;
dest_mask = calculate_logical_dest_mask(pdmask);
/* update physical dest field */
rte.full &= ~IOAPIC_RTE_DEST_MASK;
rte.full |= dest_mask << IOAPIC_RTE_DEST_SHIFT;
rte.bits.dest_field = dest_mask;
dev_dbg(ACRN_DBG_IRQ, "IOAPIC RTE = 0x%x:%x(V) -> 0x%x:%x(P)",
virt_rte.u.hi_32, virt_rte.u.lo_32,
@ -167,10 +167,11 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
/* just update trigger mode */
ioapic_get_rte(phys_irq, &phys_rte);
rte.full = phys_rte.full & (~IOAPIC_RTE_TRGRMOD);
vpic_get_irqline_trigger_mode(vm, virt_sid->intx_id.pin, &trigger);
rte = phys_rte;
rte.bits.trigger_mode = IOAPIC_RTE_TRGRMODE_EDGE;
vpic_get_irqline_trigger_mode(vm, (uint32_t)virt_sid->intx_id.pin, &trigger);
if (trigger == LEVEL_TRIGGER) {
rte.full |= IOAPIC_RTE_TRGRLVL;
rte.bits.trigger_mode = IOAPIC_RTE_TRGRMODE_LEVEL;
}
dev_dbg(ACRN_DBG_IRQ, "IOAPIC RTE = 0x%x:%x(P) -> 0x%x:%x(P)",
@ -367,8 +368,8 @@ static void ptirq_handle_intx(struct acrn_vm *vm,
bool trigger_lvl = false;
/* VPIN_IOAPIC src means we have vioapic enabled */
vioapic_get_rte(vm, virt_sid->intx_id.pin, &rte);
if ((rte.full & IOAPIC_RTE_TRGRMOD) == IOAPIC_RTE_TRGRLVL) {
vioapic_get_rte(vm, (uint32_t)virt_sid->intx_id.pin, &rte);
if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) {
trigger_lvl = true;
}
@ -557,7 +558,7 @@ static void activate_physical_ioapic(struct acrn_vm *vm,
{
union ioapic_rte rte;
uint32_t phys_irq = entry->allocated_pirq;
uint32_t intr_mask;
uint64_t intr_mask;
bool is_lvl_trigger = false;
/* disable interrupt */
@ -565,19 +566,19 @@ static void activate_physical_ioapic(struct acrn_vm *vm,
/* build physical IOAPIC RTE */
rte = ptirq_build_physical_rte(vm, entry);
intr_mask = (uint32_t)(rte.full & IOAPIC_RTE_INTMASK);
intr_mask = rte.bits.intr_mask;
/* update irq trigger mode according to info in guest */
if ((rte.full & IOAPIC_RTE_TRGRMOD) == IOAPIC_RTE_TRGRLVL) {
if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) {
is_lvl_trigger = true;
}
set_irq_trigger_mode(phys_irq, is_lvl_trigger);
/* set rte entry when masked */
rte.full |= IOAPIC_RTE_INTMSET;
rte.bits.intr_mask = IOAPIC_RTE_MASK_SET;
ioapic_set_rte(phys_irq, rte);
if (intr_mask == IOAPIC_RTE_INTMCLR) {
if (intr_mask == IOAPIC_RTE_MASK_CLR) {
ioapic_gsi_unmask_irq(phys_irq);
}
}

View File

@ -1806,13 +1806,13 @@ vlapic_deliver_intr(struct acrn_vm *vm, bool level, uint32_t dest, bool phys,
uint64_t dmask;
struct acrn_vcpu *target_vcpu;
if ((delmode != IOAPIC_RTE_DELFIXED) &&
(delmode != IOAPIC_RTE_DELLOPRI) &&
(delmode != IOAPIC_RTE_DELEXINT)) {
if ((delmode != IOAPIC_RTE_DELMODE_FIXED) &&
(delmode != IOAPIC_RTE_DELMODE_LOPRI) &&
(delmode != IOAPIC_RTE_DELMODE_EXINT)) {
dev_dbg(ACRN_DBG_LAPIC,
"vlapic intr invalid delmode %#x", delmode);
} else {
lowprio = (delmode == IOAPIC_RTE_DELLOPRI) || rh;
lowprio = (delmode == IOAPIC_RTE_DELMODE_LOPRI) || rh;
/*
* We don't provide any virtual interrupt redirection hardware so
@ -1829,7 +1829,7 @@ vlapic_deliver_intr(struct acrn_vm *vm, bool level, uint32_t dest, bool phys,
/* only make request when vlapic enabled */
vlapic = vcpu_vlapic(target_vcpu);
if (vlapic_enabled(vlapic)) {
if (delmode == IOAPIC_RTE_DELEXINT) {
if (delmode == IOAPIC_RTE_DELMODE_EXINT) {
vcpu_inject_extint(target_vcpu);
} else {
vlapic_set_intr(target_vcpu, vec, level);

View File

@ -45,23 +45,23 @@ static const uint32_t legacy_irq_to_pin[NR_LEGACY_IRQ] = {
15U, /* IRQ15*/
};
static const uint64_t legacy_irq_trigger_mode[NR_LEGACY_IRQ] = {
IOAPIC_RTE_TRGREDG, /* IRQ0*/
IOAPIC_RTE_TRGREDG, /* IRQ1*/
IOAPIC_RTE_TRGREDG, /* IRQ2*/
IOAPIC_RTE_TRGREDG, /* IRQ3*/
IOAPIC_RTE_TRGREDG, /* IRQ4*/
IOAPIC_RTE_TRGREDG, /* IRQ5*/
IOAPIC_RTE_TRGREDG, /* IRQ6*/
IOAPIC_RTE_TRGREDG, /* IRQ7*/
IOAPIC_RTE_TRGREDG, /* IRQ8*/
IOAPIC_RTE_TRGRLVL, /* IRQ9*/
IOAPIC_RTE_TRGREDG, /* IRQ10*/
IOAPIC_RTE_TRGREDG, /* IRQ11*/
IOAPIC_RTE_TRGREDG, /* IRQ12*/
IOAPIC_RTE_TRGREDG, /* IRQ13*/
IOAPIC_RTE_TRGREDG, /* IRQ14*/
IOAPIC_RTE_TRGREDG, /* IRQ15*/
static const uint32_t legacy_irq_trigger_mode[NR_LEGACY_IRQ] = {
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ0*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ1*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ2*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ3*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ4*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ5*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ6*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ7*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ8*/
IOAPIC_RTE_TRGRMODE_LEVEL, /* IRQ9*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ10*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ11*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ12*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ13*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ14*/
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ15*/
};
static const uint32_t pic_ioapic_pin_map[NR_LEGACY_PIN] = {
@ -184,17 +184,18 @@ create_rte_for_legacy_irq(uint32_t irq, uint32_t vr)
* before we have ACPI table parsing in HV we use common hardcode
*/
rte.full = IOAPIC_RTE_INTMSET;
rte.full |= legacy_irq_trigger_mode[irq];
rte.full |= DEFAULT_DEST_MODE;
rte.full |= DEFAULT_DELIVERY_MODE;
rte.full |= (IOAPIC_RTE_INTVEC & (uint64_t)vr);
rte.full = 0UL;
rte.bits.intr_mask = IOAPIC_RTE_MASK_SET;
rte.bits.trigger_mode = legacy_irq_trigger_mode[irq];
rte.bits.dest_mode = DEFAULT_DEST_MODE;
rte.bits.delivery_mode = DEFAULT_DELIVERY_MODE;
rte.bits.vector = vr;
/* Fixed to active high */
rte.full |= IOAPIC_RTE_INTAHI;
rte.bits.intr_polarity = IOAPIC_RTE_INTPOL_AHI;
/* Dest field: legacy irq fixed to CPU0 */
rte.full |= (1UL << IOAPIC_RTE_DEST_SHIFT);
rte.bits.dest_field = 1U;
return rte;
}
@ -204,21 +205,23 @@ create_rte_for_gsi_irq(uint32_t irq, uint32_t vr)
{
union ioapic_rte rte;
rte.full = 0UL;
if (irq < NR_LEGACY_IRQ) {
rte = create_rte_for_legacy_irq(irq, vr);
} else {
/* irq default masked, level trig */
rte.full = IOAPIC_RTE_INTMSET;
rte.full |= IOAPIC_RTE_TRGRLVL;
rte.full |= DEFAULT_DEST_MODE;
rte.full |= DEFAULT_DELIVERY_MODE;
rte.full |= (IOAPIC_RTE_INTVEC & (uint64_t)vr);
rte.bits.intr_mask = IOAPIC_RTE_MASK_SET;
rte.bits.trigger_mode = IOAPIC_RTE_TRGRMODE_LEVEL;
rte.bits.dest_mode = DEFAULT_DEST_MODE;
rte.bits.delivery_mode = DEFAULT_DELIVERY_MODE;
rte.bits.vector = vr;
/* Fixed to active high */
rte.full |= IOAPIC_RTE_INTAHI;
rte.bits.intr_polarity = IOAPIC_RTE_INTPOL_AHI;
/* Dest field */
rte.full |= (ALL_CPUS_MASK << IOAPIC_RTE_DEST_SHIFT);
rte.bits.dest_field = ALL_CPUS_MASK;
}
return rte;
@ -233,7 +236,7 @@ static void ioapic_set_routing(uint32_t gsi, uint32_t vr)
rte = create_rte_for_gsi_irq(gsi, vr);
ioapic_set_rte_entry(addr, gsi_table_data[gsi].pin, rte);
if ((rte.full & IOAPIC_RTE_TRGRMOD) != 0UL) {
if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) {
set_irq_trigger_mode(gsi, true);
} else {
set_irq_trigger_mode(gsi, false);
@ -322,9 +325,9 @@ ioapic_irq_gsi_mask_unmask(uint32_t irq, bool mask)
if (addr != NULL) {
ioapic_get_rte_entry(addr, pin, &rte);
if (mask) {
rte.full |= IOAPIC_RTE_INTMSET;
rte.bits.intr_mask = IOAPIC_RTE_MASK_SET;
} else {
rte.full &= ~IOAPIC_RTE_INTMASK;
rte.bits.intr_mask = IOAPIC_RTE_MASK_CLR;
}
ioapic_set_rte_entry(addr, pin, rte);
dev_dbg(ACRN_DBG_PTIRQ, "update: irq:%d pin:%hhu rte:%lx",

View File

@ -927,8 +927,8 @@ static void get_entry_info(const struct ptirq_remapping_info *entry, char *type,
(void)strncpy_s(type, 16U, "PIC", 16U);
}
ioapic_get_rte(phys_irq, &rte);
*dest = rte.full >> IOAPIC_RTE_DEST_SHIFT;
if ((rte.full & IOAPIC_RTE_TRGRLVL) != 0UL) {
*dest = rte.bits.dest_field;
if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) {
*lvl_tm = true;
} else {
*lvl_tm = false;
@ -1047,13 +1047,13 @@ static void get_vioapic_info(char *str_arg, size_t str_max, uint16_t vmid)
rte.full = 0UL;
for (pin = 0U; pin < pincount; pin++) {
vioapic_get_rte(vm, pin, &rte);
mask = ((rte.full & IOAPIC_RTE_INTMASK) == IOAPIC_RTE_INTMSET);
remote_irr = ((rte.full & IOAPIC_RTE_REM_IRR) == IOAPIC_RTE_REM_IRR);
phys = ((rte.full & IOAPIC_RTE_DESTMOD) == IOAPIC_RTE_DESTPHY);
delmode = (uint32_t)(rte.full & IOAPIC_RTE_DELMOD);
level = ((rte.full & IOAPIC_RTE_TRGRLVL) != 0UL);
vector = rte.u.lo_32 & IOAPIC_RTE_LOW_INTVEC;
dest = (uint32_t)(rte.full >> IOAPIC_RTE_DEST_SHIFT);
mask = (rte.bits.intr_mask == IOAPIC_RTE_MASK_SET);
remote_irr = (rte.bits.remote_irr == IOAPIC_RTE_REM_IRR);
phys = (rte.bits.dest_mode == IOAPIC_RTE_DESTMODE_PHY);
delmode = rte.bits.delivery_mode;
level = (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL);
vector = rte.bits.vector;
dest = rte.bits.dest_field;
len = snprintf(str, size, "\r\n%hhu\t0x%X\t%s\t0x%X\t%s\t%u\t%d\t%d",
pin, vector, phys ? "phys" : "logic", dest, level ? "level" : "edge",
@ -1092,18 +1092,6 @@ static int32_t shell_show_vioapic_info(int32_t argc, char **argv)
return -EINVAL;
}
static void get_rte_info(union ioapic_rte rte, bool *mask, bool *irr,
bool *phys, uint32_t *delmode, bool *level, uint32_t *vector, uint32_t *dest)
{
*mask = ((rte.full & IOAPIC_RTE_INTMASK) == IOAPIC_RTE_INTMSET);
*irr = ((rte.full & IOAPIC_RTE_REM_IRR) == IOAPIC_RTE_REM_IRR);
*phys = ((rte.full & IOAPIC_RTE_DESTMOD) == IOAPIC_RTE_DESTPHY);
*delmode = (uint32_t)(rte.full & IOAPIC_RTE_DELMOD);
*level = ((rte.full & IOAPIC_RTE_TRGRLVL) != 0UL);
*vector = (uint32_t)(rte.full & IOAPIC_RTE_INTVEC);
*dest = (uint32_t)(rte.full >> APIC_ID_SHIFT);
}
/**
* @brief Get information of ioapic
*
@ -1133,9 +1121,6 @@ static int32_t get_ioapic_info(char *str_arg, size_t str_max_len)
uint32_t pin = ioapic_irq_to_pin(irq);
union ioapic_rte rte;
bool irr, phys, level, mask;
uint32_t delmode, vector, dest;
/* Add NULL check for addr, INVALID_PIN check for pin */
if ((addr == NULL) || (!ioapic_is_pin_valid(pin))) {
goto overflow;
@ -1143,8 +1128,6 @@ static int32_t get_ioapic_info(char *str_arg, size_t str_max_len)
ioapic_get_rte_entry(addr, pin, &rte);
get_rte_info(rte, &mask, &irr, &phys, &delmode, &level, &vector, &dest);
len = snprintf(str, size, "\r\n%03d\t%03hhu\t0x%08X\t0x%08X\t", irq, pin, rte.u.hi_32, rte.u.lo_32);
if (len >= size) {
goto overflow;
@ -1153,7 +1136,9 @@ static int32_t get_ioapic_info(char *str_arg, size_t str_max_len)
str += len;
len = snprintf(str, size, "0x%02X\t0x%02X\t%s\t%s\t%u\t%d\t%d",
vector, dest, phys ? "phys" : "logic", level ? "level" : "edge", delmode >> 8, irr, mask);
rte.bits.vector, rte.bits.dest_field, rte.bits.dest_mode ? "logic" : "phys",
rte.bits.trigger_mode ? "level" : "edge", rte.bits.delivery_mode, rte.bits.remote_irr,
rte.bits.intr_mask);
if (len >= size) {
goto overflow;
}

View File

@ -143,7 +143,7 @@ static void vuart_toggle_intr(const struct acrn_vuart *vu)
* modify the vioapic setting, as it's only for debug uart,
* we want to make it as an known issue.
*/
if ((rte.full & IOAPIC_RTE_INTPOL) != 0UL) {
if (rte.bits.intr_polarity == IOAPIC_RTE_INTPOL_ALO) {
operation = (intr_reason != IIR_NOPEND) ? GSI_SET_LOW : GSI_SET_HIGH;
} else {
operation = (intr_reason != IIR_NOPEND) ? GSI_SET_HIGH : GSI_SET_LOW;

View File

@ -32,8 +32,7 @@
#include <hypervisor.h>
#define RTBL_RO_BITS (uint32_t)(IOAPIC_RTE_REM_IRR | IOAPIC_RTE_DELIVS)
#define NEED_EOI_EXIT_UPDATE (IOAPIC_RTE_TRGRMOD | IOAPIC_RTE_DELMOD | IOAPIC_RTE_DEST_MASK | IOAPIC_RTE_INTVEC)
#define RTBL_RO_BITS ((uint32_t)0x00004000U | (uint32_t)0x00001000U) /*Remote IRR and Delivery Status bits*/
#define ACRN_DBG_IOAPIC 6U
#define ACRN_IOAPIC_VERSION 0x11U
@ -53,22 +52,22 @@ vioapic_generate_intr(struct acrn_vioapic *vioapic, uint32_t pin)
rte = vioapic->rtbl[pin];
if ((rte.full & IOAPIC_RTE_INTMASK) == IOAPIC_RTE_INTMSET) {
if (rte.bits.intr_mask == IOAPIC_RTE_MASK_SET) {
dev_dbg(ACRN_DBG_IOAPIC, "ioapic pin%hhu: masked", pin);
} else {
phys = ((rte.full & IOAPIC_RTE_DESTMOD) == IOAPIC_RTE_DESTPHY);
delmode = (uint32_t)(rte.full & IOAPIC_RTE_DELMOD);
level = ((rte.full & IOAPIC_RTE_TRGRLVL) != 0UL);
phys = (rte.bits.dest_mode == IOAPIC_RTE_DESTMODE_PHY);
delmode = rte.bits.delivery_mode;
level = (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL);
/* For level trigger irq, avoid send intr if
* previous one hasn't received EOI
*/
if (!level || ((vioapic->rtbl[pin].full & IOAPIC_RTE_REM_IRR) == 0UL)) {
if (!level || (vioapic->rtbl[pin].bits.remote_irr == 0UL)) {
if (level) {
vioapic->rtbl[pin].full |= IOAPIC_RTE_REM_IRR;
vioapic->rtbl[pin].bits.remote_irr = IOAPIC_RTE_REM_IRR;
}
vector = rte.u.lo_32 & IOAPIC_RTE_LOW_INTVEC;
dest = (uint32_t)(rte.full >> IOAPIC_RTE_DEST_SHIFT);
vector = rte.bits.vector;
dest = rte.bits.dest_field;
vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector, false);
}
}
@ -89,14 +88,14 @@ vioapic_set_pinstate(struct acrn_vioapic *vioapic, uint32_t pin, uint32_t level)
if (level == 0U) {
/* clear pin_state and deliver interrupt according to polarity */
bitmap_clear_nolock((uint16_t)(pin & 0x3FU), &vioapic->pin_state[pin >> 6U]);
if (((rte.full & IOAPIC_RTE_INTPOL) != 0UL)
if ((rte.bits.intr_polarity == IOAPIC_RTE_INTPOL_ALO)
&& old_lvl != level) {
vioapic_generate_intr(vioapic, pin);
}
} else {
/* set pin_state and deliver intrrupt according to polarity */
bitmap_set_nolock((uint16_t)(pin & 0x3FU), &vioapic->pin_state[pin >> 6U]);
if (((rte.full & IOAPIC_RTE_INTPOL) == 0UL)
if ((rte.bits.intr_polarity == IOAPIC_RTE_INTPOL_AHI)
&& old_lvl != level) {
vioapic_generate_intr(vioapic, pin);
}
@ -200,19 +199,19 @@ vioapic_update_eoi_exit(const struct acrn_vioapic *vioapic)
for (pin = 0U; pin < pincount; pin++) {
rte = vioapic->rtbl[pin];
level = ((rte.full & IOAPIC_RTE_TRGRLVL) != 0UL);
vector = rte.u.lo_32 & IOAPIC_RTE_LOW_INTVEC;
level = (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL);
vector = rte.bits.vector;
if (level && ((vector >= 0x20U) && (vector < NR_MAX_VECTOR))) {
/* if level-trigger and vector is valid */
delmode = (uint32_t)(rte.full & IOAPIC_RTE_DELMOD);
delmode = (uint32_t)rte.bits.delivery_mode;
if ((delmode != APIC_DELMODE_FIXED) && (delmode != APIC_DELMODE_LOWPRIO)) {
if ((delmode != IOAPIC_RTE_DELMODE_FIXED) && (delmode != IOAPIC_RTE_DELMODE_LOPRI)) {
dev_dbg(ACRN_DBG_IOAPIC,
"Ignoring level trigger-mode for delivery-mode 0x%x", delmode);
} else {
dest = (uint32_t)((rte.full) >> IOAPIC_RTE_DEST_SHIFT);
phys = ((rte.full & IOAPIC_RTE_DESTLOG) == 0UL);
dest = (uint32_t)rte.bits.dest_field;
phys = (rte.bits.dest_mode == IOAPIC_RTE_DESTMODE_PHY);
vlapic_calcdest(vioapic->vm, &mask, dest, phys, false);
for (vcpu_id = ffs64(mask); vcpu_id != INVALID_BIT_INDEX; vcpu_id = ffs64(mask)) {
@ -285,8 +284,8 @@ static inline bool vioapic_need_intr(const struct acrn_vioapic *vioapic, uint16_
} else {
rte = vioapic->rtbl[pin];
lvl = (uint32_t)bitmap_test(pin & 0x3FU, &vioapic->pin_state[pin >> 6U]);
ret = !!((((rte.full & IOAPIC_RTE_INTPOL) != 0UL) && lvl == 0U) ||
(((rte.full & IOAPIC_RTE_INTPOL) == 0UL) && lvl != 0U));
ret = !!(((rte.bits.intr_polarity == IOAPIC_RTE_INTPOL_ALO) && lvl == 0U) ||
((rte.bits.intr_polarity == IOAPIC_RTE_INTPOL_AHI) && lvl != 0U));
}
return ret;
@ -298,8 +297,7 @@ static inline bool vioapic_need_intr(const struct acrn_vioapic *vioapic, uint16_
*/
static void vioapic_indirect_write(struct acrn_vioapic *vioapic, uint32_t addr, uint32_t data)
{
union ioapic_rte last, new;
uint64_t changed;
union ioapic_rte last, new, changed;
uint32_t regnum;
uint32_t pin, pincount = vioapic_pincount(vioapic->vm);
@ -344,15 +342,15 @@ static void vioapic_indirect_write(struct acrn_vioapic *vioapic, uint32_t addr,
* 0x20 version IOAPIC, otherwise use switch Trigger Mode to
* Edge Sensitive to clear it.
*/
if ((new.full & IOAPIC_RTE_TRGRLVL) == 0U) {
new.full &= ~IOAPIC_RTE_REM_IRR;
if (new.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_EDGE) {
new.bits.remote_irr = 0U;
}
changed = last.full ^ new.full;
changed.full = last.full ^ new.full;
/* pin0 from vpic mask/unmask */
if ((pin == 0U) && ((changed & IOAPIC_RTE_INTMASK) != 0UL)) {
if ((pin == 0U) && (changed.bits.intr_mask != 0UL)) {
/* mask -> umask */
if ((last.full & IOAPIC_RTE_INTMASK) != 0UL) {
if (last.bits.intr_mask == IOAPIC_RTE_MASK_SET) {
if ((vioapic->vm->wire_mode == VPIC_WIRE_NULL) ||
(vioapic->vm->wire_mode == VPIC_WIRE_INTR)) {
vioapic->vm->wire_mode = VPIC_WIRE_IOAPIC;
@ -380,7 +378,8 @@ static void vioapic_indirect_write(struct acrn_vioapic *vioapic, uint32_t addr,
* rendezvous all the vcpus to update their vlapic
* trigger-mode registers.
*/
if ((changed & NEED_EOI_EXIT_UPDATE) != 0UL) {
if ((changed.bits.vector != 0UL) || (changed.bits.delivery_mode != 0UL)
|| (changed.bits.trigger_mode != 0UL) || (changed.bits.dest_field != 0UL)) {
dev_dbg(ACRN_DBG_IOAPIC, "ioapic pin%hhu: recalculate vlapic trigger-mode reg", pin);
vioapic_update_eoi_exit(vioapic);
}
@ -391,15 +390,15 @@ static void vioapic_indirect_write(struct acrn_vioapic *vioapic, uint32_t addr,
* - previous interrupt has been EOIed
* - pin level is asserted
*/
if (((vioapic->rtbl[pin].full & IOAPIC_RTE_INTMASK) == IOAPIC_RTE_INTMCLR) &&
((vioapic->rtbl[pin].full & IOAPIC_RTE_REM_IRR) == 0UL) &&
if ((vioapic->rtbl[pin].bits.intr_mask == IOAPIC_RTE_MASK_CLR) &&
(vioapic->rtbl[pin].bits.remote_irr == 0UL) &&
vioapic_need_intr(vioapic, (uint16_t)pin)) {
dev_dbg(ACRN_DBG_IOAPIC, "ioapic pin%hhu: asserted at rtbl write", pin);
vioapic_generate_intr(vioapic, pin);
}
/* remap for ptdev */
if (((new.full & IOAPIC_RTE_INTMASK) == 0UL) || ((last.full & IOAPIC_RTE_INTMASK) == 0UL)) {
if ((new.bits.intr_mask == IOAPIC_RTE_MASK_CLR) || (last.bits.intr_mask == IOAPIC_RTE_MASK_CLR)) {
/* VM enable intr */
/* NOTE: only support max 256 pin */
(void)ptirq_intx_pin_remap(vioapic->vm, pin, PTDEV_VPIN_IOAPIC);
@ -465,8 +464,8 @@ vioapic_process_eoi(struct acrn_vm *vm, uint32_t vector)
/* notify device to ack if assigned pin */
for (pin = 0U; pin < pincount; pin++) {
rte = vioapic->rtbl[pin];
if (((rte.u.lo_32 & IOAPIC_RTE_LOW_INTVEC) != vector) ||
((rte.full & IOAPIC_RTE_REM_IRR) == 0UL)) {
if ((rte.bits.vector != vector) ||
(rte.bits.remote_irr == 0U)) {
continue;
}
@ -480,12 +479,12 @@ vioapic_process_eoi(struct acrn_vm *vm, uint32_t vector)
spinlock_obtain(&(vioapic->mtx));
for (pin = 0U; pin < pincount; pin++) {
rte = vioapic->rtbl[pin];
if (((rte.u.lo_32 & IOAPIC_RTE_LOW_INTVEC) != vector) ||
((rte.full & IOAPIC_RTE_REM_IRR) == 0UL)) {
if ((rte.bits.vector != vector) ||
(rte.bits.remote_irr == 0U)) {
continue;
}
vioapic->rtbl[pin].full &= (~IOAPIC_RTE_REM_IRR);
vioapic->rtbl[pin].bits.remote_irr = 0U;
if (vioapic_need_intr(vioapic, (uint16_t)pin)) {
dev_dbg(ACRN_DBG_IOAPIC,
"ioapic pin%hhu: asserted at eoi", pin);

View File

@ -166,6 +166,30 @@ struct ioapic {
uint32_t rsv1[3];
};
/*
* Macros for bits in union ioapic_rte
*/
#define IOAPIC_RTE_MASK_CLR 0x0U /* Interrupt Mask: Clear */
#define IOAPIC_RTE_MASK_SET 0x1U /* Interrupt Mask: Set */
#define IOAPIC_RTE_TRGRMODE_EDGE 0x0U /* Trigger Mode: Edge */
#define IOAPIC_RTE_TRGRMODE_LEVEL 0x1U /* Trigger Mode: Level */
#define IOAPIC_RTE_REM_IRR 0x1U /* Remote IRR: Read-Only */
#define IOAPIC_RTE_INTPOL_AHI 0x0U /* Interrupt Polarity: active high */
#define IOAPIC_RTE_INTPOL_ALO 0x1U /* Interrupt Polarity: active low */
#define IOAPIC_RTE_DELIVS 0x1U /* Delivery Status: Read-Only */
#define IOAPIC_RTE_DESTMODE_PHY 0x0U /* Destination Mode: Physical */
#define IOAPIC_RTE_DESTMODE_LOGICAL 0x1U /* Destination Mode: Logical */
#define IOAPIC_RTE_DELMODE_FIXED 0x0U /* Delivery Mode: Fixed */
#define IOAPIC_RTE_DELMODE_LOPRI 0x1U /* Delivery Mode: Lowest priority */
#define IOAPIC_RTE_DELMODE_INIT 0x5U /* Delivery Mode: INIT signal */
#define IOAPIC_RTE_DELMODE_EXINT 0x7U /* Delivery Mode: External INTerrupt */
/* IOAPIC Redirection Table (RTE) Entry structure */
union ioapic_rte {
uint64_t full;
@ -173,6 +197,18 @@ union ioapic_rte {
uint32_t lo_32;
uint32_t hi_32;
} u;
struct {
uint64_t vector:8;
uint64_t delivery_mode:3;
uint64_t dest_mode:1;
uint64_t delivery_status:1;
uint64_t intr_polarity:1;
uint64_t remote_irr:1;
uint64_t trigger_mode:1;
uint64_t intr_mask:1;
uint64_t rsvd_1:39;
uint64_t dest_field:8;
} bits __packed;
};
/******************************************************************************
@ -390,45 +426,4 @@ union ioapic_rte {
#define IOAPIC_MAX_RTE_MASK 0x00ff0000U
#define MAX_RTE_SHIFT 16U
/*
* fields in the IO APIC's redirection table entries
*/
#define IOAPIC_RTE_DEST_SHIFT 56U
/* broadcast addr: all APICs */
#define IOAPIC_RTE_DEST_MASK 0xff00000000000000UL
#define IOAPIC_RTE_RESV 0x00fe0000UL /* reserved */
#define IOAPIC_RTE_INTMASK 0x00010000UL /* R/W: INTerrupt mask */
#define IOAPIC_RTE_INTMCLR 0x00000000UL /* clear, allow INTs */
#define IOAPIC_RTE_INTMSET 0x00010000UL /* set, inhibit INTs */
#define IOAPIC_RTE_TRGRMOD 0x00008000UL /* R/W: trigger mode */
#define IOAPIC_RTE_TRGREDG 0x00000000UL /* edge */
#define IOAPIC_RTE_TRGRLVL 0x00008000UL /* level */
#define IOAPIC_RTE_REM_IRR 0x00004000UL /* RO: remote IRR */
#define IOAPIC_RTE_INTPOL 0x00002000UL /*R/W:INT input pin polarity*/
#define IOAPIC_RTE_INTAHI 0x00000000UL /* active high */
#define IOAPIC_RTE_INTALO 0x00002000UL /* active low */
#define IOAPIC_RTE_DELIVS 0x00001000UL /* RO: delivery status */
#define IOAPIC_RTE_DESTMOD 0x00000800UL /*R/W:destination mode*/
#define IOAPIC_RTE_DESTPHY 0x00000000UL /* physical */
#define IOAPIC_RTE_DESTLOG 0x00000800UL /* logical */
#define IOAPIC_RTE_DELMOD 0x00000700UL /* R/W: delivery mode */
#define IOAPIC_RTE_DELFIXED 0x00000000UL /* fixed */
#define IOAPIC_RTE_DELLOPRI 0x00000100UL /* lowest priority */
#define IOAPIC_RTE_DELSMI 0x00000200UL /*System Management INT*/
#define IOAPIC_RTE_DELRSV1 0x00000300UL /* reserved */
#define IOAPIC_RTE_DELNMI 0x00000400UL /* NMI signal */
#define IOAPIC_RTE_DELINIT 0x00000500UL /* INIT signal */
#define IOAPIC_RTE_DELRSV2 0x00000600UL /* reserved */
#define IOAPIC_RTE_DELEXINT 0x00000700UL /* External INTerrupt */
#define IOAPIC_RTE_INTVEC 0x000000ffUL /*R/W: INT vector field*/
#endif /* APICREG_H */

View File

@ -48,9 +48,9 @@
#define POSTED_INTR_NOTIFY_IRQ (NR_IRQS - 3U)
#define PMI_IRQ (NR_IRQS - 4U)
#define DEFAULT_DEST_MODE IOAPIC_RTE_DESTLOG
#define DEFAULT_DELIVERY_MODE IOAPIC_RTE_DELLOPRI
#define ALL_CPUS_MASK ((1UL << (uint64_t)get_pcpu_nums()) - 1UL)
#define DEFAULT_DEST_MODE IOAPIC_RTE_DESTMODE_LOGICAL
#define DEFAULT_DELIVERY_MODE IOAPIC_RTE_DELMODE_LOPRI
#define ALL_CPUS_MASK (uint32_t) (((uint32_t)1U << (uint32_t) get_pcpu_nums()) - (uint32_t)1U)
#define IRQ_ALLOC_BITMAP_SIZE INT_DIV_ROUNDUP(NR_IRQS, 64U)