hv: Introduce Global System Interrupt (GSI) into INTx Remapping

As ACRN prepares to support platforms with multiple IO-APICs,
GSI is a better way to represent physical and virtual INTx interrupt
source.
1) This patch replaces usage of "pin" with "gsi" whereever applicable
across the modules.
2) PIC pin to gsi is trickier and needs to consider the usage of
"Interrupt Source Override" structure in ACPI for the corresponding VM.

Tracked-On: #4151
Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com>
Acked-by: Eddie Dong <eddie.dong@Intel.com>
This commit is contained in:
Sainath Grandhi
2020-03-11 13:03:43 -07:00
committed by wenlingz
parent b0997e7606
commit ec86921444
12 changed files with 198 additions and 128 deletions

View File

@@ -130,10 +130,10 @@ vioapic_set_pinstate(struct acrn_vioapic *vioapic, uint32_t pin, uint32_t level)
* @return None
*/
void
vioapic_set_irqline_nolock(const struct acrn_vm *vm, uint32_t irqline, uint32_t operation)
vioapic_set_irqline_nolock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t operation)
{
struct acrn_vioapic *vioapic;
uint32_t pin = irqline;
uint32_t pin = vgsi;
vioapic = vm_ioapic(vm);
@@ -174,9 +174,10 @@ vioapic_set_irqline_nolock(const struct acrn_vm *vm, uint32_t irqline, uint32_t
* @return None
*/
void
vioapic_set_irqline_lock(const struct acrn_vm *vm, uint32_t irqline, uint32_t operation)
vioapic_set_irqline_lock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t operation)
{
uint64_t rflags;
uint32_t irqline = vgsi;
struct acrn_vioapic *vioapic = vm_ioapic(vm);
if (vioapic->ready) {
spinlock_irqsave_obtain(&(vioapic->mtx), &rflags);
@@ -524,9 +525,10 @@ int32_t vioapic_mmio_access_handler(struct io_request *io_req, void *handler_pri
* @pre vm->arch_vm.vioapic != NULL
* @pre rte != NULL
*/
void vioapic_get_rte(const struct acrn_vm *vm, uint32_t pin, union ioapic_rte *rte)
void vioapic_get_rte(const struct acrn_vm *vm, uint32_t vgsi, union ioapic_rte *rte)
{
struct acrn_vioapic *vioapic;
uint32_t pin = vgsi;
vioapic = vm_ioapic(vm);
*rte = vioapic->rtbl[pin];

View File

@@ -32,6 +32,7 @@
#include <assign.h>
#include <spinlock.h>
#include <logmsg.h>
#include <ioapic.h>
#define DBG_LEVEL_PIC 6U
@@ -311,6 +312,79 @@ static int32_t vpic_icw4(const struct acrn_vpic *vpic, struct i8259_reg_state *i
return ret;
}
static uint32_t vpin_to_vgsi(const struct acrn_vm *vm, uint32_t vpin)
{
uint32_t vgsi = vpin;
/*
* Remap depending on the type of VM
*/
if (is_sos_vm(vm)) {
/*
* For SOS VM vPIC pin to GSI is same as the one
* that is used for platform
*/
vgsi = get_pic_pin_from_ioapic_pin(vpin);
} else if (is_postlaunched_vm(vm)) {
/*
* Devicemodel provides Interrupt Source Override Structure
* via ACPI to Post-Launched VM.
*
* 1) Interrupt source connected to vPIC pin 0 is connected to vIOAPIC pin 2
* 2) Devicemodel, as of today, does not request to hold ptirq entry with vPIC as
* interrupt controller, for a Post-Launched VM.
*/
if (vpin == 0U) {
vgsi = 2U;
}
} else {
/*
* For Pre-launched VMs, Interrupt Source Override Structure
* and IO-APIC Structure are not provided in the VM's ACPI info.
* No remapping needed.
*/
}
return vgsi;
}
static uint32_t vgsi_to_vpin(const struct acrn_vm *vm, uint32_t vgsi)
{
uint32_t vpin = vgsi;
/*
* Remap depending on the type of VM
*/
if (is_sos_vm(vm)) {
/*
* For SOS VM vPIC pin to GSI is same as the one
* that is used for platform
*/
vpin = get_pic_pin_from_ioapic_pin(vgsi);
} else if (is_postlaunched_vm(vm)) {
/*
* Devicemodel provides Interrupt Source Override Structure
* via ACPI to Post-Launched VM.
*
* 1) Interrupt source connected to vPIC pin 0 is connected to vIOAPIC pin 2
* 2) Devicemodel, as of today, does not request to hold ptirq entry with vPIC as
* interrupt controller, for a Post-Launched VM.
*/
if (vgsi == 2U) {
vpin = 0U;
}
} else {
/*
* For Pre-launched VMs, Interrupt Source Override Structure
* and IO-APIC Structure are not provided in the VM's ACPI info.
* No remapping needed.
*/
}
return vpin;
}
static int32_t vpic_ocw1(const struct acrn_vpic *vpic, struct i8259_reg_state *i8259, uint8_t val)
{
uint32_t pin, i, bit;
@@ -331,6 +405,7 @@ static int32_t vpic_ocw1(const struct acrn_vpic *vpic, struct i8259_reg_state *i
*/
if (((i8259->mask & bit) == 0U) && ((old & bit) != 0U)) {
uint32_t virt_pin;
uint32_t vgsi;
/* master i8259 pin2 connect with slave i8259,
* not device, so not need pt remap
@@ -342,7 +417,9 @@ static int32_t vpic_ocw1(const struct acrn_vpic *vpic, struct i8259_reg_state *i
virt_pin = (master_pic(vpic, i8259)) ?
pin : (pin + 8U);
(void)ptirq_intx_pin_remap(vpic->vm, virt_pin, INTX_CTLR_PIC);
vgsi = vpin_to_vgsi(vpic->vm, virt_pin);
(void)ptirq_intx_pin_remap(vpic->vm, vgsi, INTX_CTLR_PIC);
}
pin = (pin + 1U) & 0x7U;
}
@@ -359,6 +436,7 @@ static int32_t vpic_ocw2(const struct acrn_vpic *vpic, struct i8259_reg_state *i
if ((val & OCW2_EOI) != 0U) {
uint32_t isr_bit;
uint32_t vgsi;
if ((val & OCW2_SL) != 0U) {
/* specific EOI */
@@ -378,8 +456,8 @@ static int32_t vpic_ocw2(const struct acrn_vpic *vpic, struct i8259_reg_state *i
/* if level ack PTDEV */
if ((i8259->elc & (1U << (isr_bit & 0x7U))) != 0U) {
ptirq_intx_ack(vpic->vm, (master_pic(vpic, i8259) ? isr_bit : isr_bit + 8U),
INTX_CTLR_PIC);
vgsi = vpin_to_vgsi(vpic->vm, (master_pic(vpic, i8259) ? isr_bit : isr_bit + 8U));
ptirq_intx_ack(vpic->vm, vgsi, INTX_CTLR_PIC);
}
} else if (((val & OCW2_SL) != 0U) && i8259->rotate) {
/* specific priority */
@@ -461,17 +539,18 @@ static void vpic_set_pinstate(struct acrn_vpic *vpic, uint32_t pin, uint8_t leve
*
* @return None
*/
void vpic_set_irqline(struct acrn_vpic *vpic, uint32_t irqline, uint32_t operation)
void vpic_set_irqline(struct acrn_vpic *vpic, uint32_t vgsi, uint32_t operation)
{
struct i8259_reg_state *i8259;
uint32_t pin;
uint64_t rflags;
if (irqline < NR_VPIC_PINS_TOTAL) {
i8259 = &vpic->i8259[irqline >> 3U];
pin = irqline;
if (vgsi < NR_VPIC_PINS_TOTAL) {
i8259 = &vpic->i8259[vgsi >> 3U];
if (i8259->ready) {
pin = vgsi_to_vpin(vpic->vm, vgsi);
spinlock_irqsave_obtain(&(vpic->lock), &rflags);
switch (operation) {
case GSI_SET_HIGH:
@@ -511,9 +590,11 @@ vpic_pincount(void)
* @pre irqline < NR_VPIC_PINS_TOTAL
* @pre this function should be called after vpic_init()
*/
void vpic_get_irqline_trigger_mode(const struct acrn_vpic *vpic, uint32_t irqline,
void vpic_get_irqline_trigger_mode(const struct acrn_vpic *vpic, uint32_t vgsi,
enum vpic_trigger *trigger)
{
uint32_t irqline = vgsi_to_vpin(vpic->vm, vgsi);
if ((vpic->i8259[irqline >> 3U].elc & (1U << (irqline & 0x7U))) != 0U) {
*trigger = LEVEL_TRIGGER;
} else {

View File

@@ -616,13 +616,13 @@ static void vuart_deinit_connection(struct acrn_vuart *vu)
vu->target_vu = NULL;
}
bool is_vuart_intx(const struct acrn_vm *vm, uint32_t intx_pin)
bool is_vuart_intx(const struct acrn_vm *vm, uint32_t intx_gsi)
{
uint8_t i;
bool ret = false;
for (i = 0U; i < MAX_VUART_NUM_PER_VM; i++) {
if ((vm->vuart[i].active) && (vm->vuart[i].irq == intx_pin)) {
if ((vm->vuart[i].active) && (vm->vuart[i].irq == intx_gsi)) {
ret = true;
}
}