[Xen-devel] [PATCH v5 23/30] ARM: vITS: handle MAPTI command
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. To be able to later find the targetting VCPU for any given LPI without having to walk *all* ITS tables, we store the VCPU ID in the pending_irq struct as well. This exports the vgic_init_pending_irq() function to be able to initialize a new struct pending_irq. As write_itte() is now eventually used, we can now add the static tag. Signed-off-by: Andre Przywara --- xen/arch/arm/gic-v3-its.c| 74 ++ xen/arch/arm/gic-v3-lpi.c| 18 ++ xen/arch/arm/vgic-v3-its.c | 76 ++-- xen/arch/arm/vgic.c | 2 +- xen/include/asm-arm/gic_v3_its.h | 6 xen/include/asm-arm/vgic.h | 2 ++ 6 files changed, 175 insertions(+), 3 deletions(-) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 76b0316..d970119 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -777,6 +777,80 @@ out: return ret; } +/* Must be called with the its_device_lock held. */ +static struct its_devices *get_its_device(struct domain *d, paddr_t vdoorbell, + uint32_t vdevid) +{ +struct rb_node *node = d->arch.vgic.its_devices.rb_node; +struct its_devices *dev; + +ASSERT(spin_is_locked(&d->arch.vgic.its_devices_lock)); + +while (node) +{ +int cmp; + +dev = rb_entry(node, struct its_devices, rbnode); +cmp = compare_its_guest_devices(dev, vdoorbell, vdevid); + +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); + +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. + * 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_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, 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 ) +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/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c index 7d20986..c997ed5 100644 --- a/xen/arch/arm/gic-v3-lpi.c +++ b/xen/arch/arm/gic-v3-lpi.c @@ -216,6 +216,24 @@ void gicv3_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; + +ASSERT(host_lpi >= LPI_OFFSET); + +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 0372ed0..079dd44 100644 --- a/xen/arch/arm/vgic-v3-its.c +++ b/xen/arch/arm/vgic-v3-its.c @@ -275,8 +275,8 @@ static bool write_itte_locked(struct virt_it
Re: [Xen-devel] [PATCH v5 23/30] ARM: vITS: handle MAPTI command
On Thu, 6 Apr 2017, 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. > To be able to later find the targetting VCPU for any given LPI without > having to walk *all* ITS tables, we store the VCPU ID in the pending_irq > struct as well. > This exports the vgic_init_pending_irq() function to be able to > initialize a new struct pending_irq. > As write_itte() is now eventually used, we can now add the static tag. > > Signed-off-by: Andre Przywara > --- > xen/arch/arm/gic-v3-its.c| 74 ++ > xen/arch/arm/gic-v3-lpi.c| 18 ++ > xen/arch/arm/vgic-v3-its.c | 76 > ++-- > xen/arch/arm/vgic.c | 2 +- > xen/include/asm-arm/gic_v3_its.h | 6 > xen/include/asm-arm/vgic.h | 2 ++ > 6 files changed, 175 insertions(+), 3 deletions(-) > > diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c > index 76b0316..d970119 100644 > --- a/xen/arch/arm/gic-v3-its.c > +++ b/xen/arch/arm/gic-v3-its.c > @@ -777,6 +777,80 @@ out: > return ret; > } > > +/* Must be called with the its_device_lock held. */ > +static struct its_devices *get_its_device(struct domain *d, paddr_t > vdoorbell, > + uint32_t vdevid) > +{ > +struct rb_node *node = d->arch.vgic.its_devices.rb_node; > +struct its_devices *dev; > + > +ASSERT(spin_is_locked(&d->arch.vgic.its_devices_lock)); > + > +while (node) > +{ > +int cmp; > + > +dev = rb_entry(node, struct its_devices, rbnode); > +cmp = compare_its_guest_devices(dev, vdoorbell, vdevid); > + > +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); > + > +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. > + * 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_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, 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 ) > +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/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c > index 7d20986..c997ed5 100644 > --- a/xen/arch/arm/gic-v3-lpi.c > +++ b/xen/arch/arm/gic-v3-lpi.c > @@ -216,6 +216,24 @@ void gicv3_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; > + > +ASSERT(host_lpi >= LPI_OFFSET); > + > +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->d
Re: [Xen-devel] [PATCH v5 23/30] ARM: vITS: handle MAPTI command
Hi Andre, On 06/04/17 00:19, 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. To be able to later find the targetting VCPU for any given LPI without having to walk *all* ITS tables, we store the VCPU ID in the pending_irq struct as well. This exports the vgic_init_pending_irq() function to be able to initialize a new struct pending_irq. As write_itte() is now eventually used, we can now add the static tag. Signed-off-by: Andre Przywara --- xen/arch/arm/gic-v3-its.c| 74 ++ xen/arch/arm/gic-v3-lpi.c| 18 ++ xen/arch/arm/vgic-v3-its.c | 76 ++-- xen/arch/arm/vgic.c | 2 +- xen/include/asm-arm/gic_v3_its.h | 6 xen/include/asm-arm/vgic.h | 2 ++ 6 files changed, 175 insertions(+), 3 deletions(-) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 76b0316..d970119 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -777,6 +777,80 @@ out: return ret; } +/* Must be called with the its_device_lock held. */ +static struct its_devices *get_its_device(struct domain *d, paddr_t vdoorbell, + uint32_t vdevid) +{ +struct rb_node *node = d->arch.vgic.its_devices.rb_node; +struct its_devices *dev; + +ASSERT(spin_is_locked(&d->arch.vgic.its_devices_lock)); + +while (node) +{ +int cmp; + +dev = rb_entry(node, struct its_devices, rbnode); +cmp = compare_its_guest_devices(dev, vdoorbell, vdevid); + +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); + +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. + * 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_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, 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 ) How pirq could be NULL if host_lpi is set? +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/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c index 7d20986..c997ed5 100644 --- a/xen/arch/arm/gic-v3-lpi.c +++ b/xen/arch/arm/gic-v3-lpi.c @@ -216,6 +216,24 @@ void gicv3_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; + +ASSERT(host_lpi >= LPI_OFFSET); + +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 0372ed0..079dd44 100644 --- a/xen/arch/arm/vgic-v3-its.
Re: [Xen-devel] [PATCH v5 23/30] ARM: vITS: handle MAPTI command
On 06/04/17 00:19, Andre Przywara wrote: +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. + */ +ret = update_lpi_property(its->d, intid, pirq); This function is introduced in a latter patch (see #26). Please re-order the patches to avoid that. +if ( ret ) +return ret; + +pirq->vcpu_id = vcpu->vcpu_id; Cheers, -- Julien Grall ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v5 23/30] ARM: vITS: handle MAPTI command
Hi, On 07/04/17 14:07, Julien Grall wrote: > > > On 06/04/17 00:19, Andre Przywara wrote: >> +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. >> + */ >> +ret = update_lpi_property(its->d, intid, pirq); > > This function is introduced in a latter patch (see #26). Please re-order > the patches to avoid that. Thanks for the heads up, I found this myself already and just fixed it. Cheers, Andre. >> +if ( ret ) >> +return ret; >> + >> +pirq->vcpu_id = vcpu->vcpu_id; > > Cheers, > ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v5 23/30] ARM: vITS: handle MAPTI command
Hi, On 06/04/17 01:45, Stefano Stabellini wrote: > On Thu, 6 Apr 2017, 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. >> To be able to later find the targetting VCPU for any given LPI without >> having to walk *all* ITS tables, we store the VCPU ID in the pending_irq >> struct as well. >> This exports the vgic_init_pending_irq() function to be able to >> initialize a new struct pending_irq. >> As write_itte() is now eventually used, we can now add the static tag. >> >> Signed-off-by: Andre Przywara >> --- >> xen/arch/arm/gic-v3-its.c| 74 ++ >> xen/arch/arm/gic-v3-lpi.c| 18 ++ >> xen/arch/arm/vgic-v3-its.c | 76 >> ++-- >> xen/arch/arm/vgic.c | 2 +- >> xen/include/asm-arm/gic_v3_its.h | 6 >> xen/include/asm-arm/vgic.h | 2 ++ >> 6 files changed, 175 insertions(+), 3 deletions(-) >> >> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c >> index 76b0316..d970119 100644 >> --- a/xen/arch/arm/gic-v3-its.c >> +++ b/xen/arch/arm/gic-v3-its.c >> @@ -777,6 +777,80 @@ out: >> return ret; >> } >> >> +/* Must be called with the its_device_lock held. */ >> +static struct its_devices *get_its_device(struct domain *d, paddr_t >> vdoorbell, >> + uint32_t vdevid) >> +{ >> +struct rb_node *node = d->arch.vgic.its_devices.rb_node; >> +struct its_devices *dev; >> + >> +ASSERT(spin_is_locked(&d->arch.vgic.its_devices_lock)); >> + >> +while (node) >> +{ >> +int cmp; >> + >> +dev = rb_entry(node, struct its_devices, rbnode); >> +cmp = compare_its_guest_devices(dev, vdoorbell, vdevid); >> + >> +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); >> + >> +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. >> + * 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_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, 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 ) >> +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/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c >> index 7d20986..c997ed5 100644 >> --- a/xen/arch/arm/gic-v3-lpi.c >> +++ b/xen/arch/arm/gic-v3-lpi.c >> @@ -216,6 +216,24 @@ void gicv3_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; >> + >> +ASSERT(host_lpi >= LPI_OFFSET); >> + >> +host_lpi -= LPI_OFFSET; >> + >> +hlpip = &lpi_data.host_lpis[host_lpi / HOST