hv: Add support to add IR tables
Interrupt Remapping hardware in x86 can hold 64K entries with each entry of size 16 bytes. So 256 entries occupy 4K. Adding a configuration for developer to choose number of IR entries, in multiples of 256. ACRN does not boot on platforms that does not support Interrupt Remapping and Extended Interrupt Mode Tracked-On: #2426 Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com> Reviewed-by: Binbin Wu <binbin.wu@intel.com>
This commit is contained in:
parent
cb46937bf5
commit
7104f0a512
|
@ -329,6 +329,12 @@ config MAX_IOAPIC_NUM
|
|||
range 1 8
|
||||
default 1
|
||||
|
||||
config MAX_IR_ENTRIES
|
||||
int "Maximum number of Interrupt Remapping Entries"
|
||||
default 256
|
||||
help
|
||||
Minimum value is 256. Value must be 2^n.
|
||||
|
||||
config IOMMU_BUS_NUM
|
||||
hex "Highest PCI bus ID used during IOMMU initialization"
|
||||
default 0x10 if PLATFORM_SBL
|
||||
|
|
|
@ -71,6 +71,7 @@ static inline uint64_t dmar_set_bitslice(uint64_t var, uint64_t mask, uint32_t p
|
|||
|
||||
#define DMAR_INVALIDATION_QUEUE_SIZE 4096U
|
||||
#define DMAR_QI_INV_ENTRY_SIZE 16U
|
||||
#define DMAR_NUM_IR_ENTRIES_PER_PAGE 256U
|
||||
|
||||
#define DMAR_INV_STATUS_WRITE_SHIFT 5U
|
||||
#define DMAR_INV_CONTEXT_CACHE_DESC 0x01UL
|
||||
|
@ -83,6 +84,9 @@ static inline uint64_t dmar_set_bitslice(uint64_t var, uint64_t mask, uint32_t p
|
|||
#define DMAR_INV_STATUS_DATA (DMAR_INV_STATUS_COMPLETED << DMAR_INV_STATUS_DATA_SHIFT)
|
||||
#define DMAR_INV_WAIT_DESC_LOWER (DMAR_INV_STATUS_WRITE | DMAR_INV_WAIT_DESC | DMAR_INV_STATUS_DATA)
|
||||
|
||||
#define DMAR_IR_ENABLE_EIM_SHIFT 11UL
|
||||
#define DMAR_IR_ENABLE_EIM (1UL << DMAR_IR_ENABLE_EIM_SHIFT)
|
||||
|
||||
enum dmar_cirg_type {
|
||||
DMAR_CIRG_RESERVED = 0,
|
||||
DMAR_CIRG_GLOBAL,
|
||||
|
@ -105,6 +109,7 @@ struct dmar_drhd_rt {
|
|||
struct dmar_drhd *drhd;
|
||||
|
||||
uint64_t root_table_addr;
|
||||
uint64_t ir_table_addr;
|
||||
uint64_t qi_queue;
|
||||
uint16_t qi_tail;
|
||||
|
||||
|
@ -150,6 +155,10 @@ struct context_table {
|
|||
struct page buses[CONFIG_IOMMU_BUS_NUM];
|
||||
};
|
||||
|
||||
struct intr_remap_table {
|
||||
struct page tables[CONFIG_MAX_IR_ENTRIES/DMAR_NUM_IR_ENTRIES_PER_PAGE];
|
||||
};
|
||||
|
||||
static inline uint8_t* get_root_table(uint32_t dmar_index)
|
||||
{
|
||||
static struct page root_tables[CONFIG_MAX_IOMMU_NUM] __aligned(PAGE_SIZE);
|
||||
|
@ -171,6 +180,12 @@ static inline uint8_t *get_qi_queue(uint32_t dmar_index)
|
|||
return qi_queues[dmar_index].contents;
|
||||
}
|
||||
|
||||
static inline uint8_t *get_ir_table(uint32_t dmar_index)
|
||||
{
|
||||
static struct intr_remap_table ir_tables[CONFIG_MAX_IOMMU_NUM] __aligned(PAGE_SIZE);
|
||||
return ir_tables[dmar_index].tables[0].contents;
|
||||
}
|
||||
|
||||
bool iommu_snoop_supported(const struct acrn_vm *vm)
|
||||
{
|
||||
bool ret;
|
||||
|
@ -461,6 +476,12 @@ static int32_t dmar_register_hrhd(struct dmar_drhd_rt *dmar_unit)
|
|||
} else if (iommu_ecap_qi(dmar_unit->ecap) == 0U) {
|
||||
pr_fatal("%s: dmar unit doesn't support Queued Invalidation!", __func__);
|
||||
ret = -ENODEV;
|
||||
} else if (iommu_ecap_ir(dmar_unit->ecap) == 0U) {
|
||||
pr_fatal("%s: dmar unit doesn't support Interrupt Remapping!", __func__);
|
||||
ret = -ENODEV;
|
||||
} else if (iommu_ecap_eim(dmar_unit->ecap) == 0U) {
|
||||
pr_fatal("%s: dmar unit doesn't support Extended Interrupt Mode!", __func__);
|
||||
ret = -ENODEV;
|
||||
} else {
|
||||
if ((iommu_ecap_c(dmar_unit->ecap) == 0U) && (dmar_unit->drhd->ignore != 0U)) {
|
||||
iommu_page_walk_coherent = false;
|
||||
|
@ -647,6 +668,33 @@ static void dmar_invalid_iotlb_global(struct dmar_drhd_rt *dmar_unit)
|
|||
dmar_invalid_iotlb(dmar_unit, 0U, 0UL, 0U, false, DMAR_IIRG_GLOBAL);
|
||||
}
|
||||
|
||||
static void dmar_set_intr_remap_table(struct dmar_drhd_rt *dmar_unit)
|
||||
{
|
||||
uint64_t address;
|
||||
uint32_t status;
|
||||
uint8_t size;
|
||||
|
||||
spinlock_obtain(&(dmar_unit->lock));
|
||||
|
||||
if (dmar_unit->ir_table_addr == 0UL) {
|
||||
dmar_unit->ir_table_addr = hva2hpa(get_ir_table(dmar_unit->index));
|
||||
}
|
||||
|
||||
address = dmar_unit->ir_table_addr | DMAR_IR_ENABLE_EIM;
|
||||
|
||||
/* Set number of bits needed to represent the entries minus 1 */
|
||||
size = (uint8_t) fls32(CONFIG_MAX_IR_ENTRIES) - 1U;
|
||||
address = address | size;
|
||||
|
||||
iommu_write64(dmar_unit, DMAR_IRTA_REG, address);
|
||||
|
||||
iommu_write32(dmar_unit, DMAR_GCMD_REG, dmar_unit->gcmd | DMA_GCMD_SIRTP);
|
||||
|
||||
dmar_wait_completion(dmar_unit, DMAR_GSTS_REG, DMA_GSTS_IRTPS, false, &status);
|
||||
|
||||
spinlock_release(&(dmar_unit->lock));
|
||||
}
|
||||
|
||||
static void dmar_set_root_table(struct dmar_drhd_rt *dmar_unit)
|
||||
{
|
||||
uint64_t address;
|
||||
|
@ -868,6 +916,7 @@ static void dmar_prepare(struct dmar_drhd_rt *dmar_unit)
|
|||
dmar_setup_interrupt(dmar_unit);
|
||||
dmar_set_root_table(dmar_unit);
|
||||
dmar_enable_qi(dmar_unit);
|
||||
dmar_set_intr_remap_table(dmar_unit);
|
||||
}
|
||||
|
||||
static void dmar_enable(struct dmar_drhd_rt *dmar_unit)
|
||||
|
|
Loading…
Reference in New Issue