[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 |