diff options
Diffstat (limited to 'hw/pci')
| -rw-r--r-- | hw/pci/Kconfig | 6 | ||||
| -rw-r--r-- | hw/pci/pci.c | 28 | ||||
| -rw-r--r-- | hw/pci/pci_host.c | 2 | ||||
| -rw-r--r-- | hw/pci/pcie.c | 38 | ||||
| -rw-r--r-- | hw/pci/trace-events | 6 |
5 files changed, 74 insertions, 6 deletions
diff --git a/hw/pci/Kconfig b/hw/pci/Kconfig index 3b8638b51d..77f8b005ff 100644 --- a/hw/pci/Kconfig +++ b/hw/pci/Kconfig @@ -7,3 +7,9 @@ config PCI_EXPRESS config PCI_DEVICES bool + +config MSI_NONBROKEN + # selected by interrupt controllers that do not support MSI, + # or support it and have a good implementation. See commit + # 47d2b0f33c664533b8dbd5cb17faa8e6a01afe1f. + bool diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 35451c1e99..a78023f669 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -147,6 +147,11 @@ static uint16_t pcibus_numa_node(PCIBus *bus) return NUMA_NODE_UNASSIGNED; } +static bool pcibus_allows_extended_config_space(PCIBus *bus) +{ + return false; +} + static void pci_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); @@ -162,6 +167,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data) pbc->is_root = pcibus_is_root; pbc->bus_num = pcibus_num; pbc->numa_node = pcibus_numa_node; + pbc->allows_extended_config_space = pcibus_allows_extended_config_space; } static const TypeInfo pci_bus_info = { @@ -182,9 +188,22 @@ static const TypeInfo conventional_pci_interface_info = { .parent = TYPE_INTERFACE, }; +static bool pciebus_allows_extended_config_space(PCIBus *bus) +{ + return true; +} + +static void pcie_bus_class_init(ObjectClass *klass, void *data) +{ + PCIBusClass *pbc = PCI_BUS_CLASS(klass); + + pbc->allows_extended_config_space = pciebus_allows_extended_config_space; +} + static const TypeInfo pcie_bus_info = { .name = TYPE_PCIE_BUS, .parent = TYPE_PCI_BUS, + .class_init = pcie_bus_class_init, }; static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); @@ -401,6 +420,11 @@ bool pci_bus_is_root(PCIBus *bus) return PCI_BUS_GET_CLASS(bus)->is_root(bus); } +bool pci_bus_allows_extended_config_space(PCIBus *bus) +{ + return PCI_BUS_GET_CLASS(bus)->allows_extended_config_space(bus); +} + void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, @@ -927,7 +951,7 @@ static uint16_t pci_req_id_cache_extract(PCIReqIDCache *cache) result = PCI_BUILD_BDF(bus_n, 0); break; default: - error_printf("Invalid PCI requester ID cache type: %d\n", + error_report("Invalid PCI requester ID cache type: %d", cache->type); exit(1); break; @@ -1532,7 +1556,7 @@ void pci_device_set_intx_routing_notifier(PCIDevice *dev, */ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) { - return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; + return pci_swizzle(PCI_SLOT(pci_dev->devfn), pin); } /***********************************************************/ diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index 5f5345dbac..9d64b2e12f 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -54,7 +54,7 @@ static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) static void pci_adjust_config_limit(PCIBus *bus, uint32_t *limit) { if (*limit > PCI_CONFIG_SPACE_SIZE) { - if (!pci_bus_is_express(bus)) { + if (!pci_bus_allows_extended_config_space(bus)) { *limit = PCI_CONFIG_SPACE_SIZE; return; } diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 640f678773..cf1ca30f93 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -914,3 +914,41 @@ void pcie_ats_init(PCIDevice *dev, uint16_t offset) pci_set_word(dev->wmask + dev->exp.ats_cap + PCI_ATS_CTRL, 0x800f); } + +/* ACS (Access Control Services) */ +void pcie_acs_init(PCIDevice *dev, uint16_t offset) +{ + bool is_downstream = pci_is_express_downstream_port(dev); + uint16_t cap_bits = 0; + + /* For endpoints, only multifunction devs may have an ACS capability: */ + assert(is_downstream || + (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) || + PCI_FUNC(dev->devfn)); + + pcie_add_capability(dev, PCI_EXT_CAP_ID_ACS, PCI_ACS_VER, offset, + PCI_ACS_SIZEOF); + dev->exp.acs_cap = offset; + + if (is_downstream) { + /* + * Downstream ports must implement SV, TB, RR, CR, UF, and DT (with + * caveats on the latter four that we ignore for simplicity). + * Endpoints may also implement a subset of ACS capabilities, + * but these are optional if the endpoint does not support + * peer-to-peer between functions and thus omitted here. + */ + cap_bits = PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | + PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT; + } + + pci_set_word(dev->config + offset + PCI_ACS_CAP, cap_bits); + pci_set_word(dev->wmask + offset + PCI_ACS_CTRL, cap_bits); +} + +void pcie_acs_reset(PCIDevice *dev) +{ + if (dev->exp.acs_cap) { + pci_set_word(dev->config + dev->exp.acs_cap + PCI_ACS_CTRL, 0); + } +} diff --git a/hw/pci/trace-events b/hw/pci/trace-events index f68c178afc..def4b3926d 100644 --- a/hw/pci/trace-events +++ b/hw/pci/trace-events @@ -1,12 +1,12 @@ # See docs/devel/tracing.txt for syntax documentation. -# hw/pci/pci.c +# pci.c pci_update_mappings_del(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64 pci_update_mappings_add(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64 -# hw/pci/pci_host.c +# pci_host.c pci_cfg_read(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x -> 0x%x" pci_cfg_write(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x <- 0x%x" -# hw/pci/msix.c +# msix.c msix_write_config(char *name, bool enabled, bool masked) "dev %s enabled %d masked %d" |