qemu/hw/pci/pcie_host.c
<<
>>
Prefs
   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, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "hw/pci/pci.h"
  24#include "hw/pci/pcie_host.h"
  25#include "qemu/module.h"
  26
  27/* a helper function to get a PCIDevice for a given mmconfig address */
  28static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s,
  29                                                     uint32_t mmcfg_addr)
  30{
  31    return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr),
  32                           PCIE_MMCFG_DEVFN(mmcfg_addr));
  33}
  34
  35static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr,
  36                                  uint64_t val, unsigned len)
  37{
  38    PCIExpressHost *e = opaque;
  39    PCIBus *s = e->pci.bus;
  40    PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
  41    uint32_t addr;
  42    uint32_t limit;
  43
  44    if (!pci_dev) {
  45        return;
  46    }
  47    addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
  48    limit = pci_config_size(pci_dev);
  49    pci_host_config_write_common(pci_dev, addr, limit, val, len);
  50}
  51
  52static uint64_t pcie_mmcfg_data_read(void *opaque,
  53                                     hwaddr mmcfg_addr,
  54                                     unsigned len)
  55{
  56    PCIExpressHost *e = opaque;
  57    PCIBus *s = e->pci.bus;
  58    PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
  59    uint32_t addr;
  60    uint32_t limit;
  61
  62    if (!pci_dev) {
  63        return ~0x0;
  64    }
  65    addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
  66    limit = pci_config_size(pci_dev);
  67    return pci_host_config_read_common(pci_dev, addr, limit, len);
  68}
  69
  70static const MemoryRegionOps pcie_mmcfg_ops = {
  71    .read = pcie_mmcfg_data_read,
  72    .write = pcie_mmcfg_data_write,
  73    .endianness = DEVICE_LITTLE_ENDIAN,
  74};
  75
  76static void pcie_host_init(Object *obj)
  77{
  78    PCIExpressHost *e = PCIE_HOST_BRIDGE(obj);
  79
  80    e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
  81    memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e, "pcie-mmcfg-mmio",
  82                          PCIE_MMCFG_SIZE_MAX);
  83}
  84
  85void pcie_host_mmcfg_unmap(PCIExpressHost *e)
  86{
  87    if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
  88        memory_region_del_subregion(get_system_memory(), &e->mmio);
  89        e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
  90    }
  91}
  92
  93void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size)
  94{
  95    assert(!(size & (size - 1)));       /* power of 2 */
  96    assert(size >= PCIE_MMCFG_SIZE_MIN);
  97    assert(size <= PCIE_MMCFG_SIZE_MAX);
  98    e->size = size;
  99    memory_region_set_size(&e->mmio, e->size);
 100}
 101
 102void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr,
 103                         uint32_t size)
 104{
 105    pcie_host_mmcfg_init(e, size);
 106    e->base_addr = addr;
 107    memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
 108}
 109
 110void pcie_host_mmcfg_update(PCIExpressHost *e,
 111                            int enable,
 112                            hwaddr addr,
 113                            uint32_t size)
 114{
 115    memory_region_transaction_begin();
 116    pcie_host_mmcfg_unmap(e);
 117    if (enable) {
 118        pcie_host_mmcfg_map(e, addr, size);
 119    }
 120    memory_region_transaction_commit();
 121}
 122
 123static const TypeInfo pcie_host_type_info = {
 124    .name = TYPE_PCIE_HOST_BRIDGE,
 125    .parent = TYPE_PCI_HOST_BRIDGE,
 126    .abstract = true,
 127    .instance_size = sizeof(PCIExpressHost),
 128    .instance_init = pcie_host_init,
 129};
 130
 131static void pcie_host_register_types(void)
 132{
 133    type_register_static(&pcie_host_type_info);
 134}
 135
 136type_init(pcie_host_register_types)
 137