hv: Add bit representation for MSI addr and data

As we enable Interrupt Remapping, bit positions in MSI address and
data registers have a different syntax for programming. This patch adds
bit granularity for MSI address and data structs.

Tracked-On: #2407
Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com>
This commit is contained in:
Sainath Grandhi 2019-01-26 01:31:14 -08:00 committed by wenlingz
parent 6825043078
commit 7d57eb056e
7 changed files with 92 additions and 55 deletions

View File

@ -77,32 +77,33 @@ static void ptirq_build_physical_msi(struct acrn_vm *vm, struct ptirq_msi_info *
bool phys; bool phys;
/* get physical destination cpu mask */ /* get physical destination cpu mask */
dest = (uint32_t)(info->vmsi_addr & MSI_ADDR_DEST) >> MSI_ADDR_DEST_SHIFT; dest = info->vmsi_addr.bits.dest_field;
phys = ((info->vmsi_addr & MSI_ADDR_LOG) != MSI_ADDR_LOG); phys = (info->vmsi_addr.bits.dest_mode == MSI_ADDR_DESTMODE_PHYS);
vlapic_calcdest(vm, &vdmask, dest, phys, false); vlapic_calcdest(vm, &vdmask, dest, phys, false);
pdmask = vcpumask2pcpumask(vm, vdmask); pdmask = vcpumask2pcpumask(vm, vdmask);
/* get physical delivery mode */ /* get physical delivery mode */
delmode = info->vmsi_data & APIC_DELMODE_MASK; delmode = info->vmsi_data.bits.delivery_mode;
if ((delmode != APIC_DELMODE_FIXED) && (delmode != APIC_DELMODE_LOWPRIO)) { if ((delmode != MSI_DATA_DELMODE_FIXED) && (delmode != MSI_DATA_DELMODE_LOPRI)) {
delmode = APIC_DELMODE_LOWPRIO; delmode = MSI_DATA_DELMODE_LOPRI;
} }
/* update physical delivery mode & vector */ /* update physical delivery mode & vector */
info->pmsi_data = info->vmsi_data; info->pmsi_data = info->vmsi_data;
info->pmsi_data &= ~0x7FFU; info->pmsi_data.bits.delivery_mode = delmode;
info->pmsi_data |= delmode | vector; info->pmsi_data.bits.vector = vector;
dest_mask = calculate_logical_dest_mask(pdmask); dest_mask = calculate_logical_dest_mask(pdmask);
/* update physical dest mode & dest field */ /* update physical dest mode & dest field */
info->pmsi_addr = info->vmsi_addr; info->pmsi_addr = info->vmsi_addr;
info->pmsi_addr &= ~0xFF00CU; info->pmsi_addr.bits.dest_mode = MSI_ADDR_DESTMODE_LOGICAL;
info->pmsi_addr |= (dest_mask << MSI_ADDR_DEST_SHIFT) | MSI_ADDR_RH | MSI_ADDR_LOG; info->pmsi_addr.bits.rh = MSI_ADDR_RH;
info->pmsi_addr.bits.dest_field = dest_mask;
dev_dbg(ACRN_DBG_IRQ, "MSI addr:data = 0x%llx:%x(V) -> 0x%llx:%x(P)", dev_dbg(ACRN_DBG_IRQ, "MSI addr:data = 0x%llx:%x(V) -> 0x%llx:%x(P)",
info->vmsi_addr, info->vmsi_data, info->vmsi_addr.full, info->vmsi_data.full,
info->pmsi_addr, info->pmsi_data); info->pmsi_addr.full, info->pmsi_data.full);
} }
static union ioapic_rte static union ioapic_rte
@ -442,14 +443,14 @@ void ptirq_softirq(uint16_t pcpu_id)
} else { } else {
if (msi != NULL) { if (msi != NULL) {
/* TODO: msi destmode check required */ /* TODO: msi destmode check required */
(void)vlapic_intr_msi(vm, msi->vmsi_addr, msi->vmsi_data); (void)vlapic_intr_msi(vm, msi->vmsi_addr.full, msi->vmsi_data.full);
dev_dbg(ACRN_DBG_PTIRQ, "dev-assign: irq=0x%x MSI VR: 0x%x-0x%x", dev_dbg(ACRN_DBG_PTIRQ, "dev-assign: irq=0x%x MSI VR: 0x%x-0x%x",
entry->allocated_pirq, entry->allocated_pirq,
msi->vmsi_data & 0xFFU, msi->vmsi_data.bits.vector,
irq_to_vector(entry->allocated_pirq)); irq_to_vector(entry->allocated_pirq));
dev_dbg(ACRN_DBG_PTIRQ, " vmsi_addr: 0x%llx vmsi_data: 0x%x", dev_dbg(ACRN_DBG_PTIRQ, " vmsi_addr: 0x%llx vmsi_data: 0x%x",
msi->vmsi_addr, msi->vmsi_addr.full,
msi->vmsi_data); msi->vmsi_data.full);
} }
} }
} }
@ -534,16 +535,16 @@ int32_t ptirq_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf,
spinlock_release(&ptdev_lock); spinlock_release(&ptdev_lock);
if (entry != NULL) { if (entry != NULL) {
if (is_entry_active(entry) && (info->vmsi_data == 0U)) { if (is_entry_active(entry) && (info->vmsi_data.full == 0U)) {
/* handle destroy case */ /* handle destroy case */
info->pmsi_data = 0U; info->pmsi_data.full = 0U;
} else { } else {
/* build physical config MSI, update to info->pmsi_xxx */ /* build physical config MSI, update to info->pmsi_xxx */
ptirq_build_physical_msi(vm, info, irq_to_vector(entry->allocated_pirq)); ptirq_build_physical_msi(vm, info, irq_to_vector(entry->allocated_pirq));
entry->msi = *info; entry->msi = *info;
dev_dbg(ACRN_DBG_IRQ, "PCI %x:%x.%x MSI VR[%d] 0x%x->0x%x assigned to vm%d", dev_dbg(ACRN_DBG_IRQ, "PCI %x:%x.%x MSI VR[%d] 0x%x->0x%x assigned to vm%d",
pci_bus(virt_bdf), pci_slot(virt_bdf), pci_func(virt_bdf), entry_nr, pci_bus(virt_bdf), pci_slot(virt_bdf), pci_func(virt_bdf), entry_nr,
info->vmsi_data & 0xFFU, irq_to_vector(entry->allocated_pirq), entry->vm->vm_id); info->vmsi_data.bits.vector, irq_to_vector(entry->allocated_pirq), entry->vm->vm_id);
} }
ret = 0; ret = 0;
} }

View File

@ -1940,10 +1940,14 @@ vlapic_intr_msi(struct acrn_vm *vm, uint64_t addr, uint64_t msg)
uint32_t dest; uint32_t dest;
bool phys, rh; bool phys, rh;
int32_t ret; int32_t ret;
union msi_addr_reg address;
union msi_data_reg data;
dev_dbg(ACRN_DBG_LAPIC, "lapic MSI addr: %#lx msg: %#lx", addr, msg); address.full = addr;
data.full = (uint32_t) msg;
dev_dbg(ACRN_DBG_LAPIC, "lapic MSI addr: %#lx msg: %#lx", address.full, data.full);
if ((addr & MSI_ADDR_MASK) == MSI_ADDR_BASE) { if (address.bits.addr_base == MSI_ADDR_BASE) {
/* /*
* Extract the x86-specific fields from the MSI addr/msg * Extract the x86-specific fields from the MSI addr/msg
* params according to the Intel Arch spec, Vol3 Ch 10. * params according to the Intel Arch spec, Vol3 Ch 10.
@ -1955,12 +1959,12 @@ vlapic_intr_msi(struct acrn_vm *vm, uint64_t addr, uint64_t msg)
* the Redirection Hint and Destination Mode are '1' and * the Redirection Hint and Destination Mode are '1' and
* physical otherwise. * physical otherwise.
*/ */
dest = (uint32_t)(addr >> 12U) & 0xffU; dest = address.bits.dest_field;
phys = ((addr & MSI_ADDR_LOG) != MSI_ADDR_LOG); phys = (address.bits.dest_mode == MSI_ADDR_DESTMODE_PHYS);
rh = ((addr & MSI_ADDR_RH) == MSI_ADDR_RH); rh = (address.bits.rh == MSI_ADDR_RH);
delmode = (uint32_t)msg & APIC_DELMODE_MASK; delmode = data.bits.delivery_mode;
vec = (uint32_t)msg & 0xffU; vec = data.bits.vector;
dev_dbg(ACRN_DBG_LAPIC, "lapic MSI %s dest %#x, vec %u", dev_dbg(ACRN_DBG_LAPIC, "lapic MSI %s dest %#x, vec %u",
phys ? "physical" : "logical", dest, vec); phys ? "physical" : "logical", dest, vec);
@ -1968,7 +1972,7 @@ vlapic_intr_msi(struct acrn_vm *vm, uint64_t addr, uint64_t msg)
vlapic_deliver_intr(vm, LAPIC_TRIG_EDGE, dest, phys, delmode, vec, rh); vlapic_deliver_intr(vm, LAPIC_TRIG_EDGE, dest, phys, delmode, vec, rh);
ret = 0; ret = 0;
} else { } else {
dev_dbg(ACRN_DBG_LAPIC, "lapic MSI invalid addr %#lx", addr); dev_dbg(ACRN_DBG_LAPIC, "lapic MSI invalid addr %#lx", address.full);
ret = -1; ret = -1;
} }

View File

@ -907,8 +907,8 @@ static void get_entry_info(const struct ptirq_remapping_info *entry, char *type,
if (is_entry_active(entry)) { if (is_entry_active(entry)) {
if (entry->intr_type == PTDEV_INTR_MSI) { if (entry->intr_type == PTDEV_INTR_MSI) {
(void)strncpy_s(type, 16U, "MSI", 16U); (void)strncpy_s(type, 16U, "MSI", 16U);
*dest = (entry->msi.pmsi_addr & 0xFF000U) >> PAGE_SHIFT; *dest = entry->msi.pmsi_addr.bits.dest_field;
if ((entry->msi.pmsi_data & APIC_TRIGMOD_LEVEL) != 0U) { if (entry->msi.pmsi_data.bits.trigger_mode == MSI_DATA_TRGRMODE_LEVEL) {
*lvl_tm = true; *lvl_tm = true;
} else { } else {
*lvl_tm = false; *lvl_tm = false;

View File

@ -69,24 +69,24 @@ static int32_t vmsi_remap(const struct pci_vdev *vdev, bool enable)
} }
info.is_msix = 0; info.is_msix = 0;
info.vmsi_addr = (uint64_t)addrlo | ((uint64_t)addrhi << 32U); info.vmsi_addr.full = (uint64_t)addrlo | ((uint64_t)addrhi << 32U);
/* MSI is being enabled or disabled */ /* MSI is being enabled or disabled */
if (enable) { if (enable) {
info.vmsi_data = msgdata; info.vmsi_data.full = msgdata;
} else { } else {
info.vmsi_data = 0U; info.vmsi_data.full = 0U;
} }
ret = ptirq_msix_remap(vm, vdev->vbdf.value, 0U, &info); ret = ptirq_msix_remap(vm, vdev->vbdf.value, 0U, &info);
if (ret == 0) { if (ret == 0) {
/* Update MSI Capability structure to physical device */ /* Update MSI Capability structure to physical device */
pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR, 0x4U, (uint32_t)info.pmsi_addr); pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR, 0x4U, (uint32_t)info.pmsi_addr.full);
if ((msgctrl & PCIM_MSICTRL_64BIT) != 0U) { if ((msgctrl & PCIM_MSICTRL_64BIT) != 0U) {
pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U, (uint32_t)(info.pmsi_addr >> 32U)); pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U, (uint32_t)(info.pmsi_addr.full >> 32U));
pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA_64BIT, 0x2U, (uint16_t)info.pmsi_data); pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA_64BIT, 0x2U, (uint16_t)info.pmsi_data.full);
} else { } else {
pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA, 0x2U, (uint16_t)info.pmsi_data); pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA, 0x2U, (uint16_t)info.pmsi_data.full);
} }
/* If MSI Enable is being set, make sure INTxDIS bit is set */ /* If MSI Enable is being set, make sure INTxDIS bit is set */

View File

@ -56,8 +56,8 @@ static int32_t vmsix_remap_entry(const struct pci_vdev *vdev, uint32_t index, bo
int32_t ret; int32_t ret;
info.is_msix = 1; info.is_msix = 1;
info.vmsi_addr = vdev->msix.tables[index].addr; info.vmsi_addr.full = vdev->msix.tables[index].addr;
info.vmsi_data = (enable) ? vdev->msix.tables[index].data : 0U; info.vmsi_data.full = (enable) ? vdev->msix.tables[index].data : 0U;
ret = ptirq_msix_remap(vdev->vpci->vm, vdev->vbdf.value, (uint16_t)index, &info); ret = ptirq_msix_remap(vdev->vpci->vm, vdev->vbdf.value, (uint16_t)index, &info);
if (ret == 0) { if (ret == 0) {
@ -71,10 +71,10 @@ static int32_t vmsix_remap_entry(const struct pci_vdev *vdev, uint32_t index, bo
* write only * write only
*/ */
stac(); stac();
mmio_write32((uint32_t)(info.pmsi_addr), (void *)&(pentry->addr)); mmio_write32((uint32_t)(info.pmsi_addr.full), (void *)&(pentry->addr));
mmio_write32((uint32_t)(info.pmsi_addr >> 32U), (void *)((char *)&(pentry->addr) + 4U)); mmio_write32((uint32_t)(info.pmsi_addr.full >> 32U), (void *)((char *)&(pentry->addr) + 4U));
mmio_write32(info.pmsi_data, (void *)&(pentry->data)); mmio_write32(info.pmsi_data.full, (void *)&(pentry->data));
mmio_write32(vdev->msix.tables[index].vector_control, (void *)&(pentry->vector_control)); mmio_write32(vdev->msix.tables[index].vector_control, (void *)&(pentry->vector_control));
clac(); clac();
} }

View File

@ -102,17 +102,6 @@ uint32_t alloc_irq_vector(uint32_t irq);
*/ */
uint32_t irq_to_vector(uint32_t irq); uint32_t irq_to_vector(uint32_t irq);
/*
* Some MSI message definitions
*/
#define MSI_ADDR_MASK 0xfff00000UL
#define MSI_ADDR_BASE 0xfee00000UL
#define MSI_ADDR_RH 0x00000008UL /* Redirection Hint */
#define MSI_ADDR_LOG 0x00000004UL /* Destination Mode */
#define MSI_ADDR_DEST 0x000FF000UL /* Destination Field */
#define MSI_ADDR_DEST_SHIFT (12U)
/* RFLAGS */ /* RFLAGS */
#define HV_ARCH_VCPU_RFLAGS_IF (1UL<<9U) #define HV_ARCH_VCPU_RFLAGS_IF (1UL<<9U)

View File

@ -36,12 +36,55 @@ union source_id {
} intx_id; } intx_id;
}; };
/*
* Macros for bits in union msi_addr_reg
*/
#define MSI_ADDR_BASE 0xfeeUL /* Base address for MSI messages */
#define MSI_ADDR_RH 0x1U /* Redirection Hint */
#define MSI_ADDR_DESTMODE_LOGICAL 0x1U /* Destination Mode: Logical*/
#define MSI_ADDR_DESTMODE_PHYS 0x0U /* Destination Mode: Physical*/
union msi_addr_reg {
uint64_t full;
struct {
uint32_t rsvd_1:2;
uint32_t dest_mode:1;
uint32_t rh:1;
uint32_t rsvd_2:8;
uint32_t dest_field:8;
uint32_t addr_base:12;
uint32_t hi_32;
} bits __packed;
};
/*
* Macros for bits in union msi_data_reg
*/
#define MSI_DATA_DELMODE_FIXED 0x0U /* Delivery Mode: Fixed */
#define MSI_DATA_DELMODE_LOPRI 0x1U /* Delivery Mode: Low Priority */
#define MSI_DATA_TRGRMODE_EDGE 0x0U /* Trigger Mode: Edge */
#define MSI_DATA_TRGRMODE_LEVEL 0x1U /* Trigger Mode: Level */
union msi_data_reg {
uint32_t full;
struct {
uint32_t vector:8;
uint32_t delivery_mode:3;
uint32_t rsvd_1:3;
uint32_t level:1;
uint32_t trigger_mode:1;
uint32_t rsvd_2:16;
} bits __packed;
};
/* entry per guest virt vector */ /* entry per guest virt vector */
struct ptirq_msi_info { struct ptirq_msi_info {
uint64_t vmsi_addr; /* virt msi_addr */ union msi_addr_reg vmsi_addr; /* virt msi_addr */
uint32_t vmsi_data; /* virt msi_data */ union msi_data_reg vmsi_data; /* virt msi_data */
uint64_t pmsi_addr; /* phys msi_addr */ union msi_addr_reg pmsi_addr; /* phys msi_addr */
uint32_t pmsi_data; /* phys msi_data */ union msi_data_reg pmsi_data; /* phys msi_data */
int32_t is_msix; /* 0-MSI, 1-MSIX */ int32_t is_msix; /* 0-MSI, 1-MSIX */
}; };