|
|
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
1.1.1.2 root 19: * with this program; if not, see <http://www.gnu.org/licenses/>.
1.1 root 20: */
21:
22: #include "hw.h"
23: #include "pci.h"
24: #include "pcie_host.h"
1.1.1.5 ! root 25: #include "exec-memory.h"
1.1 root 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),
1.1.1.4 root 53: PCIE_MMCFG_DEVFN(mmcfg_addr));
1.1 root 54: }
55:
1.1.1.5 ! root 56: static void pcie_mmcfg_data_write(void *opaque, target_phys_addr_t mmcfg_addr,
! 57: uint64_t val, unsigned len)
1.1 root 58: {
1.1.1.5 ! root 59: PCIExpressHost *e = opaque;
! 60: PCIBus *s = e->pci.bus;
1.1 root 61: PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
1.1.1.5 ! root 62: uint32_t addr;
! 63: uint32_t limit;
1.1 root 64:
1.1.1.5 ! root 65: if (!pci_dev) {
1.1 root 66: return;
1.1.1.5 ! root 67: }
! 68: addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
! 69: limit = pci_config_size(pci_dev);
! 70: if (limit <= addr) {
! 71: /* conventional pci device can be behind pcie-to-pci bridge.
! 72: 256 <= addr < 4K has no effects. */
! 73: return;
! 74: }
! 75: pci_host_config_write_common(pci_dev, addr, limit, val, len);
1.1 root 76: }
77:
1.1.1.5 ! root 78: static uint64_t pcie_mmcfg_data_read(void *opaque,
! 79: target_phys_addr_t mmcfg_addr,
! 80: unsigned len)
1.1 root 81: {
1.1.1.5 ! root 82: PCIExpressHost *e = opaque;
! 83: PCIBus *s = e->pci.bus;
! 84: PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
! 85: uint32_t addr;
! 86: uint32_t limit;
1.1 root 87:
88: if (!pci_dev) {
89: return ~0x0;
90: }
1.1.1.5 ! root 91: addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
! 92: limit = pci_config_size(pci_dev);
! 93: if (limit <= addr) {
! 94: /* conventional pci device can be behind pcie-to-pci bridge.
! 95: 256 <= addr < 4K has no effects. */
! 96: return ~0x0;
! 97: }
! 98: return pci_host_config_read_common(pci_dev, addr, limit, len);
1.1 root 99: }
100:
1.1.1.5 ! root 101: static const MemoryRegionOps pcie_mmcfg_ops = {
! 102: .read = pcie_mmcfg_data_read,
! 103: .write = pcie_mmcfg_data_write,
! 104: .endianness = DEVICE_NATIVE_ENDIAN,
1.1 root 105: };
106:
107: /* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */
108: #define PCIE_BASE_ADDR_UNMAPPED ((target_phys_addr_t)-1ULL)
109:
1.1.1.5 ! root 110: int pcie_host_init(PCIExpressHost *e, uint32_t size)
1.1 root 111: {
1.1.1.5 ! root 112: assert(!(size & (size - 1))); /* power of 2 */
! 113: assert(size >= PCIE_MMCFG_SIZE_MIN);
! 114: assert(size <= PCIE_MMCFG_SIZE_MAX);
1.1 root 115: e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
1.1.1.5 ! root 116: e->size = size;
! 117: memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size);
1.1 root 118:
119: return 0;
120: }
121:
122: void pcie_host_mmcfg_unmap(PCIExpressHost *e)
123: {
124: if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
1.1.1.5 ! root 125: memory_region_del_subregion(get_system_memory(), &e->mmio);
1.1 root 126: e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
127: }
128: }
129:
1.1.1.5 ! root 130: void pcie_host_mmcfg_map(PCIExpressHost *e, target_phys_addr_t addr)
1.1 root 131: {
132: e->base_addr = addr;
1.1.1.5 ! root 133: memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
1.1 root 134: }
135:
136: void pcie_host_mmcfg_update(PCIExpressHost *e,
137: int enable,
1.1.1.5 ! root 138: target_phys_addr_t addr)
1.1 root 139: {
140: pcie_host_mmcfg_unmap(e);
141: if (enable) {
1.1.1.5 ! root 142: pcie_host_mmcfg_map(e, addr);
1.1 root 143: }
144: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.