msix_mask_all() is supposed to invoke the release vector notifier if the state of the respective vector changed from unmasked or masked. The way it's currently called from msix_reset(), though, may result in calling the release notifier even if the vector is already masked.
1) msix_reset() clears out the msix_cap field and the msix_table. 2) msix_mask_all() runs with was_masked=false for all vectors because of 1), which results in calling the release notifier on all vectors. 3) if msix_reset() is subsequently called again, it goes through the same steps and calls the release notifier on all vectors again. This commit moves msix_mask_all() up so it runs before the device state is lost. And it adds a call to msix_update_function_masked() so that the device remembers that MSI-X is masked. This is likely a low impact issue, found while debugging an already broken device. It is however easy to fix and the expectation that the use and release notifier invocations are always balanced is very natural. Signed-off-by: Ladi Prosek <lpro...@redhat.com> --- hw/pci/msix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index c944c02135..34656de9b0 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -500,11 +500,12 @@ void msix_reset(PCIDevice *dev) return; } msix_clear_all_vectors(dev); + msix_mask_all(dev, dev->msix_entries_nr); dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8); - msix_mask_all(dev, dev->msix_entries_nr); + msix_update_function_masked(dev); } /* PCI spec suggests that devices make it possible for software to configure -- 2.13.5