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 19*70539e18SBlue 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), 52a9f49946SIsaku Yamahata PCI_SLOT(PCIE_MMCFG_DEVFN(mmcfg_addr)), 53a9f49946SIsaku Yamahata PCI_FUNC(PCIE_MMCFG_DEVFN(mmcfg_addr))); 54a9f49946SIsaku Yamahata } 55a9f49946SIsaku Yamahata 56a9f49946SIsaku Yamahata static void pcie_mmcfg_data_write(PCIBus *s, 57a9f49946SIsaku Yamahata uint32_t mmcfg_addr, uint32_t val, int len) 58a9f49946SIsaku Yamahata { 598d6514f8SIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); 60a9f49946SIsaku Yamahata 61a9f49946SIsaku Yamahata if (!pci_dev) 62a9f49946SIsaku Yamahata return; 63a9f49946SIsaku Yamahata 64a9f49946SIsaku Yamahata pci_dev->config_write(pci_dev, 65a9f49946SIsaku Yamahata PCIE_MMCFG_CONFOFFSET(mmcfg_addr), val, len); 66a9f49946SIsaku Yamahata } 67a9f49946SIsaku Yamahata 684677d8edSMichael S. Tsirkin static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len) 69a9f49946SIsaku Yamahata { 708d6514f8SIsaku Yamahata PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr); 71a9f49946SIsaku Yamahata 724677d8edSMichael S. Tsirkin assert(len == 1 || len == 2 || len == 4); 73a9f49946SIsaku Yamahata if (!pci_dev) { 744677d8edSMichael S. Tsirkin return ~0x0; 75a9f49946SIsaku Yamahata } 764677d8edSMichael S. Tsirkin return pci_dev->config_read(pci_dev, PCIE_MMCFG_CONFOFFSET(addr), len); 77a9f49946SIsaku Yamahata } 78a9f49946SIsaku Yamahata 79a9f49946SIsaku Yamahata static void pcie_mmcfg_data_writeb(void *opaque, 80a9f49946SIsaku Yamahata target_phys_addr_t addr, uint32_t value) 81a9f49946SIsaku Yamahata { 82a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 83a9f49946SIsaku Yamahata pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 1); 84a9f49946SIsaku Yamahata } 85a9f49946SIsaku Yamahata 86a9f49946SIsaku Yamahata static void pcie_mmcfg_data_writew(void *opaque, 87a9f49946SIsaku Yamahata target_phys_addr_t addr, uint32_t value) 88a9f49946SIsaku Yamahata { 89a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 90a9f49946SIsaku Yamahata pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 2); 91a9f49946SIsaku Yamahata } 92a9f49946SIsaku Yamahata 93a9f49946SIsaku Yamahata static void pcie_mmcfg_data_writel(void *opaque, 94a9f49946SIsaku Yamahata target_phys_addr_t addr, uint32_t value) 95a9f49946SIsaku Yamahata { 96a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 97a9f49946SIsaku Yamahata pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 4); 98a9f49946SIsaku Yamahata } 99a9f49946SIsaku Yamahata 100a9f49946SIsaku Yamahata static uint32_t pcie_mmcfg_data_readb(void *opaque, target_phys_addr_t addr) 101a9f49946SIsaku Yamahata { 102a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 103a9f49946SIsaku Yamahata return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 1); 104a9f49946SIsaku Yamahata } 105a9f49946SIsaku Yamahata 106a9f49946SIsaku Yamahata static uint32_t pcie_mmcfg_data_readw(void *opaque, target_phys_addr_t addr) 107a9f49946SIsaku Yamahata { 108a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 109a9f49946SIsaku Yamahata return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 2); 110a9f49946SIsaku Yamahata } 111a9f49946SIsaku Yamahata 112a9f49946SIsaku Yamahata static uint32_t pcie_mmcfg_data_readl(void *opaque, target_phys_addr_t addr) 113a9f49946SIsaku Yamahata { 114a9f49946SIsaku Yamahata PCIExpressHost *e = opaque; 115a9f49946SIsaku Yamahata return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 4); 116a9f49946SIsaku Yamahata } 117a9f49946SIsaku Yamahata 118a9f49946SIsaku Yamahata 119a9f49946SIsaku Yamahata static CPUWriteMemoryFunc * const pcie_mmcfg_write[] = 120a9f49946SIsaku Yamahata { 121a9f49946SIsaku Yamahata pcie_mmcfg_data_writeb, 122a9f49946SIsaku Yamahata pcie_mmcfg_data_writew, 123a9f49946SIsaku Yamahata pcie_mmcfg_data_writel, 124a9f49946SIsaku Yamahata }; 125a9f49946SIsaku Yamahata 126a9f49946SIsaku Yamahata static CPUReadMemoryFunc * const pcie_mmcfg_read[] = 127a9f49946SIsaku Yamahata { 128a9f49946SIsaku Yamahata pcie_mmcfg_data_readb, 129a9f49946SIsaku Yamahata pcie_mmcfg_data_readw, 130a9f49946SIsaku Yamahata pcie_mmcfg_data_readl, 131a9f49946SIsaku Yamahata }; 132a9f49946SIsaku Yamahata 133a9f49946SIsaku Yamahata /* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ 134a9f49946SIsaku Yamahata #define PCIE_BASE_ADDR_UNMAPPED ((target_phys_addr_t)-1ULL) 135a9f49946SIsaku Yamahata 136a9f49946SIsaku Yamahata int pcie_host_init(PCIExpressHost *e) 137a9f49946SIsaku Yamahata { 138a9f49946SIsaku Yamahata e->base_addr = PCIE_BASE_ADDR_UNMAPPED; 139a9f49946SIsaku Yamahata e->mmio_index = 140a9f49946SIsaku Yamahata cpu_register_io_memory(pcie_mmcfg_read, pcie_mmcfg_write, e); 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