Re: [PATCH 01/10] vpci: move lock

2021-11-23 Thread Oleksandr Andrushchenko
Hi, Roger, Jan!

I think the below work will help with solving issues brought up by [1].

So, after thinking a bit more I concluded that indeed we do not actually
need a per-domain vPCI lock, but instead we just want to protect pdev->vpci
which is done in this patch.

At the moment I see four entities which may run concurrently and touch vpci:
1. hypercalls PHYSDEVOP_pci_device_{add|remove} - for Dom0 only
2. hypercalls XEN_DOMCTL_{de|}assign_device - any domain
3. MMIO trap handlers vpci_{read|write}
4. vpci_process_pending

 From the above #1 will update pdev->vpci and #4 may remove pdev->vpci
with vpci_remove_device on error path for Dom0. #2 and #3 seem to be
readers only. So, it is possible to improve this patch to not only take
pdev->vpci->lock out of struct vpci, but also to convert it into RW lock.

Hope this is what is needed in context of vpci and locking.

Thank you,
Oleksandr

On 20.06.18 17:42, Roger Pau Monne wrote:
> To the outside of the vpci struct. This way the lock can be used to
> check whether vpci is present, and removal can be performed while
> holding the lock, in order to make sure there are no accesses to the
> contents of the vpci struct. Previously removal could race with
> vpci_read for example, since the log was dropped prior to freeing
> pdev->vpci.
>
> Signed-off-by: Roger Pau Monné 
> ---
> Cc: Andrew Cooper 
> Cc: George Dunlap 
> Cc: Ian Jackson 
> Cc: Jan Beulich 
> Cc: Julien Grall 
> Cc: Konrad Rzeszutek Wilk 
> Cc: Stefano Stabellini 
> Cc: Tim Deegan 
> Cc: Wei Liu 
> ---
>   tools/tests/vpci/emul.h   |  5 ++--
>   tools/tests/vpci/main.c   |  4 +--
>   xen/arch/x86/hvm/vmsi.c   |  8 +++---
>   xen/drivers/passthrough/pci.c |  1 +
>   xen/drivers/vpci/header.c | 19 +
>   xen/drivers/vpci/msi.c| 11 +---
>   xen/drivers/vpci/msix.c   |  8 +++---
>   xen/drivers/vpci/vpci.c   | 51 ++-
>   xen/include/xen/pci.h |  1 +
>   xen/include/xen/vpci.h|  3 +--
>   10 files changed, 70 insertions(+), 41 deletions(-)
>
> diff --git a/tools/tests/vpci/emul.h b/tools/tests/vpci/emul.h
> index 5d47544bf7..d344ef71c9 100644
> --- a/tools/tests/vpci/emul.h
> +++ b/tools/tests/vpci/emul.h
> @@ -44,6 +44,7 @@ struct domain {
>   };
>   
>   struct pci_dev {
> +bool vpci_lock;
>   struct vpci *vpci;
>   };
>   
> @@ -53,10 +54,8 @@ struct vcpu
>   };
>   
>   extern const struct vcpu *current;
> -extern const struct pci_dev test_pdev;
> +extern struct pci_dev test_pdev;
>   
> -typedef bool spinlock_t;
> -#define spin_lock_init(l) (*(l) = false)
>   #define spin_lock(l) (*(l) = true)
>   #define spin_unlock(l) (*(l) = false)
>   
> diff --git a/tools/tests/vpci/main.c b/tools/tests/vpci/main.c
> index b9a0a6006b..26c95b08b6 100644
> --- a/tools/tests/vpci/main.c
> +++ b/tools/tests/vpci/main.c
> @@ -23,7 +23,8 @@ static struct vpci vpci;
>   
>   const static struct domain d;
>   
> -const struct pci_dev test_pdev = {
> +struct pci_dev test_pdev = {
> +.vpci_lock = false,
>   .vpci = &vpci,
>   };
>   
> @@ -158,7 +159,6 @@ main(int argc, char **argv)
>   int rc;
>   
>   INIT_LIST_HEAD(&vpci.handlers);
> -spin_lock_init(&vpci.lock);
>   
>   VPCI_ADD_REG(vpci_read32, vpci_write32, 0, 4, r0);
>   VPCI_READ_CHECK(0, 4, r0);
> diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c
> index 3001d5c488..94550cb8c4 100644
> --- a/xen/arch/x86/hvm/vmsi.c
> +++ b/xen/arch/x86/hvm/vmsi.c
> @@ -893,14 +893,14 @@ int vpci_msix_arch_print(const struct vpci_msix *msix)
>   {
>   struct pci_dev *pdev = msix->pdev;
>   
> -spin_unlock(&msix->pdev->vpci->lock);
> +spin_unlock(&msix->pdev->vpci_lock);
>   process_pending_softirqs();
>   /* NB: we assume that pdev cannot go away for an alive domain. 
> */
> -if ( !pdev->vpci || !spin_trylock(&pdev->vpci->lock) )
> +if ( !spin_trylock(&pdev->vpci_lock) )
>   return -EBUSY;
> -if ( pdev->vpci->msix != msix )
> +if ( !pdev->vpci || pdev->vpci->msix != msix )
>   {
> -spin_unlock(&pdev->vpci->lock);
> +spin_unlock(&pdev->vpci_lock);
>   return -EAGAIN;
>   }
>   }
> diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
> index c4890a4295..a5d59b83b7 100644
> --- a/xen/drivers/passthrough/pci.c
> +++ b/xen/drivers/passthrough/pci.c
> @@ -315,6 +315,7 @@ static struct pci_dev *alloc_pdev(struct pci_seg *pseg, 
> u8 bus, u8 devfn)
>   *((u8*) &pdev->devfn) = devfn;
>   pdev->domain = NULL;
>   INIT_LIST_HEAD(&pdev->msi_list);
> +spin_lock_init(&pdev->vpci_lock);
>   
>   if ( pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn), 
> PCI_FUNC(devfn),
>PCI_CAP_ID_MSIX) )
> diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
> index 0ec4

Re: [Xen-devel] [PATCH 01/10] vpci: move lock

2018-06-29 Thread Julien Grall

Hi Roger,

On 29/06/18 14:27, Roger Pau Monné wrote:

On Fri, Jun 29, 2018 at 11:19:57AM +0100, Wei Liu wrote:

On Wed, Jun 20, 2018 at 04:42:25PM +0200, Roger Pau Monne wrote:

diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index 0ec4c082a6..9d5607d5f8 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -131,11 +131,12 @@ bool vpci_process_pending(struct vcpu *v)
  if ( rc == -ERESTART )
  return true;
  
-spin_lock(&v->vpci.pdev->vpci->lock);

-/* Disable memory decoding unconditionally on failure. */
-modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
-!rc && v->vpci.rom_only);
-spin_unlock(&v->vpci.pdev->vpci->lock);
+spin_lock(&v->vpci.pdev->vpci_lock);
+if ( v->vpci.pdev->vpci )


The purpose of this check is to fix a latent bug in the original code?


Previous code didn't support removing devices, so it's more about
making it capable of supporting vpci device removal.


+/* Disable memory decoding unconditionally on failure. */
+modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
+!rc && v->vpci.rom_only);
+spin_unlock(&v->vpci.pdev->vpci_lock);
  

[...]

diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
index 82607bdb9a..7d52bcf8d0 100644
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -35,9 +35,8 @@ extern vpci_register_init_t *const __start_vpci_array[];
  extern vpci_register_init_t *const __end_vpci_array[];
  #define NUM_VPCI_INIT (__end_vpci_array - __start_vpci_array)
  
-void vpci_remove_device(struct pci_dev *pdev)

+static void vpci_remove_device_locked(struct pci_dev *pdev)
  {
-spin_lock(&pdev->vpci->lock);


ASSERT(spin_is_locked(&pdev->vpci_lock));


Er, yes. But keep in mind that this is going to return `true` even if
vpci_lock is locked by another CPU. Asserting lock ownership only
works correctly with recursive locks.


While I agree with your statement, the point of the ASSERT is to catch 
misuse, there are a fair amount of chance to have no contention on the 
lock (something would need to be done if it was the case anyway).


So in general, I still recommend developer to use 
ASSERT(spin_is_lock(...)) in any function relying on a lock taken. And 
who knows, maybe some day we would have a spin lock helper checking the 
CPU making the ASSERT more reliable.


Cheers,

--
Julien Grall

___
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

Re: [Xen-devel] [PATCH 01/10] vpci: move lock

2018-06-29 Thread Roger Pau Monné
On Fri, Jun 29, 2018 at 11:19:57AM +0100, Wei Liu wrote:
> On Wed, Jun 20, 2018 at 04:42:25PM +0200, Roger Pau Monne wrote:
> > diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
> > index 0ec4c082a6..9d5607d5f8 100644
> > --- a/xen/drivers/vpci/header.c
> > +++ b/xen/drivers/vpci/header.c
> > @@ -131,11 +131,12 @@ bool vpci_process_pending(struct vcpu *v)
> >  if ( rc == -ERESTART )
> >  return true;
> >  
> > -spin_lock(&v->vpci.pdev->vpci->lock);
> > -/* Disable memory decoding unconditionally on failure. */
> > -modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
> > -!rc && v->vpci.rom_only);
> > -spin_unlock(&v->vpci.pdev->vpci->lock);
> > +spin_lock(&v->vpci.pdev->vpci_lock);
> > +if ( v->vpci.pdev->vpci )
> 
> The purpose of this check is to fix a latent bug in the original code?

Previous code didn't support removing devices, so it's more about
making it capable of supporting vpci device removal.

> > +/* Disable memory decoding unconditionally on failure. */
> > +modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
> > +!rc && v->vpci.rom_only);
> > +spin_unlock(&v->vpci.pdev->vpci_lock);
> >  
> [...]
> > diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
> > index 82607bdb9a..7d52bcf8d0 100644
> > --- a/xen/drivers/vpci/vpci.c
> > +++ b/xen/drivers/vpci/vpci.c
> > @@ -35,9 +35,8 @@ extern vpci_register_init_t *const __start_vpci_array[];
> >  extern vpci_register_init_t *const __end_vpci_array[];
> >  #define NUM_VPCI_INIT (__end_vpci_array - __start_vpci_array)
> >  
> > -void vpci_remove_device(struct pci_dev *pdev)
> > +static void vpci_remove_device_locked(struct pci_dev *pdev)
> >  {
> > -spin_lock(&pdev->vpci->lock);
> 
> ASSERT(spin_is_locked(&pdev->vpci_lock));

Er, yes. But keep in mind that this is going to return `true` even if
vpci_lock is locked by another CPU. Asserting lock ownership only
works correctly with recursive locks.

> > @@ -383,7 +391,7 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
> > unsigned int size)
> >  
> >  data = merge_result(data, tmp_data, size - data_offset, 
> > data_offset);
> >  }
> > -spin_unlock(&pdev->vpci->lock);
> > +spin_unlock(&pdev->vpci_lock);
> 
> I think the critical section in this function and the write function can
> shrink a bit. Reading from / writing to hardware shouldn't need to be
> protected by vpci_lock.

There's no further usage of contents of the vpci struct, so I guess I
can move the unlock a little bit up. The same applies to the write
counterpart.

Thanks, Roger.

___
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

Re: [Xen-devel] [PATCH 01/10] vpci: move lock

2018-06-29 Thread Wei Liu
On Wed, Jun 20, 2018 at 04:42:25PM +0200, Roger Pau Monne wrote:
> To the outside of the vpci struct. This way the lock can be used to
> check whether vpci is present, and removal can be performed while
> holding the lock, in order to make sure there are no accesses to the
> contents of the vpci struct. Previously removal could race with
> vpci_read for example, since the log was dropped prior to freeing

log -> lock.

> pdev->vpci.
> 
> Signed-off-by: Roger Pau Monné 
[...]
> diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
> index 0ec4c082a6..9d5607d5f8 100644
> --- a/xen/drivers/vpci/header.c
> +++ b/xen/drivers/vpci/header.c
> @@ -131,11 +131,12 @@ bool vpci_process_pending(struct vcpu *v)
>  if ( rc == -ERESTART )
>  return true;
>  
> -spin_lock(&v->vpci.pdev->vpci->lock);
> -/* Disable memory decoding unconditionally on failure. */
> -modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
> -!rc && v->vpci.rom_only);
> -spin_unlock(&v->vpci.pdev->vpci->lock);
> +spin_lock(&v->vpci.pdev->vpci_lock);
> +if ( v->vpci.pdev->vpci )

The purpose of this check is to fix a latent bug in the original code?

> +/* Disable memory decoding unconditionally on failure. */
> +modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
> +!rc && v->vpci.rom_only);
> +spin_unlock(&v->vpci.pdev->vpci_lock);
>  
[...]
> diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
> index 82607bdb9a..7d52bcf8d0 100644
> --- a/xen/drivers/vpci/vpci.c
> +++ b/xen/drivers/vpci/vpci.c
> @@ -35,9 +35,8 @@ extern vpci_register_init_t *const __start_vpci_array[];
>  extern vpci_register_init_t *const __end_vpci_array[];
>  #define NUM_VPCI_INIT (__end_vpci_array - __start_vpci_array)
>  
> -void vpci_remove_device(struct pci_dev *pdev)
> +static void vpci_remove_device_locked(struct pci_dev *pdev)
>  {
> -spin_lock(&pdev->vpci->lock);

ASSERT(spin_is_locked(&pdev->vpci_lock));

>  while ( !list_empty(&pdev->vpci->handlers) )
>  {
>  struct vpci_register *r = list_first_entry(&pdev->vpci->handlers,
> @@ -47,13 +46,20 @@ void vpci_remove_device(struct pci_dev *pdev)
>  list_del(&r->node);
>  xfree(r);
>  }
> -spin_unlock(&pdev->vpci->lock);
>  xfree(pdev->vpci->msix);
>  xfree(pdev->vpci->msi);
>  xfree(pdev->vpci);
>  pdev->vpci = NULL;
>  }
>  
> +void vpci_remove_device(struct pci_dev *pdev)
> +{
> +spin_lock(&pdev->vpci_lock);
> +vpci_remove_device_locked(pdev);
> +spin_unlock(&pdev->vpci_lock);
> +}
> +
> +

Too many blank lines.

>  int __hwdom_init vpci_add_handlers(struct pci_dev *pdev)
>  {
>  unsigned int i;
> @@ -62,12 +68,15 @@ int __hwdom_init vpci_add_handlers(struct pci_dev *pdev)
>  if ( !has_vpci(pdev->domain) )
>  return 0;
>  
> +spin_lock(&pdev->vpci_lock);
>  pdev->vpci = xzalloc(struct vpci);
>  if ( !pdev->vpci )
> +{
> +spin_unlock(&pdev->vpci_lock);
>  return -ENOMEM;
> +}
>  
>  INIT_LIST_HEAD(&pdev->vpci->handlers);
> -spin_lock_init(&pdev->vpci->lock);
>  
>  for ( i = 0; i < NUM_VPCI_INIT; i++ )
>  {
[...]
> @@ -77,7 +86,8 @@ int __hwdom_init vpci_add_handlers(struct pci_dev *pdev)
> @@ -315,7 +318,7 @@ static uint32_t merge_result(uint32_t data, uint32_t new, 
> unsigned int size,
>  uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, unsigned int size)
>  {
>  const struct domain *d = current->domain;
> -const struct pci_dev *pdev;
> +struct pci_dev *pdev;
>  const struct vpci_register *r;
>  unsigned int data_offset = 0;
>  uint32_t data = ~(uint32_t)0;
> @@ -331,7 +334,12 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
> unsigned int size)
>  if ( !pdev )
>  return vpci_read_hw(sbdf, reg, size);
>  
> -spin_lock(&pdev->vpci->lock);
> +spin_lock(&pdev->vpci_lock);
> +if ( !pdev->vpci )
> +{
> +spin_unlock(&pdev->vpci_lock);
> +return vpci_read_hw(sbdf, reg, size);
> +}
>  
>  /* Read from the hardware or the emulated register handlers. */
>  list_for_each_entry ( r, &pdev->vpci->handlers, node )
> @@ -383,7 +391,7 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
> unsigned int size)
>  
>  data = merge_result(data, tmp_data, size - data_offset, data_offset);
>  }
> -spin_unlock(&pdev->vpci->lock);
> +spin_unlock(&pdev->vpci_lock);

I think the critical section in this function and the write function can
shrink a bit. Reading from / writing to hardware shouldn't need to be
protected by vpci_lock.

Wei.

___
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

[Xen-devel] [PATCH 01/10] vpci: move lock

2018-06-20 Thread Roger Pau Monne
To the outside of the vpci struct. This way the lock can be used to
check whether vpci is present, and removal can be performed while
holding the lock, in order to make sure there are no accesses to the
contents of the vpci struct. Previously removal could race with
vpci_read for example, since the log was dropped prior to freeing
pdev->vpci.

Signed-off-by: Roger Pau Monné 
---
Cc: Andrew Cooper 
Cc: George Dunlap 
Cc: Ian Jackson 
Cc: Jan Beulich 
Cc: Julien Grall 
Cc: Konrad Rzeszutek Wilk 
Cc: Stefano Stabellini 
Cc: Tim Deegan 
Cc: Wei Liu 
---
 tools/tests/vpci/emul.h   |  5 ++--
 tools/tests/vpci/main.c   |  4 +--
 xen/arch/x86/hvm/vmsi.c   |  8 +++---
 xen/drivers/passthrough/pci.c |  1 +
 xen/drivers/vpci/header.c | 19 +
 xen/drivers/vpci/msi.c| 11 +---
 xen/drivers/vpci/msix.c   |  8 +++---
 xen/drivers/vpci/vpci.c   | 51 ++-
 xen/include/xen/pci.h |  1 +
 xen/include/xen/vpci.h|  3 +--
 10 files changed, 70 insertions(+), 41 deletions(-)

diff --git a/tools/tests/vpci/emul.h b/tools/tests/vpci/emul.h
index 5d47544bf7..d344ef71c9 100644
--- a/tools/tests/vpci/emul.h
+++ b/tools/tests/vpci/emul.h
@@ -44,6 +44,7 @@ struct domain {
 };
 
 struct pci_dev {
+bool vpci_lock;
 struct vpci *vpci;
 };
 
@@ -53,10 +54,8 @@ struct vcpu
 };
 
 extern const struct vcpu *current;
-extern const struct pci_dev test_pdev;
+extern struct pci_dev test_pdev;
 
-typedef bool spinlock_t;
-#define spin_lock_init(l) (*(l) = false)
 #define spin_lock(l) (*(l) = true)
 #define spin_unlock(l) (*(l) = false)
 
diff --git a/tools/tests/vpci/main.c b/tools/tests/vpci/main.c
index b9a0a6006b..26c95b08b6 100644
--- a/tools/tests/vpci/main.c
+++ b/tools/tests/vpci/main.c
@@ -23,7 +23,8 @@ static struct vpci vpci;
 
 const static struct domain d;
 
-const struct pci_dev test_pdev = {
+struct pci_dev test_pdev = {
+.vpci_lock = false,
 .vpci = &vpci,
 };
 
@@ -158,7 +159,6 @@ main(int argc, char **argv)
 int rc;
 
 INIT_LIST_HEAD(&vpci.handlers);
-spin_lock_init(&vpci.lock);
 
 VPCI_ADD_REG(vpci_read32, vpci_write32, 0, 4, r0);
 VPCI_READ_CHECK(0, 4, r0);
diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c
index 3001d5c488..94550cb8c4 100644
--- a/xen/arch/x86/hvm/vmsi.c
+++ b/xen/arch/x86/hvm/vmsi.c
@@ -893,14 +893,14 @@ int vpci_msix_arch_print(const struct vpci_msix *msix)
 {
 struct pci_dev *pdev = msix->pdev;
 
-spin_unlock(&msix->pdev->vpci->lock);
+spin_unlock(&msix->pdev->vpci_lock);
 process_pending_softirqs();
 /* NB: we assume that pdev cannot go away for an alive domain. */
-if ( !pdev->vpci || !spin_trylock(&pdev->vpci->lock) )
+if ( !spin_trylock(&pdev->vpci_lock) )
 return -EBUSY;
-if ( pdev->vpci->msix != msix )
+if ( !pdev->vpci || pdev->vpci->msix != msix )
 {
-spin_unlock(&pdev->vpci->lock);
+spin_unlock(&pdev->vpci_lock);
 return -EAGAIN;
 }
 }
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index c4890a4295..a5d59b83b7 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -315,6 +315,7 @@ static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 
bus, u8 devfn)
 *((u8*) &pdev->devfn) = devfn;
 pdev->domain = NULL;
 INIT_LIST_HEAD(&pdev->msi_list);
+spin_lock_init(&pdev->vpci_lock);
 
 if ( pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
  PCI_CAP_ID_MSIX) )
diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index 0ec4c082a6..9d5607d5f8 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -131,11 +131,12 @@ bool vpci_process_pending(struct vcpu *v)
 if ( rc == -ERESTART )
 return true;
 
-spin_lock(&v->vpci.pdev->vpci->lock);
-/* Disable memory decoding unconditionally on failure. */
-modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
-!rc && v->vpci.rom_only);
-spin_unlock(&v->vpci.pdev->vpci->lock);
+spin_lock(&v->vpci.pdev->vpci_lock);
+if ( v->vpci.pdev->vpci )
+/* Disable memory decoding unconditionally on failure. */
+modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
+!rc && v->vpci.rom_only);
+spin_unlock(&v->vpci.pdev->vpci_lock);
 
 rangeset_destroy(v->vpci.mem);
 v->vpci.mem = NULL;
@@ -267,6 +268,12 @@ static int modify_bars(const struct pci_dev *pdev, bool 
map, bool rom_only)
 continue;
 }
 
+spin_lock(&tmp->vpci_lock);
+if ( !tmp->vpci )
+{
+spin_unlock(&tmp->vpci_lock);
+continue;
+}
 for ( i = 0; i < ARRAY_SIZE(tmp->vpci->header.bars); i+