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 22c759b24fSMichael S. Tsirkin #include "hw/hw.h" 23c759b24fSMichael S. Tsirkin #include "hw/pci/pci.h" 24c759b24fSMichael S. Tsirkin #include "hw/pci/pcie_host.h" 25022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 26a9f49946SIsaku Yamahata 27a9f49946SIsaku Yamahata /* a helper function to get a PCIDevice for a given mmconfig address */ 288d6514f8SIsaku Yamahata static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, 298d6514f8SIsaku Yamahata uint32_t mmcfg_addr) 30a9f49946SIsaku Yamahata { 31a9f49946SIsaku Yamahata return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), 325256d8bfSIsaku Yamahata PCIE_MMCFG_DEVFN(mmcfg_addr)); 33a9f49946SIsaku Yamahata } 34a9f49946SIsaku Yamahata 35a8170e5eSAvi Kivity static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, 36c76f990eSAvi Kivity uint64_t val, unsigned len) 37a9f49946SIsaku Yamahata { 38c76f990eSAvi Kivity PCIExpressHost *e = opaque; 39c76f990eSAvi Kivity PCIBus *s = e->pci.bus; 408d6514f8SIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); 4143e86c8fSIsaku Yamahata uint32_t addr; 4243e86c8fSIsaku Yamahata uint32_t limit; 43a9f49946SIsaku Yamahata 4442e4126bSJan Kiszka if (!pci_dev) { 45a9f49946SIsaku Yamahata return; 4642e4126bSJan Kiszka } 4743e86c8fSIsaku Yamahata addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); 4843e86c8fSIsaku Yamahata limit = pci_config_size(pci_dev); 4943e86c8fSIsaku Yamahata if (limit <= addr) { 5043e86c8fSIsaku Yamahata /* conventional pci device can be behind pcie-to-pci bridge. 5143e86c8fSIsaku Yamahata 256 <= addr < 4K has no effects. */ 5243e86c8fSIsaku Yamahata return; 5343e86c8fSIsaku Yamahata } 5443e86c8fSIsaku Yamahata pci_host_config_write_common(pci_dev, addr, limit, val, len); 55a9f49946SIsaku Yamahata } 56a9f49946SIsaku Yamahata 57c76f990eSAvi Kivity static uint64_t pcie_mmcfg_data_read(void *opaque, 58a8170e5eSAvi Kivity hwaddr mmcfg_addr, 59c76f990eSAvi Kivity unsigned len) 60a9f49946SIsaku Yamahata { 61c76f990eSAvi Kivity PCIExpressHost *e = opaque; 62c76f990eSAvi Kivity PCIBus *s = e->pci.bus; 6343e86c8fSIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); 6443e86c8fSIsaku Yamahata uint32_t addr; 6543e86c8fSIsaku Yamahata uint32_t limit; 66a9f49946SIsaku Yamahata 67a9f49946SIsaku Yamahata if (!pci_dev) { 684677d8edSMichael S. Tsirkin return ~0x0; 69a9f49946SIsaku Yamahata } 7043e86c8fSIsaku Yamahata addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); 7143e86c8fSIsaku Yamahata limit = pci_config_size(pci_dev); 7243e86c8fSIsaku Yamahata if (limit <= addr) { 7343e86c8fSIsaku Yamahata /* conventional pci device can be behind pcie-to-pci bridge. 7443e86c8fSIsaku Yamahata 256 <= addr < 4K has no effects. */ 7543e86c8fSIsaku Yamahata return ~0x0; 7643e86c8fSIsaku Yamahata } 7743e86c8fSIsaku Yamahata return pci_host_config_read_common(pci_dev, addr, limit, len); 78a9f49946SIsaku Yamahata } 79a9f49946SIsaku Yamahata 80c76f990eSAvi Kivity static const MemoryRegionOps pcie_mmcfg_ops = { 81c76f990eSAvi Kivity .read = pcie_mmcfg_data_read, 82c76f990eSAvi Kivity .write = pcie_mmcfg_data_write, 83c76f990eSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 84a9f49946SIsaku Yamahata }; 85a9f49946SIsaku Yamahata 867c8b7248SAndreas Färber static void pcie_host_init(Object *obj) 87a9f49946SIsaku Yamahata { 887c8b7248SAndreas Färber PCIExpressHost *e = PCIE_HOST_BRIDGE(obj); 89a9f49946SIsaku Yamahata 907c8b7248SAndreas Färber e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 91*3a8f2a9cSPaolo Bonzini memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e, "pcie-mmcfg-mmio", 92*3a8f2a9cSPaolo Bonzini PCIE_MMCFG_SIZE_MAX); 93a9f49946SIsaku Yamahata } 94a9f49946SIsaku Yamahata 95a9f49946SIsaku Yamahata void pcie_host_mmcfg_unmap(PCIExpressHost *e) 96a9f49946SIsaku Yamahata { 97a9f49946SIsaku Yamahata if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { 98c76f990eSAvi Kivity memory_region_del_subregion(get_system_memory(), &e->mmio); 99a9f49946SIsaku Yamahata e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 100a9f49946SIsaku Yamahata } 101a9f49946SIsaku Yamahata } 102a9f49946SIsaku Yamahata 10327fb9688SAlexander Graf void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size) 104a9f49946SIsaku Yamahata { 105c702ddb8SJason Baron assert(!(size & (size - 1))); /* power of 2 */ 106c702ddb8SJason Baron assert(size >= PCIE_MMCFG_SIZE_MIN); 107c702ddb8SJason Baron assert(size <= PCIE_MMCFG_SIZE_MAX); 108c702ddb8SJason Baron e->size = size; 109*3a8f2a9cSPaolo Bonzini memory_region_set_size(&e->mmio, e->size); 11027fb9688SAlexander Graf } 11127fb9688SAlexander Graf 11227fb9688SAlexander Graf void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, 11327fb9688SAlexander Graf uint32_t size) 11427fb9688SAlexander Graf { 11527fb9688SAlexander Graf pcie_host_mmcfg_init(e, size); 116a9f49946SIsaku Yamahata e->base_addr = addr; 117c76f990eSAvi Kivity memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); 118a9f49946SIsaku Yamahata } 119a9f49946SIsaku Yamahata 120a9f49946SIsaku Yamahata void pcie_host_mmcfg_update(PCIExpressHost *e, 121a9f49946SIsaku Yamahata int enable, 122c702ddb8SJason Baron hwaddr addr, 123c702ddb8SJason Baron uint32_t size) 124a9f49946SIsaku Yamahata { 125*3a8f2a9cSPaolo Bonzini memory_region_transaction_begin(); 126a9f49946SIsaku Yamahata pcie_host_mmcfg_unmap(e); 127a9f49946SIsaku Yamahata if (enable) { 128c702ddb8SJason Baron pcie_host_mmcfg_map(e, addr, size); 129a9f49946SIsaku Yamahata } 130*3a8f2a9cSPaolo Bonzini memory_region_transaction_commit(); 131a9f49946SIsaku Yamahata } 132bc927e48SJason Baron 133bc927e48SJason Baron static const TypeInfo pcie_host_type_info = { 134bc927e48SJason Baron .name = TYPE_PCIE_HOST_BRIDGE, 135bc927e48SJason Baron .parent = TYPE_PCI_HOST_BRIDGE, 136bc927e48SJason Baron .abstract = true, 137bc927e48SJason Baron .instance_size = sizeof(PCIExpressHost), 1387c8b7248SAndreas Färber .instance_init = pcie_host_init, 139bc927e48SJason Baron }; 140bc927e48SJason Baron 141bc927e48SJason Baron static void pcie_host_register_types(void) 142bc927e48SJason Baron { 143bc927e48SJason Baron type_register_static(&pcie_host_type_info); 144bc927e48SJason Baron } 145bc927e48SJason Baron 146bc927e48SJason Baron type_init(pcie_host_register_types) 147