qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

pci_host.c (7276B)


      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 "qemu/osdep.h"
     22 #include "hw/pci/pci.h"
     23 #include "hw/pci/pci_bridge.h"
     24 #include "hw/pci/pci_host.h"
     25 #include "hw/qdev-properties.h"
     26 #include "qemu/module.h"
     27 #include "hw/pci/pci_bus.h"
     28 #include "migration/vmstate.h"
     29 #include "trace.h"
     30 
     31 /* debug PCI */
     32 //#define DEBUG_PCI
     33 
     34 #ifdef DEBUG_PCI
     35 #define PCI_DPRINTF(fmt, ...) \
     36 do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
     37 #else
     38 #define PCI_DPRINTF(fmt, ...)
     39 #endif
     40 
     41 /*
     42  * PCI address
     43  * bit 16 - 24: bus number
     44  * bit  8 - 15: devfun number
     45  * bit  0 -  7: offset in configuration space of a given pci device
     46  */
     47 
     48 /* the helper function to get a PCIDevice* for a given pci address */
     49 static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
     50 {
     51     uint8_t bus_num = addr >> 16;
     52     uint8_t devfn = addr >> 8;
     53 
     54     return pci_find_device(bus, bus_num, devfn);
     55 }
     56 
     57 static void pci_adjust_config_limit(PCIBus *bus, uint32_t *limit)
     58 {
     59     if ((*limit > PCI_CONFIG_SPACE_SIZE) &&
     60         !pci_bus_allows_extended_config_space(bus)) {
     61         *limit = PCI_CONFIG_SPACE_SIZE;
     62     }
     63 }
     64 
     65 void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
     66                                   uint32_t limit, uint32_t val, uint32_t len)
     67 {
     68     pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
     69     if (limit <= addr) {
     70         return;
     71     }
     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         !pci_dev->has_power) {
     79         return;
     80     }
     81 
     82     trace_pci_cfg_write(pci_dev->name, pci_dev_bus_num(pci_dev),
     83                         PCI_SLOT(pci_dev->devfn),
     84                         PCI_FUNC(pci_dev->devfn), addr, val);
     85     pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
     86 }
     87 
     88 uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
     89                                      uint32_t limit, uint32_t len)
     90 {
     91     uint32_t ret;
     92 
     93     pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
     94     if (limit <= addr) {
     95         return ~0x0;
     96     }
     97 
     98     assert(len <= 4);
     99     /* non-zero functions are only exposed when function 0 is present,
    100      * allowing direct removal of unexposed functions.
    101      */
    102     if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
    103         !pci_dev->has_power) {
    104         return ~0x0;
    105     }
    106 
    107     ret = pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
    108     trace_pci_cfg_read(pci_dev->name, pci_dev_bus_num(pci_dev),
    109                        PCI_SLOT(pci_dev->devfn),
    110                        PCI_FUNC(pci_dev->devfn), addr, ret);
    111 
    112     return ret;
    113 }
    114 
    115 void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, unsigned len)
    116 {
    117     PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
    118     uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
    119 
    120     if (!pci_dev) {
    121         return;
    122     }
    123 
    124     pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
    125                                  val, len);
    126 }
    127 
    128 uint32_t pci_data_read(PCIBus *s, uint32_t addr, unsigned len)
    129 {
    130     PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
    131     uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
    132 
    133     if (!pci_dev) {
    134         return ~0x0;
    135     }
    136 
    137     return pci_host_config_read_common(pci_dev, config_addr,
    138                                        PCI_CONFIG_SPACE_SIZE, len);
    139 }
    140 
    141 static void pci_host_config_write(void *opaque, hwaddr addr,
    142                                   uint64_t val, unsigned len)
    143 {
    144     PCIHostState *s = opaque;
    145 
    146     PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
    147                 __func__, addr, len, val);
    148     if (addr != 0 || len != 4) {
    149         return;
    150     }
    151     s->config_reg = val;
    152 }
    153 
    154 static uint64_t pci_host_config_read(void *opaque, hwaddr addr,
    155                                      unsigned len)
    156 {
    157     PCIHostState *s = opaque;
    158     uint32_t val = s->config_reg;
    159 
    160     PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n",
    161                 __func__, addr, len, val);
    162     return val;
    163 }
    164 
    165 static void pci_host_data_write(void *opaque, hwaddr addr,
    166                                 uint64_t val, unsigned len)
    167 {
    168     PCIHostState *s = opaque;
    169 
    170     if (s->config_reg & (1u << 31))
    171         pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
    172 }
    173 
    174 static uint64_t pci_host_data_read(void *opaque,
    175                                    hwaddr addr, unsigned len)
    176 {
    177     PCIHostState *s = opaque;
    178 
    179     if (!(s->config_reg & (1U << 31))) {
    180         return 0xffffffff;
    181     }
    182     return pci_data_read(s->bus, s->config_reg | (addr & 3), len);
    183 }
    184 
    185 const MemoryRegionOps pci_host_conf_le_ops = {
    186     .read = pci_host_config_read,
    187     .write = pci_host_config_write,
    188     .endianness = DEVICE_LITTLE_ENDIAN,
    189 };
    190 
    191 const MemoryRegionOps pci_host_conf_be_ops = {
    192     .read = pci_host_config_read,
    193     .write = pci_host_config_write,
    194     .endianness = DEVICE_BIG_ENDIAN,
    195 };
    196 
    197 const MemoryRegionOps pci_host_data_le_ops = {
    198     .read = pci_host_data_read,
    199     .write = pci_host_data_write,
    200     .endianness = DEVICE_LITTLE_ENDIAN,
    201 };
    202 
    203 const MemoryRegionOps pci_host_data_be_ops = {
    204     .read = pci_host_data_read,
    205     .write = pci_host_data_write,
    206     .endianness = DEVICE_BIG_ENDIAN,
    207 };
    208 
    209 static bool pci_host_needed(void *opaque)
    210 {
    211     PCIHostState *s = opaque;
    212     return s->mig_enabled;
    213 }
    214 
    215 const VMStateDescription vmstate_pcihost = {
    216     .name = "PCIHost",
    217     .needed = pci_host_needed,
    218     .version_id = 1,
    219     .minimum_version_id = 1,
    220     .fields = (VMStateField[]) {
    221         VMSTATE_UINT32(config_reg, PCIHostState),
    222         VMSTATE_END_OF_LIST()
    223     }
    224 };
    225 
    226 static Property pci_host_properties_common[] = {
    227     DEFINE_PROP_BOOL("x-config-reg-migration-enabled", PCIHostState,
    228                      mig_enabled, true),
    229     DEFINE_PROP_BOOL("bypass-iommu", PCIHostState, bypass_iommu, false),
    230     DEFINE_PROP_END_OF_LIST(),
    231 };
    232 
    233 static void pci_host_class_init(ObjectClass *klass, void *data)
    234 {
    235     DeviceClass *dc = DEVICE_CLASS(klass);
    236     device_class_set_props(dc, pci_host_properties_common);
    237     dc->vmsd = &vmstate_pcihost;
    238 }
    239 
    240 static const TypeInfo pci_host_type_info = {
    241     .name = TYPE_PCI_HOST_BRIDGE,
    242     .parent = TYPE_SYS_BUS_DEVICE,
    243     .abstract = true,
    244     .class_size = sizeof(PCIHostBridgeClass),
    245     .instance_size = sizeof(PCIHostState),
    246     .class_init = pci_host_class_init,
    247 };
    248 
    249 static void pci_host_register_types(void)
    250 {
    251     type_register_static(&pci_host_type_info);
    252 }
    253 
    254 type_init(pci_host_register_types)