[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 19/26] ARM: vITS: handle MAPTI command
On Fri, Mar 31, 2017 at 11:35 PM, Andre Przywara <andre.przywara@xxxxxxx> 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 IRQ 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. > This exports the vgic_init_pending_irq() function for that purpose. > > Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx> > --- > xen/arch/arm/gic-v3-its.c | 74 > ++++++++++++++++++++++++++++++++++++++++ > xen/arch/arm/gic-v3-lpi.c | 16 +++++++++ > xen/arch/arm/vgic-v3-its.c | 36 +++++++++++++++++-- > xen/arch/arm/vgic.c | 2 +- > xen/include/asm-arm/gic_v3_its.h | 6 ++++ > xen/include/asm-arm/vgic.h | 1 + > 6 files changed, 132 insertions(+), 3 deletions(-) > > diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c > index 8db2a09..39f16b2 100644 > --- a/xen/arch/arm/gic-v3-its.c > +++ b/xen/arch/arm/gic-v3-its.c > @@ -747,6 +747,80 @@ restart: > spin_unlock(&d->arch.vgic.its_devices_lock); > } > > +/* Must be called with the its_device_lock held. */ > +static struct its_devices *get_its_device(struct domain *d, paddr_t doorbell, > + uint32_t devid) > +{ > + struct rb_node *node = d->arch.vgic.its_devices.rb_node; > + struct its_devices *dev; > + > + while (node) > + { > + int cmp; > + > + dev = rb_entry(node, struct its_devices, rbnode); > + cmp = compare_its_guest_devices(dev, doorbell, devid); > + > + if ( !cmp ) > + return dev; > + > + if ( cmp > 0 ) > + node = node->rb_left; > + else > + node = node->rb_right; > + } > + > + return NULL; > +} > + > +static uint32_t get_host_lpi(struct its_devices *dev, uint32_t eventid) > +{ > + uint32_t host_lpi = 0; > + > + if ( dev && (eventid < dev->eventids) ) > + { > + host_lpi = dev->host_lpi_blocks[eventid / LPI_BLOCK] + > + (eventid % LPI_BLOCK); > + if ( !is_lpi(host_lpi) ) > + host_lpi = 0; > + } > + > + return host_lpi; > +} > + > +/* > + * 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. > + */ > +struct pending_irq *gicv3_assign_guest_event(struct domain *d, > + paddr_t doorbell_address, > + uint32_t devid, uint32_t > eventid, > + struct vcpu *v, uint32_t > virt_lpi) > +{ > + struct its_devices *dev; > + struct pending_irq *pirq = NULL; > + uint32_t host_lpi = 0; > + > + spin_lock(&d->arch.vgic.its_devices_lock); > + dev = get_its_device(d, doorbell_address, devid); > + if ( dev ) > + { > + host_lpi = get_host_lpi(dev, eventid); > + pirq = &dev->pend_irqs[eventid]; > + } > + spin_unlock(&d->arch.vgic.its_devices_lock); > + > + if ( !host_lpi || !pirq ) > + return NULL; > + > + gicv3_lpi_update_host_entry(host_lpi, d->domain_id, > + v ? v->vcpu_id : -1, 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/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c > index 2301d53..a6b728e 100644 > --- a/xen/arch/arm/gic-v3-lpi.c > +++ b/xen/arch/arm/gic-v3-lpi.c > @@ -178,6 +178,22 @@ void do_LPI(unsigned int lpi) > rcu_unlock_domain(d); > } > > +void gicv3_lpi_update_host_entry(uint32_t host_lpi, int domain_id, > + unsigned int vcpu_id, uint32_t virt_lpi) > +{ > + union host_lpi *hlpip, hlpi; > + > + host_lpi -= LPI_OFFSET; > + > + hlpip = &lpi_data.host_lpis[host_lpi / HOST_LPIS_PER_PAGE][host_lpi % > HOST_LPIS_PER_PAGE]; > + > + hlpi.virt_lpi = virt_lpi; > + hlpi.dom_id = domain_id; > + hlpi.vcpu_id = vcpu_id; > + > + write_u64_atomic(&hlpip->data, hlpi.data); > +} > + > static int gicv3_lpi_allocate_pendtable(uint64_t *reg) > { > uint64_t val; > diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c > index 36b44f2..d9dce3f 100644 > --- a/xen/arch/arm/vgic-v3-its.c > +++ b/xen/arch/arm/vgic-v3-its.c > @@ -258,8 +258,8 @@ static bool read_itte(struct virt_its *its, uint32_t > devid, uint32_t evid, > } > > #define SKIP_LPI_UPDATE 1 > -bool write_itte(struct virt_its *its, uint32_t devid, uint32_t evid, > - uint32_t collid, uint32_t vlpi, struct vcpu **vcpu) > +static bool write_itte(struct virt_its *its, uint32_t devid, uint32_t evid, > + uint32_t collid, uint32_t vlpi, struct vcpu **vcpu) > { > struct vits_itte *itte; > > @@ -421,6 +421,34 @@ 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); > + uint16_t collid = its_cmd_get_collection(cmdptr); > + struct pending_irq *pirq; > + struct vcpu *vcpu; > + > + if ( its_cmd_get_command(cmdptr) == GITS_CMD_MAPI ) > + intid = eventid; > + > + pirq = gicv3_assign_guest_event(its->d, its->doorbell_address, > + devid, eventid, vcpu, intid); This series does not compile. vcpu is not initliazed. > + if ( !pirq ) > + return -1; > + > + vgic_init_pending_irq(pirq, intid); > + write_lock(&its->d->arch.vgic.pend_lpi_tree_lock); > + radix_tree_insert(&its->d->arch.vgic.pend_lpi_tree, intid, pirq); > + write_unlock(&its->d->arch.vgic.pend_lpi_tree_lock); > + > + if ( !write_itte(its, devid, eventid, collid, intid, &vcpu) ) > + return -1; > + > + return 0; > +} > + > #define ITS_CMD_BUFFER_SIZE(baser) ((((baser) & 0xff) + 1) << 12) > > static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its, > @@ -470,6 +498,10 @@ static int vgic_its_handle_cmds(struct domain *d, struct > virt_its *its, > case GITS_CMD_MAPD: > ret = its_handle_mapd(its, cmdptr); > break; > + case GITS_CMD_MAPI: > + case GITS_CMD_MAPTI: > + ret = its_handle_mapti(its, cmdptr); > + break; > case GITS_CMD_SYNC: > /* We handle ITS commands synchronously, so we ignore SYNC. */ > break; > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c > index 2aee20f..94eb9c5 100644 > --- a/xen/arch/arm/vgic.c > +++ b/xen/arch/arm/vgic.c > @@ -61,7 +61,7 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, > unsigned int irq) > return vgic_get_rank(v, rank); > } > > -static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq) > +void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq) > { > INIT_LIST_HEAD(&p->inflight); > INIT_LIST_HEAD(&p->lr_queue); > diff --git a/xen/include/asm-arm/gic_v3_its.h > b/xen/include/asm-arm/gic_v3_its.h > index bc9b42a..35a3e22 100644 > --- a/xen/include/asm-arm/gic_v3_its.h > +++ b/xen/include/asm-arm/gic_v3_its.h > @@ -161,6 +161,12 @@ void gicv3_its_unmap_all_devices(struct domain *d); > int gicv3_allocate_host_lpi_block(struct domain *d, uint32_t *first_lpi); > void gicv3_free_host_lpi_block(uint32_t first_lpi); > > +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); > + > #else > > static LIST_HEAD(host_its_list); > diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h > index 9f48e9a..3fb7433 100644 > --- a/xen/include/asm-arm/vgic.h > +++ b/xen/include/asm-arm/vgic.h > @@ -298,6 +298,7 @@ extern struct vcpu *vgic_get_target_vcpu(struct vcpu *v, > unsigned int virq); > extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq); > extern void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq); > extern void vgic_clear_pending_irqs(struct vcpu *v); > +extern void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq); > extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq); > extern struct pending_irq *spi_to_pending(struct domain *d, unsigned int > irq); > extern struct pending_irq *lpi_to_pending(struct domain *d, unsigned int > irq); > -- > 2.9.0 > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |