|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v8 19/27] ARM: vITS: handle MAPTI command
Hi,
On 12/04/17 17:18, Julien Grall wrote:
> Hi Andre,
>
> On 12/04/17 01:44, Andre Przywara wrote:
>> The MAPTI commands associates a DeviceID/EventID pair with a LPI/CPU
>> pair and actually instantiates LPI interrupts.
>> We connect the already allocated host LPI to this virtual LPI, so that
>> any triggering LPI on the host can be quickly forwarded to a guest.
>> Beside entering the VCPU and the virtual LPI number in the respective
>> host LPI entry, we also initialize and add the already allocated
>> struct pending_irq to our radix tree, so that we can now easily find it
>> by its virtual LPI number.
>> We also read the property table to update the enabled bit and the
>> priority for our new LPI, as we might have missed this during an earlier
>> INVALL call (which only checks mapped LPIs).
>>
>> Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx>
>> ---
>> xen/arch/arm/gic-v3-its.c | 35 ++++++++++++
>> xen/arch/arm/vgic-v3-its.c | 114
>> +++++++++++++++++++++++++++++++++++++++
>> xen/include/asm-arm/gic_v3_its.h | 3 ++
>> 3 files changed, 152 insertions(+)
>>
>> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
>> index 900c9d1..fa1f2d5 100644
>> --- a/xen/arch/arm/gic-v3-its.c
>> +++ b/xen/arch/arm/gic-v3-its.c
>> @@ -860,6 +860,41 @@ int gicv3_remove_guest_event(struct domain *d,
>> paddr_t vdoorbell_address,
>> return 0;
>> }
>>
>> +/*
>> + * Connects the event ID for an already assigned device to the given
>> VCPU/vLPI
>> + * pair. The corresponding physical LPI is already mapped on the host
>> side
>> + * (when assigning the physical device to the guest), so we just
>> connect the
>> + * target VCPU/vLPI pair to that interrupt to inject it properly if
>> it fires.
>> + * Returns a pointer to the already allocated struct pending_irq that is
>> + * meant to be used by that event.
>> + */
>> +struct pending_irq *gicv3_assign_guest_event(struct domain *d,
>> + paddr_t vdoorbell_address,
>> + uint32_t vdevid,
>> uint32_t veventid,
>> + struct vcpu *v, uint32_t
>> virt_lpi)
>> +{
>> + struct its_device *dev;
>> + struct pending_irq *pirq = NULL;
>> + uint32_t host_lpi = 0;
>> +
>> + spin_lock(&d->arch.vgic.its_devices_lock);
>> + dev = get_its_device(d, vdoorbell_address, vdevid);
>> + if ( dev )
>> + {
>> + host_lpi = get_host_lpi(dev, veventid);
>> + pirq = &dev->pend_irqs[veventid];
>> + }
>> + spin_unlock(&d->arch.vgic.its_devices_lock);
>> +
>> + if ( !host_lpi || !pirq )
>
> Again, how pirq could be NULL if host_lpi is set?
Aaargh, I missed that again. Originally I wanted to be super sure, but
it's really not necessary. Sorry, consider this fixed.
Cheers,
Andre.
>> + return NULL;
>> +
>> + gicv3_lpi_update_host_entry(host_lpi, d->domain_id,
>> + v ? v->vcpu_id : INVALID_VCPU_ID,
>> virt_lpi);
>> +
>> + return pirq;
>> +}
>> +
>> /* Scan the DT for any ITS nodes and create a list of host ITSes out
>> of it. */
>> void gicv3_its_dt_init(const struct dt_device_node *node)
>> {
>> diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
>> index 104017e..b7e61b2 100644
>> --- a/xen/arch/arm/vgic-v3-its.c
>> +++ b/xen/arch/arm/vgic-v3-its.c
>> @@ -390,6 +390,34 @@ static int its_handle_int(struct virt_its *its,
>> uint64_t *cmdptr)
>> return 0;
>> }
>>
>> +/*
>> + * For a given virtual LPI read the enabled bit and priority from the
>> virtual
>> + * property table and update the virtual IRQ's state in the given
>> pending_irq.
>> + * Must be called with the respective VGIC VCPU lock held.
>> + */
>> +static int update_lpi_property(struct domain *d, uint32_t vlpi,
>> + struct pending_irq *p)
>> +{
>> + paddr_t addr;
>> + uint8_t property;
>> + int ret;
>> +
>> + addr = d->arch.vgic.rdist_propbase & GENMASK(51, 12);
>> +
>> + ret = vgic_access_guest_memory(d, addr + vlpi - LPI_OFFSET,
>> + &property, sizeof(property), false);
>> + if ( ret )
>> + return ret;
>> +
>> + p->lpi_priority = property & LPI_PROP_PRIO_MASK;
>> + if ( property & LPI_PROP_ENABLED )
>> + set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
>> + else
>> + clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
>> +
>> + return 0;
>> +}
>> +
>> static int its_handle_mapc(struct virt_its *its, uint64_t *cmdptr)
>> {
>> uint32_t collid = its_cmd_get_collection(cmdptr);
>> @@ -532,6 +560,88 @@ static int its_handle_mapd(struct virt_its *its,
>> uint64_t *cmdptr)
>> return ret;
>> }
>>
>> +static int its_handle_mapti(struct virt_its *its, uint64_t *cmdptr)
>> +{
>> + uint32_t devid = its_cmd_get_deviceid(cmdptr);
>> + uint32_t eventid = its_cmd_get_id(cmdptr);
>> + uint32_t intid = its_cmd_get_physical_id(cmdptr), _intid;
>> + uint16_t collid = its_cmd_get_collection(cmdptr);
>> + struct pending_irq *pirq;
>> + struct vcpu *vcpu = NULL;
>> + int ret = -1;
>> +
>> + if ( its_cmd_get_command(cmdptr) == GITS_CMD_MAPI )
>> + intid = eventid;
>> +
>> + spin_lock(&its->its_lock);
>> + /*
>> + * Check whether there is a valid existing mapping. If yes,
>> behavior is
>> + * unpredictable, we choose to ignore this command here.
>> + * This makes sure we start with a pristine pending_irq below.
>> + */
>> + if ( read_itte_locked(its, devid, eventid, &vcpu, &_intid) &&
>> + _intid != INVALID_LPI )
>> + {
>> + spin_unlock(&its->its_lock);
>> + return -1;
>> + }
>> +
>> + /* Enter the mapping in our virtual ITS tables. */
>> + if ( !write_itte_locked(its, devid, eventid, collid, intid, &vcpu) )
>> + {
>> + spin_unlock(&its->its_lock);
>> + return -1;
>> + }
>> +
>> + spin_unlock(&its->its_lock);
>> +
>> + /*
>> + * Connect this virtual LPI to the corresponding host LPI, which is
>> + * determined by the same device ID and event ID on the host side.
>> + * This returns us the corresponding, still unused pending_irq.
>> + */
>> + pirq = gicv3_assign_guest_event(its->d, its->doorbell_address,
>> + devid, eventid, vcpu, intid);
>> + if ( !pirq )
>> + goto out_remove_mapping;
>> +
>> + vgic_init_pending_irq(pirq, intid);
>> +
>> + /*
>> + * Now read the guest's property table to initialize our cached
>> state.
>> + * It can't fire at this time, because it is not known to the
>> host yet.
>> + * We don't need the VGIC VCPU lock here, because the pending_irq
>> isn't
>> + * in the radix tree yet.
>> + */
>> + ret = update_lpi_property(its->d, intid, pirq);
>> + if ( ret )
>> + goto out_remove_host_entry;
>> +
>> + pirq->lpi_vcpu_id = vcpu->vcpu_id;
>> +
>> + /*
>> + * Now insert the pending_irq into the domain's LPI tree, so that
>> + * it becomes live.
>> + */
>> + write_lock(&its->d->arch.vgic.pend_lpi_tree_lock);
>> + ret = radix_tree_insert(&its->d->arch.vgic.pend_lpi_tree, intid,
>> pirq);
>> + write_unlock(&its->d->arch.vgic.pend_lpi_tree_lock);
>> +
>> + if ( !ret )
>> + return 0;
>> +
>> +out_remove_host_entry:
>> + gicv3_remove_guest_event(its->d, its->doorbell_address, devid,
>> eventid);
>> +
>> +out_remove_mapping:
>> + spin_lock(&its->its_lock);
>> + write_itte_locked(its, devid, eventid,
>> + UNMAPPED_COLLECTION, INVALID_LPI, NULL);
>> + spin_unlock(&its->its_lock);
>> +
>> + return ret;
>> +}
>> +
>> #define ITS_CMD_BUFFER_SIZE(baser) ((((baser) & 0xff) + 1) << 12)
>> #define ITS_CMD_OFFSET(reg) ((reg) & GENMASK(19, 5))
>>
>> @@ -573,6 +683,10 @@ static int vgic_its_handle_cmds(struct domain *d,
>> struct virt_its *its)
>> case GITS_CMD_MAPD:
>> ret = its_handle_mapd(its, command);
>> break;
>> + case GITS_CMD_MAPI:
>> + case GITS_CMD_MAPTI:
>> + ret = its_handle_mapti(its, command);
>> + break;
>> case GITS_CMD_SYNC:
>> /* We handle ITS commands synchronously, so we ignore
>> SYNC. */
>> break;
>> diff --git a/xen/include/asm-arm/gic_v3_its.h
>> b/xen/include/asm-arm/gic_v3_its.h
>> index 60ffdb6..7b16aeb 100644
>> --- a/xen/include/asm-arm/gic_v3_its.h
>> +++ b/xen/include/asm-arm/gic_v3_its.h
>> @@ -172,6 +172,9 @@ void gicv3_free_host_lpi_block(uint32_t first_lpi);
>> int gicv3_remove_guest_event(struct domain *d, paddr_t
>> vdoorbell_address,
>> uint32_t vdevid, uint32_t
>> veventid);
>>
>> +struct pending_irq *gicv3_assign_guest_event(struct domain *d,
>> paddr_t doorbell,
>> + uint32_t devid, uint32_t
>> eventid,
>> + struct vcpu *v, uint32_t
>> virt_lpi);
>> void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id,
>> unsigned int vcpu_id, uint32_t
>> virt_lpi);
>>
>>
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |