mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-23 14:07:42 +00:00
hv: vlapic: remove ISR vector stack
The current implement will cache each ISR vector in ISR vector stack and do ISR vector stack check when updating PPR. However, there is no need to do this because: 1) We will not touch vlapic->isrvec_stk[0] except doing vlapic_reset: So we don't need to do vlapic->isrvec_stk[0] check. 2) We only deliver higher priority interrupt from IRR to ISR: So we don't need to check whether vlapic->isrvec_stk interrupts is always increasing. 3) There're only 15 different priority interrupt, It will not happened that more that 15 interrupts could been delivered to ISR: So we don't need to check whether vlapic->isrvec_stk_top will larger than ISRVEC_STK_SIZE which is 16. This patch try to remove ISR vector stack and use isrv to cache the vector number for the highest priority bit that is set in the ISR. Tracked-On: #1842 Signed-off-by: Li, Fei1 <fei1.li@intel.com>
This commit is contained in:
parent
31e23cd09c
commit
e793b5d091
@ -79,7 +79,7 @@ static inline void vlapic_dump_isr(const struct acrn_vlapic *vlapic, const char
|
|||||||
const struct lapic_reg *isrptr = &(vlapic->apic_page.isr[0]);
|
const struct lapic_reg *isrptr = &(vlapic->apic_page.isr[0]);
|
||||||
|
|
||||||
for (uint8_t i = 0U; i < 8U; i++) {
|
for (uint8_t i = 0U; i < 8U; i++) {
|
||||||
dev_dbg(ACRN_DBG_LAPIC, "%s isr%u 0x%08x", msg, i, isrptr[0].v);
|
dev_dbg(ACRN_DBG_LAPIC, "%s isr%u 0x%08x", msg, i, isrptr[i].v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -202,6 +202,27 @@ static inline void vlapic_build_x2apic_id(struct acrn_vlapic *vlapic)
|
|||||||
lapic->ldr.v = (cluster_id << 16U) | (1U << logical_id);
|
lapic->ldr.v = (cluster_id << 16U) | (1U << logical_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t vlapic_find_isrv(const struct acrn_vlapic *vlapic)
|
||||||
|
{
|
||||||
|
const struct lapic_regs *lapic = &(vlapic->apic_page);
|
||||||
|
uint32_t i, val, bitpos, isrv = 0U;
|
||||||
|
const struct lapic_reg *isrptr;
|
||||||
|
|
||||||
|
isrptr = &lapic->isr[0];
|
||||||
|
|
||||||
|
/* i ranges effectively from 7 to 1 */
|
||||||
|
for (i = 7U; i > 0U; i--) {
|
||||||
|
val = isrptr[i].v;
|
||||||
|
if (val != 0U) {
|
||||||
|
bitpos = (uint32_t)fls32(val);
|
||||||
|
isrv = (i << 5U) | bitpos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isrv;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vlapic_dfr_write_handler(struct acrn_vlapic *vlapic)
|
vlapic_dfr_write_handler(struct acrn_vlapic *vlapic)
|
||||||
{
|
{
|
||||||
@ -807,22 +828,6 @@ vlapic_fire_lvt(struct acrn_vlapic *vlapic, uint32_t lvt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
dump_isrvec_stk(const struct acrn_vlapic *vlapic)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
const struct lapic_reg *isrptr;
|
|
||||||
|
|
||||||
isrptr = &(vlapic->apic_page.isr[0]);
|
|
||||||
for (i = 0U; i < 8U; i++) {
|
|
||||||
printf("ISR%u 0x%08x\n", i, isrptr[i].v);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0U; i <= vlapic->isrvec_stk_top; i++) {
|
|
||||||
printf("isrvec_stk[%u] = %hhu\n", i, vlapic->isrvec_stk[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Algorithm adopted from section "Interrupt, Task and Processor Priority"
|
* Algorithm adopted from section "Interrupt, Task and Processor Priority"
|
||||||
* in Intel Architecture Manual Vol 3a.
|
* in Intel Architecture Manual Vol 3a.
|
||||||
@ -830,68 +835,15 @@ dump_isrvec_stk(const struct acrn_vlapic *vlapic)
|
|||||||
static void
|
static void
|
||||||
vlapic_update_ppr(struct acrn_vlapic *vlapic)
|
vlapic_update_ppr(struct acrn_vlapic *vlapic)
|
||||||
{
|
{
|
||||||
uint32_t top_isrvec;
|
uint32_t isrv, tpr, ppr;
|
||||||
uint32_t tpr, ppr;
|
|
||||||
|
|
||||||
/*
|
isrv = vlapic->isrv;
|
||||||
* Note that the value on the stack at index 0 is always 0.
|
|
||||||
*
|
|
||||||
* This is a placeholder for the value of ISRV when none of the
|
|
||||||
* bits is set in the ISRx registers.
|
|
||||||
*/
|
|
||||||
top_isrvec = (uint32_t)vlapic->isrvec_stk[vlapic->isrvec_stk_top];
|
|
||||||
tpr = vlapic->apic_page.tpr.v;
|
tpr = vlapic->apic_page.tpr.v;
|
||||||
|
|
||||||
/* update ppr */
|
if (prio(tpr) >= prio(isrv)) {
|
||||||
{
|
|
||||||
int32_t lastprio, curprio;
|
|
||||||
struct lapic_reg *isrptr;
|
|
||||||
uint32_t i, idx, vector;
|
|
||||||
uint32_t isrvec;
|
|
||||||
|
|
||||||
if ((vlapic->isrvec_stk_top == 0U) && (top_isrvec != 0U)) {
|
|
||||||
panic("isrvec_stk is corrupted: %u", top_isrvec);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure that the priority of the nested interrupts is
|
|
||||||
* always increasing.
|
|
||||||
*/
|
|
||||||
lastprio = -1;
|
|
||||||
for (i = 1U; i <= vlapic->isrvec_stk_top; i++) {
|
|
||||||
isrvec = (uint32_t)vlapic->isrvec_stk[i];
|
|
||||||
curprio = (int32_t)prio(isrvec);
|
|
||||||
if (curprio <= lastprio) {
|
|
||||||
dump_isrvec_stk(vlapic);
|
|
||||||
panic("isrvec_stk does not satisfy invariant");
|
|
||||||
}
|
|
||||||
lastprio = curprio;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure that each bit set in the ISRx registers has a
|
|
||||||
* corresponding entry on the isrvec stack.
|
|
||||||
*/
|
|
||||||
i = 1U;
|
|
||||||
isrptr = &(vlapic->apic_page.isr[0]);
|
|
||||||
for (vector = 0U; vector < 256U; vector++) {
|
|
||||||
idx = vector >> 5U;
|
|
||||||
if (((isrptr[idx].v & (1U << (vector & 0x1fU))) != 0U)
|
|
||||||
&& (i < ISRVEC_STK_SIZE)) {
|
|
||||||
isrvec = (uint32_t)vlapic->isrvec_stk[i];
|
|
||||||
if ((i > vlapic->isrvec_stk_top) || (isrvec != vector)) {
|
|
||||||
dump_isrvec_stk(vlapic);
|
|
||||||
panic("ISR and isrvec_stk out of sync");
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prio(tpr) >= prio(top_isrvec)) {
|
|
||||||
ppr = tpr;
|
ppr = tpr;
|
||||||
} else {
|
} else {
|
||||||
ppr = top_isrvec & 0xf0U;
|
ppr = isrv & 0xf0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
vlapic->apic_page.ppr.v = ppr;
|
vlapic->apic_page.ppr.v = ppr;
|
||||||
@ -908,27 +860,22 @@ vlapic_process_eoi(struct acrn_vlapic *vlapic)
|
|||||||
isrptr = &lapic->isr[0];
|
isrptr = &lapic->isr[0];
|
||||||
tmrptr = &lapic->tmr[0];
|
tmrptr = &lapic->tmr[0];
|
||||||
|
|
||||||
/* i ranges effectively from 7 to 0 */
|
if (vlapic->isrv != 0U) {
|
||||||
for (i = 8U; i > 0U; ) {
|
vector = vlapic->isrv;
|
||||||
i--;
|
i = (vector >> 5U);
|
||||||
bitpos = (uint32_t)fls32(isrptr[i].v);
|
bitpos = (vector & 0x1fU);
|
||||||
if (bitpos != INVALID_BIT_INDEX) {
|
|
||||||
if (vlapic->isrvec_stk_top == 0U) {
|
|
||||||
panic("invalid vlapic isrvec_stk_top %u",
|
|
||||||
vlapic->isrvec_stk_top);
|
|
||||||
}
|
|
||||||
isrptr[i].v &= ~(1U << bitpos);
|
isrptr[i].v &= ~(1U << bitpos);
|
||||||
vector = (i * 32U) + bitpos;
|
|
||||||
dev_dbg(ACRN_DBG_LAPIC, "EOI vector %u", vector);
|
dev_dbg(ACRN_DBG_LAPIC, "EOI vector %u", vector);
|
||||||
vlapic_dump_isr(vlapic, "vlapic_process_eoi");
|
vlapic_dump_isr(vlapic, "vlapic_process_eoi");
|
||||||
vlapic->isrvec_stk_top--;
|
|
||||||
|
vlapic->isrv = vlapic_find_isrv(vlapic);
|
||||||
vlapic_update_ppr(vlapic);
|
vlapic_update_ppr(vlapic);
|
||||||
|
|
||||||
if ((tmrptr[i].v & (1U << bitpos)) != 0U) {
|
if ((tmrptr[i].v & (1U << bitpos)) != 0U) {
|
||||||
/* hook to vIOAPIC */
|
/* hook to vIOAPIC */
|
||||||
vioapic_process_eoi(vlapic->vm, vector);
|
vioapic_process_eoi(vlapic->vm, vector);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_LAPIC, "Gratuitous EOI");
|
dev_dbg(ACRN_DBG_LAPIC, "Gratuitous EOI");
|
||||||
@ -1384,7 +1331,7 @@ static void vlapic_get_deliverable_intr(struct acrn_vlapic *vlapic, uint32_t vec
|
|||||||
{
|
{
|
||||||
struct lapic_regs *lapic = &(vlapic->apic_page);
|
struct lapic_regs *lapic = &(vlapic->apic_page);
|
||||||
struct lapic_reg *irrptr, *isrptr;
|
struct lapic_reg *irrptr, *isrptr;
|
||||||
uint32_t idx, stk_top;
|
uint32_t idx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clear the ready bit for vector being accepted in irr
|
* clear the ready bit for vector being accepted in irr
|
||||||
@ -1400,17 +1347,11 @@ static void vlapic_get_deliverable_intr(struct acrn_vlapic *vlapic, uint32_t vec
|
|||||||
isrptr[idx].v |= 1U << (vector & 0x1fU);
|
isrptr[idx].v |= 1U << (vector & 0x1fU);
|
||||||
vlapic_dump_isr(vlapic, "vlapic_get_deliverable_intr");
|
vlapic_dump_isr(vlapic, "vlapic_get_deliverable_intr");
|
||||||
|
|
||||||
|
vlapic->isrv = vector;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the PPR
|
* Update the PPR
|
||||||
*/
|
*/
|
||||||
vlapic->isrvec_stk_top++;
|
|
||||||
|
|
||||||
stk_top = vlapic->isrvec_stk_top;
|
|
||||||
if (stk_top >= ISRVEC_STK_SIZE) {
|
|
||||||
panic("isrvec_stk_top overflow %u", stk_top);
|
|
||||||
}
|
|
||||||
|
|
||||||
vlapic->isrvec_stk[stk_top] = (uint8_t)vector;
|
|
||||||
vlapic_update_ppr(vlapic);
|
vlapic_update_ppr(vlapic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1707,11 +1648,7 @@ vlapic_reset(struct acrn_vlapic *vlapic)
|
|||||||
vlapic->lvt_last[i] = 0U;
|
vlapic->lvt_last[i] = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0U; i < ISRVEC_STK_SIZE; i++) {
|
vlapic->isrv = 0U;
|
||||||
vlapic->isrvec_stk[i] = 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
vlapic->isrvec_stk_top = 0U;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,11 +42,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 16 priority levels with at most one vector injected per level.
|
|
||||||
*/
|
|
||||||
#define ISRVEC_STK_SIZE (16U + 1U)
|
|
||||||
|
|
||||||
#define VLAPIC_MAXLVT_INDEX APIC_LVT_CMCI
|
#define VLAPIC_MAXLVT_INDEX APIC_LVT_CMCI
|
||||||
|
|
||||||
struct vlapic_pir_desc {
|
struct vlapic_pir_desc {
|
||||||
@ -82,21 +77,9 @@ struct acrn_vlapic {
|
|||||||
struct vlapic_timer vtimer;
|
struct vlapic_timer vtimer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The 'isrvec_stk' is a stack of vectors injected by the local apic.
|
* isrv: vector number for the highest priority bit that is set in the ISR
|
||||||
* A vector is popped from the stack when the processor does an EOI.
|
|
||||||
* The vector on the top of the stack is used to compute the
|
|
||||||
* Processor Priority in conjunction with the TPR.
|
|
||||||
*
|
|
||||||
* Note: isrvec_stk_top is unsigned and always equal to the number of
|
|
||||||
* vectors in the stack.
|
|
||||||
*
|
|
||||||
* Operations:
|
|
||||||
* init: isrvec_stk_top = 0;
|
|
||||||
* push: isrvec_stk_top++; isrvec_stk[isrvec_stk_top] = x;
|
|
||||||
* pop : isrvec_stk_top--;
|
|
||||||
*/
|
*/
|
||||||
uint8_t isrvec_stk[ISRVEC_STK_SIZE];
|
uint32_t isrv;
|
||||||
uint32_t isrvec_stk_top;
|
|
||||||
|
|
||||||
uint64_t msr_apicbase;
|
uint64_t msr_apicbase;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user