From patchwork Fri Oct 9 06:28:56 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaku Yamahata X-Patchwork-Id: 35597 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id EAA61B7BEE for ; Fri, 9 Oct 2009 19:40:32 +1100 (EST) Received: from localhost ([127.0.0.1]:38822 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MwB1Z-0007yr-BG for incoming@patchwork.ozlabs.org; Fri, 09 Oct 2009 04:40:29 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MwAxZ-0006uE-Oo for qemu-devel@nongnu.org; Fri, 09 Oct 2009 04:36:21 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MwAxV-0006ss-9m for qemu-devel@nongnu.org; Fri, 09 Oct 2009 04:36:21 -0400 Received: from [199.232.76.173] (port=39270 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MwAxV-0006sc-5Q for qemu-devel@nongnu.org; Fri, 09 Oct 2009 04:36:17 -0400 Received: from mail.valinux.co.jp ([210.128.90.3]:47307) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MwAxT-0002lr-SU for qemu-devel@nongnu.org; Fri, 09 Oct 2009 04:36:16 -0400 Received: from nm.local.valinux.co.jp (vagw.valinux.co.jp [210.128.90.14]) by mail.valinux.co.jp (Postfix) with ESMTP id 4D64C49E2A; Fri, 9 Oct 2009 15:30:40 +0900 (JST) Received: from yamahata by nm.local.valinux.co.jp with local (Exim 4.69) (envelope-from ) id 1Mw8yN-000477-50; Fri, 09 Oct 2009 15:29:03 +0900 From: Isaku Yamahata To: qemu-devel@nongnu.org, mst@redhat.com Date: Fri, 9 Oct 2009 15:28:56 +0900 Message-Id: <1255069742-15724-24-git-send-email-yamahata@valinux.co.jp> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: <1255069742-15724-1-git-send-email-yamahata@valinux.co.jp> References: <1255069742-15724-1-git-send-email-yamahata@valinux.co.jp> X-Virus-Scanned: clamav-milter 0.95.2 at va-mail.local.valinux.co.jp X-Virus-Status: Clean X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 3) Cc: yamahata@valinux.co.jp Subject: [Qemu-devel] [PATCH V5 23/29] pci: pcie host and mmcfg support. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- Makefile.target | 2 +- hw/hw.h | 12 ++++ hw/pci.c | 86 ++++++++++++++++++++++++----- hw/pci.h | 27 ++++++++- hw/pcie_host.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pcie_host.h | 53 ++++++++++++++++++ 6 files changed, 327 insertions(+), 19 deletions(-) create mode 100644 hw/pcie_host.c create mode 100644 hw/pcie_host.h diff --git a/Makefile.target b/Makefile.target index cc555cb..ced7f65 100644 --- a/Makefile.target +++ b/Makefile.target @@ -154,7 +154,7 @@ endif #CONFIG_BSD_USER # System emulator target ifdef CONFIG_SOFTMMU -obj-y = vl.o monitor.o pci.o pci_host.o machine.o gdbstub.o +obj-y = vl.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o diff --git a/hw/hw.h b/hw/hw.h index e867af4..fba3167 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -494,6 +494,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)) \ +} + extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_I2C_SLAVE(_field, _state) { \ diff --git a/hw/pci.c b/hw/pci.c index 99b420f..4436e12 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" @@ -241,18 +242,24 @@ 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[PCI_CONFIG_SPACE_SIZE]; + uint8_t *config; int i; - assert(size == sizeof config); - qemu_get_buffer(f, config, sizeof config); - for (i = 0; i < sizeof config; ++i) - if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i]) + assert(size == pci_config_size(s)); + config = qemu_malloc(size); + + qemu_get_buffer(f, config, size); + for (i = 0; i < size; ++i) { + if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i]) { + qemu_free(config); return -EINVAL; - memcpy(s->config, config, sizeof config); + } + } + memcpy(s->config, config, size); pci_update_mappings(s); + qemu_free(config); return 0; } @@ -260,6 +267,7 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) { const uint8_t *v = pv; + assert(size == pci_config_size(container_of(pv, PCIDevice, config))); qemu_put_buffer(f, v, size); } @@ -276,21 +284,42 @@ 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_ARRAY_POINTER(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_ARRAY_POINTER(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 inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) +{ + return pci_is_express(s) ? &vmstate_pcie_device : &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) @@ -399,14 +428,34 @@ static void pci_init_cmask(PCIDevice *dev) static void pci_init_wmask(PCIDevice *dev) { int i; + int config_size = pci_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 = pci_config_size(pci_dev); + + pci_dev->config = qemu_mallocz(config_size); + pci_dev->cmask = qemu_mallocz(config_size); + pci_dev->wmask = qemu_mallocz(config_size); + pci_dev->used = qemu_mallocz(config_size); +} + +static void pci_config_free(PCIDevice *pci_dev) +{ + qemu_free(pci_dev->config); + qemu_free(pci_dev->cmask); + qemu_free(pci_dev->wmask); + qemu_free(pci_dev->used); +} + /* -1 for devfn means auto assign */ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, const char *name, int devfn, @@ -427,6 +476,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); @@ -494,6 +544,7 @@ static int pci_unregister_device(DeviceState *dev) qemu_free_irqs(pci_dev->irq); pci_dev->bus->devices[pci_dev->devfn] = NULL; + pci_config_free(pci_dev); return 0; } @@ -632,7 +683,7 @@ uint32_t pci_default_read_config(PCIDevice *d, { uint32_t val = 0; assert(len == 1 || len == 2 || len == 4); - len = MIN(len, PCI_CONFIG_SPACE_SIZE - address); + len = MIN(len, pci_config_size(d) - address); memcpy(&val, d->config + address, len); return le32_to_cpu(val); } @@ -641,10 +692,11 @@ 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 = pci_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); } @@ -1015,6 +1067,11 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) PCIBus *bus; int devfn, rc; + /* initialize cap_present for pci_is_express() and pci_config_size() */ + if (info->is_express) { + pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; + } + bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); devfn = pci_dev->devfn; pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn, @@ -1071,9 +1128,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 = pci_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 5b8f5cf..bfa29c8 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -166,28 +166,31 @@ typedef struct PCIIORegion { #define PCI_CONFIG_HEADER_SIZE 0x40 /* Size of the standard PCI config space */ #define PCI_CONFIG_SPACE_SIZE 0x100 +/* Size of the standart PCIe config space: 4KB */ +#define PCIE_CONFIG_SPACE_SIZE 0x1000 #define PCI_NUM_PINS 4 /* A-D */ /* Bits in cap_present field. */ enum { QEMU_PCI_CAP_MSIX = 0x1, + QEMU_PCI_CAP_EXPRESS = 0x2, }; 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; @@ -361,6 +364,12 @@ typedef struct { PCIUnregisterFunc *exit; PCIConfigReadFunc *config_read; PCIConfigWriteFunc *config_write; + + /* pcie stuff */ + int is_express; /* is this device pci express? + * initialization code needs to know this before + * each specific device initialization. + */ } PCIDeviceInfo; void pci_qdev_register(PCIDeviceInfo *info); @@ -369,6 +378,16 @@ void pci_qdev_register_many(PCIDeviceInfo *info); PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); +static inline int pci_is_express(PCIDevice *d) +{ + return d->cap_present & QEMU_PCI_CAP_EXPRESS; +} + +static inline uint32_t pci_config_size(PCIDevice *d) +{ + return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; +} + /* lsi53c895a.c */ #define LSI_MAX_DEVS 7 diff --git a/hw/pcie_host.c b/hw/pcie_host.c new file mode 100644 index 0000000..134d348 --- /dev/null +++ b/hw/pcie_host.c @@ -0,0 +1,166 @@ +/* + * pcie_host.c + * utility functions for pci express host bridge. + * + * Copyright (c) 2009 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "hw.h" +#include "pci.h" +#include "pcie_host.h" + +/* + * PCI express mmcfig address + * bit 20 - 28: bus number + * bit 15 - 19: device number + * bit 12 - 14: function number + * bit 0 - 11: offset in configuration space of a given device + */ +#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) +#define PCIE_MMCFG_SIZE_MIN (1ULL << 20) +#define PCIE_MMCFG_BUS_BIT 20 +#define PCIE_MMCFG_BUS_MASK 0x1ff +#define PCIE_MMCFG_DEVFN_BIT 12 +#define PCIE_MMCFG_DEVFN_MASK 0xff +#define PCIE_MMCFG_CONFOFFSET_MASK 0xfff +#define PCIE_MMCFG_BUS(addr) (((addr) >> PCIE_MMCFG_BUS_BIT) & \ + PCIE_MMCFG_BUS_MASK) +#define PCIE_MMCFG_DEVFN(addr) (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \ + PCIE_MMCFG_DEVFN_MASK) +#define PCIE_MMCFG_CONFOFFSET(addr) ((addr) & PCIE_MMCFG_CONFOFFSET_MASK) + + +/* a helper function to get a PCIDevice for a given mmconfig address */ +static inline PCIDevice *pcie_mmcfg_addr_to_dev(PCIBus *s, uint32_t mmcfg_addr) +{ + return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr), + PCI_SLOT(PCIE_MMCFG_DEVFN(mmcfg_addr)), + PCI_FUNC(PCIE_MMCFG_DEVFN(mmcfg_addr))); +} + +static void pcie_mmcfg_data_write(PCIBus *s, + uint32_t mmcfg_addr, uint32_t val, int len) +{ + pci_dev_write_config(pcie_mmcfg_addr_to_dev(s, mmcfg_addr), + PCIE_MMCFG_CONFOFFSET(mmcfg_addr), + val, len); +} + +static uint32_t pcie_mmcfg_data_read(PCIBus *s, + uint32_t mmcfg_addr, int len) +{ + return pci_dev_read_config(pcie_mmcfg_addr_to_dev(s, mmcfg_addr), + PCIE_MMCFG_CONFOFFSET(mmcfg_addr), + len); +} + +static void pcie_mmcfg_data_writeb(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + PCIExpressHost *e = opaque; + pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 1); +} + +static void pcie_mmcfg_data_writew(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + PCIExpressHost *e = opaque; + pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 2); +} + +static void pcie_mmcfg_data_writel(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + PCIExpressHost *e = opaque; + pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 4); +} + +static uint32_t pcie_mmcfg_data_readb(void *opaque, target_phys_addr_t addr) +{ + PCIExpressHost *e = opaque; + return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 1); +} + +static uint32_t pcie_mmcfg_data_readw(void *opaque, target_phys_addr_t addr) +{ + PCIExpressHost *e = opaque; + return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 2); +} + +static uint32_t pcie_mmcfg_data_readl(void *opaque, target_phys_addr_t addr) +{ + PCIExpressHost *e = opaque; + return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 4); +} + + +static CPUWriteMemoryFunc * const pcie_mmcfg_write[] = +{ + pcie_mmcfg_data_writeb, + pcie_mmcfg_data_writew, + pcie_mmcfg_data_writel, +}; + +static CPUReadMemoryFunc * const pcie_mmcfg_read[] = +{ + pcie_mmcfg_data_readb, + pcie_mmcfg_data_readw, + pcie_mmcfg_data_readl, +}; + +int pcie_host_init(PCIExpressHost *e) +{ + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; + e->mmio_index = + cpu_register_io_memory(pcie_mmcfg_read, pcie_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_UNMAPPED) { + cpu_register_physical_memory(e->base_addr, e->size, IO_MEM_UNASSIGNED); + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; + } +} + +void pcie_host_mmcfg_map(PCIExpressHost *e, + target_phys_addr_t addr, uint32_t size) +{ + assert(!(size & (size - 1))); /* power of 2 */ + assert(size >= PCIE_MMCFG_SIZE_MIN); + assert(size <= PCIE_MMCFG_SIZE_MAX); + + 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); + } +} diff --git a/hw/pcie_host.h b/hw/pcie_host.h new file mode 100644 index 0000000..f4116b3 --- /dev/null +++ b/hw/pcie_host.h @@ -0,0 +1,53 @@ +/* + * pcie_host.h + * + * Copyright (c) 2009 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PCIE_HOST_H +#define PCIE_HOST_H + +#include "pci_host.h" + +typedef struct { + PCIHostState pci; + + /* express part */ + + /* base address of MMCONFIG area is mapped. + * PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. + */ + target_phys_addr_t base_addr; +#define PCIE_BASE_ADDR_UNMAPPED ((target_phys_addr_t)-1ULL) + + /* the size of MMCONFIG area. It's host bridge dependent */ + target_phys_addr_t size; + + /* result of cpu_resiger_io_memory() to map MMCONFIG area */ + int mmio_index; +} PCIExpressHost; + +int pcie_host_init(PCIExpressHost *e); +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 /* PCIE_HOST_H */