diff mbox

[1/6] xen/MSI-X: latch MSI-X table writes

Message ID 5571AB41020000780008153F@mail.emea.novell.com
State New
Headers show

Commit Message

Jan Beulich June 5, 2015, 11:59 a.m. UTC
The remaining log message in pci_msix_write() is wrong, as there guest
behavior may only appear to be wrong: For one, the old logic didn't
take the mask-all bit into account. And then this shouldn't depend on
host device state (i.e. the host may have masked the entry without the
guest having done so). Plus these writes shouldn't be dropped even when
an entry gets unmasked. Instead, if they can't be made take effect
right away, they should take effect on the next unmasking or enabling
operation - the specification explicitly describes such caching
behavior.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
xen/MSI-X: latch MSI-X table writes

The remaining log message in pci_msix_write() is wrong, as there guest
behavior may only appear to be wrong: For one, the old logic didn't
take the mask-all bit into account. And then this shouldn't depend on
host device state (i.e. the host may have masked the entry without the
guest having done so). Plus these writes shouldn't be dropped even when
an entry gets unmasked. Instead, if they can't be made take effect
right away, they should take effect on the next unmasking or enabling
operation - the specification explicitly describes such caching
behavior.

Signed-off-by: Jan Beulich <jbeulich@suse.com>

--- a/qemu/upstream/hw/xen/xen_pt.h
+++ b/qemu/upstream/hw/xen/xen_pt.h
@@ -175,9 +175,8 @@ typedef struct XenPTMSIXEntry {
     int pirq;
     uint64_t addr;
     uint32_t data;
-    uint32_t vector_ctrl;
+    uint32_t latch[4];
     bool updated; /* indicate whether MSI ADDR or DATA is updated */
-    bool warned;  /* avoid issuing (bogus) warning more than once */
 } XenPTMSIXEntry;
 typedef struct XenPTMSIX {
     uint32_t ctrl_offset;
--- a/qemu/upstream/hw/xen/xen_pt_msi.c
+++ b/qemu/upstream/hw/xen/xen_pt_msi.c
@@ -25,6 +25,7 @@
 #define XEN_PT_GFLAGSSHIFT_DELIV_MODE     12
 #define XEN_PT_GFLAGSSHIFT_TRG_MODE       15
 
+#define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
 
 /*
  * Helpers
@@ -322,6 +323,13 @@ static int xen_pt_msix_update_one(XenPCI
 
     pirq = entry->pirq;
 
+    if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
+        (entry->latch(VECTOR_CTRL) & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+        entry->addr = entry->latch(LOWER_ADDR) |
+                      ((uint64_t)entry->latch(UPPER_ADDR) << 32);
+        entry->data = entry->latch(DATA);
+    }
+
     rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
                         entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
     if (rc) {
@@ -396,35 +404,15 @@ int xen_pt_msix_update_remap(XenPCIPasst
 
 static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
 {
-    switch (offset) {
-    case PCI_MSIX_ENTRY_LOWER_ADDR:
-        return e->addr & UINT32_MAX;
-    case PCI_MSIX_ENTRY_UPPER_ADDR:
-        return e->addr >> 32;
-    case PCI_MSIX_ENTRY_DATA:
-        return e->data;
-    case PCI_MSIX_ENTRY_VECTOR_CTRL:
-        return e->vector_ctrl;
-    default:
-        return 0;
-    }
+    return !(offset % sizeof(*e->latch))
+           ? e->latch[offset / sizeof(*e->latch)] : 0;
 }
 
 static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
 {
-    switch (offset) {
-    case PCI_MSIX_ENTRY_LOWER_ADDR:
-        e->addr = (e->addr & ((uint64_t)UINT32_MAX << 32)) | val;
-        break;
-    case PCI_MSIX_ENTRY_UPPER_ADDR:
-        e->addr = (uint64_t)val << 32 | (e->addr & UINT32_MAX);
-        break;
-    case PCI_MSIX_ENTRY_DATA:
-        e->data = val;
-        break;
-    case PCI_MSIX_ENTRY_VECTOR_CTRL:
-        e->vector_ctrl = val;
-        break;
+    if (!(offset % sizeof(*e->latch)))
+    {
+        e->latch[offset / sizeof(*e->latch)] = val;
     }
 }
 
@@ -444,39 +432,28 @@ static void pci_msix_write(void *opaque,
     offset = addr % PCI_MSIX_ENTRY_SIZE;
 
     if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
-        const volatile uint32_t *vec_ctrl;
-
         if (get_entry_value(entry, offset) == val
             && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
             return;
         }
 
+        entry->updated = true;
+    } else if (msix->enabled && entry->updated &&
+               !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+        const volatile uint32_t *vec_ctrl;
+
         /*
          * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
          * up-to-date. Read from hardware directly.
          */
         vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
             + PCI_MSIX_ENTRY_VECTOR_CTRL;
+        set_entry_value(entry, offset, *vec_ctrl);
 
-        if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
-            if (!entry->warned) {
-                entry->warned = true;
-                XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
-                           " already enabled.\n", entry_nr);
-            }
-            return;
-        }
-
-        entry->updated = true;
+        xen_pt_msix_update_one(s, entry_nr);
     }
 
     set_entry_value(entry, offset, val);
-
-    if (offset == PCI_MSIX_ENTRY_VECTOR_CTRL) {
-        if (msix->enabled && !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
-            xen_pt_msix_update_one(s, entry_nr);
-        }
-    }
 }
 
 static uint64_t pci_msix_read(void *opaque, hwaddr addr,

Comments

Stefano Stabellini June 16, 2015, 1:35 p.m. UTC | #1
On Fri, 5 Jun 2015, Jan Beulich wrote:
> The remaining log message in pci_msix_write() is wrong, as there guest
> behavior may only appear to be wrong: For one, the old logic didn't
> take the mask-all bit into account. And then this shouldn't depend on
> host device state (i.e. the host may have masked the entry without the
> guest having done so). Plus these writes shouldn't be dropped even when
> an entry gets unmasked. Instead, if they can't be made take effect
> right away, they should take effect on the next unmasking or enabling
> operation - the specification explicitly describes such caching
> behavior.
> 
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> 
> @@ -322,6 +323,13 @@ static int xen_pt_msix_update_one(XenPCI
>  
>      pirq = entry->pirq;
>  
> +    if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
> +        (entry->latch(VECTOR_CTRL) & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {

I admit I am having difficulties understanding the full purpose of these
checks. Please add a comment on them.

I guess the intention is only to make changes using the latest values,
the ones in entry->latch, when the right conditions are met, otherwise
keep using the old values. Is that right?

In that case, don't we want to use the latest values on MASKBIT ->
!MASKBIT transitions? In general when unmasking? Here it looks like we
are using the latest values when maskall is set or
PCI_MSIX_ENTRY_CTRL_MASKBIT is set, that is the opposite of what we
want.


> +        entry->addr = entry->latch(LOWER_ADDR) |
> +                      ((uint64_t)entry->latch(UPPER_ADDR) << 32);
> +        entry->data = entry->latch(DATA);
> +    }
> +
>      rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
>                          entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
>      if (rc) {
> @@ -444,39 +432,28 @@ static void pci_msix_write(void *opaque,
>      offset = addr % PCI_MSIX_ENTRY_SIZE;
>  
>      if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
> -        const volatile uint32_t *vec_ctrl;
> -
>          if (get_entry_value(entry, offset) == val
>              && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
>              return;
>          }
>  
> +        entry->updated = true;
> +    } else if (msix->enabled && entry->updated &&
> +               !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
> +        const volatile uint32_t *vec_ctrl;
> +
>          /*
>           * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
>           * up-to-date. Read from hardware directly.
>           */
>          vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
>              + PCI_MSIX_ENTRY_VECTOR_CTRL;
> +        set_entry_value(entry, offset, *vec_ctrl);

Why are you calling set_entry_value with the hardware vec_ctrl value? It
doesn't look correct to me.  In any case, if you wanted to do it,
shouldn't you just set/unset PCI_MSIX_ENTRY_CTRL_MASKBIT instead of the
whole *vec_ctrl?


> -        if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
> -            if (!entry->warned) {
> -                entry->warned = true;
> -                XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
> -                           " already enabled.\n", entry_nr);
> -            }
> -            return;
> -        }
> -
> -        entry->updated = true;
> +        xen_pt_msix_update_one(s, entry_nr);

Shouldn't we call xen_pt_msix_update_one only if (*vec_ctrl &
PCI_MSIX_ENTRY_CTRL_MASKBIT)? In other words, only when we see a
MASKBIT -> !MASKBIT transition?


>      }
>  
>      set_entry_value(entry, offset, val);
> -
> -    if (offset == PCI_MSIX_ENTRY_VECTOR_CTRL) {
> -        if (msix->enabled && !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
> -            xen_pt_msix_update_one(s, entry_nr);
> -        }
> -    }
>  }
>  
>  static uint64_t pci_msix_read(void *opaque, hwaddr addr,
Jan Beulich June 16, 2015, 2:04 p.m. UTC | #2
>>> On 16.06.15 at 15:35, <stefano.stabellini@eu.citrix.com> wrote:
> On Fri, 5 Jun 2015, Jan Beulich wrote:
>> @@ -322,6 +323,13 @@ static int xen_pt_msix_update_one(XenPCI
>>  
>>      pirq = entry->pirq;
>>  
>> +    if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
>> +        (entry->latch(VECTOR_CTRL) & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
> 
> I admit I am having difficulties understanding the full purpose of these
> checks. Please add a comment on them.

The comment would (pointlessly imo) re-state what the code already
says:

> I guess the intention is only to make changes using the latest values,
> the ones in entry->latch, when the right conditions are met, otherwise
> keep using the old values. Is that right?
> 
> In that case, don't we want to use the latest values on MASKBIT ->
> !MASKBIT transitions? In general when unmasking?

This is what we want. And with that, the questions you ask further
down should be answered too: The function gets invoked with the
pre-change mask flag state in ->latch[], and updates the values
used for actually setting up when that one has the entry masked
(or mask-all is set). The actual new value gets written to ->latch[]
after the call.

>> @@ -444,39 +432,28 @@ static void pci_msix_write(void *opaque,
>>      offset = addr % PCI_MSIX_ENTRY_SIZE;
>>  
>>      if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
>> -        const volatile uint32_t *vec_ctrl;
>> -
>>          if (get_entry_value(entry, offset) == val
>>              && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
>>              return;
>>          }
>>  
>> +        entry->updated = true;
>> +    } else if (msix->enabled && entry->updated &&
>> +               !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
>> +        const volatile uint32_t *vec_ctrl;
>> +
>>          /*
>>           * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
>>           * up-to-date. Read from hardware directly.
>>           */
>>          vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
>>              + PCI_MSIX_ENTRY_VECTOR_CTRL;
>> +        set_entry_value(entry, offset, *vec_ctrl);
> 
> Why are you calling set_entry_value with the hardware vec_ctrl value? It
> doesn't look correct to me.  In any case, if you wanted to do it,
> shouldn't you just set/unset PCI_MSIX_ENTRY_CTRL_MASKBIT instead of the
> whole *vec_ctrl?

The comment above the code explains it: What we have stored locally
may not reflect reality, as we may not have seen all writes (and this
indeed isn't just a "may"). And if out cached value isn't valid anymore,
why would we not want to update all of it, rather than just the mask
bit?

>> -        if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
>> -            if (!entry->warned) {
>> -                entry->warned = true;
>> -                XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
>> -                           " already enabled.\n", entry_nr);
>> -            }
>> -            return;
>> -        }
>> -
>> -        entry->updated = true;
>> +        xen_pt_msix_update_one(s, entry_nr);
> 
> Shouldn't we call xen_pt_msix_update_one only if (*vec_ctrl &
> PCI_MSIX_ENTRY_CTRL_MASKBIT)? In other words, only when we see a
> MASKBIT -> !MASKBIT transition?

The combination of the !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)
check in the if() surrounding this call and the
(entry->latch(VECTOR_CTRL) & PCI_MSIX_ENTRY_CTRL_MASKBIT)
check inside the function guarantee just that (i.e. the function
invocation is benign in the other case, as entry->addr/entry->data
would remain unchanged).

Jan
Stefano Stabellini June 16, 2015, 2:48 p.m. UTC | #3
On Tue, 16 Jun 2015, Jan Beulich wrote:
> >>> On 16.06.15 at 15:35, <stefano.stabellini@eu.citrix.com> wrote:
> > On Fri, 5 Jun 2015, Jan Beulich wrote:
> >> @@ -322,6 +323,13 @@ static int xen_pt_msix_update_one(XenPCI
> >>  
> >>      pirq = entry->pirq;
> >>  
> >> +    if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
> >> +        (entry->latch(VECTOR_CTRL) & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
> > 
> > I admit I am having difficulties understanding the full purpose of these
> > checks. Please add a comment on them.
> 
> The comment would (pointlessly imo) re-state what the code already
> says:
> 
> > I guess the intention is only to make changes using the latest values,
> > the ones in entry->latch, when the right conditions are met, otherwise
> > keep using the old values. Is that right?
> > 
> > In that case, don't we want to use the latest values on MASKBIT ->
> > !MASKBIT transitions? In general when unmasking?
> 
> This is what we want. And with that, the questions you ask further
> down should be answered too: The function gets invoked with the
> pre-change mask flag state in ->latch[], and updates the values
> used for actually setting up when that one has the entry masked
> (or mask-all is set). The actual new value gets written to ->latch[]
> after the call.

I think this logic is counter-intuitive and prone to confuse the reader.
This change doesn't make sense on its own: when one will read
xen_pt_msix_update_one, won't be able to understand the function without
checking the call sites.

Could we turn it around to be more obvious?  Here check if
!(entry->latch(VECTOR_CTRL) & PCI_MSIX_ENTRY_CTRL_MASKBIT) and below only
call xen_pt_msix_update_one on MASKBIT -> !MASKBIT transactions?

Or something like that?


> >> @@ -444,39 +432,28 @@ static void pci_msix_write(void *opaque,
> >>      offset = addr % PCI_MSIX_ENTRY_SIZE;
> >>  
> >>      if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
> >> -        const volatile uint32_t *vec_ctrl;
> >> -
> >>          if (get_entry_value(entry, offset) == val
> >>              && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
> >>              return;
> >>          }
> >>  
> >> +        entry->updated = true;
> >> +    } else if (msix->enabled && entry->updated &&
> >> +               !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
> >> +        const volatile uint32_t *vec_ctrl;
> >> +
> >>          /*
> >>           * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
> >>           * up-to-date. Read from hardware directly.
> >>           */
> >>          vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
> >>              + PCI_MSIX_ENTRY_VECTOR_CTRL;
> >> +        set_entry_value(entry, offset, *vec_ctrl);
> > 
> > Why are you calling set_entry_value with the hardware vec_ctrl value? It
> > doesn't look correct to me.  In any case, if you wanted to do it,
> > shouldn't you just set/unset PCI_MSIX_ENTRY_CTRL_MASKBIT instead of the
> > whole *vec_ctrl?
> 
> The comment above the code explains it: What we have stored locally
> may not reflect reality, as we may not have seen all writes (and this
> indeed isn't just a "may"). And if out cached value isn't valid anymore,
> why would we not want to update all of it, rather than just the mask
> bit?

OK, however the previous code wasn't actually updating the entirety of
vector_ctrl. It was just using the updated value to check for
PCI_MSIX_ENTRY_CTRL_MASKBIT.  This is something else.  The new behavior
might be correct, but at least the commit message needs to explain it.


> >> -        if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
> >> -            if (!entry->warned) {
> >> -                entry->warned = true;
> >> -                XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
> >> -                           " already enabled.\n", entry_nr);
> >> -            }
> >> -            return;
> >> -        }
> >> -
> >> -        entry->updated = true;
> >> +        xen_pt_msix_update_one(s, entry_nr);
> > 
> > Shouldn't we call xen_pt_msix_update_one only if (*vec_ctrl &
> > PCI_MSIX_ENTRY_CTRL_MASKBIT)? In other words, only when we see a
> > MASKBIT -> !MASKBIT transition?
> 
> The combination of the !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)
> check in the if() surrounding this call and the
> (entry->latch(VECTOR_CTRL) & PCI_MSIX_ENTRY_CTRL_MASKBIT)
> check inside the function guarantee just that (i.e. the function
> invocation is benign in the other case, as entry->addr/entry->data
> would remain unchanged).

OK, maybe the code works as is, but it took me a long time to make sense
of it because it relies on the combinations of three checks in three
different places. I would prefer to change it into something more
obvious.
diff mbox

Patch

--- a/qemu/upstream/hw/xen/xen_pt.h
+++ b/qemu/upstream/hw/xen/xen_pt.h
@@ -175,9 +175,8 @@  typedef struct XenPTMSIXEntry {
     int pirq;
     uint64_t addr;
     uint32_t data;
-    uint32_t vector_ctrl;
+    uint32_t latch[4];
     bool updated; /* indicate whether MSI ADDR or DATA is updated */
-    bool warned;  /* avoid issuing (bogus) warning more than once */
 } XenPTMSIXEntry;
 typedef struct XenPTMSIX {
     uint32_t ctrl_offset;
--- a/qemu/upstream/hw/xen/xen_pt_msi.c
+++ b/qemu/upstream/hw/xen/xen_pt_msi.c
@@ -25,6 +25,7 @@ 
 #define XEN_PT_GFLAGSSHIFT_DELIV_MODE     12
 #define XEN_PT_GFLAGSSHIFT_TRG_MODE       15
 
+#define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
 
 /*
  * Helpers
@@ -322,6 +323,13 @@  static int xen_pt_msix_update_one(XenPCI
 
     pirq = entry->pirq;
 
+    if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
+        (entry->latch(VECTOR_CTRL) & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+        entry->addr = entry->latch(LOWER_ADDR) |
+                      ((uint64_t)entry->latch(UPPER_ADDR) << 32);
+        entry->data = entry->latch(DATA);
+    }
+
     rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
                         entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
     if (rc) {
@@ -396,35 +404,15 @@  int xen_pt_msix_update_remap(XenPCIPasst
 
 static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
 {
-    switch (offset) {
-    case PCI_MSIX_ENTRY_LOWER_ADDR:
-        return e->addr & UINT32_MAX;
-    case PCI_MSIX_ENTRY_UPPER_ADDR:
-        return e->addr >> 32;
-    case PCI_MSIX_ENTRY_DATA:
-        return e->data;
-    case PCI_MSIX_ENTRY_VECTOR_CTRL:
-        return e->vector_ctrl;
-    default:
-        return 0;
-    }
+    return !(offset % sizeof(*e->latch))
+           ? e->latch[offset / sizeof(*e->latch)] : 0;
 }
 
 static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
 {
-    switch (offset) {
-    case PCI_MSIX_ENTRY_LOWER_ADDR:
-        e->addr = (e->addr & ((uint64_t)UINT32_MAX << 32)) | val;
-        break;
-    case PCI_MSIX_ENTRY_UPPER_ADDR:
-        e->addr = (uint64_t)val << 32 | (e->addr & UINT32_MAX);
-        break;
-    case PCI_MSIX_ENTRY_DATA:
-        e->data = val;
-        break;
-    case PCI_MSIX_ENTRY_VECTOR_CTRL:
-        e->vector_ctrl = val;
-        break;
+    if (!(offset % sizeof(*e->latch)))
+    {
+        e->latch[offset / sizeof(*e->latch)] = val;
     }
 }
 
@@ -444,39 +432,28 @@  static void pci_msix_write(void *opaque,
     offset = addr % PCI_MSIX_ENTRY_SIZE;
 
     if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
-        const volatile uint32_t *vec_ctrl;
-
         if (get_entry_value(entry, offset) == val
             && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
             return;
         }
 
+        entry->updated = true;
+    } else if (msix->enabled && entry->updated &&
+               !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+        const volatile uint32_t *vec_ctrl;
+
         /*
          * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
          * up-to-date. Read from hardware directly.
          */
         vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
             + PCI_MSIX_ENTRY_VECTOR_CTRL;
+        set_entry_value(entry, offset, *vec_ctrl);
 
-        if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
-            if (!entry->warned) {
-                entry->warned = true;
-                XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
-                           " already enabled.\n", entry_nr);
-            }
-            return;
-        }
-
-        entry->updated = true;
+        xen_pt_msix_update_one(s, entry_nr);
     }
 
     set_entry_value(entry, offset, val);
-
-    if (offset == PCI_MSIX_ENTRY_VECTOR_CTRL) {
-        if (msix->enabled && !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
-            xen_pt_msix_update_one(s, entry_nr);
-        }
-    }
 }
 
 static uint64_t pci_msix_read(void *opaque, hwaddr addr,