|
|
1.1 ! root 1: /* ! 2: * pcie_host.c ! 3: * utility functions for pci express host bridge. ! 4: * ! 5: * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> ! 6: * VA Linux Systems Japan K.K. ! 7: * ! 8: * This program is free software; you can redistribute it and/or modify ! 9: * it under the terms of the GNU General Public License as published by ! 10: * the Free Software Foundation; either version 2 of the License, or ! 11: * (at your option) any later version. ! 12: ! 13: * This program is distributed in the hope that it will be useful, ! 14: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: * GNU General Public License for more details. ! 17: ! 18: * You should have received a copy of the GNU General Public License along ! 19: * with this program; if not, write to the Free Software Foundation, Inc., ! 20: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ! 21: */ ! 22: ! 23: #include "hw.h" ! 24: #include "pci.h" ! 25: #include "pcie_host.h" ! 26: ! 27: /* ! 28: * PCI express mmcfig address ! 29: * bit 20 - 28: bus number ! 30: * bit 15 - 19: device number ! 31: * bit 12 - 14: function number ! 32: * bit 0 - 11: offset in configuration space of a given device ! 33: */ ! 34: #define PCIE_MMCFG_SIZE_MAX (1ULL << 28) ! 35: #define PCIE_MMCFG_SIZE_MIN (1ULL << 20) ! 36: #define PCIE_MMCFG_BUS_BIT 20 ! 37: #define PCIE_MMCFG_BUS_MASK 0x1ff ! 38: #define PCIE_MMCFG_DEVFN_BIT 12 ! 39: #define PCIE_MMCFG_DEVFN_MASK 0xff ! 40: #define PCIE_MMCFG_CONFOFFSET_MASK 0xfff ! 41: #define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ ! 42: PCIE_MMCFG_BUS_MASK) ! 43: #define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ ! 44: PCIE_MMCFG_DEVFN_MASK) ! 45: #define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) ! 46: ! 47: ! 48: /* a helper function to get a PCIDevice for a given mmconfig address */ ! 49: static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, ! 50: uint32_t mmcfg_addr) ! 51: { ! 52: return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), ! 53: PCI_SLOT(PCIE_MMCFG_DEVFN(mmcfg_addr)), ! 54: PCI_FUNC(PCIE_MMCFG_DEVFN(mmcfg_addr))); ! 55: } ! 56: ! 57: static void pcie_mmcfg_data_write(PCIBus *s, ! 58: uint32_t mmcfg_addr, uint32_t val, int len) ! 59: { ! 60: PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr); ! 61: ! 62: if (!pci_dev) ! 63: return; ! 64: ! 65: pci_dev->config_write(pci_dev, ! 66: PCIE_MMCFG_CONFOFFSET(mmcfg_addr), val, len); ! 67: } ! 68: ! 69: static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len) ! 70: { ! 71: PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr); ! 72: ! 73: assert(len == 1 || len == 2 || len == 4); ! 74: if (!pci_dev) { ! 75: return ~0x0; ! 76: } ! 77: return pci_dev->config_read(pci_dev, PCIE_MMCFG_CONFOFFSET(addr), len); ! 78: } ! 79: ! 80: static void pcie_mmcfg_data_writeb(void *opaque, ! 81: target_phys_addr_t addr, uint32_t value) ! 82: { ! 83: PCIExpressHost *e = opaque; ! 84: pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 1); ! 85: } ! 86: ! 87: static void pcie_mmcfg_data_writew(void *opaque, ! 88: target_phys_addr_t addr, uint32_t value) ! 89: { ! 90: PCIExpressHost *e = opaque; ! 91: pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 2); ! 92: } ! 93: ! 94: static void pcie_mmcfg_data_writel(void *opaque, ! 95: target_phys_addr_t addr, uint32_t value) ! 96: { ! 97: PCIExpressHost *e = opaque; ! 98: pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 4); ! 99: } ! 100: ! 101: static uint32_t pcie_mmcfg_data_readb(void *opaque, target_phys_addr_t addr) ! 102: { ! 103: PCIExpressHost *e = opaque; ! 104: return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 1); ! 105: } ! 106: ! 107: static uint32_t pcie_mmcfg_data_readw(void *opaque, target_phys_addr_t addr) ! 108: { ! 109: PCIExpressHost *e = opaque; ! 110: return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 2); ! 111: } ! 112: ! 113: static uint32_t pcie_mmcfg_data_readl(void *opaque, target_phys_addr_t addr) ! 114: { ! 115: PCIExpressHost *e = opaque; ! 116: return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 4); ! 117: } ! 118: ! 119: ! 120: static CPUWriteMemoryFunc * const pcie_mmcfg_write[] = ! 121: { ! 122: pcie_mmcfg_data_writeb, ! 123: pcie_mmcfg_data_writew, ! 124: pcie_mmcfg_data_writel, ! 125: }; ! 126: ! 127: static CPUReadMemoryFunc * const pcie_mmcfg_read[] = ! 128: { ! 129: pcie_mmcfg_data_readb, ! 130: pcie_mmcfg_data_readw, ! 131: pcie_mmcfg_data_readl, ! 132: }; ! 133: ! 134: /* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ ! 135: #define PCIE_BASE_ADDR_UNMAPPED ((target_phys_addr_t)-1ULL) ! 136: ! 137: int pcie_host_init(PCIExpressHost *e) ! 138: { ! 139: e->base_addr = PCIE_BASE_ADDR_UNMAPPED; ! 140: e->mmio_index = ! 141: cpu_register_io_memory(pcie_mmcfg_read, pcie_mmcfg_write, e); ! 142: if (e->mmio_index < 0) { ! 143: return -1; ! 144: } ! 145: ! 146: return 0; ! 147: } ! 148: ! 149: void pcie_host_mmcfg_unmap(PCIExpressHost *e) ! 150: { ! 151: if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { ! 152: cpu_register_physical_memory(e->base_addr, e->size, IO_MEM_UNASSIGNED); ! 153: e->base_addr = PCIE_BASE_ADDR_UNMAPPED; ! 154: } ! 155: } ! 156: ! 157: void pcie_host_mmcfg_map(PCIExpressHost *e, ! 158: target_phys_addr_t addr, uint32_t size) ! 159: { ! 160: assert(!(size & (size - 1))); /* power of 2 */ ! 161: assert(size >= PCIE_MMCFG_SIZE_MIN); ! 162: assert(size <= PCIE_MMCFG_SIZE_MAX); ! 163: ! 164: e->base_addr = addr; ! 165: e->size = size; ! 166: cpu_register_physical_memory(e->base_addr, e->size, e->mmio_index); ! 167: } ! 168: ! 169: void pcie_host_mmcfg_update(PCIExpressHost *e, ! 170: int enable, ! 171: target_phys_addr_t addr, uint32_t size) ! 172: { ! 173: pcie_host_mmcfg_unmap(e); ! 174: if (enable) { ! 175: pcie_host_mmcfg_map(e, addr, size); ! 176: } ! 177: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.