qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: [PATCH 16/23] pci: pcie host and mmcfg support.


From: Michael S. Tsirkin
Subject: [Qemu-devel] Re: [PATCH 16/23] pci: pcie host and mmcfg support.
Date: Mon, 5 Oct 2009 13:01:43 +0200
User-agent: Mutt/1.5.19 (2009-01-05)

On Mon, Oct 05, 2009 at 07:06:56PM +0900, Isaku Yamahata wrote:
> This patch adds common routines for pcie host bridge and pcie mmcfg.
> This will be used by q35 based chipset emulation.
> 
> Signed-off-by: Isaku Yamahata <address@hidden>

Looks like most my comments on this patch were ignored.
I started repeating them here but then I grew tired,
so only partially repeated them. Are you going to address this?

Generally, pci express code isn't well separated from pci, here.  Please
try to generalize pci code, then express support would only touch a
couple of places.  Maybe even a separate file like msix.  Also, pci
express spec requires pci express capability to be present. I expected
to see this code using capability machinery.

> ---
>  hw/hw.h       |   12 +++
>  hw/pci.c      |  247 
> ++++++++++++++++++++++++++++++++++++++++++++++++++-------
>  hw/pci.h      |   36 ++++++++-
>  hw/pci_host.h |   22 +++++
>  4 files changed, 285 insertions(+), 32 deletions(-)
> 
> diff --git a/hw/hw.h b/hw/hw.h
> index cf266b3..478b0b2 100644
> --- a/hw/hw.h
> +++ b/hw/hw.h
> @@ -428,6 +428,18 @@ extern const VMStateDescription vmstate_pci_device;
>              + type_check(PCIDevice,typeof_field(_state, _field))     \
>  }
>  
> +extern const VMStateDescription vmstate_pcie_device;
> +
> +#define VMSTATE_PCIE_DEVICE(_field, _state) {                        \
> +    .name       = (stringify(_field)),                               \
> +    .version_id = 2,                                                 \
> +    .size       = sizeof(PCIDevice),                                 \
> +    .vmsd       = &vmstate_pcie_device,                              \
> +    .flags      = VMS_STRUCT,                                        \
> +    .offset     = offsetof(_state, _field)                           \
> +            + type_check(PCIDevice,typeof_field(_state, _field))     \
> +}
> +
>  /* _f : field name
>     _f_n : num of elements field_name
>     _n : num of elements
> diff --git a/hw/pci.c b/hw/pci.c
> index 5f808ff..12260da 100644
> --- a/hw/pci.c
> +++ b/hw/pci.c
> @@ -23,6 +23,7 @@
>   */
>  #include "hw.h"
>  #include "pci.h"
> +#include "pci_host.h"
>  #include "monitor.h"
>  #include "net.h"
>  #include "sysemu.h"
> @@ -184,9 +185,12 @@ int pci_bus_num(PCIBus *s)
>  static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
>  {
>      PCIDevice *s = container_of(pv, PCIDevice, config);
> -    uint8_t config[size];
> +    uint8_t *config;
>      int i;
>  
> +    assert(size == pcie_config_size(s));
> +    config = qemu_malloc(size * sizeof(config[0]));
> +
>      qemu_get_buffer(f, config, size);
>      for (i = 0; i < size; ++i)
>          if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i])
> @@ -195,6 +199,7 @@ static int get_pci_config_device(QEMUFile *f, void *pv, 
> size_t size)
>  
>      pci_update_mappings(s);
>  
> +    qemu_free(config);
>      return 0;
>  }
>  
> @@ -202,6 +207,7 @@ static int get_pci_config_device(QEMUFile *f, void *pv, 
> size_t size)
>  static void put_pci_config_device(QEMUFile *f, const void *pv, size_t size)
>  {
>      const uint8_t *v = pv;
> +    assert(size == pcie_config_size(container_of(pv, PCIDevice, config)));
>      qemu_put_buffer(f, v, size);
>  }
>  
> @@ -211,6 +217,17 @@ static VMStateInfo vmstate_info_pci_config = {
>      .put  = put_pci_config_device,
>  };
>  
> +#define VMSTATE_PCI_CONFIG(_field, _state, _version, _info, _type,   \
> +                           _size) {                                  \
> +    .name       = (stringify(_field)),                               \
> +    .version_id = (_version),                                        \
> +    .size       = (_size),                                           \
> +    .info       = &(_info),                                          \
> +    .flags      = VMS_SINGLE | VMS_POINTER,                          \
> +    .offset     = offsetof(_state, _field)                           \
> +            + type_check(_type,typeof_field(_state, _field))         \
> +}
> +
>  const VMStateDescription vmstate_pci_device = {
>      .name = "PCIDevice",
>      .version_id = 2,
> @@ -218,21 +235,46 @@ const VMStateDescription vmstate_pci_device = {
>      .minimum_version_id_old = 1,
>      .fields      = (VMStateField []) {
>          VMSTATE_INT32_LE(version_id, PCIDevice),
> -        VMSTATE_SINGLE(config, PCIDevice, 0, vmstate_info_pci_config,
> -                       typeof_field(PCIDevice,config)),
> +        VMSTATE_PCI_CONFIG(config, PCIDevice, 0, vmstate_info_pci_config,
> +                           typeof_field(PCIDevice, config),
> +                           PCI_CONFIG_SPACE_SIZE),
> +        VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, PCI_NUM_PINS, 2),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +const VMStateDescription vmstate_pcie_device = {
> +    .name = "PCIDevice",
> +    .version_id = 2,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields      = (VMStateField []) {
> +        VMSTATE_INT32_LE(version_id, PCIDevice),
> +        VMSTATE_PCI_CONFIG(config, PCIDevice, 0, vmstate_info_pci_config,
> +                           typeof_field(PCIDevice, config),
> +                           PCIE_CONFIG_SPACE_SIZE),
>          VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, PCI_NUM_PINS, 2),
>          VMSTATE_END_OF_LIST()
>      }
>  };
>  
> +static const VMStateDescription *pci_get_vmstate(PCIDevice *s)
> +{
> +    if (pci_is_pcie(s)) {
> +        return &vmstate_pcie_device;
> +    }
> +
> +    return &vmstate_pci_device;
> +}
> +
>  void pci_device_save(PCIDevice *s, QEMUFile *f)
>  {
> -    vmstate_save_state(f, &vmstate_pci_device, s);
> +    vmstate_save_state(f, pci_get_vmstate(s), s);
>  }
>  
>  int pci_device_load(PCIDevice *s, QEMUFile *f)
>  {
> -    return vmstate_load_state(f, &vmstate_pci_device, s, s->version_id);
> +    return vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
>  }
>  
>  static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
> @@ -341,14 +383,31 @@ static void pci_init_cmask(PCIDevice *dev)
>  static void pci_init_wmask(PCIDevice *dev)
>  {
>      int i;
> +    uint32_t config_size = pcie_config_size(dev);
> +
>      dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff;
>      dev->wmask[PCI_INTERRUPT_LINE] = 0xff;
>      dev->wmask[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY
>                                | PCI_COMMAND_MASTER;
> -    for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i)
> +    for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i)
>          dev->wmask[i] = 0xff;
>  }
>  
> +static void pci_config_alloc(PCIDevice *pci_dev)
> +{
> +    int config_size = pcie_config_size(pci_dev);
> +#define PCI_CONFIG_ALLOC(d, member, size)                               \
> +    do {                                                                \
> +        (d)->member =                                                   \
> +            (typeof((d)->member))qemu_mallocz(sizeof((d)->member[0]) *  \
> +                                              size);                    \
> +    } while (0)
> +    PCI_CONFIG_ALLOC(pci_dev, config, config_size);
> +    PCI_CONFIG_ALLOC(pci_dev, cmask, config_size);
> +    PCI_CONFIG_ALLOC(pci_dev, wmask, config_size);
> +    PCI_CONFIG_ALLOC(pci_dev, used, config_size);

Please don't abuse macros in this way.
And sizeof is a single byte anyway, so just qemu_mallocz(config_size)
is all you need.

Also, I don't see this memory freed anywhere.

> +}
> +
>  /* -1 for devfn means auto assign */
>  static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
>                                           const char *name, int devfn,
> @@ -369,6 +428,7 @@ static PCIDevice *do_pci_register_device(PCIDevice 
> *pci_dev, PCIBus *bus,
>      pci_dev->devfn = devfn;
>      pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
>      memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
> +    pci_config_alloc(pci_dev);
>      pci_set_default_subsystem_id(pci_dev);
>      pci_init_cmask(pci_dev);
>      pci_init_wmask(pci_dev);
> @@ -586,40 +646,48 @@ static void pci_update_mappings(PCIDevice *d)
>      }
>  }
>  
> +static uint8_t pcie_config_get_byte(PCIDevice *d, uint32_t addr)
> +{
> +    uint8_t *conf = &d->config[addr];
> +    if (conf != NULL)
> +        return *conf;
> +    return 0;
> +}
> +

config is never NULL here.

> +static uint32_t pcie_config_get(PCIDevice *d, uint32_t addr, int len)
> +{
> +    int i;
> +    union {
> +        uint8_t val8[4];
> +        uint32_t val32;
> +    } v = { .val32 = 0 };
> +
> +    for (i = 0; i < len; i++) {
> +        v.val8[i] = pcie_config_get_byte(d, addr + i);
> +    }
> +
> +    return le32_to_cpu(v.val32);
> +}
> +

You seem to displike memcpy :) It's more readbable and generates better
code than an open loop. I already posted a single-line replacement for
this function:
uint32_t val = 0;
memcpy(&val, d->config + addr, len);
return le32_to_cpu(val);

which is now small enough to be open-coded.
Also, names starting with pcie are inappropriate for
generic pci code.


>  uint32_t pci_default_read_config(PCIDevice *d,
>                                   uint32_t address, int len)
>  {
> -    uint32_t val;
> +    uint32_t config_size = pcie_config_size(d);
>  
> -    switch(len) {
> -    default:
> -    case 4:
> -     if (address <= 0xfc) {
> -            val = pci_get_long(d->config + address);
> -         break;
> -     }
> -     /* fall through */
> -    case 2:
> -        if (address <= 0xfe) {
> -            val = pci_get_word(d->config + address);
> -         break;
> -     }
> -     /* fall through */
> -    case 1:
> -        val = pci_get_byte(d->config + address);
> -        break;
> -    }
> -    return val;
> +    assert(len == 1 || len == 2 || len == 4);
> +    len = MIN(len, config_size - MIN(config_size, address));
> +    return pcie_config_get(d, address, len);
>  }
>  
>  void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int 
> l)
>  {
>      uint8_t orig[PCI_CONFIG_SPACE_SIZE];
>      int i;
> +    uint32_t config_size = pcie_config_size(d);
>  
>      /* not efficient, but simple */
>      memcpy(orig, d->config, PCI_CONFIG_SPACE_SIZE);
> -    for(i = 0; i < l && addr < PCI_CONFIG_SPACE_SIZE; val >>= 8, ++i, 
> ++addr) {
> +    for(i = 0; i < l && addr < config_size; val >>= 8, ++i, ++addr) {
>          uint8_t wmask = d->wmask[addr];
>          d->config[addr] = (d->config[addr] & ~wmask) | (val & wmask);
>      }
> @@ -703,6 +771,128 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int 
> len)
>      return pci_data_read_common(pci_addr_to_dev(s, addr),
>                                  pci_addr_to_config(addr), len);
>  }
> +
> +#define PCIE_MASK(val, hi_bit, low_bit)                 \
> +    (((val) & (((1ULL << (hi_bit)) - 1))) >> (low_bit))

Why long long? Should be 1UL?

> +#define PCIE_VAL(VAL, val)                                              \
> +    PCIE_MASK((val), PCIE_MMCFG_ ## VAL ## _HI, PCIE_MMCFG_ ## VAL ## _LOW)

Please kill these macros.

> +#define PCIE_MMCFG_BUS_HI               28
> +#define PCIE_MMCFG_BUS_LOW              20
> +#define PCIE_MMCFG_DEV_HI               19
> +#define PCIE_MMCFG_DEV_LOW              15
> +#define PCIE_MMCFG_FUNC_HI              14
> +#define PCIE_MMCFG_FUNC_LOW             12
> +#define PCIE_MMCFG_CONFADDR_HI          11
> +#define PCIE_MMCFG_CONFADDR_LOW         0

HI/LOW are confusing: you don't know whether HI is last bit or one after
last. _BIT and _MASK are unambigious and would be better.

> +#define PCIE_MMCFG_BUS(addr)            PCIE_VAL(BUS, (addr))
> +#define PCIE_MMCFG_DEV(addr)            PCIE_VAL(DEV, (addr))
> +#define PCIE_MMCFG_FUNC(addr)           PCIE_VAL(FUNC, (addr))
> +#define PCIE_MMCFG_CONFADDR(addr)       PCIE_VAL(CONFADDR, (addr))
> +
> +void pcie_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
> +{
> +    PCIBus *s = opaque;
> +    pci_data_write_common(pci_find_device(s, PCIE_MMCFG_BUS(addr),
> +                                          PCIE_MMCFG_DEV(addr),
> +                                          PCIE_MMCFG_FUNC(addr)),
> +                          PCIE_MMCFG_CONFADDR(addr),
> +                          val, len);
> +}
> +
> +uint32_t pcie_data_read(void *opaque, uint32_t addr, int len)
> +{
> +    PCIBus *s = opaque;
> +    return pci_data_read_common(pci_find_device(s, PCIE_MMCFG_BUS(addr),
> +                                                PCIE_MMCFG_DEV(addr),
> +                                                PCIE_MMCFG_FUNC(addr)),
> +                                PCIE_MMCFG_CONFADDR(addr),
> +                                len);
> +}

These are only for mmcfg, right? So please name these
pcie_mmcfg_data_read.

> +
> +#define DEFINE_PCIE_HOST_DATA_READ(len)                         \
> +    static uint32_t pcie_host_data_read_ ## len (               \
> +        void *opaque, target_phys_addr_t addr)                  \
> +    {                                                           \
> +        PCIExpressHost *e = (PCIExpressHost *)opaque;           \


Do not cast void * values. This way if type is changed
at some point, you get compiler error.

> +        return pcie_data_read(e->pci.bus,                       \
> +                              addr - e->base_addr, (len));      \
> +    }
> +
> +#define DEFINE_PCIE_HOST_DATA_WRITE(len)                        \
> +    static void pcie_host_data_write_ ## len (                  \
> +        void *opaque, target_phys_addr_t addr, uint32_t value)  \
> +    {                                                           \
> +        PCIExpressHost *e = (PCIExpressHost *)opaque;           \
> +        pcie_data_write(e->pci.bus,                             \
> +                        addr - e->base_addr, value, (len));     \
> +    }
> +
> +#define DEFINE_PCIE_HOST_DATA_MMIO(len)      \
> +        DEFINE_PCIE_HOST_DATA_READ(len)      \
> +        DEFINE_PCIE_HOST_DATA_WRITE(len)
> +
> +DEFINE_PCIE_HOST_DATA_MMIO(1)
> +DEFINE_PCIE_HOST_DATA_MMIO(2)
> +DEFINE_PCIE_HOST_DATA_MMIO(4)
> +
> +#define DEFINE_PCIE_MEMORY_FUNCS(Type, type)                            \
> +    static CPU ## Type ## MemoryFunc *pcie_host_data_ ## type [] =      \
> +    {                                                                   \
> +        &pcie_host_data_ ## type ## _1,                                 \
> +        &pcie_host_data_ ## type ## _2,                                 \
> +        &pcie_host_data_ ## type ## _4,                                 \
> +    };
> +
> +DEFINE_PCIE_MEMORY_FUNCS(Read, read)
> +DEFINE_PCIE_MEMORY_FUNCS(Write, write)

Please just init structures in the plain way.  Then editors, taggers
have a chance in hell to figure out how a function gets called.  These
macros obfuscate code terribly, and do not really buy us anything.

> +
> +int pcie_host_init(PCIExpressHost *e,
> +                   CPUReadMemoryFunc **mmcfg_read,
> +                   CPUWriteMemoryFunc **mmcfg_write)
> +{
> +    e->base_addr = PCIE_BASE_ADDR_INVALID;
> +
> +    if (mmcfg_read == NULL)

Replace == NULL with !

> +        mmcfg_read = pcie_host_data_read;
> +    if (mmcfg_write == NULL)
> +        mmcfg_write = pcie_host_data_write;

Do you already need special casing reads/writes?
It seems unlikely that anyone would override these.

> +    e->mmio_index = cpu_register_io_memory(mmcfg_read, mmcfg_write, e);
> +    if (e->mmio_index < 0) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +void pcie_host_mmcfg_unmap(PCIExpressHost *e)
> +{
> +    if (e->base_addr != PCIE_BASE_ADDR_INVALID) {
> +        cpu_register_physical_memory(e->base_addr, e->size, 
> IO_MEM_UNASSIGNED);
> +    }
> +}
> +
> +void pcie_host_mmcfg_map(PCIExpressHost *e,
> +                         target_phys_addr_t addr, uint32_t size)
> +{
> +    assert((size & (size - 1)) == 0); /* power of 2 */

Replace == 0 with !

> +    assert(size >= (1ULL << PCIE_MMCFG_BUS_LOW));
> +    assert(size <= (1ULL << PCIE_MMCFG_BUS_HI));
> +
> +    e->base_addr = addr;
> +    e->size = size;
> +    cpu_register_physical_memory(e->base_addr, e->size, e->mmio_index);
> +}
> +
> +void pcie_host_mmcfg_update(PCIExpressHost *e,
> +                            int enable,
> +                            target_phys_addr_t addr, uint32_t size)
> +{
> +    pcie_host_mmcfg_unmap(e);
> +    if (enable) {
> +        pcie_host_mmcfg_map(e, addr, size);
> +    }
> +}
> +
>  /***********************************************************/
>  /* generic PCI irq support */
>  
> @@ -1052,9 +1242,10 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, 
> const char *name)
>  
>  static int pci_find_space(PCIDevice *pdev, uint8_t size)
>  {
> +    int config_size = pcie_config_size(pdev);
>      int offset = PCI_CONFIG_HEADER_SIZE;
>      int i;
> -    for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i)
> +    for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i)
>          if (pdev->used[i])
>              offset = i + 1;
>          else if (i - offset + 1 == size)
> diff --git a/hw/pci.h b/hw/pci.h
> index 00f2b78..1f402d2 100644
> --- a/hw/pci.h
> +++ b/hw/pci.h
> @@ -175,20 +175,26 @@ enum {
>      QEMU_PCI_CAP_MSIX = 0x1,
>  };
>  
> +/* Size of the standart PCIe config space: 4KB */
> +#define PCIE_CONFIG_SPACE_SIZE  0x1000
> +#define PCIE_EXT_CONFIG_SPACE_SIZE                      \
> +    (PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE)
> +

where's this used?

>  struct PCIDevice {
>      DeviceState qdev;
> +
>      /* PCI config space */
> -    uint8_t config[PCI_CONFIG_SPACE_SIZE];
> +    uint8_t *config;
>  
>      /* Used to enable config checks on load. Note that writeable bits are
>       * never checked even if set in cmask. */
> -    uint8_t cmask[PCI_CONFIG_SPACE_SIZE];
> +    uint8_t *cmask;
>  
>      /* Used to implement R/W bytes */
> -    uint8_t wmask[PCI_CONFIG_SPACE_SIZE];
> +    uint8_t *wmask;
>  
>      /* Used to allocate config space for capabilities. */
> -    uint8_t used[PCI_CONFIG_SPACE_SIZE];
> +    uint8_t *used;
>  
>      /* the following fields are read only */
>      PCIBus *bus;
> @@ -270,6 +276,8 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char 
> *default_model,
>                          const char *default_devaddr);
>  void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
>  uint32_t pci_data_read(void *opaque, uint32_t addr, int len);
> +void pcie_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
> +uint32_t pcie_data_read(void *opaque, uint32_t addr, int len);
>  int pci_bus_num(PCIBus *s);
>  void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, 
> PCIDevice *d));
>  PCIBus *pci_find_host_bus(int domain);
> @@ -356,6 +364,9 @@ typedef struct {
>      pci_qdev_initfn init;
>      PCIConfigReadFunc *config_read;
>      PCIConfigWriteFunc *config_write;
> +
> +    /* pcie stuff */
> +    int pcie;
>  } PCIDeviceInfo;
>  
>  void pci_qdev_register(PCIDeviceInfo *info);
> @@ -365,6 +376,23 @@ PCIDevice *pci_create(const char *name, const char 
> *devaddr);
>  PCIDevice *pci_create_noinit(PCIBus *bus, int devfn, const char *name);
>  PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
>  
> +static inline int pci_is_pcie(PCIDevice *d)
> +{
> +    /*
> +     * At the moment, all the pci devices aren't qdevfied. So
> +     * d->qdev.info might be NULL.
> +     * Given that pcie device emulator hasn't exist, we conclude that
> +     * such a device isn't pcie.
> +     */
> +    return d->qdev.info != NULL &&

kill != NULL

> +        container_of(d->qdev.info, PCIDeviceInfo, qdev)->pcie;
> +}
> +

I think this should use capabilities just like msix does.
So you would have a bit set in the cap_present field
instead of adding and using an extra field.


> +static inline uint32_t pcie_config_size(PCIDevice *d)
> +{
> +    return pci_is_pcie(d)? PCIE_CONFIG_SPACE_SIZE: PCI_CONFIG_SPACE_SIZE;

space before ?

> +}
> +

Should be pci_config_size. Generally pcie_xxx should be for
express only, generic stuff should be pci_xxx.

>  /* lsi53c895a.c */
>  #define LSI_MAX_DEVS 7
>  
> diff --git a/hw/pci_host.h b/hw/pci_host.h
> index ea98ed2..59147cf 100644
> --- a/hw/pci_host.h
> +++ b/hw/pci_host.h
> @@ -48,4 +48,26 @@ uint32_t pci_host_data_readb_ioport(void* opaque, uint32_t 
> addr);
>  uint32_t pci_host_data_readw_ioport(void* opaque, uint32_t addr);
>  uint32_t pci_host_data_readl_ioport(void* opaque, uint32_t addr);
>  
> +typedef struct {
> +    PCIHostState pci;
> +
> +    /* express part */
> +    target_phys_addr_t  base_addr;
> +#define PCIE_BASE_ADDR_INVALID  ((target_phys_addr_t)-1ULL)

Isn't this the same as PCI? Let's reuse it?

> +    target_phys_addr_t  size;
> +    int bus_num_order;
> +    int mmio_index;
> +} PCIExpressHost;
> +
> +int pcie_host_init(PCIExpressHost *e,
> +                   CPUReadMemoryFunc **mmcfg_read,
> +                   CPUWriteMemoryFunc **mmcfg_write);
> +
> +void pcie_host_mmcfg_unmap(PCIExpressHost *e);
> +void pcie_host_mmcfg_map(PCIExpressHost *e,
> +                         target_phys_addr_t addr, uint32_t size);
> +void pcie_host_mmcfg_update(PCIExpressHost *e,
> +                            int enable,
> +                            target_phys_addr_t addr, uint32_t size);
> +
>  #endif /* PCI_HOST_H */
> -- 
> 1.6.0.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]