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 22a9f49946SIsaku Yamahata #include "hw.h" 23a9f49946SIsaku Yamahata #include "pci.h" 24a9f49946SIsaku Yamahata #include "pcie_host.h" 25a9f49946SIsaku Yamahata 26a9f49946SIsaku Yamahata /* 27a9f49946SIsaku Yamahata * PCI express mmcfig address 28a9f49946SIsaku Yamahata * bit 20 - 28: bus number 29a9f49946SIsaku Yamahata * bit 15 - 19: device number 30a9f49946SIsaku Yamahata * bit 12 - 14: function number 31a9f49946SIsaku Yamahata * bit 0 - 11: offset in configuration space of a given device 32a9f49946SIsaku Yamahata */ 33a9f49946SIsaku Yamahata #define PCIE_MMCFG_SIZE_MAX (1ULL << 28) 34a9f49946SIsaku Yamahata #define PCIE_MMCFG_SIZE_MIN (1ULL << 20) 35a9f49946SIsaku Yamahata #define PCIE_MMCFG_BUS_BIT 20 36a9f49946SIsaku Yamahata #define PCIE_MMCFG_BUS_MASK 0x1ff 37a9f49946SIsaku Yamahata #define PCIE_MMCFG_DEVFN_BIT 12 38a9f49946SIsaku Yamahata #define PCIE_MMCFG_DEVFN_MASK 0xff 39a9f49946SIsaku Yamahata #define PCIE_MMCFG_CONFOFFSET_MASK 0xfff 40a9f49946SIsaku Yamahata #define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ 41a9f49946SIsaku Yamahata PCIE_MMCFG_BUS_MASK) 42a9f49946SIsaku Yamahata #define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ 43a9f49946SIsaku Yamahata PCIE_MMCFG_DEVFN_MASK) 44a9f49946SIsaku Yamahata #define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) 45a9f49946SIsaku Yamahata 46a9f49946SIsaku Yamahata 47a9f49946SIsaku Yamahata /* a helper function to get a PCIDevice for a given mmconfig address */ 488d6514f8SIsaku Yamahata static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, 498d6514f8SIsaku Yamahata uint32_t mmcfg_addr) 50a9f49946SIsaku Yamahata { 51a9f49946SIsaku Yamahata return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), 525256d8bfSIsaku Yamahata PCIE_MMCFG_DEVFN(mmcfg_addr)); 53a9f49946SIsaku Yamahata } 54a9f49946SIsaku Yamahata 55a9f49946SIsaku Yamahata static void pcie_mmcfg_data_write(PCIBus *s, 56a9f49946SIsaku Yamahata uint32_t mmcfg_addr, uint32_t val, int len) 57a9f49946SIsaku Yamahata { 588d6514f8SIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); 59a9f49946SIsaku Yamahata 60*42e4126bSJan Kiszka if (!pci_dev) { 61a9f49946SIsaku Yamahata return; 62*42e4126bSJan Kiszka } 63*42e4126bSJan Kiszka pci_host_config_write_common(pci_dev, PCIE_MMCFG_CONFOFFSET(mmcfg_addr), 64*42e4126bSJan Kiszka pci_config_size(pci_dev), val, len); 65a9f49946SIsaku Yamahata } 66a9f49946SIsaku Yamahata 674677d8edSMichael S. Tsirkin static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len) 68a9f49946SIsaku Yamahata { 698d6514f8SIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr); 70a9f49946SIsaku Yamahata 71a9f49946SIsaku Yamahata if (!pci_dev) { 724677d8edSMichael S. Tsirkin return ~0x0; 73a9f49946SIsaku Yamahata } 74*42e4126bSJan Kiszka return pci_host_config_read_common(pci_dev, PCIE_MMCFG_CONFOFFSET(addr), 75*42e4126bSJan Kiszka pci_config_size(pci_dev), len); 76a9f49946SIsaku Yamahata } 77a9f49946SIsaku Yamahata 78a9f49946SIsaku Yamahata static void pcie_mmcfg_data_writeb(void *opaque, 79a9f49946SIsaku Yamahata target_phys_addr_t addr, uint32_t value) 80a9f49946SIsaku Yamahata { 81a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 82a9f49946SIsaku Yamahata pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 1); 83a9f49946SIsaku Yamahata } 84a9f49946SIsaku Yamahata 85a9f49946SIsaku Yamahata static void pcie_mmcfg_data_writew(void *opaque, 86a9f49946SIsaku Yamahata target_phys_addr_t addr, uint32_t value) 87a9f49946SIsaku Yamahata { 88a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 89a9f49946SIsaku Yamahata pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 2); 90a9f49946SIsaku Yamahata } 91a9f49946SIsaku Yamahata 92a9f49946SIsaku Yamahata static void pcie_mmcfg_data_writel(void *opaque, 93a9f49946SIsaku Yamahata target_phys_addr_t addr, uint32_t value) 94a9f49946SIsaku Yamahata { 95a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 96a9f49946SIsaku Yamahata pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 4); 97a9f49946SIsaku Yamahata } 98a9f49946SIsaku Yamahata 99a9f49946SIsaku Yamahata static uint32_t pcie_mmcfg_data_readb(void *opaque, target_phys_addr_t addr) 100a9f49946SIsaku Yamahata { 101a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 102a9f49946SIsaku Yamahata return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 1); 103a9f49946SIsaku Yamahata } 104a9f49946SIsaku Yamahata 105a9f49946SIsaku Yamahata static uint32_t pcie_mmcfg_data_readw(void *opaque, target_phys_addr_t addr) 106a9f49946SIsaku Yamahata { 107a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 108a9f49946SIsaku Yamahata return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 2); 109a9f49946SIsaku Yamahata } 110a9f49946SIsaku Yamahata 111a9f49946SIsaku Yamahata static uint32_t pcie_mmcfg_data_readl(void *opaque, target_phys_addr_t addr) 112a9f49946SIsaku Yamahata { 113a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 114a9f49946SIsaku Yamahata return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 4); 115a9f49946SIsaku Yamahata } 116a9f49946SIsaku Yamahata 117a9f49946SIsaku Yamahata 118a9f49946SIsaku Yamahata static CPUWriteMemoryFunc * const pcie_mmcfg_write[] = 119a9f49946SIsaku Yamahata { 120a9f49946SIsaku Yamahata pcie_mmcfg_data_writeb, 121a9f49946SIsaku Yamahata pcie_mmcfg_data_writew, 122a9f49946SIsaku Yamahata pcie_mmcfg_data_writel, 123a9f49946SIsaku Yamahata }; 124a9f49946SIsaku Yamahata 125a9f49946SIsaku Yamahata static CPUReadMemoryFunc * const pcie_mmcfg_read[] = 126a9f49946SIsaku Yamahata { 127a9f49946SIsaku Yamahata pcie_mmcfg_data_readb, 128a9f49946SIsaku Yamahata pcie_mmcfg_data_readw, 129a9f49946SIsaku Yamahata pcie_mmcfg_data_readl, 130a9f49946SIsaku Yamahata }; 131a9f49946SIsaku Yamahata 132a9f49946SIsaku Yamahata /* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ 133a9f49946SIsaku Yamahata #define PCIE_BASE_ADDR_UNMAPPED ((target_phys_addr_t)-1ULL) 134a9f49946SIsaku Yamahata 135a9f49946SIsaku Yamahata int pcie_host_init(PCIExpressHost *e) 136a9f49946SIsaku Yamahata { 137a9f49946SIsaku Yamahata e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 138a9f49946SIsaku Yamahata e->mmio_index = 1392507c12aSAlexander Graf cpu_register_io_memory(pcie_mmcfg_read, pcie_mmcfg_write, e, 1402507c12aSAlexander Graf DEVICE_NATIVE_ENDIAN); 141a9f49946SIsaku Yamahata if (e->mmio_index < 0) { 142a9f49946SIsaku Yamahata return -1; 143a9f49946SIsaku Yamahata } 144a9f49946SIsaku Yamahata 145a9f49946SIsaku Yamahata return 0; 146a9f49946SIsaku Yamahata } 147a9f49946SIsaku Yamahata 148a9f49946SIsaku Yamahata void pcie_host_mmcfg_unmap(PCIExpressHost *e) 149a9f49946SIsaku Yamahata { 150a9f49946SIsaku Yamahata if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { 151a9f49946SIsaku Yamahata cpu_register_physical_memory(e->base_addr, e->size, IO_MEM_UNASSIGNED); 152a9f49946SIsaku Yamahata e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 153a9f49946SIsaku Yamahata } 154a9f49946SIsaku Yamahata } 155a9f49946SIsaku Yamahata 156a9f49946SIsaku Yamahata void pcie_host_mmcfg_map(PCIExpressHost *e, 157a9f49946SIsaku Yamahata target_phys_addr_t addr, uint32_t size) 158a9f49946SIsaku Yamahata { 159a9f49946SIsaku Yamahata assert(!(size & (size - 1))); /* power of 2 */ 160a9f49946SIsaku Yamahata assert(size >= PCIE_MMCFG_SIZE_MIN); 161a9f49946SIsaku Yamahata assert(size <= PCIE_MMCFG_SIZE_MAX); 162a9f49946SIsaku Yamahata 163a9f49946SIsaku Yamahata e->base_addr = addr; 164a9f49946SIsaku Yamahata e->size = size; 165a9f49946SIsaku Yamahata cpu_register_physical_memory(e->base_addr, e->size, e->mmio_index); 166a9f49946SIsaku Yamahata } 167a9f49946SIsaku Yamahata 168a9f49946SIsaku Yamahata void pcie_host_mmcfg_update(PCIExpressHost *e, 169a9f49946SIsaku Yamahata int enable, 170a9f49946SIsaku Yamahata target_phys_addr_t addr, uint32_t size) 171a9f49946SIsaku Yamahata { 172a9f49946SIsaku Yamahata pcie_host_mmcfg_unmap(e); 173a9f49946SIsaku Yamahata if (enable) { 174a9f49946SIsaku Yamahata pcie_host_mmcfg_map(e, addr, size); 175a9f49946SIsaku Yamahata } 176a9f49946SIsaku Yamahata } 177