1a9f49946SIsaku Yamahata /* 2a9f49946SIsaku Yamahata * pcie_host.c 3a9f49946SIsaku Yamahata * utility functions for pci express host bridge. 4a9f49946SIsaku Yamahata * 5a9f49946SIsaku Yamahata * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> 6a9f49946SIsaku Yamahata * VA Linux Systems Japan K.K. 7a9f49946SIsaku Yamahata * 8a9f49946SIsaku Yamahata * This program is free software; you can redistribute it and/or modify 9a9f49946SIsaku Yamahata * it under the terms of the GNU General Public License as published by 10a9f49946SIsaku Yamahata * the Free Software Foundation; either version 2 of the License, or 11a9f49946SIsaku Yamahata * (at your option) any later version. 12a9f49946SIsaku Yamahata 13a9f49946SIsaku Yamahata * This program is distributed in the hope that it will be useful, 14a9f49946SIsaku Yamahata * but WITHOUT ANY WARRANTY; without even the implied warranty of 15a9f49946SIsaku Yamahata * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16a9f49946SIsaku Yamahata * GNU General Public License for more details. 17a9f49946SIsaku Yamahata 18a9f49946SIsaku Yamahata * You should have received a copy of the GNU General Public License along 1970539e18SBlue Swirl * with this program; if not, see <http://www.gnu.org/licenses/>. 20a9f49946SIsaku Yamahata */ 21a9f49946SIsaku Yamahata 2297d5408fSPeter Maydell #include "qemu/osdep.h" 23c759b24fSMichael S. Tsirkin #include "hw/hw.h" 24c759b24fSMichael S. Tsirkin #include "hw/pci/pci.h" 25c759b24fSMichael S. Tsirkin #include "hw/pci/pcie_host.h" 26022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 27a9f49946SIsaku Yamahata 28a9f49946SIsaku Yamahata /* a helper function to get a PCIDevice for a given mmconfig address */ 298d6514f8SIsaku Yamahata static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, 308d6514f8SIsaku Yamahata uint32_t mmcfg_addr) 31a9f49946SIsaku Yamahata { 32a9f49946SIsaku Yamahata return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), 335256d8bfSIsaku Yamahata PCIE_MMCFG_DEVFN(mmcfg_addr)); 34a9f49946SIsaku Yamahata } 35a9f49946SIsaku Yamahata 36a8170e5eSAvi Kivity static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, 37c76f990eSAvi Kivity uint64_t val, unsigned len) 38a9f49946SIsaku Yamahata { 39c76f990eSAvi Kivity PCIExpressHost *e = opaque; 40c76f990eSAvi Kivity PCIBus *s = e->pci.bus; 418d6514f8SIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); 4243e86c8fSIsaku Yamahata uint32_t addr; 4343e86c8fSIsaku Yamahata uint32_t limit; 44a9f49946SIsaku Yamahata 4542e4126bSJan Kiszka if (!pci_dev) { 46a9f49946SIsaku Yamahata return; 4742e4126bSJan Kiszka } 4843e86c8fSIsaku Yamahata addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); 4943e86c8fSIsaku Yamahata limit = pci_config_size(pci_dev); 5043e86c8fSIsaku Yamahata if (limit <= addr) { 5143e86c8fSIsaku Yamahata /* conventional pci device can be behind pcie-to-pci bridge. 5243e86c8fSIsaku Yamahata 256 <= addr < 4K has no effects. */ 5343e86c8fSIsaku Yamahata return; 5443e86c8fSIsaku Yamahata } 5543e86c8fSIsaku Yamahata pci_host_config_write_common(pci_dev, addr, limit, val, len); 56a9f49946SIsaku Yamahata } 57a9f49946SIsaku Yamahata 58c76f990eSAvi Kivity static uint64_t pcie_mmcfg_data_read(void *opaque, 59a8170e5eSAvi Kivity hwaddr mmcfg_addr, 60c76f990eSAvi Kivity unsigned len) 61a9f49946SIsaku Yamahata { 62c76f990eSAvi Kivity PCIExpressHost *e = opaque; 63c76f990eSAvi Kivity PCIBus *s = e->pci.bus; 6443e86c8fSIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); 6543e86c8fSIsaku Yamahata uint32_t addr; 6643e86c8fSIsaku Yamahata uint32_t limit; 67a9f49946SIsaku Yamahata 68a9f49946SIsaku Yamahata if (!pci_dev) { 694677d8edSMichael S. Tsirkin return ~0x0; 70a9f49946SIsaku Yamahata } 7143e86c8fSIsaku Yamahata addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); 7243e86c8fSIsaku Yamahata limit = pci_config_size(pci_dev); 7343e86c8fSIsaku Yamahata if (limit <= addr) { 7443e86c8fSIsaku Yamahata /* conventional pci device can be behind pcie-to-pci bridge. 7543e86c8fSIsaku Yamahata 256 <= addr < 4K has no effects. */ 7643e86c8fSIsaku Yamahata return ~0x0; 7743e86c8fSIsaku Yamahata } 7843e86c8fSIsaku Yamahata return pci_host_config_read_common(pci_dev, addr, limit, len); 79a9f49946SIsaku Yamahata } 80a9f49946SIsaku Yamahata 81c76f990eSAvi Kivity static const MemoryRegionOps pcie_mmcfg_ops = { 82c76f990eSAvi Kivity .read = pcie_mmcfg_data_read, 83c76f990eSAvi Kivity .write = pcie_mmcfg_data_write, 84*a6c242aaSMatt Redfearn .endianness = DEVICE_LITTLE_ENDIAN, 85a9f49946SIsaku Yamahata }; 86a9f49946SIsaku Yamahata 877c8b7248SAndreas Färber static void pcie_host_init(Object *obj) 88a9f49946SIsaku Yamahata { 897c8b7248SAndreas Färber PCIExpressHost *e = PCIE_HOST_BRIDGE(obj); 90a9f49946SIsaku Yamahata 917c8b7248SAndreas Färber e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 923a8f2a9cSPaolo Bonzini memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e, "pcie-mmcfg-mmio", 933a8f2a9cSPaolo Bonzini PCIE_MMCFG_SIZE_MAX); 94a9f49946SIsaku Yamahata } 95a9f49946SIsaku Yamahata 96a9f49946SIsaku Yamahata void pcie_host_mmcfg_unmap(PCIExpressHost *e) 97a9f49946SIsaku Yamahata { 98a9f49946SIsaku Yamahata if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { 99c76f990eSAvi Kivity memory_region_del_subregion(get_system_memory(), &e->mmio); 100a9f49946SIsaku Yamahata e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 101a9f49946SIsaku Yamahata } 102a9f49946SIsaku Yamahata } 103a9f49946SIsaku Yamahata 10427fb9688SAlexander Graf void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size) 105a9f49946SIsaku Yamahata { 106c702ddb8SJason Baron assert(!(size & (size - 1))); /* power of 2 */ 107c702ddb8SJason Baron assert(size >= PCIE_MMCFG_SIZE_MIN); 108c702ddb8SJason Baron assert(size <= PCIE_MMCFG_SIZE_MAX); 109c702ddb8SJason Baron e->size = size; 1103a8f2a9cSPaolo Bonzini memory_region_set_size(&e->mmio, e->size); 11127fb9688SAlexander Graf } 11227fb9688SAlexander Graf 11327fb9688SAlexander Graf void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, 11427fb9688SAlexander Graf uint32_t size) 11527fb9688SAlexander Graf { 11627fb9688SAlexander Graf pcie_host_mmcfg_init(e, size); 117a9f49946SIsaku Yamahata e->base_addr = addr; 118c76f990eSAvi Kivity memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); 119a9f49946SIsaku Yamahata } 120a9f49946SIsaku Yamahata 121a9f49946SIsaku Yamahata void pcie_host_mmcfg_update(PCIExpressHost *e, 122a9f49946SIsaku Yamahata int enable, 123c702ddb8SJason Baron hwaddr addr, 124c702ddb8SJason Baron uint32_t size) 125a9f49946SIsaku Yamahata { 1263a8f2a9cSPaolo Bonzini memory_region_transaction_begin(); 127a9f49946SIsaku Yamahata pcie_host_mmcfg_unmap(e); 128a9f49946SIsaku Yamahata if (enable) { 129c702ddb8SJason Baron pcie_host_mmcfg_map(e, addr, size); 130a9f49946SIsaku Yamahata } 1313a8f2a9cSPaolo Bonzini memory_region_transaction_commit(); 132a9f49946SIsaku Yamahata } 133bc927e48SJason Baron 134bc927e48SJason Baron static const TypeInfo pcie_host_type_info = { 135bc927e48SJason Baron .name = TYPE_PCIE_HOST_BRIDGE, 136bc927e48SJason Baron .parent = TYPE_PCI_HOST_BRIDGE, 137bc927e48SJason Baron .abstract = true, 138bc927e48SJason Baron .instance_size = sizeof(PCIExpressHost), 1397c8b7248SAndreas Färber .instance_init = pcie_host_init, 140bc927e48SJason Baron }; 141bc927e48SJason Baron 142bc927e48SJason Baron static void pcie_host_register_types(void) 143bc927e48SJason Baron { 144bc927e48SJason Baron type_register_static(&pcie_host_type_info); 145bc927e48SJason Baron } 146bc927e48SJason Baron 147bc927e48SJason Baron type_init(pcie_host_register_types) 148