[Xen-devel] [PATCH v5 23/30] ARM: vITS: handle MAPTI command

2017-04-05 Thread Andre Przywara
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

2017-04-05 Thread Stefano Stabellini
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

2017-04-07 Thread Julien Grall

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

2017-04-07 Thread Julien Grall



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

2017-04-07 Thread Andre Przywara
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

2017-04-11 Thread Andre Przywara
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