1d64e5eabSAndrey Smirnov /* 2d64e5eabSAndrey Smirnov * Copyright (c) 2018, Impinj, Inc. 3d64e5eabSAndrey Smirnov * 4d64e5eabSAndrey Smirnov * Designware PCIe IP block emulation 5d64e5eabSAndrey Smirnov * 6d64e5eabSAndrey Smirnov * This library is free software; you can redistribute it and/or 7d64e5eabSAndrey Smirnov * modify it under the terms of the GNU Lesser General Public 8d64e5eabSAndrey Smirnov * License as published by the Free Software Foundation; either 961f3c91aSChetan Pant * version 2.1 of the License, or (at your option) any later version. 10d64e5eabSAndrey Smirnov * 11d64e5eabSAndrey Smirnov * This library is distributed in the hope that it will be useful, 12d64e5eabSAndrey Smirnov * but WITHOUT ANY WARRANTY; without even the implied warranty of 13d64e5eabSAndrey Smirnov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14d64e5eabSAndrey Smirnov * Lesser General Public License for more details. 15d64e5eabSAndrey Smirnov * 16d64e5eabSAndrey Smirnov * You should have received a copy of the GNU Lesser General Public 17d64e5eabSAndrey Smirnov * License along with this library; if not, see 18d64e5eabSAndrey Smirnov * <http://www.gnu.org/licenses/>. 19d64e5eabSAndrey Smirnov */ 20d64e5eabSAndrey Smirnov 21d64e5eabSAndrey Smirnov #include "qemu/osdep.h" 22d64e5eabSAndrey Smirnov #include "qapi/error.h" 230b8fa32fSMarkus Armbruster #include "qemu/module.h" 244f2a5202SPrasad J Pandit #include "qemu/log.h" 25d64e5eabSAndrey Smirnov #include "hw/pci/msi.h" 26d64e5eabSAndrey Smirnov #include "hw/pci/pci_bridge.h" 27d64e5eabSAndrey Smirnov #include "hw/pci/pci_host.h" 28d64e5eabSAndrey Smirnov #include "hw/pci/pcie_port.h" 29a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 30d6454270SMarkus Armbruster #include "migration/vmstate.h" 3164552b6bSMarkus Armbruster #include "hw/irq.h" 32d64e5eabSAndrey Smirnov #include "hw/pci-host/designware.h" 33d64e5eabSAndrey Smirnov 34d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_PORT_LINK_CONTROL 0x710 35d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_PHY_DEBUG_R1 0x72C 36d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP BIT(4) 37d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C 38d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE BIT(17) 39d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_MSI_ADDR_LO 0x820 40d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_MSI_ADDR_HI 0x824 41d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_MSI_INTR0_ENABLE 0x828 42d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_MSI_INTR0_MASK 0x82C 43d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_MSI_INTR0_STATUS 0x830 44d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_VIEWPORT 0x900 45d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_REGION_INBOUND BIT(31) 46d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_CR1 0x904 47d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_TYPE_MEM (0x0 << 0) 48d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_CR2 0x908 49d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_ENABLE BIT(31) 50d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_LOWER_BASE 0x90C 51d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_UPPER_BASE 0x910 52d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_LIMIT 0x914 53d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_LOWER_TARGET 0x918 54d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_BUS(x) (((x) >> 24) & 0xff) 55d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff) 56d64e5eabSAndrey Smirnov #define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C 57d64e5eabSAndrey Smirnov 58*faa2150aSBernhard Beschow static void designware_pcie_root_bus_class_init(ObjectClass *klass, void *data) 59*faa2150aSBernhard Beschow { 60*faa2150aSBernhard Beschow BusClass *k = BUS_CLASS(klass); 61*faa2150aSBernhard Beschow 62*faa2150aSBernhard Beschow /* 63*faa2150aSBernhard Beschow * Designware has only a single root complex. Enforce the limit on the 64*faa2150aSBernhard Beschow * parent bus 65*faa2150aSBernhard Beschow */ 66*faa2150aSBernhard Beschow k->max_dev = 1; 67*faa2150aSBernhard Beschow } 68*faa2150aSBernhard Beschow 69d64e5eabSAndrey Smirnov static DesignwarePCIEHost * 70d64e5eabSAndrey Smirnov designware_pcie_root_to_host(DesignwarePCIERoot *root) 71d64e5eabSAndrey Smirnov { 72d64e5eabSAndrey Smirnov BusState *bus = qdev_get_parent_bus(DEVICE(root)); 73d64e5eabSAndrey Smirnov return DESIGNWARE_PCIE_HOST(bus->parent); 74d64e5eabSAndrey Smirnov } 75d64e5eabSAndrey Smirnov 764f2a5202SPrasad J Pandit static uint64_t designware_pcie_root_msi_read(void *opaque, hwaddr addr, 774f2a5202SPrasad J Pandit unsigned size) 784f2a5202SPrasad J Pandit { 794f2a5202SPrasad J Pandit /* 804f2a5202SPrasad J Pandit * Attempts to read from the MSI address are undefined in 814f2a5202SPrasad J Pandit * the PCI specifications. For this hardware, the datasheet 824f2a5202SPrasad J Pandit * specifies that a read from the magic address is simply not 834f2a5202SPrasad J Pandit * intercepted by the MSI controller, and will go out to the 844f2a5202SPrasad J Pandit * AHB/AXI bus like any other PCI-device-initiated DMA read. 854f2a5202SPrasad J Pandit * This is not trivial to implement in QEMU, so since 864f2a5202SPrasad J Pandit * well-behaved guests won't ever ask a PCI device to DMA from 874f2a5202SPrasad J Pandit * this address we just log the missing functionality. 884f2a5202SPrasad J Pandit */ 894f2a5202SPrasad J Pandit qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); 904f2a5202SPrasad J Pandit return 0; 914f2a5202SPrasad J Pandit } 924f2a5202SPrasad J Pandit 93d64e5eabSAndrey Smirnov static void designware_pcie_root_msi_write(void *opaque, hwaddr addr, 94d64e5eabSAndrey Smirnov uint64_t val, unsigned len) 95d64e5eabSAndrey Smirnov { 96d64e5eabSAndrey Smirnov DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(opaque); 97d64e5eabSAndrey Smirnov DesignwarePCIEHost *host = designware_pcie_root_to_host(root); 98d64e5eabSAndrey Smirnov 99d64e5eabSAndrey Smirnov root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable; 100d64e5eabSAndrey Smirnov 101d64e5eabSAndrey Smirnov if (root->msi.intr[0].status & ~root->msi.intr[0].mask) { 1021b326f27SBernhard Beschow qemu_set_irq(host->pci.msi, 1); 103d64e5eabSAndrey Smirnov } 104d64e5eabSAndrey Smirnov } 105d64e5eabSAndrey Smirnov 106d64e5eabSAndrey Smirnov static const MemoryRegionOps designware_pci_host_msi_ops = { 1074f2a5202SPrasad J Pandit .read = designware_pcie_root_msi_read, 108d64e5eabSAndrey Smirnov .write = designware_pcie_root_msi_write, 109d64e5eabSAndrey Smirnov .endianness = DEVICE_LITTLE_ENDIAN, 110d64e5eabSAndrey Smirnov .valid = { 111d64e5eabSAndrey Smirnov .min_access_size = 4, 112d64e5eabSAndrey Smirnov .max_access_size = 4, 113d64e5eabSAndrey Smirnov }, 114d64e5eabSAndrey Smirnov }; 115d64e5eabSAndrey Smirnov 116d64e5eabSAndrey Smirnov static void designware_pcie_root_update_msi_mapping(DesignwarePCIERoot *root) 117d64e5eabSAndrey Smirnov 118d64e5eabSAndrey Smirnov { 119d64e5eabSAndrey Smirnov MemoryRegion *mem = &root->msi.iomem; 120d64e5eabSAndrey Smirnov const uint64_t base = root->msi.base; 121d64e5eabSAndrey Smirnov const bool enable = root->msi.intr[0].enable; 122d64e5eabSAndrey Smirnov 123d64e5eabSAndrey Smirnov memory_region_set_address(mem, base); 124d64e5eabSAndrey Smirnov memory_region_set_enabled(mem, enable); 125d64e5eabSAndrey Smirnov } 126d64e5eabSAndrey Smirnov 127d64e5eabSAndrey Smirnov static DesignwarePCIEViewport * 128d64e5eabSAndrey Smirnov designware_pcie_root_get_current_viewport(DesignwarePCIERoot *root) 129d64e5eabSAndrey Smirnov { 130d64e5eabSAndrey Smirnov const unsigned int idx = root->atu_viewport & 0xF; 131d64e5eabSAndrey Smirnov const unsigned int dir = 132d64e5eabSAndrey Smirnov !!(root->atu_viewport & DESIGNWARE_PCIE_ATU_REGION_INBOUND); 133d64e5eabSAndrey Smirnov return &root->viewports[dir][idx]; 134d64e5eabSAndrey Smirnov } 135d64e5eabSAndrey Smirnov 136d64e5eabSAndrey Smirnov static uint32_t 137d64e5eabSAndrey Smirnov designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len) 138d64e5eabSAndrey Smirnov { 139d64e5eabSAndrey Smirnov DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d); 140d64e5eabSAndrey Smirnov DesignwarePCIEViewport *viewport = 141d64e5eabSAndrey Smirnov designware_pcie_root_get_current_viewport(root); 142d64e5eabSAndrey Smirnov 143d64e5eabSAndrey Smirnov uint32_t val; 144d64e5eabSAndrey Smirnov 145d64e5eabSAndrey Smirnov switch (address) { 146d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_PORT_LINK_CONTROL: 147d64e5eabSAndrey Smirnov /* 148d64e5eabSAndrey Smirnov * Linux guest uses this register only to configure number of 149d64e5eabSAndrey Smirnov * PCIE lane (which in our case is irrelevant) and doesn't 150d64e5eabSAndrey Smirnov * really care about the value it reads from this register 151d64e5eabSAndrey Smirnov */ 152d64e5eabSAndrey Smirnov val = 0xDEADBEEF; 153d64e5eabSAndrey Smirnov break; 154d64e5eabSAndrey Smirnov 155d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL: 156d64e5eabSAndrey Smirnov /* 157d64e5eabSAndrey Smirnov * To make sure that any code in guest waiting for speed 158d64e5eabSAndrey Smirnov * change does not time out we always report 159d64e5eabSAndrey Smirnov * PORT_LOGIC_SPEED_CHANGE as set 160d64e5eabSAndrey Smirnov */ 161d64e5eabSAndrey Smirnov val = DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE; 162d64e5eabSAndrey Smirnov break; 163d64e5eabSAndrey Smirnov 164d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_ADDR_LO: 165d64e5eabSAndrey Smirnov val = root->msi.base; 166d64e5eabSAndrey Smirnov break; 167d64e5eabSAndrey Smirnov 168d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_ADDR_HI: 169d64e5eabSAndrey Smirnov val = root->msi.base >> 32; 170d64e5eabSAndrey Smirnov break; 171d64e5eabSAndrey Smirnov 172d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: 173d64e5eabSAndrey Smirnov val = root->msi.intr[0].enable; 174d64e5eabSAndrey Smirnov break; 175d64e5eabSAndrey Smirnov 176d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_INTR0_MASK: 177d64e5eabSAndrey Smirnov val = root->msi.intr[0].mask; 178d64e5eabSAndrey Smirnov break; 179d64e5eabSAndrey Smirnov 180d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_INTR0_STATUS: 181d64e5eabSAndrey Smirnov val = root->msi.intr[0].status; 182d64e5eabSAndrey Smirnov break; 183d64e5eabSAndrey Smirnov 184d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_PHY_DEBUG_R1: 185d64e5eabSAndrey Smirnov val = DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP; 186d64e5eabSAndrey Smirnov break; 187d64e5eabSAndrey Smirnov 188d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_VIEWPORT: 189d64e5eabSAndrey Smirnov val = root->atu_viewport; 190d64e5eabSAndrey Smirnov break; 191d64e5eabSAndrey Smirnov 192d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_LOWER_BASE: 193d64e5eabSAndrey Smirnov val = viewport->base; 194d64e5eabSAndrey Smirnov break; 195d64e5eabSAndrey Smirnov 196d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_UPPER_BASE: 197d64e5eabSAndrey Smirnov val = viewport->base >> 32; 198d64e5eabSAndrey Smirnov break; 199d64e5eabSAndrey Smirnov 200d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_LOWER_TARGET: 201d64e5eabSAndrey Smirnov val = viewport->target; 202d64e5eabSAndrey Smirnov break; 203d64e5eabSAndrey Smirnov 204d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_UPPER_TARGET: 205d64e5eabSAndrey Smirnov val = viewport->target >> 32; 206d64e5eabSAndrey Smirnov break; 207d64e5eabSAndrey Smirnov 208d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_LIMIT: 209d64e5eabSAndrey Smirnov val = viewport->limit; 210d64e5eabSAndrey Smirnov break; 211d64e5eabSAndrey Smirnov 212d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_CR1: 2137ddd4ceaSPhilippe Mathieu-Daudé case DESIGNWARE_PCIE_ATU_CR2: 214d64e5eabSAndrey Smirnov val = viewport->cr[(address - DESIGNWARE_PCIE_ATU_CR1) / 215d64e5eabSAndrey Smirnov sizeof(uint32_t)]; 216d64e5eabSAndrey Smirnov break; 217d64e5eabSAndrey Smirnov 218d64e5eabSAndrey Smirnov default: 219d64e5eabSAndrey Smirnov val = pci_default_read_config(d, address, len); 220d64e5eabSAndrey Smirnov break; 221d64e5eabSAndrey Smirnov } 222d64e5eabSAndrey Smirnov 223d64e5eabSAndrey Smirnov return val; 224d64e5eabSAndrey Smirnov } 225d64e5eabSAndrey Smirnov 226d64e5eabSAndrey Smirnov static uint64_t designware_pcie_root_data_access(void *opaque, hwaddr addr, 227d64e5eabSAndrey Smirnov uint64_t *val, unsigned len) 228d64e5eabSAndrey Smirnov { 229d64e5eabSAndrey Smirnov DesignwarePCIEViewport *viewport = opaque; 230d64e5eabSAndrey Smirnov DesignwarePCIERoot *root = viewport->root; 231d64e5eabSAndrey Smirnov 232d64e5eabSAndrey Smirnov const uint8_t busnum = DESIGNWARE_PCIE_ATU_BUS(viewport->target); 233d64e5eabSAndrey Smirnov const uint8_t devfn = DESIGNWARE_PCIE_ATU_DEVFN(viewport->target); 234d64e5eabSAndrey Smirnov PCIBus *pcibus = pci_get_bus(PCI_DEVICE(root)); 235d64e5eabSAndrey Smirnov PCIDevice *pcidev = pci_find_device(pcibus, busnum, devfn); 236d64e5eabSAndrey Smirnov 237d64e5eabSAndrey Smirnov if (pcidev) { 238d64e5eabSAndrey Smirnov addr &= pci_config_size(pcidev) - 1; 239d64e5eabSAndrey Smirnov 240d64e5eabSAndrey Smirnov if (val) { 241d64e5eabSAndrey Smirnov pci_host_config_write_common(pcidev, addr, 242d64e5eabSAndrey Smirnov pci_config_size(pcidev), 243d64e5eabSAndrey Smirnov *val, len); 244d64e5eabSAndrey Smirnov } else { 245d64e5eabSAndrey Smirnov return pci_host_config_read_common(pcidev, addr, 246d64e5eabSAndrey Smirnov pci_config_size(pcidev), 247d64e5eabSAndrey Smirnov len); 248d64e5eabSAndrey Smirnov } 249d64e5eabSAndrey Smirnov } 250d64e5eabSAndrey Smirnov 251d64e5eabSAndrey Smirnov return UINT64_MAX; 252d64e5eabSAndrey Smirnov } 253d64e5eabSAndrey Smirnov 254d64e5eabSAndrey Smirnov static uint64_t designware_pcie_root_data_read(void *opaque, hwaddr addr, 255d64e5eabSAndrey Smirnov unsigned len) 256d64e5eabSAndrey Smirnov { 257d64e5eabSAndrey Smirnov return designware_pcie_root_data_access(opaque, addr, NULL, len); 258d64e5eabSAndrey Smirnov } 259d64e5eabSAndrey Smirnov 260d64e5eabSAndrey Smirnov static void designware_pcie_root_data_write(void *opaque, hwaddr addr, 261d64e5eabSAndrey Smirnov uint64_t val, unsigned len) 262d64e5eabSAndrey Smirnov { 263d64e5eabSAndrey Smirnov designware_pcie_root_data_access(opaque, addr, &val, len); 264d64e5eabSAndrey Smirnov } 265d64e5eabSAndrey Smirnov 266d64e5eabSAndrey Smirnov static const MemoryRegionOps designware_pci_host_conf_ops = { 267d64e5eabSAndrey Smirnov .read = designware_pcie_root_data_read, 268d64e5eabSAndrey Smirnov .write = designware_pcie_root_data_write, 269d64e5eabSAndrey Smirnov .endianness = DEVICE_LITTLE_ENDIAN, 270d64e5eabSAndrey Smirnov .valid = { 271d64e5eabSAndrey Smirnov .min_access_size = 1, 272d64e5eabSAndrey Smirnov .max_access_size = 4, 273d64e5eabSAndrey Smirnov }, 274d64e5eabSAndrey Smirnov }; 275d64e5eabSAndrey Smirnov 276d64e5eabSAndrey Smirnov static void designware_pcie_update_viewport(DesignwarePCIERoot *root, 277d64e5eabSAndrey Smirnov DesignwarePCIEViewport *viewport) 278d64e5eabSAndrey Smirnov { 279d64e5eabSAndrey Smirnov const uint64_t target = viewport->target; 280d64e5eabSAndrey Smirnov const uint64_t base = viewport->base; 281d64e5eabSAndrey Smirnov const uint64_t size = (uint64_t)viewport->limit - base + 1; 282d64e5eabSAndrey Smirnov const bool enabled = viewport->cr[1] & DESIGNWARE_PCIE_ATU_ENABLE; 283d64e5eabSAndrey Smirnov 284d64e5eabSAndrey Smirnov MemoryRegion *current, *other; 285d64e5eabSAndrey Smirnov 286d64e5eabSAndrey Smirnov if (viewport->cr[0] == DESIGNWARE_PCIE_ATU_TYPE_MEM) { 287d64e5eabSAndrey Smirnov current = &viewport->mem; 288d64e5eabSAndrey Smirnov other = &viewport->cfg; 289d64e5eabSAndrey Smirnov memory_region_set_alias_offset(current, target); 290d64e5eabSAndrey Smirnov } else { 291d64e5eabSAndrey Smirnov current = &viewport->cfg; 292d64e5eabSAndrey Smirnov other = &viewport->mem; 293d64e5eabSAndrey Smirnov } 294d64e5eabSAndrey Smirnov 295d64e5eabSAndrey Smirnov /* 296d64e5eabSAndrey Smirnov * An outbound viewport can be reconfigure from being MEM to CFG, 297d64e5eabSAndrey Smirnov * to account for that we disable the "other" memory region that 298d64e5eabSAndrey Smirnov * becomes unused due to that fact. 299d64e5eabSAndrey Smirnov */ 300d64e5eabSAndrey Smirnov memory_region_set_enabled(other, false); 301d64e5eabSAndrey Smirnov if (enabled) { 302d64e5eabSAndrey Smirnov memory_region_set_size(current, size); 303d64e5eabSAndrey Smirnov memory_region_set_address(current, base); 304d64e5eabSAndrey Smirnov } 305d64e5eabSAndrey Smirnov memory_region_set_enabled(current, enabled); 306d64e5eabSAndrey Smirnov } 307d64e5eabSAndrey Smirnov 308d64e5eabSAndrey Smirnov static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, 309d64e5eabSAndrey Smirnov uint32_t val, int len) 310d64e5eabSAndrey Smirnov { 311d64e5eabSAndrey Smirnov DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d); 312d64e5eabSAndrey Smirnov DesignwarePCIEHost *host = designware_pcie_root_to_host(root); 313d64e5eabSAndrey Smirnov DesignwarePCIEViewport *viewport = 314d64e5eabSAndrey Smirnov designware_pcie_root_get_current_viewport(root); 315d64e5eabSAndrey Smirnov 316d64e5eabSAndrey Smirnov switch (address) { 317d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_PORT_LINK_CONTROL: 318d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL: 319d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_PHY_DEBUG_R1: 320d64e5eabSAndrey Smirnov /* No-op */ 321d64e5eabSAndrey Smirnov break; 322d64e5eabSAndrey Smirnov 323d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_ADDR_LO: 324d64e5eabSAndrey Smirnov root->msi.base &= 0xFFFFFFFF00000000ULL; 325d64e5eabSAndrey Smirnov root->msi.base |= val; 32697b7e29bSAndrey Smirnov designware_pcie_root_update_msi_mapping(root); 327d64e5eabSAndrey Smirnov break; 328d64e5eabSAndrey Smirnov 329d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_ADDR_HI: 330d64e5eabSAndrey Smirnov root->msi.base &= 0x00000000FFFFFFFFULL; 331d64e5eabSAndrey Smirnov root->msi.base |= (uint64_t)val << 32; 33297b7e29bSAndrey Smirnov designware_pcie_root_update_msi_mapping(root); 333d64e5eabSAndrey Smirnov break; 334d64e5eabSAndrey Smirnov 3354eb42b81SAndrey Smirnov case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: 336d64e5eabSAndrey Smirnov root->msi.intr[0].enable = val; 337d64e5eabSAndrey Smirnov designware_pcie_root_update_msi_mapping(root); 338d64e5eabSAndrey Smirnov break; 339d64e5eabSAndrey Smirnov 340d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_INTR0_MASK: 341d64e5eabSAndrey Smirnov root->msi.intr[0].mask = val; 342d64e5eabSAndrey Smirnov break; 343d64e5eabSAndrey Smirnov 344d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_MSI_INTR0_STATUS: 345d64e5eabSAndrey Smirnov root->msi.intr[0].status ^= val; 346d64e5eabSAndrey Smirnov if (!root->msi.intr[0].status) { 3471b326f27SBernhard Beschow qemu_set_irq(host->pci.msi, 0); 348d64e5eabSAndrey Smirnov } 349d64e5eabSAndrey Smirnov break; 350d64e5eabSAndrey Smirnov 351d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_VIEWPORT: 3528a731520SGuenter Roeck val &= DESIGNWARE_PCIE_ATU_REGION_INBOUND | 3538a731520SGuenter Roeck (DESIGNWARE_PCIE_NUM_VIEWPORTS - 1); 354d64e5eabSAndrey Smirnov root->atu_viewport = val; 355d64e5eabSAndrey Smirnov break; 356d64e5eabSAndrey Smirnov 357d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_LOWER_BASE: 358d64e5eabSAndrey Smirnov viewport->base &= 0xFFFFFFFF00000000ULL; 359d64e5eabSAndrey Smirnov viewport->base |= val; 360d64e5eabSAndrey Smirnov break; 361d64e5eabSAndrey Smirnov 362d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_UPPER_BASE: 363d64e5eabSAndrey Smirnov viewport->base &= 0x00000000FFFFFFFFULL; 364d64e5eabSAndrey Smirnov viewport->base |= (uint64_t)val << 32; 365d64e5eabSAndrey Smirnov break; 366d64e5eabSAndrey Smirnov 367d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_LOWER_TARGET: 368d64e5eabSAndrey Smirnov viewport->target &= 0xFFFFFFFF00000000ULL; 369d64e5eabSAndrey Smirnov viewport->target |= val; 370d64e5eabSAndrey Smirnov break; 371d64e5eabSAndrey Smirnov 372d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_UPPER_TARGET: 373d64e5eabSAndrey Smirnov viewport->target &= 0x00000000FFFFFFFFULL; 374d64e5eabSAndrey Smirnov viewport->target |= val; 375d64e5eabSAndrey Smirnov break; 376d64e5eabSAndrey Smirnov 377d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_LIMIT: 378d64e5eabSAndrey Smirnov viewport->limit = val; 379d64e5eabSAndrey Smirnov break; 380d64e5eabSAndrey Smirnov 381d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_CR1: 382d64e5eabSAndrey Smirnov viewport->cr[0] = val; 383d64e5eabSAndrey Smirnov break; 384d64e5eabSAndrey Smirnov case DESIGNWARE_PCIE_ATU_CR2: 385d64e5eabSAndrey Smirnov viewport->cr[1] = val; 386d64e5eabSAndrey Smirnov designware_pcie_update_viewport(root, viewport); 387d64e5eabSAndrey Smirnov break; 388d64e5eabSAndrey Smirnov 389d64e5eabSAndrey Smirnov default: 390d64e5eabSAndrey Smirnov pci_bridge_write_config(d, address, val, len); 391d64e5eabSAndrey Smirnov break; 392d64e5eabSAndrey Smirnov } 393d64e5eabSAndrey Smirnov } 394d64e5eabSAndrey Smirnov 395d64e5eabSAndrey Smirnov static char *designware_pcie_viewport_name(const char *direction, 396d64e5eabSAndrey Smirnov unsigned int i, 397d64e5eabSAndrey Smirnov const char *type) 398d64e5eabSAndrey Smirnov { 399d64e5eabSAndrey Smirnov return g_strdup_printf("PCI %s Viewport %u [%s]", 400d64e5eabSAndrey Smirnov direction, i, type); 401d64e5eabSAndrey Smirnov } 402d64e5eabSAndrey Smirnov 403d64e5eabSAndrey Smirnov static void designware_pcie_root_realize(PCIDevice *dev, Error **errp) 404d64e5eabSAndrey Smirnov { 405d64e5eabSAndrey Smirnov DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(dev); 406d64e5eabSAndrey Smirnov DesignwarePCIEHost *host = designware_pcie_root_to_host(root); 40750e4291dSPhilippe Mathieu-Daudé MemoryRegion *host_mem = get_system_memory(); 408d64e5eabSAndrey Smirnov MemoryRegion *address_space = &host->pci.memory; 409d64e5eabSAndrey Smirnov PCIBridge *br = PCI_BRIDGE(dev); 410d64e5eabSAndrey Smirnov DesignwarePCIEViewport *viewport; 411d64e5eabSAndrey Smirnov /* 412d64e5eabSAndrey Smirnov * Dummy values used for initial configuration of MemoryRegions 413d64e5eabSAndrey Smirnov * that belong to a given viewport 414d64e5eabSAndrey Smirnov */ 415d64e5eabSAndrey Smirnov const hwaddr dummy_offset = 0; 416d64e5eabSAndrey Smirnov const uint64_t dummy_size = 4; 417d64e5eabSAndrey Smirnov size_t i; 418d64e5eabSAndrey Smirnov 419d64e5eabSAndrey Smirnov br->bus_name = "dw-pcie"; 420d64e5eabSAndrey Smirnov 421d64e5eabSAndrey Smirnov pci_set_word(dev->config + PCI_COMMAND, 422d64e5eabSAndrey Smirnov PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); 423d64e5eabSAndrey Smirnov 424d64e5eabSAndrey Smirnov pci_config_set_interrupt_pin(dev->config, 1); 425d64e5eabSAndrey Smirnov pci_bridge_initfn(dev, TYPE_PCIE_BUS); 426d64e5eabSAndrey Smirnov 427d64e5eabSAndrey Smirnov pcie_port_init_reg(dev); 428d64e5eabSAndrey Smirnov 429d64e5eabSAndrey Smirnov pcie_cap_init(dev, 0x70, PCI_EXP_TYPE_ROOT_PORT, 430d64e5eabSAndrey Smirnov 0, &error_fatal); 431d64e5eabSAndrey Smirnov 432d64e5eabSAndrey Smirnov msi_nonbroken = true; 433d64e5eabSAndrey Smirnov msi_init(dev, 0x50, 32, true, true, &error_fatal); 434d64e5eabSAndrey Smirnov 435d64e5eabSAndrey Smirnov for (i = 0; i < DESIGNWARE_PCIE_NUM_VIEWPORTS; i++) { 436d64e5eabSAndrey Smirnov MemoryRegion *source, *destination, *mem; 437d64e5eabSAndrey Smirnov const char *direction; 438d64e5eabSAndrey Smirnov char *name; 439d64e5eabSAndrey Smirnov 440d64e5eabSAndrey Smirnov viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][i]; 441d64e5eabSAndrey Smirnov viewport->inbound = true; 442d64e5eabSAndrey Smirnov viewport->base = 0x0000000000000000ULL; 443d64e5eabSAndrey Smirnov viewport->target = 0x0000000000000000ULL; 444d64e5eabSAndrey Smirnov viewport->limit = UINT32_MAX; 445d64e5eabSAndrey Smirnov viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM; 446d64e5eabSAndrey Smirnov 447d64e5eabSAndrey Smirnov source = &host->pci.address_space_root; 44850e4291dSPhilippe Mathieu-Daudé destination = host_mem; 449d64e5eabSAndrey Smirnov direction = "Inbound"; 450d64e5eabSAndrey Smirnov 451d64e5eabSAndrey Smirnov /* 452d64e5eabSAndrey Smirnov * Configure MemoryRegion implementing PCI -> CPU memory 453d64e5eabSAndrey Smirnov * access 454d64e5eabSAndrey Smirnov */ 455d64e5eabSAndrey Smirnov mem = &viewport->mem; 456d64e5eabSAndrey Smirnov name = designware_pcie_viewport_name(direction, i, "MEM"); 457d64e5eabSAndrey Smirnov memory_region_init_alias(mem, OBJECT(root), name, destination, 458d64e5eabSAndrey Smirnov dummy_offset, dummy_size); 459d64e5eabSAndrey Smirnov memory_region_add_subregion_overlap(source, dummy_offset, mem, -1); 460d64e5eabSAndrey Smirnov memory_region_set_enabled(mem, false); 461d64e5eabSAndrey Smirnov g_free(name); 462d64e5eabSAndrey Smirnov 463d64e5eabSAndrey Smirnov viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_OUTBOUND][i]; 464d64e5eabSAndrey Smirnov viewport->root = root; 465d64e5eabSAndrey Smirnov viewport->inbound = false; 466d64e5eabSAndrey Smirnov viewport->base = 0x0000000000000000ULL; 467d64e5eabSAndrey Smirnov viewport->target = 0x0000000000000000ULL; 468d64e5eabSAndrey Smirnov viewport->limit = UINT32_MAX; 469d64e5eabSAndrey Smirnov viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM; 470d64e5eabSAndrey Smirnov 471d64e5eabSAndrey Smirnov destination = &host->pci.memory; 472d64e5eabSAndrey Smirnov direction = "Outbound"; 47350e4291dSPhilippe Mathieu-Daudé source = host_mem; 474d64e5eabSAndrey Smirnov 475d64e5eabSAndrey Smirnov /* 476d64e5eabSAndrey Smirnov * Configure MemoryRegion implementing CPU -> PCI memory 477d64e5eabSAndrey Smirnov * access 478d64e5eabSAndrey Smirnov */ 479d64e5eabSAndrey Smirnov mem = &viewport->mem; 480d64e5eabSAndrey Smirnov name = designware_pcie_viewport_name(direction, i, "MEM"); 481d64e5eabSAndrey Smirnov memory_region_init_alias(mem, OBJECT(root), name, destination, 482d64e5eabSAndrey Smirnov dummy_offset, dummy_size); 483d64e5eabSAndrey Smirnov memory_region_add_subregion(source, dummy_offset, mem); 484d64e5eabSAndrey Smirnov memory_region_set_enabled(mem, false); 485d64e5eabSAndrey Smirnov g_free(name); 486d64e5eabSAndrey Smirnov 487d64e5eabSAndrey Smirnov /* 488d64e5eabSAndrey Smirnov * Configure MemoryRegion implementing access to configuration 489d64e5eabSAndrey Smirnov * space 490d64e5eabSAndrey Smirnov */ 491d64e5eabSAndrey Smirnov mem = &viewport->cfg; 492d64e5eabSAndrey Smirnov name = designware_pcie_viewport_name(direction, i, "CFG"); 493d64e5eabSAndrey Smirnov memory_region_init_io(&viewport->cfg, OBJECT(root), 494d64e5eabSAndrey Smirnov &designware_pci_host_conf_ops, 495d64e5eabSAndrey Smirnov viewport, name, dummy_size); 496d64e5eabSAndrey Smirnov memory_region_add_subregion(source, dummy_offset, mem); 497d64e5eabSAndrey Smirnov memory_region_set_enabled(mem, false); 498d64e5eabSAndrey Smirnov g_free(name); 499d64e5eabSAndrey Smirnov } 500d64e5eabSAndrey Smirnov 501d64e5eabSAndrey Smirnov /* 502d64e5eabSAndrey Smirnov * If no inbound iATU windows are configured, HW defaults to 503f1c0cff8SMichael Tokarev * letting inbound TLPs to pass in. We emulate that by explicitly 504d64e5eabSAndrey Smirnov * configuring first inbound window to cover all of target's 505d64e5eabSAndrey Smirnov * address space. 506d64e5eabSAndrey Smirnov * 507d64e5eabSAndrey Smirnov * NOTE: This will not work correctly for the case when first 508d64e5eabSAndrey Smirnov * configured inbound window is window 0 509d64e5eabSAndrey Smirnov */ 510d64e5eabSAndrey Smirnov viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][0]; 511d64e5eabSAndrey Smirnov viewport->cr[1] = DESIGNWARE_PCIE_ATU_ENABLE; 512d64e5eabSAndrey Smirnov designware_pcie_update_viewport(root, viewport); 513d64e5eabSAndrey Smirnov 514d64e5eabSAndrey Smirnov memory_region_init_io(&root->msi.iomem, OBJECT(root), 515d64e5eabSAndrey Smirnov &designware_pci_host_msi_ops, 516d64e5eabSAndrey Smirnov root, "pcie-msi", 0x4); 517d64e5eabSAndrey Smirnov /* 518f1c0cff8SMichael Tokarev * We initially place MSI interrupt I/O region at address 0 and 519d64e5eabSAndrey Smirnov * disable it. It'll be later moved to correct offset and enabled 520d64e5eabSAndrey Smirnov * in designware_pcie_root_update_msi_mapping() as a part of 521d64e5eabSAndrey Smirnov * initialization done by guest OS 522d64e5eabSAndrey Smirnov */ 523d64e5eabSAndrey Smirnov memory_region_add_subregion(address_space, dummy_offset, &root->msi.iomem); 524d64e5eabSAndrey Smirnov memory_region_set_enabled(&root->msi.iomem, false); 525d64e5eabSAndrey Smirnov } 526d64e5eabSAndrey Smirnov 527d64e5eabSAndrey Smirnov static void designware_pcie_set_irq(void *opaque, int irq_num, int level) 528d64e5eabSAndrey Smirnov { 529d64e5eabSAndrey Smirnov DesignwarePCIEHost *host = DESIGNWARE_PCIE_HOST(opaque); 530d64e5eabSAndrey Smirnov 531d64e5eabSAndrey Smirnov qemu_set_irq(host->pci.irqs[irq_num], level); 532d64e5eabSAndrey Smirnov } 533d64e5eabSAndrey Smirnov 534d64e5eabSAndrey Smirnov static const char * 535d64e5eabSAndrey Smirnov designware_pcie_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) 536d64e5eabSAndrey Smirnov { 537d64e5eabSAndrey Smirnov return "0000:00"; 538d64e5eabSAndrey Smirnov } 539d64e5eabSAndrey Smirnov 540d64e5eabSAndrey Smirnov static const VMStateDescription vmstate_designware_pcie_msi_bank = { 541d64e5eabSAndrey Smirnov .name = "designware-pcie-msi-bank", 542d64e5eabSAndrey Smirnov .version_id = 1, 543d64e5eabSAndrey Smirnov .minimum_version_id = 1, 544e2bd53a3SRichard Henderson .fields = (const VMStateField[]) { 545d64e5eabSAndrey Smirnov VMSTATE_UINT32(enable, DesignwarePCIEMSIBank), 546d64e5eabSAndrey Smirnov VMSTATE_UINT32(mask, DesignwarePCIEMSIBank), 547d64e5eabSAndrey Smirnov VMSTATE_UINT32(status, DesignwarePCIEMSIBank), 548d64e5eabSAndrey Smirnov VMSTATE_END_OF_LIST() 549d64e5eabSAndrey Smirnov } 550d64e5eabSAndrey Smirnov }; 551d64e5eabSAndrey Smirnov 552d64e5eabSAndrey Smirnov static const VMStateDescription vmstate_designware_pcie_msi = { 553d64e5eabSAndrey Smirnov .name = "designware-pcie-msi", 554d64e5eabSAndrey Smirnov .version_id = 1, 555d64e5eabSAndrey Smirnov .minimum_version_id = 1, 556e2bd53a3SRichard Henderson .fields = (const VMStateField[]) { 557d64e5eabSAndrey Smirnov VMSTATE_UINT64(base, DesignwarePCIEMSI), 558d64e5eabSAndrey Smirnov VMSTATE_STRUCT_ARRAY(intr, 559d64e5eabSAndrey Smirnov DesignwarePCIEMSI, 560d64e5eabSAndrey Smirnov DESIGNWARE_PCIE_NUM_MSI_BANKS, 561d64e5eabSAndrey Smirnov 1, 562d64e5eabSAndrey Smirnov vmstate_designware_pcie_msi_bank, 563d64e5eabSAndrey Smirnov DesignwarePCIEMSIBank), 564d64e5eabSAndrey Smirnov VMSTATE_END_OF_LIST() 565d64e5eabSAndrey Smirnov } 566d64e5eabSAndrey Smirnov }; 567d64e5eabSAndrey Smirnov 568d64e5eabSAndrey Smirnov static const VMStateDescription vmstate_designware_pcie_viewport = { 569d64e5eabSAndrey Smirnov .name = "designware-pcie-viewport", 570d64e5eabSAndrey Smirnov .version_id = 1, 571d64e5eabSAndrey Smirnov .minimum_version_id = 1, 572e2bd53a3SRichard Henderson .fields = (const VMStateField[]) { 573d64e5eabSAndrey Smirnov VMSTATE_UINT64(base, DesignwarePCIEViewport), 574d64e5eabSAndrey Smirnov VMSTATE_UINT64(target, DesignwarePCIEViewport), 575d64e5eabSAndrey Smirnov VMSTATE_UINT32(limit, DesignwarePCIEViewport), 576d64e5eabSAndrey Smirnov VMSTATE_UINT32_ARRAY(cr, DesignwarePCIEViewport, 2), 577d64e5eabSAndrey Smirnov VMSTATE_END_OF_LIST() 578d64e5eabSAndrey Smirnov } 579d64e5eabSAndrey Smirnov }; 580d64e5eabSAndrey Smirnov 581d64e5eabSAndrey Smirnov static const VMStateDescription vmstate_designware_pcie_root = { 582d64e5eabSAndrey Smirnov .name = "designware-pcie-root", 583d64e5eabSAndrey Smirnov .version_id = 1, 584d64e5eabSAndrey Smirnov .minimum_version_id = 1, 585e2bd53a3SRichard Henderson .fields = (const VMStateField[]) { 586d64e5eabSAndrey Smirnov VMSTATE_PCI_DEVICE(parent_obj, PCIBridge), 587d64e5eabSAndrey Smirnov VMSTATE_UINT32(atu_viewport, DesignwarePCIERoot), 588d64e5eabSAndrey Smirnov VMSTATE_STRUCT_2DARRAY(viewports, 589d64e5eabSAndrey Smirnov DesignwarePCIERoot, 590d64e5eabSAndrey Smirnov 2, 591d64e5eabSAndrey Smirnov DESIGNWARE_PCIE_NUM_VIEWPORTS, 592d64e5eabSAndrey Smirnov 1, 593d64e5eabSAndrey Smirnov vmstate_designware_pcie_viewport, 594d64e5eabSAndrey Smirnov DesignwarePCIEViewport), 595d64e5eabSAndrey Smirnov VMSTATE_STRUCT(msi, 596d64e5eabSAndrey Smirnov DesignwarePCIERoot, 597d64e5eabSAndrey Smirnov 1, 598d64e5eabSAndrey Smirnov vmstate_designware_pcie_msi, 599d64e5eabSAndrey Smirnov DesignwarePCIEMSI), 600d64e5eabSAndrey Smirnov VMSTATE_END_OF_LIST() 601d64e5eabSAndrey Smirnov } 602d64e5eabSAndrey Smirnov }; 603d64e5eabSAndrey Smirnov 604d64e5eabSAndrey Smirnov static void designware_pcie_root_class_init(ObjectClass *klass, void *data) 605d64e5eabSAndrey Smirnov { 606d64e5eabSAndrey Smirnov PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 607d64e5eabSAndrey Smirnov DeviceClass *dc = DEVICE_CLASS(klass); 608d64e5eabSAndrey Smirnov 609d64e5eabSAndrey Smirnov set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 610d64e5eabSAndrey Smirnov 611d64e5eabSAndrey Smirnov k->vendor_id = PCI_VENDOR_ID_SYNOPSYS; 612d64e5eabSAndrey Smirnov k->device_id = 0xABCD; 613d64e5eabSAndrey Smirnov k->revision = 0; 614d64e5eabSAndrey Smirnov k->class_id = PCI_CLASS_BRIDGE_PCI; 615d64e5eabSAndrey Smirnov k->exit = pci_bridge_exitfn; 616d64e5eabSAndrey Smirnov k->realize = designware_pcie_root_realize; 617d64e5eabSAndrey Smirnov k->config_read = designware_pcie_root_config_read; 618d64e5eabSAndrey Smirnov k->config_write = designware_pcie_root_config_write; 619d64e5eabSAndrey Smirnov 620e3d08143SPeter Maydell device_class_set_legacy_reset(dc, pci_bridge_reset); 621d64e5eabSAndrey Smirnov /* 622d64e5eabSAndrey Smirnov * PCI-facing part of the host bridge, not usable without the 623d64e5eabSAndrey Smirnov * host-facing part, which can't be device_add'ed, yet. 624d64e5eabSAndrey Smirnov */ 625d64e5eabSAndrey Smirnov dc->user_creatable = false; 626d64e5eabSAndrey Smirnov dc->vmsd = &vmstate_designware_pcie_root; 627d64e5eabSAndrey Smirnov } 628d64e5eabSAndrey Smirnov 629d64e5eabSAndrey Smirnov static uint64_t designware_pcie_host_mmio_read(void *opaque, hwaddr addr, 630d64e5eabSAndrey Smirnov unsigned int size) 631d64e5eabSAndrey Smirnov { 632d64e5eabSAndrey Smirnov PCIHostState *pci = PCI_HOST_BRIDGE(opaque); 633d64e5eabSAndrey Smirnov PCIDevice *device = pci_find_device(pci->bus, 0, 0); 634d64e5eabSAndrey Smirnov 635d64e5eabSAndrey Smirnov return pci_host_config_read_common(device, 636d64e5eabSAndrey Smirnov addr, 637d64e5eabSAndrey Smirnov pci_config_size(device), 638d64e5eabSAndrey Smirnov size); 639d64e5eabSAndrey Smirnov } 640d64e5eabSAndrey Smirnov 641d64e5eabSAndrey Smirnov static void designware_pcie_host_mmio_write(void *opaque, hwaddr addr, 642d64e5eabSAndrey Smirnov uint64_t val, unsigned int size) 643d64e5eabSAndrey Smirnov { 644d64e5eabSAndrey Smirnov PCIHostState *pci = PCI_HOST_BRIDGE(opaque); 645d64e5eabSAndrey Smirnov PCIDevice *device = pci_find_device(pci->bus, 0, 0); 646d64e5eabSAndrey Smirnov 647d64e5eabSAndrey Smirnov return pci_host_config_write_common(device, 648d64e5eabSAndrey Smirnov addr, 649d64e5eabSAndrey Smirnov pci_config_size(device), 650d64e5eabSAndrey Smirnov val, size); 651d64e5eabSAndrey Smirnov } 652d64e5eabSAndrey Smirnov 653d64e5eabSAndrey Smirnov static const MemoryRegionOps designware_pci_mmio_ops = { 654d64e5eabSAndrey Smirnov .read = designware_pcie_host_mmio_read, 655d64e5eabSAndrey Smirnov .write = designware_pcie_host_mmio_write, 656d64e5eabSAndrey Smirnov .endianness = DEVICE_LITTLE_ENDIAN, 657d64e5eabSAndrey Smirnov .impl = { 658d64e5eabSAndrey Smirnov /* 659d64e5eabSAndrey Smirnov * Our device would not work correctly if the guest was doing 660d64e5eabSAndrey Smirnov * unaligned access. This might not be a limitation on the real 661d64e5eabSAndrey Smirnov * device but in practice there is no reason for a guest to access 662d64e5eabSAndrey Smirnov * this device unaligned. 663d64e5eabSAndrey Smirnov */ 664d64e5eabSAndrey Smirnov .min_access_size = 4, 665d64e5eabSAndrey Smirnov .max_access_size = 4, 666d64e5eabSAndrey Smirnov .unaligned = false, 667d64e5eabSAndrey Smirnov }, 668d64e5eabSAndrey Smirnov }; 669d64e5eabSAndrey Smirnov 670d64e5eabSAndrey Smirnov static AddressSpace *designware_pcie_host_set_iommu(PCIBus *bus, void *opaque, 671d64e5eabSAndrey Smirnov int devfn) 672d64e5eabSAndrey Smirnov { 673d64e5eabSAndrey Smirnov DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(opaque); 674d64e5eabSAndrey Smirnov 675d64e5eabSAndrey Smirnov return &s->pci.address_space; 676d64e5eabSAndrey Smirnov } 677d64e5eabSAndrey Smirnov 678ba7d12ebSYi Liu static const PCIIOMMUOps designware_iommu_ops = { 679ba7d12ebSYi Liu .get_address_space = designware_pcie_host_set_iommu, 680ba7d12ebSYi Liu }; 681ba7d12ebSYi Liu 682d64e5eabSAndrey Smirnov static void designware_pcie_host_realize(DeviceState *dev, Error **errp) 683d64e5eabSAndrey Smirnov { 684d64e5eabSAndrey Smirnov PCIHostState *pci = PCI_HOST_BRIDGE(dev); 685d64e5eabSAndrey Smirnov DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(dev); 686d64e5eabSAndrey Smirnov SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 687d64e5eabSAndrey Smirnov size_t i; 688d64e5eabSAndrey Smirnov 689d64e5eabSAndrey Smirnov for (i = 0; i < ARRAY_SIZE(s->pci.irqs); i++) { 690d64e5eabSAndrey Smirnov sysbus_init_irq(sbd, &s->pci.irqs[i]); 691d64e5eabSAndrey Smirnov } 6921b326f27SBernhard Beschow sysbus_init_irq(sbd, &s->pci.msi); 693d64e5eabSAndrey Smirnov 694d64e5eabSAndrey Smirnov memory_region_init_io(&s->mmio, 695d64e5eabSAndrey Smirnov OBJECT(s), 696d64e5eabSAndrey Smirnov &designware_pci_mmio_ops, 697d64e5eabSAndrey Smirnov s, 698d64e5eabSAndrey Smirnov "pcie.reg", 4 * 1024); 699d64e5eabSAndrey Smirnov sysbus_init_mmio(sbd, &s->mmio); 700d64e5eabSAndrey Smirnov 701d64e5eabSAndrey Smirnov memory_region_init(&s->pci.io, OBJECT(s), "pcie-pio", 16); 702d64e5eabSAndrey Smirnov memory_region_init(&s->pci.memory, OBJECT(s), 703d64e5eabSAndrey Smirnov "pcie-bus-memory", 704d64e5eabSAndrey Smirnov UINT64_MAX); 705d64e5eabSAndrey Smirnov 706d64e5eabSAndrey Smirnov pci->bus = pci_register_root_bus(dev, "pcie", 707d64e5eabSAndrey Smirnov designware_pcie_set_irq, 708d64e5eabSAndrey Smirnov pci_swizzle_map_irq_fn, 709d64e5eabSAndrey Smirnov s, 710d64e5eabSAndrey Smirnov &s->pci.memory, 711d64e5eabSAndrey Smirnov &s->pci.io, 712d64e5eabSAndrey Smirnov 0, 4, 713*faa2150aSBernhard Beschow TYPE_DESIGNWARE_PCIE_ROOT_BUS); 7143d449bc6SJason Chien pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; 715d64e5eabSAndrey Smirnov 716d64e5eabSAndrey Smirnov memory_region_init(&s->pci.address_space_root, 717d64e5eabSAndrey Smirnov OBJECT(s), 718d64e5eabSAndrey Smirnov "pcie-bus-address-space-root", 719d64e5eabSAndrey Smirnov UINT64_MAX); 720d64e5eabSAndrey Smirnov memory_region_add_subregion(&s->pci.address_space_root, 721d64e5eabSAndrey Smirnov 0x0, &s->pci.memory); 722d64e5eabSAndrey Smirnov address_space_init(&s->pci.address_space, 723d64e5eabSAndrey Smirnov &s->pci.address_space_root, 724d64e5eabSAndrey Smirnov "pcie-bus-address-space"); 725ba7d12ebSYi Liu pci_setup_iommu(pci->bus, &designware_iommu_ops, s); 726d64e5eabSAndrey Smirnov 72799ba777eSMarkus Armbruster qdev_realize(DEVICE(&s->root), BUS(pci->bus), &error_fatal); 728d64e5eabSAndrey Smirnov } 729d64e5eabSAndrey Smirnov 730d64e5eabSAndrey Smirnov static const VMStateDescription vmstate_designware_pcie_host = { 731d64e5eabSAndrey Smirnov .name = "designware-pcie-host", 732d64e5eabSAndrey Smirnov .version_id = 1, 733d64e5eabSAndrey Smirnov .minimum_version_id = 1, 734e2bd53a3SRichard Henderson .fields = (const VMStateField[]) { 735d64e5eabSAndrey Smirnov VMSTATE_STRUCT(root, 736d64e5eabSAndrey Smirnov DesignwarePCIEHost, 737d64e5eabSAndrey Smirnov 1, 738d64e5eabSAndrey Smirnov vmstate_designware_pcie_root, 739d64e5eabSAndrey Smirnov DesignwarePCIERoot), 740d64e5eabSAndrey Smirnov VMSTATE_END_OF_LIST() 741d64e5eabSAndrey Smirnov } 742d64e5eabSAndrey Smirnov }; 743d64e5eabSAndrey Smirnov 744d64e5eabSAndrey Smirnov static void designware_pcie_host_class_init(ObjectClass *klass, void *data) 745d64e5eabSAndrey Smirnov { 746d64e5eabSAndrey Smirnov DeviceClass *dc = DEVICE_CLASS(klass); 747d64e5eabSAndrey Smirnov PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); 748d64e5eabSAndrey Smirnov 749d64e5eabSAndrey Smirnov hc->root_bus_path = designware_pcie_host_root_bus_path; 750d64e5eabSAndrey Smirnov dc->realize = designware_pcie_host_realize; 751d64e5eabSAndrey Smirnov set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 752d64e5eabSAndrey Smirnov dc->fw_name = "pci"; 753d64e5eabSAndrey Smirnov dc->vmsd = &vmstate_designware_pcie_host; 754d64e5eabSAndrey Smirnov } 755d64e5eabSAndrey Smirnov 756d64e5eabSAndrey Smirnov static void designware_pcie_host_init(Object *obj) 757d64e5eabSAndrey Smirnov { 758d64e5eabSAndrey Smirnov DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(obj); 759d64e5eabSAndrey Smirnov DesignwarePCIERoot *root = &s->root; 760d64e5eabSAndrey Smirnov 7619fc7fc4dSMarkus Armbruster object_initialize_child(obj, "root", root, TYPE_DESIGNWARE_PCIE_ROOT); 762d64e5eabSAndrey Smirnov qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0)); 763d64e5eabSAndrey Smirnov qdev_prop_set_bit(DEVICE(root), "multifunction", false); 764d64e5eabSAndrey Smirnov } 765d64e5eabSAndrey Smirnov 76613a07eb1SPhilippe Mathieu-Daudé static const TypeInfo designware_pcie_types[] = { 76713a07eb1SPhilippe Mathieu-Daudé { 768*faa2150aSBernhard Beschow .name = TYPE_DESIGNWARE_PCIE_ROOT_BUS, 769*faa2150aSBernhard Beschow .parent = TYPE_PCIE_BUS, 770*faa2150aSBernhard Beschow .instance_size = sizeof(DesignwarePCIERootBus), 771*faa2150aSBernhard Beschow .class_init = designware_pcie_root_bus_class_init, 772*faa2150aSBernhard Beschow }, { 77313a07eb1SPhilippe Mathieu-Daudé .name = TYPE_DESIGNWARE_PCIE_HOST, 77413a07eb1SPhilippe Mathieu-Daudé .parent = TYPE_PCI_HOST_BRIDGE, 77513a07eb1SPhilippe Mathieu-Daudé .instance_size = sizeof(DesignwarePCIEHost), 77613a07eb1SPhilippe Mathieu-Daudé .instance_init = designware_pcie_host_init, 77713a07eb1SPhilippe Mathieu-Daudé .class_init = designware_pcie_host_class_init, 77813a07eb1SPhilippe Mathieu-Daudé }, { 779d64e5eabSAndrey Smirnov .name = TYPE_DESIGNWARE_PCIE_ROOT, 780d64e5eabSAndrey Smirnov .parent = TYPE_PCI_BRIDGE, 781d64e5eabSAndrey Smirnov .instance_size = sizeof(DesignwarePCIERoot), 782d64e5eabSAndrey Smirnov .class_init = designware_pcie_root_class_init, 783d64e5eabSAndrey Smirnov .interfaces = (InterfaceInfo[]) { 784d64e5eabSAndrey Smirnov { INTERFACE_PCIE_DEVICE }, 785d64e5eabSAndrey Smirnov { } 786d64e5eabSAndrey Smirnov }, 78713a07eb1SPhilippe Mathieu-Daudé }, 788d64e5eabSAndrey Smirnov }; 789d64e5eabSAndrey Smirnov 79013a07eb1SPhilippe Mathieu-Daudé DEFINE_TYPES(designware_pcie_types) 791