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" 26*0b8fa32fSMarkus Armbruster #include "qemu/module.h" 27022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 28a9f49946SIsaku Yamahata 29a9f49946SIsaku Yamahata /* a helper function to get a PCIDevice for a given mmconfig address */ 308d6514f8SIsaku Yamahata static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, 318d6514f8SIsaku Yamahata uint32_t mmcfg_addr) 32a9f49946SIsaku Yamahata { 33a9f49946SIsaku Yamahata return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), 345256d8bfSIsaku Yamahata PCIE_MMCFG_DEVFN(mmcfg_addr)); 35a9f49946SIsaku Yamahata } 36a9f49946SIsaku Yamahata 37a8170e5eSAvi Kivity static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, 38c76f990eSAvi Kivity uint64_t val, unsigned len) 39a9f49946SIsaku Yamahata { 40c76f990eSAvi Kivity PCIExpressHost *e = opaque; 41c76f990eSAvi Kivity PCIBus *s = e->pci.bus; 428d6514f8SIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); 4343e86c8fSIsaku Yamahata uint32_t addr; 4443e86c8fSIsaku Yamahata uint32_t limit; 45a9f49946SIsaku Yamahata 4642e4126bSJan Kiszka if (!pci_dev) { 47a9f49946SIsaku Yamahata return; 4842e4126bSJan Kiszka } 4943e86c8fSIsaku Yamahata addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); 5043e86c8fSIsaku Yamahata limit = pci_config_size(pci_dev); 5143e86c8fSIsaku Yamahata pci_host_config_write_common(pci_dev, addr, limit, val, len); 52a9f49946SIsaku Yamahata } 53a9f49946SIsaku Yamahata 54c76f990eSAvi Kivity static uint64_t pcie_mmcfg_data_read(void *opaque, 55a8170e5eSAvi Kivity hwaddr mmcfg_addr, 56c76f990eSAvi Kivity unsigned len) 57a9f49946SIsaku Yamahata { 58c76f990eSAvi Kivity PCIExpressHost *e = opaque; 59c76f990eSAvi Kivity PCIBus *s = e->pci.bus; 6043e86c8fSIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); 6143e86c8fSIsaku Yamahata uint32_t addr; 6243e86c8fSIsaku Yamahata uint32_t limit; 63a9f49946SIsaku Yamahata 64a9f49946SIsaku Yamahata if (!pci_dev) { 654677d8edSMichael S. Tsirkin return ~0x0; 66a9f49946SIsaku Yamahata } 6743e86c8fSIsaku Yamahata addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); 6843e86c8fSIsaku Yamahata limit = pci_config_size(pci_dev); 6943e86c8fSIsaku Yamahata return pci_host_config_read_common(pci_dev, addr, limit, len); 70a9f49946SIsaku Yamahata } 71a9f49946SIsaku Yamahata 72c76f990eSAvi Kivity static const MemoryRegionOps pcie_mmcfg_ops = { 73c76f990eSAvi Kivity .read = pcie_mmcfg_data_read, 74c76f990eSAvi Kivity .write = pcie_mmcfg_data_write, 75a6c242aaSMatt Redfearn .endianness = DEVICE_LITTLE_ENDIAN, 76a9f49946SIsaku Yamahata }; 77a9f49946SIsaku Yamahata 787c8b7248SAndreas Färber static void pcie_host_init(Object *obj) 79a9f49946SIsaku Yamahata { 807c8b7248SAndreas Färber PCIExpressHost *e = PCIE_HOST_BRIDGE(obj); 81a9f49946SIsaku Yamahata 827c8b7248SAndreas Färber e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 833a8f2a9cSPaolo Bonzini memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e, "pcie-mmcfg-mmio", 843a8f2a9cSPaolo Bonzini PCIE_MMCFG_SIZE_MAX); 85a9f49946SIsaku Yamahata } 86a9f49946SIsaku Yamahata 87a9f49946SIsaku Yamahata void pcie_host_mmcfg_unmap(PCIExpressHost *e) 88a9f49946SIsaku Yamahata { 89a9f49946SIsaku Yamahata if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { 90c76f990eSAvi Kivity memory_region_del_subregion(get_system_memory(), &e->mmio); 91a9f49946SIsaku Yamahata e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 92a9f49946SIsaku Yamahata } 93a9f49946SIsaku Yamahata } 94a9f49946SIsaku Yamahata 9527fb9688SAlexander Graf void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size) 96a9f49946SIsaku Yamahata { 97c702ddb8SJason Baron assert(!(size & (size - 1))); /* power of 2 */ 98c702ddb8SJason Baron assert(size >= PCIE_MMCFG_SIZE_MIN); 99c702ddb8SJason Baron assert(size <= PCIE_MMCFG_SIZE_MAX); 100c702ddb8SJason Baron e->size = size; 1013a8f2a9cSPaolo Bonzini memory_region_set_size(&e->mmio, e->size); 10227fb9688SAlexander Graf } 10327fb9688SAlexander Graf 10427fb9688SAlexander Graf void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, 10527fb9688SAlexander Graf uint32_t size) 10627fb9688SAlexander Graf { 10727fb9688SAlexander Graf pcie_host_mmcfg_init(e, size); 108a9f49946SIsaku Yamahata e->base_addr = addr; 109c76f990eSAvi Kivity memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); 110a9f49946SIsaku Yamahata } 111a9f49946SIsaku Yamahata 112a9f49946SIsaku Yamahata void pcie_host_mmcfg_update(PCIExpressHost *e, 113a9f49946SIsaku Yamahata int enable, 114c702ddb8SJason Baron hwaddr addr, 115c702ddb8SJason Baron uint32_t size) 116a9f49946SIsaku Yamahata { 1173a8f2a9cSPaolo Bonzini memory_region_transaction_begin(); 118a9f49946SIsaku Yamahata pcie_host_mmcfg_unmap(e); 119a9f49946SIsaku Yamahata if (enable) { 120c702ddb8SJason Baron pcie_host_mmcfg_map(e, addr, size); 121a9f49946SIsaku Yamahata } 1223a8f2a9cSPaolo Bonzini memory_region_transaction_commit(); 123a9f49946SIsaku Yamahata } 124bc927e48SJason Baron 125bc927e48SJason Baron static const TypeInfo pcie_host_type_info = { 126bc927e48SJason Baron .name = TYPE_PCIE_HOST_BRIDGE, 127bc927e48SJason Baron .parent = TYPE_PCI_HOST_BRIDGE, 128bc927e48SJason Baron .abstract = true, 129bc927e48SJason Baron .instance_size = sizeof(PCIExpressHost), 1307c8b7248SAndreas Färber .instance_init = pcie_host_init, 131bc927e48SJason Baron }; 132bc927e48SJason Baron 133bc927e48SJason Baron static void pcie_host_register_types(void) 134bc927e48SJason Baron { 135bc927e48SJason Baron type_register_static(&pcie_host_type_info); 136bc927e48SJason Baron } 137bc927e48SJason Baron 138bc927e48SJason Baron type_init(pcie_host_register_types) 139