static void pci_msix_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { XenPCIPassthroughState *s = opaque; XenPTMSIX *msix = s->msix; XenPTMSIXEntry *entry; int entry_nr, offset; entry_nr = addr / PCI_MSIX_ENTRY_SIZE; if (entry_nr < 0 || entry_nr >= msix->total_entries) { XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr); return; } entry = &msix->msix_entry[entry_nr]; 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; } /* * 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; if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) { XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is" " already enabled.\n", entry_nr); return; } entry->updated = true; } 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); } } }