Do necessary allocations for GICv4 VLPI injection. When creating a domain allocate its_vm and property tables. For each VCPU allocate a VPe with a unique vpe id and separate pending table.
Signed-off-by: Mykyta Poturai <[email protected]> --- xen/arch/arm/gic-v3-its.c | 157 ++++++++++++---- xen/arch/arm/gic-v3-lpi.c | 61 +++++- xen/arch/arm/gic-v3.c | 18 ++ xen/arch/arm/gic-v4-its.c | 259 ++++++++++++++++++++++++++ xen/arch/arm/include/asm/gic_v3_its.h | 17 ++ xen/arch/arm/include/asm/gic_v4_its.h | 1 + xen/arch/arm/include/asm/vgic.h | 3 + xen/arch/arm/vgic.c | 25 ++- 8 files changed, 496 insertions(+), 45 deletions(-) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 2328595a85..fb1d2709be 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -31,6 +31,8 @@ LIST_HEAD(host_its_list); +unsigned int nvpeid = 16; + /* * It is unlikely that a platform implements ITSes with different quirks, * so assume they all share the same. @@ -228,7 +230,7 @@ int gicv3_its_wait_commands(struct host_its *hw_its) return -ETIMEDOUT; } -static uint64_t encode_rdbase(struct host_its *hw_its, unsigned int cpu, +uint64_t encode_rdbase(struct host_its *hw_its, unsigned int cpu, uint64_t reg) { reg &= ~GENMASK(51, 16); @@ -443,6 +445,54 @@ struct its_baser *its_get_baser(struct host_its *hw_its, uint32_t type) return NULL; } +bool its_alloc_table_entry(struct its_baser *baser, uint32_t id) +{ + uint64_t reg = baser->val; + bool indirect = reg & GITS_BASER_INDIRECT; + unsigned int idx; + __le64 *table; + unsigned int entry_size = GITS_BASER_ENTRY_SIZE(reg); + + /* Don't allow id that exceeds single, flat table limit */ + if ( !indirect ) + return (id < (baser->table_size / entry_size)); + + /* Compute 1st level table index & check if that exceeds table limit */ + idx = id / (baser->pagesz / entry_size); + if ( idx >= (baser->pagesz / GITS_LVL1_ENTRY_SIZE) ) + return false; + + table = baser->base; + + /* Allocate memory for 2nd level table */ + if (!table[idx]) + { + unsigned int page_size = baser->pagesz; + void *buffer; + + buffer = alloc_xenheap_pages(get_order_from_bytes(page_size), + gicv3_its_get_memflags()); + if ( !buffer ) + return -ENOMEM; + + /* Flush Lvl2 table to PoC if hw doesn't support coherency */ + if ( gicv3_its_get_cacheability() <= GIC_BASER_CACHE_nC ) + clean_and_invalidate_dcache_va_range(buffer, page_size); + + table[idx] = cpu_to_le64(virt_to_maddr(buffer) | GITS_VALID_BIT); + + /* Flush Lvl1 entry to PoC if hw doesn't support coherency */ + if ( gicv3_its_get_cacheability() <= GIC_BASER_CACHE_nC ) + clean_and_invalidate_dcache_va_range(table + idx, + GITS_LVL1_ENTRY_SIZE); + + /* Ensure updated table contents are visible to ITS hardware */ + dsb(sy); + } + + return true; +} + static int its_map_baser(void __iomem *basereg, uint64_t regc, unsigned int nr_items, struct its_baser *baser) { @@ -737,13 +787,75 @@ static int gicv3_its_map_host_events(struct host_its *its, return ret; } - /* TODO: Consider using INVALL here. Didn't work on the model, though. */ + return 0; +} + +static bool its_alloc_device_table(struct host_its *hw_its, uint32_t dev_id) +{ + struct its_baser *baser; + + baser = its_get_baser(hw_its, GITS_BASER_TYPE_DEVICE); + if ( !baser ) + return false; + + return its_alloc_table_entry(baser, dev_id); +} + +struct its_device *its_create_device(struct host_its *hw_its, + uint32_t host_devid, uint64_t nr_events) +{ + void *itt_addr = NULL; + struct its_device *dev = NULL; + int ret; + + /* Sanitise the provided hardware values against the host ITS. */ + if ( host_devid >= BIT(hw_its->devid_bits, UL) ) + return NULL; + + dev = xzalloc(struct its_device); + if ( !dev ) + return NULL; + + /* An Interrupt Translation Table needs to be 256-byte aligned. */ + dev->itt_order = get_order_from_bytes(nr_events * hw_its->itte_size); + itt_addr = alloc_xenheap_pages(dev->itt_order, gicv3_its_get_memflags()); + if ( !itt_addr ) + goto fail_dev; + + clean_and_invalidate_dcache_va_range(itt_addr, + nr_events * hw_its->itte_size); + - ret = its_send_cmd_sync(its, 0); + if ( !its_alloc_device_table(hw_its, host_devid) ) + goto fail_itt; + + ret = its_send_cmd_mapd(hw_its, host_devid, max(fls(nr_events - 1), 1U), + virt_to_maddr(itt_addr), true); if ( ret ) - return ret; + goto fail_itt; - return gicv3_its_wait_commands(its); + dev->itt_addr = itt_addr; + dev->hw_its = hw_its; + dev->host_devid = host_devid; + dev->eventids = nr_events; + + return dev; + +fail_itt: + free_xenheap_pages(itt_addr, dev->itt_order); +fail_dev: + xfree(dev); + + return NULL; +} + +static void its_free_device(struct its_device *dev) +{ + xfree(dev->host_lpi_blocks); + xfree(dev->itt_addr); + if ( dev->pend_irqs ) + xfree(dev->pend_irqs); + xfree(dev); } /* @@ -758,12 +870,10 @@ int gicv3_its_map_guest_device(struct domain *d, paddr_t guest_doorbell, uint32_t guest_devid, uint64_t nr_events, bool valid) { - void *itt_addr = NULL; struct host_its *hw_its; struct its_device *dev = NULL; struct rb_node **new = &d->arch.vgic.its_devices.rb_node, *parent = NULL; int i, ret = -ENOENT; /* "i" must be signed to check for >= 0 below. */ - unsigned int order; hw_its = gicv3_its_find_by_doorbell(host_doorbell); if ( !hw_its ) @@ -823,23 +933,12 @@ int gicv3_its_map_guest_device(struct domain *d, if ( !valid ) goto out_unlock; - ret = -ENOMEM; - - /* An Interrupt Translation Table needs to be 256-byte aligned. */ - order = get_order_from_bytes(max(nr_events * hw_its->itte_size, 256UL)); - itt_addr = alloc_xenheap_pages(order, gicv3_its_get_memflags()); - if ( !itt_addr ) - goto out_unlock; - - memset(itt_addr, 0, PAGE_SIZE << order); - - clean_and_invalidate_dcache_va_range(itt_addr, - nr_events * hw_its->itte_size); - - dev = xzalloc(struct its_device); + dev = its_create_device(hw_its, host_devid, nr_events); if ( !dev ) goto out_unlock; + ret = -ENOMEM; + /* * Allocate the pending_irqs for each virtual LPI. They will be put * into the domain's radix tree upon the guest's MAPTI command. @@ -860,14 +959,6 @@ int gicv3_its_map_guest_device(struct domain *d, if ( !dev->host_lpi_blocks ) goto out_unlock; - ret = its_send_cmd_mapd(hw_its, host_devid, fls(nr_events - 1), - virt_to_maddr(itt_addr), true); - if ( ret ) - goto out_unlock; - - dev->itt_addr = itt_addr; - dev->itt_order = order; - dev->hw_its = hw_its; dev->guest_doorbell = guest_doorbell; dev->guest_devid = guest_devid; dev->host_devid = host_devid; @@ -920,13 +1011,7 @@ out_unlock: out: if ( dev ) - { - xfree(dev->pend_irqs); - xfree(dev->host_lpi_blocks); - } - if ( itt_addr ) - free_xenheap_pages(itt_addr, order); - xfree(dev); + its_free_device(dev); return ret; } diff --git a/xen/arch/arm/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c index c029d5d7a4..3c2649b695 100644 --- a/xen/arch/arm/gic-v3-lpi.c +++ b/xen/arch/arm/gic-v3-lpi.c @@ -58,6 +58,7 @@ static DEFINE_PER_CPU(struct lpi_redist_data, lpi_redist); #define MAX_NR_HOST_LPIS (lpi_data.max_host_lpi_ids - LPI_OFFSET) #define HOST_LPIS_PER_PAGE (PAGE_SIZE / sizeof(union host_lpi)) +uint32_t lpi_id_bits; static union host_lpi *gic_get_host_lpi(uint32_t plpi) { @@ -202,14 +203,11 @@ void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id, write_u64_atomic(&hlpip->data, hlpi.data); } -static int gicv3_lpi_allocate_pendtable(unsigned int cpu) +struct page_info *lpi_allocate_pendtable(void) { void *pendtable; unsigned int order; - if ( per_cpu(lpi_redist, cpu).pending_table ) - return -EBUSY; - /* * The pending table holds one bit per LPI and even covers bits for * interrupt IDs below 8192, so we allocate the full range. @@ -219,20 +217,34 @@ static int gicv3_lpi_allocate_pendtable(unsigned int cpu) order = get_order_from_bytes(max(lpi_data.max_host_lpi_ids / 8, (unsigned long)SZ_64K)); pendtable = alloc_xenheap_pages(order, gicv3_its_get_memflags()); if ( !pendtable ) - return -ENOMEM; + return NULL; memset(pendtable, 0, PAGE_SIZE << order); /* Make sure the physical address can be encoded in the register. */ if ( virt_to_maddr(pendtable) & ~GENMASK(51, 16) ) { free_xenheap_pages(pendtable, order); - return -ERANGE; + return NULL; } clean_and_invalidate_dcache_va_range(pendtable, lpi_data.max_host_lpi_ids / 8); - per_cpu(lpi_redist, cpu).pending_table = pendtable; + return virt_to_page(pendtable); +} + +static int gicv3_lpi_allocate_pendtable(unsigned int cpu) +{ + struct page_info *pendtable; + + if ( per_cpu(lpi_redist, cpu).pending_table ) + return -EBUSY; + + pendtable = lpi_allocate_pendtable(); + if ( !pendtable ) + return -EINVAL; + per_cpu(lpi_redist, cpu).pending_table = page_to_virt(pendtable); + return 0; } @@ -274,6 +286,38 @@ static int gicv3_lpi_set_pendtable(void __iomem *rdist_base) return 0; } +void *lpi_allocate_proptable(void) +{ + void *table; + int order; + + /* The property table holds one byte per LPI. */ + order = get_order_from_bytes(lpi_data.max_host_lpi_ids); + table = alloc_xenheap_pages(order, gicv3_its_get_memflags()); + if ( !table ) + return NULL; + + /* Make sure the physical address can be encoded in the register. */ + if ( (virt_to_maddr(table) & ~GENMASK(51, 12)) ) + { + free_xenheap_pages(table, order); + return NULL; + } + memset(table, GIC_PRI_IRQ | LPI_PROP_RES1, MAX_NR_HOST_LPIS); + clean_and_invalidate_dcache_va_range(table, MAX_NR_HOST_LPIS); + + return table; +} + +void lpi_free_proptable(void *vproptable) +{ + int order; + + /* The property table holds one byte per LPI. */ + order = get_order_from_bytes(lpi_data.max_host_lpi_ids); + free_xenheap_pages(vproptable, order); +} + /* * Tell a redistributor about the (shared) property table, allocating one * if not already done. @@ -314,7 +358,8 @@ static int gicv3_lpi_set_proptable(void __iomem * rdist_base) } /* Encode the number of bits needed, minus one */ - reg |= fls(lpi_data.max_host_lpi_ids - 1) - 1; + lpi_id_bits = fls(lpi_data.max_host_lpi_ids - 1); + reg |= lpi_id_bits - 1; reg |= virt_to_maddr(lpi_data.lpi_property); diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 14852d18c2..d4af332b0e 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -2083,6 +2083,22 @@ static bool gic_dist_supports_lpis(void) return (readl_relaxed(GICD + GICD_TYPER) & GICD_TYPE_LPIS); } +#ifdef CONFIG_GICV4 +static void __init gicv4_init(void) +{ + gicv3_info.hw_version = GIC_V4; + + + gicv4_its_vpeid_allocator_init(); + +} +#else +static void __init gicv4_init(void) +{ + ASSERT_UNREACHABLE(); +} +#endif + /* Set up the GIC */ static int __init gicv3_init(void) { @@ -2157,6 +2173,8 @@ static int __init gicv3_init(void) gicv3_hyp_init(); + if ( gic_is_gicv4() ) + gicv4_init(); out: spin_unlock(&gicv3.lock); diff --git a/xen/arch/arm/gic-v4-its.c b/xen/arch/arm/gic-v4-its.c index 358d0bffb9..fac3b44a94 100644 --- a/xen/arch/arm/gic-v4-its.c +++ b/xen/arch/arm/gic-v4-its.c @@ -27,6 +27,83 @@ #include <asm/vgic.h> +/* + * VPE ID is at most 16 bits. + * Using a bitmap here limits us to 65536 concurrent VPEs. + */ +static unsigned long *vpeid_mask; + +static spinlock_t vpeid_alloc_lock = SPIN_LOCK_UNLOCKED; + +void __init gicv4_its_vpeid_allocator_init(void) +{ + /* Allocate space for vpeid_mask based on MAX_VPEID */ + vpeid_mask = xzalloc_array(unsigned long, BITS_TO_LONGS(MAX_VPEID)); + + if ( !vpeid_mask ) + panic("Could not allocate VPEID bitmap space\n"); +} + +static int __init its_alloc_vpeid(struct its_vpe *vpe) +{ + int id; + + spin_lock(&vpeid_alloc_lock); + + id = find_first_zero_bit(vpeid_mask, MAX_VPEID); + + if ( id == MAX_VPEID ) + { + id = -EBUSY; + printk(XENLOG_ERR "VPEID pool exhausted\n"); + goto out; + } + + set_bit(id, vpeid_mask); + +out: + spin_unlock(&vpeid_alloc_lock); + + return id; +} + +static void __init its_free_vpeid(uint32_t vpe_id) +{ + spin_lock(&vpeid_alloc_lock); + + clear_bit(vpe_id, vpeid_mask); + + spin_unlock(&vpeid_alloc_lock); +} + +static bool __init its_alloc_vpe_entry(uint32_t vpe_id) +{ + struct host_its *hw_its; + + /* + * Make sure the L2 tables are allocated on *all* v4 ITSs. We + * could try and only do it on ITSs corresponding to devices + * that have interrupts targeted at this VPE, but the + * complexity becomes crazy. + */ + list_for_each_entry(hw_its, &host_its_list, entry) + { + struct its_baser *baser; + + if ( !hw_its->is_v4 ) + continue; + + baser = its_get_baser(hw_its, GITS_BASER_TYPE_VCPU); + if ( !baser ) + return false; + + if ( !its_alloc_table_entry(baser, vpe_id) ) + return false; + } + + return true; +} + static int its_send_cmd_vsync(struct host_its *its, uint16_t vpeid) { uint64_t cmd[4]; @@ -39,6 +116,188 @@ static int its_send_cmd_vsync(struct host_its *its, uint16_t vpeid) return its_send_command(its, cmd); } +static int its_send_cmd_vmapp(struct host_its *its, struct its_vpe *vpe, + bool valid) +{ + uint64_t cmd[4]; + uint16_t vpeid = vpe->vpe_id; + uint64_t vpt_addr; + int ret; + + cmd[0] = GITS_CMD_VMAPP; + cmd[1] = (uint64_t)vpeid << 32; + cmd[2] = valid ? GITS_VALID_BIT : 0; + + /* Unmap command */ + if ( !valid ) + goto out; + + /* Target redistributor */ + cmd[2] |= encode_rdbase(its, vpe->col_idx, 0x0); + vpt_addr = virt_to_maddr(vpe->vpendtable); + cmd[3] = (vpt_addr & GENMASK(51, 16)) | + ((HOST_LPIS_NRBITS - 1) & GENMASK(4, 0)); + + out: + ret = its_send_command(its, cmd); + + return ret; +} + +static int its_send_cmd_vinvall(struct host_its *its, struct its_vpe *vpe) +{ + uint64_t cmd[4]; + uint16_t vpeid = vpe->vpe_id; + + cmd[0] = GITS_CMD_VINVALL; + cmd[1] = (uint64_t)vpeid << 32; + cmd[2] = 0x00; + cmd[3] = 0x00; + + return its_send_command(its, cmd); +} + +static int its_map_vpe(struct host_its *its, struct its_vpe *vpe) +{ + int ret; + + /* + * VMAPP command maps the vPE to the target RDbase, including an + * associated virtual LPI Pending table. + */ + ret = its_send_cmd_vmapp(its, vpe, true); + if ( ret ) + return ret; + + ret = its_send_cmd_vinvall(its, vpe); + if ( ret ) + return ret; + + ret = its_send_cmd_vsync(its, vpe->vpe_id); + if ( ret ) + return ret; + + return 0; +} +static int __init its_vpe_init(struct its_vpe *vpe) +{ + int vpe_id, rc = -ENOMEM; + struct page_info *vpendtable; + struct host_its *hw_its; + + /* Allocate vpe id */ + vpe_id = its_alloc_vpeid(vpe); + if ( vpe_id < 0 ) + return rc; + + /* Allocate VPT */ + vpendtable = lpi_allocate_pendtable(); + + if ( !vpendtable ) + goto fail_vpt; + + if ( !its_alloc_vpe_entry(vpe_id) ) + goto fail_entry; + + rwlock_init(&vpe->lock); + vpe->vpe_id = vpe_id; + vpe->vpendtable = page_to_virt(vpendtable); + /* + * We eagerly inform all the v4 ITS and map vPE to the first + * possible CPU + */ + vpe->col_idx = cpumask_first(&cpu_online_map); + list_for_each_entry(hw_its, &host_its_list, entry) + { + if ( !hw_its->is_v4 ) + continue; + + if ( its_map_vpe(hw_its, vpe) ) + goto fail_entry; + } + + return 0; + + fail_entry: + xfree(page_to_virt(vpendtable)); + fail_vpt: + its_free_vpeid(vpe_id); + + return rc; +} + +static void __init its_vpe_teardown(struct its_vpe *vpe) +{ + unsigned int order; + + order = get_order_from_bytes(max(lpi_data.max_host_lpi_ids / 8, (unsigned long)SZ_64K)); + its_free_vpeid(vpe->vpe_id); + free_xenheap_pages(vpe->vpendtable, order); + xfree(vpe); +} + +int vgic_v4_its_vm_init(struct domain *d) +{ + unsigned int nr_vcpus = d->max_vcpus; + int ret = -ENOMEM; + + if ( !gicv3_its_host_has_its() ) + return 0; + + d->arch.vgic.its_vm = xzalloc(struct its_vm); + if ( !d->arch.vgic.its_vm ) + return ret; + + d->arch.vgic.its_vm->vpes = xzalloc_array(struct its_vpe *, nr_vcpus); + if ( !d->arch.vgic.its_vm->vpes ) + goto fail_vpes; + d->arch.vgic.its_vm->nr_vpes = nr_vcpus; + + d->arch.vgic.its_vm->vproptable = lpi_allocate_proptable(); + if ( !d->arch.vgic.its_vm->vproptable ) + goto fail_vprop; + + return 0; + +fail_vprop: + xfree(d->arch.vgic.its_vm->vpes); + fail_vpes: + xfree(d->arch.vgic.its_vm); + + return ret; +} + +void vgic_v4_free_its_vm(struct domain *d) +{ + struct its_vm *its_vm = d->arch.vgic.its_vm; + if ( its_vm->vpes ) + xfree(its_vm->vpes); + if ( its_vm->vproptable ) + lpi_free_proptable(its_vm); +} + +int vgic_v4_its_vpe_init(struct vcpu *vcpu) +{ + int ret; + struct its_vm *its_vm = vcpu->domain->arch.vgic.its_vm; + unsigned int vcpuid = vcpu->vcpu_id; + + vcpu->arch.vgic.its_vpe = xzalloc(struct its_vpe); + if ( !vcpu->arch.vgic.its_vpe ) + return -ENOMEM; + + its_vm->vpes[vcpuid] = vcpu->arch.vgic.its_vpe; + vcpu->arch.vgic.its_vpe->its_vm = its_vm; + + ret = its_vpe_init(vcpu->arch.vgic.its_vpe); + if ( ret ) + { + its_vpe_teardown(vcpu->arch.vgic.its_vpe); + return ret; + } + return 0; +} + static int its_send_cmd_vmapti(struct host_its *its, struct its_device *dev, uint32_t eventid) { diff --git a/xen/arch/arm/include/asm/gic_v3_its.h b/xen/arch/arm/include/asm/gic_v3_its.h index bd2696f354..411beb81c8 100644 --- a/xen/arch/arm/include/asm/gic_v3_its.h +++ b/xen/arch/arm/include/asm/gic_v3_its.h @@ -77,6 +77,7 @@ #define GITS_BASER_ENTRY_SIZE_SHIFT 48 #define GITS_BASER_ENTRY_SIZE(reg) \ ((((reg) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1) +#define GITS_LVL1_ENTRY_SIZE 8UL #define GITS_BASER_SHAREABILITY_SHIFT 10 #define GITS_BASER_PAGE_SIZE_SHIFT 8 #define GITS_BASER_SIZE_MASK 0xff @@ -117,9 +118,19 @@ /* We allocate LPIs on the hosts in chunks of 32 to reduce handling overhead. */ #define LPI_BLOCK 32U +extern unsigned int nvpeid; +/* The maximum number of VPEID bits supported by VLPI commands */ +#define ITS_MAX_VPEID_BITS nvpeid +#define MAX_VPEID (1UL << ITS_MAX_VPEID_BITS) + #ifdef CONFIG_GICV4 #include <asm/gic_v4_its.h> #endif + +extern uint32_t lpi_id_bits; +#define HOST_LPIS_NRBITS lpi_id_bits +#define MAX_HOST_LPIS BIT(lpi_id_bits, UL) + /* * Describes a device which is using the ITS and is used by a guest. * Since device IDs are per ITS (in contrast to vLPIs, which are per @@ -169,6 +180,7 @@ struct host_its { void *cmd_buf; unsigned int flags; struct its_baser tables[GITS_BASER_NR_REGS]; + bool is_v4; }; /* Map a collection for this host CPU to each host ITS. */ @@ -273,8 +285,13 @@ struct pending_irq *gicv3_assign_guest_event(struct domain *d, void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id, uint32_t virt_lpi); struct its_baser *its_get_baser(struct host_its *hw_its, uint32_t type); +bool its_alloc_table_entry(struct its_baser *baser, uint32_t id); +struct page_info *lpi_allocate_pendtable(void); +void *lpi_allocate_proptable(void); +void lpi_free_proptable(void *vproptable); void lpi_write_config(uint8_t *prop_table, uint32_t lpi, uint8_t clr, uint8_t set); +uint64_t encode_rdbase(struct host_its *hw_its, unsigned int cpu, uint64_t reg); int its_send_command(struct host_its *hw_its, const void *its_cmd); struct its_device *get_its_device(struct domain *d, paddr_t vdoorbell, diff --git a/xen/arch/arm/include/asm/gic_v4_its.h b/xen/arch/arm/include/asm/gic_v4_its.h index 722247ec60..fb0ef37bbe 100644 --- a/xen/arch/arm/include/asm/gic_v4_its.h +++ b/xen/arch/arm/include/asm/gic_v4_its.h @@ -49,6 +49,7 @@ struct event_vlpi_map { unsigned int nr_vlpis; }; +void gicv4_its_vpeid_allocator_init(void); #endif /* diff --git a/xen/arch/arm/include/asm/vgic.h b/xen/arch/arm/include/asm/vgic.h index f12d736808..580310fec4 100644 --- a/xen/arch/arm/include/asm/vgic.h +++ b/xen/arch/arm/include/asm/vgic.h @@ -414,6 +414,9 @@ bool gic_is_gicv4(void); #define gic_is_gicv4() (false) #endif +int vgic_v4_its_vm_init(struct domain *d); +void vgic_v4_free_its_vm(struct domain *d); +int vgic_v4_its_vpe_init(struct vcpu *vcpu); #endif /* !CONFIG_NEW_VGIC */ /*** Common VGIC functions used by Xen arch code ****/ diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 0da8c1a425..6baf870ad5 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -22,6 +22,7 @@ #include <asm/mmio.h> #include <asm/gic.h> +#include <asm/gic_v3_its.h> #include <asm/vgic.h> @@ -329,6 +330,15 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) for ( i = 0; i < NR_GIC_SGI; i++ ) set_bit(i, d->arch.vgic.allocated_irqs); + if ( gic_is_gicv4() ) + { + ret = vgic_v4_its_vm_init(d); + if ( ret ) + { + printk(XENLOG_ERR "GICv4 its vm allocation failed\n"); + return ret; + } + } return 0; } @@ -366,11 +376,14 @@ void domain_vgic_free(struct domain *d) #endif xfree(d->arch.vgic.pending_irqs); xfree(d->arch.vgic.allocated_irqs); + + if ( gic_is_gicv4() ) + vgic_v4_free_its_vm(d); } int vcpu_vgic_init(struct vcpu *v) { - int i; + int i, ret; v->arch.vgic.private_irqs = xzalloc(struct vgic_irq_rank); if ( v->arch.vgic.private_irqs == NULL ) @@ -389,6 +402,16 @@ int vcpu_vgic_init(struct vcpu *v) INIT_LIST_HEAD(&v->arch.vgic.lr_pending); spin_lock_init(&v->arch.vgic.lock); + if ( gic_is_gicv4() && gicv3_its_host_has_its()) + { + ret = vgic_v4_its_vpe_init(v); + if ( ret ) + { + printk(XENLOG_ERR "GICv4 its vpe allocation failed\n"); + return ret; + } + } + return 0; } -- 2.51.2
