MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) { uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; MSIMessage msg; msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); return msg; }
/* PCIe MMCFG */ static void mch_update_pciexbar(MCHPCIState *mch) { PCIDevice *pci_dev = PCI_DEVICE(mch); BusState *bus = qdev_get_parent_bus(DEVICE(mch)); PCIExpressHost *pehb = PCIE_HOST_BRIDGE(bus->parent); uint64_t pciexbar; int enable; uint64_t addr; uint64_t addr_mask; uint32_t length; pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR); enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN; addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK; switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) { case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M: length = 256 * 1024 * 1024; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M: length = 128 * 1024 * 1024; addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK | MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M: length = 64 * 1024 * 1024; addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD: default: abort(); } addr = pciexbar & addr_mask; pcie_host_mmcfg_update(pehb, enable, addr, length); /* Leave enough space for the MCFG BAR */ /* * TODO: this matches current bios behaviour, but it's not a power of two, * which means an MTRR can't cover it exactly. */ if (enable) { range_set_bounds(&mch->pci_hole, addr + length, IO_APIC_DEFAULT_ADDRESS - 1); } else { range_set_bounds(&mch->pci_hole, MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT, IO_APIC_DEFAULT_ADDRESS - 1); } }
/* Send an MSI-X message */ void msix_notify(PCIDevice *dev, unsigned vector) { uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE; uint64_t address; uint32_t data; if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) return; if (msix_is_masked(dev, vector)) { msix_set_pending(dev, vector); return; } address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); stl_le_phys(address, data); }
/* PCIe MMCFG */ static void mch_update_pciexbar(MCHPCIState *mch) { PCIDevice *pci_dev = &mch->d; BusState *bus = qdev_get_parent_bus(&pci_dev->qdev); DeviceState *qdev = bus->parent; Q35PCIHost *s = Q35_HOST_DEVICE(qdev); uint64_t pciexbar; int enable; uint64_t addr; uint64_t addr_mask; uint32_t length; pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR); enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN; addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK; switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) { case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M: length = 256 * 1024 * 1024; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M: length = 128 * 1024 * 1024; addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK | MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M: length = 64 * 1024 * 1024; addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD: default: enable = 0; length = 0; abort(); break; } addr = pciexbar & addr_mask; pcie_host_mmcfg_update(&s->host, enable, addr, length); }