1 /* 2 * pci_host.c 3 * 4 * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> 5 * VA Linux Systems Japan K.K. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "hw/pci/pci.h" 22 #include "hw/pci/pci_host.h" 23 #include "hw/pci/pci_bus.h" 24 #include "trace.h" 25 26 /* debug PCI */ 27 //#define DEBUG_PCI 28 29 #ifdef DEBUG_PCI 30 #define PCI_DPRINTF(fmt, ...) \ 31 do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) 32 #else 33 #define PCI_DPRINTF(fmt, ...) 34 #endif 35 36 /* 37 * PCI address 38 * bit 16 - 24: bus number 39 * bit 8 - 15: devfun number 40 * bit 0 - 7: offset in configuration space of a given pci device 41 */ 42 43 /* the helper function to get a PCIDevice* for a given pci address */ 44 static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) 45 { 46 uint8_t bus_num = addr >> 16; 47 uint8_t devfn = addr >> 8; 48 49 return pci_find_device(bus, bus_num, devfn); 50 } 51 52 void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, 53 uint32_t limit, uint32_t val, uint32_t len) 54 { 55 assert(len <= 4); 56 /* non-zero functions are only exposed when function 0 is present, 57 * allowing direct removal of unexposed functions. 58 */ 59 if (pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) { 60 return; 61 } 62 63 trace_pci_cfg_write(pci_dev->name, PCI_SLOT(pci_dev->devfn), 64 PCI_FUNC(pci_dev->devfn), addr, val); 65 pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr)); 66 } 67 68 uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr, 69 uint32_t limit, uint32_t len) 70 { 71 uint32_t ret; 72 73 assert(len <= 4); 74 /* non-zero functions are only exposed when function 0 is present, 75 * allowing direct removal of unexposed functions. 76 */ 77 if (pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) { 78 return ~0x0; 79 } 80 81 ret = pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr)); 82 trace_pci_cfg_read(pci_dev->name, PCI_SLOT(pci_dev->devfn), 83 PCI_FUNC(pci_dev->devfn), addr, ret); 84 85 return ret; 86 } 87 88 void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len) 89 { 90 PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); 91 uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); 92 93 if (!pci_dev) { 94 return; 95 } 96 97 PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n", 98 __func__, pci_dev->name, config_addr, val, len); 99 pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE, 100 val, len); 101 } 102 103 uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) 104 { 105 PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr); 106 uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); 107 uint32_t val; 108 109 if (!pci_dev) { 110 return ~0x0; 111 } 112 113 val = pci_host_config_read_common(pci_dev, config_addr, 114 PCI_CONFIG_SPACE_SIZE, len); 115 PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n", 116 __func__, pci_dev->name, config_addr, val, len); 117 118 return val; 119 } 120 121 static void pci_host_config_write(void *opaque, hwaddr addr, 122 uint64_t val, unsigned len) 123 { 124 PCIHostState *s = opaque; 125 126 PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", 127 __func__, addr, len, val); 128 if (addr != 0 || len != 4) { 129 return; 130 } 131 s->config_reg = val; 132 } 133 134 static uint64_t pci_host_config_read(void *opaque, hwaddr addr, 135 unsigned len) 136 { 137 PCIHostState *s = opaque; 138 uint32_t val = s->config_reg; 139 140 PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n", 141 __func__, addr, len, val); 142 return val; 143 } 144 145 static void pci_host_data_write(void *opaque, hwaddr addr, 146 uint64_t val, unsigned len) 147 { 148 PCIHostState *s = opaque; 149 PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n", 150 addr, len, (unsigned)val); 151 if (s->config_reg & (1u << 31)) 152 pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); 153 } 154 155 static uint64_t pci_host_data_read(void *opaque, 156 hwaddr addr, unsigned len) 157 { 158 PCIHostState *s = opaque; 159 uint32_t val; 160 if (!(s->config_reg & (1U << 31))) { 161 return 0xffffffff; 162 } 163 val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); 164 PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n", 165 addr, len, val); 166 return val; 167 } 168 169 const MemoryRegionOps pci_host_conf_le_ops = { 170 .read = pci_host_config_read, 171 .write = pci_host_config_write, 172 .endianness = DEVICE_LITTLE_ENDIAN, 173 }; 174 175 const MemoryRegionOps pci_host_conf_be_ops = { 176 .read = pci_host_config_read, 177 .write = pci_host_config_write, 178 .endianness = DEVICE_BIG_ENDIAN, 179 }; 180 181 const MemoryRegionOps pci_host_data_le_ops = { 182 .read = pci_host_data_read, 183 .write = pci_host_data_write, 184 .endianness = DEVICE_LITTLE_ENDIAN, 185 }; 186 187 const MemoryRegionOps pci_host_data_be_ops = { 188 .read = pci_host_data_read, 189 .write = pci_host_data_write, 190 .endianness = DEVICE_BIG_ENDIAN, 191 }; 192 193 static const TypeInfo pci_host_type_info = { 194 .name = TYPE_PCI_HOST_BRIDGE, 195 .parent = TYPE_SYS_BUS_DEVICE, 196 .abstract = true, 197 .class_size = sizeof(PCIHostBridgeClass), 198 .instance_size = sizeof(PCIHostState), 199 }; 200 201 static void pci_host_register_types(void) 202 { 203 type_register_static(&pci_host_type_info); 204 } 205 206 type_init(pci_host_register_types) 207