[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci |
Date: |
Wed, 12 Dec 2012 19:53:45 +0000 |
On Wed, Dec 12, 2012 at 1:14 PM, Michael S. Tsirkin <address@hidden> wrote:
> Move files and modify makefiles to pick them at the
> new location.
Please fix coding style before moving.
For easier review, please use git flag -M to detect renames.
>
> Signed-off-by: Michael S. Tsirkin <address@hidden>
> ---
> hw/Makefile.objs | 10 +-
> hw/i386/Makefile.objs | 2 +-
> hw/msi.c | 395 ---------
> hw/msi.h | 50 --
> hw/msix.c | 562 -------------
> hw/msix.h | 41 -
> hw/pci-hotplug.c | 293 -------
> hw/pci-stub.c | 47 --
> hw/pci.c | 2168
> ------------------------------------------------
> hw/pci.h | 684 ---------------
> hw/pci/Makefile.objs | 6 +
> hw/pci/msi.c | 395 +++++++++
> hw/pci/msi.h | 50 ++
> hw/pci/msix.c | 562 +++++++++++++
> hw/pci/msix.h | 41 +
> hw/pci/pci-hotplug.c | 293 +++++++
> hw/pci/pci-stub.c | 47 ++
> hw/pci/pci.c | 2168
> ++++++++++++++++++++++++++++++++++++++++++++++++
> hw/pci/pci.h | 684 +++++++++++++++
> hw/pci/pci_bridge.c | 363 ++++++++
> hw/pci/pci_bridge.h | 66 ++
> hw/pci/pci_host.c | 180 ++++
> hw/pci/pci_host.h | 62 ++
> hw/pci/pci_ids.h | 147 ++++
> hw/pci/pci_internals.h | 78 ++
> hw/pci/pci_regs.h | 717 ++++++++++++++++
> hw/pci/pcie.c | 555 +++++++++++++
> hw/pci/pcie.h | 142 ++++
> hw/pci/pcie_aer.c | 1032 +++++++++++++++++++++++
> hw/pci/pcie_aer.h | 106 +++
> hw/pci/pcie_host.c | 161 ++++
> hw/pci/pcie_host.h | 54 ++
> hw/pci/pcie_port.c | 114 +++
> hw/pci/pcie_port.h | 51 ++
> hw/pci/pcie_regs.h | 156 ++++
> hw/pci/shpc.c | 681 +++++++++++++++
> hw/pci/shpc.h | 48 ++
> hw/pci/slotid_cap.c | 44 +
> hw/pci/slotid_cap.h | 11 +
> hw/pci_bridge.c | 363 --------
> hw/pci_bridge.h | 66 --
> hw/pci_host.c | 180 ----
> hw/pci_host.h | 62 --
> hw/pci_ids.h | 147 ----
> hw/pci_internals.h | 78 --
> hw/pci_regs.h | 717 ----------------
> hw/pcie.c | 555 -------------
> hw/pcie.h | 142 ----
> hw/pcie_aer.c | 1032 -----------------------
> hw/pcie_aer.h | 106 ---
> hw/pcie_host.c | 161 ----
> hw/pcie_host.h | 54 --
> hw/pcie_port.c | 114 ---
> hw/pcie_port.h | 51 --
> hw/pcie_regs.h | 156 ----
> hw/ppc/Makefile.objs | 2 +-
> hw/shpc.c | 681 ---------------
> hw/shpc.h | 48 --
> hw/slotid_cap.c | 44 -
> hw/slotid_cap.h | 11 -
> 60 files changed, 9018 insertions(+), 9018 deletions(-)
> delete mode 100644 hw/msi.c
> delete mode 100644 hw/msi.h
> delete mode 100644 hw/msix.c
> delete mode 100644 hw/msix.h
> delete mode 100644 hw/pci-hotplug.c
> delete mode 100644 hw/pci-stub.c
> delete mode 100644 hw/pci.c
> delete mode 100644 hw/pci.h
> create mode 100644 hw/pci/Makefile.objs
> create mode 100644 hw/pci/msi.c
> create mode 100644 hw/pci/msi.h
> create mode 100644 hw/pci/msix.c
> create mode 100644 hw/pci/msix.h
> create mode 100644 hw/pci/pci-hotplug.c
> create mode 100644 hw/pci/pci-stub.c
> create mode 100644 hw/pci/pci.c
> create mode 100644 hw/pci/pci.h
> create mode 100644 hw/pci/pci_bridge.c
> create mode 100644 hw/pci/pci_bridge.h
> create mode 100644 hw/pci/pci_host.c
> create mode 100644 hw/pci/pci_host.h
> create mode 100644 hw/pci/pci_ids.h
> create mode 100644 hw/pci/pci_internals.h
> create mode 100644 hw/pci/pci_regs.h
> create mode 100644 hw/pci/pcie.c
> create mode 100644 hw/pci/pcie.h
> create mode 100644 hw/pci/pcie_aer.c
> create mode 100644 hw/pci/pcie_aer.h
> create mode 100644 hw/pci/pcie_host.c
> create mode 100644 hw/pci/pcie_host.h
> create mode 100644 hw/pci/pcie_port.c
> create mode 100644 hw/pci/pcie_port.h
> create mode 100644 hw/pci/pcie_regs.h
> create mode 100644 hw/pci/shpc.c
> create mode 100644 hw/pci/shpc.h
> create mode 100644 hw/pci/slotid_cap.c
> create mode 100644 hw/pci/slotid_cap.h
> delete mode 100644 hw/pci_bridge.c
> delete mode 100644 hw/pci_bridge.h
> delete mode 100644 hw/pci_host.c
> delete mode 100644 hw/pci_host.h
> delete mode 100644 hw/pci_ids.h
> delete mode 100644 hw/pci_internals.h
> delete mode 100644 hw/pci_regs.h
> delete mode 100644 hw/pcie.c
> delete mode 100644 hw/pcie.h
> delete mode 100644 hw/pcie_aer.c
> delete mode 100644 hw/pcie_aer.h
> delete mode 100644 hw/pcie_host.c
> delete mode 100644 hw/pcie_host.h
> delete mode 100644 hw/pcie_port.c
> delete mode 100644 hw/pcie_port.h
> delete mode 100644 hw/pcie_regs.h
> delete mode 100644 hw/shpc.c
> delete mode 100644 hw/shpc.h
> delete mode 100644 hw/slotid_cap.c
> delete mode 100644 hw/slotid_cap.h
>
> diff --git a/hw/Makefile.objs b/hw/Makefile.objs
> index d581d8d..228acd6 100644
> --- a/hw/Makefile.objs
> +++ b/hw/Makefile.objs
> @@ -1,14 +1,10 @@
> -common-obj-y = usb/ ide/
> +common-obj-y = usb/ ide/ pci/
> common-obj-y += loader.o
> common-obj-$(CONFIG_VIRTIO) += virtio-console.o
> common-obj-$(CONFIG_VIRTIO) += virtio-rng.o
> common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
> common-obj-y += fw_cfg.o
> -common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o
> -common-obj-$(CONFIG_PCI) += msix.o msi.o
> -common-obj-$(CONFIG_PCI) += shpc.o
> -common-obj-$(CONFIG_PCI) += slotid_cap.o
> -common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
> +common-obj-$(CONFIG_PCI) += pci_bridge_dev.o
> common-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
> common-obj-$(CONFIG_PCI) += i82801b11.o
> common-obj-y += watchdog.o
> @@ -102,8 +98,6 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o
> # PCI watchdog devices
> common-obj-$(CONFIG_PCI) += wdt_i6300esb.o
>
> -common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
> -
> # PCI network cards
> common-obj-$(CONFIG_NE2000_PCI) += ne2000.o
> common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
> index 0d3f6a8..257f3c1 100644
> --- a/hw/i386/Makefile.objs
> +++ b/hw/i386/Makefile.objs
> @@ -2,7 +2,7 @@ obj-y += mc146818rtc.o pc.o
> obj-y += apic_common.o apic.o kvmvapic.o
> obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o
> obj-y += vmport.o
> -obj-y += pci-hotplug.o smbios.o wdt_ib700.o
> +obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o
> obj-y += debugcon.o multiboot.o
> obj-y += pc_piix.o
> obj-y += pc_sysfw.o
> diff --git a/hw/msi.c b/hw/msi.c
> deleted file mode 100644
> index 33037a8..0000000
> --- a/hw/msi.c
> +++ /dev/null
> @@ -1,395 +0,0 @@
> -/*
> - * msi.c
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "msi.h"
> -#include "range.h"
> -
> -/* Eventually those constants should go to Linux pci_regs.h */
> -#define PCI_MSI_PENDING_32 0x10
> -#define PCI_MSI_PENDING_64 0x14
> -
> -/* PCI_MSI_ADDRESS_LO */
> -#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
> -
> -/* If we get rid of cap allocator, we won't need those. */
> -#define PCI_MSI_32_SIZEOF 0x0a
> -#define PCI_MSI_64_SIZEOF 0x0e
> -#define PCI_MSI_32M_SIZEOF 0x14
> -#define PCI_MSI_64M_SIZEOF 0x18
> -
> -#define PCI_MSI_VECTORS_MAX 32
> -
> -/* Flag for interrupt controller to declare MSI/MSI-X support */
> -bool msi_supported;
> -
> -/* If we get rid of cap allocator, we won't need this. */
> -static inline uint8_t msi_cap_sizeof(uint16_t flags)
> -{
> - switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) {
> - case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT:
> - return PCI_MSI_64M_SIZEOF;
> - case PCI_MSI_FLAGS_64BIT:
> - return PCI_MSI_64_SIZEOF;
> - case PCI_MSI_FLAGS_MASKBIT:
> - return PCI_MSI_32M_SIZEOF;
> - case 0:
> - return PCI_MSI_32_SIZEOF;
> - default:
> - abort();
> - break;
> - }
> - return 0;
> -}
> -
> -//#define MSI_DEBUG
> -
> -#ifdef MSI_DEBUG
> -# define MSI_DPRINTF(fmt, ...) \
> - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
> -#else
> -# define MSI_DPRINTF(fmt, ...) do { } while (0)
> -#endif
> -#define MSI_DEV_PRINTF(dev, fmt, ...) \
> - MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
> -
> -static inline unsigned int msi_nr_vectors(uint16_t flags)
> -{
> - return 1U <<
> - ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1));
> -}
> -
> -static inline uint8_t msi_flags_off(const PCIDevice* dev)
> -{
> - return dev->msi_cap + PCI_MSI_FLAGS;
> -}
> -
> -static inline uint8_t msi_address_lo_off(const PCIDevice* dev)
> -{
> - return dev->msi_cap + PCI_MSI_ADDRESS_LO;
> -}
> -
> -static inline uint8_t msi_address_hi_off(const PCIDevice* dev)
> -{
> - return dev->msi_cap + PCI_MSI_ADDRESS_HI;
> -}
> -
> -static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit)
> -{
> - return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32);
> -}
> -
> -static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit)
> -{
> - return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32);
> -}
> -
> -static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit)
> -{
> - return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 :
> PCI_MSI_PENDING_32);
> -}
> -
> -/*
> - * Special API for POWER to configure the vectors through
> - * a side channel. Should never be used by devices.
> - */
> -void msi_set_message(PCIDevice *dev, MSIMessage msg)
> -{
> - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> -
> - if (msi64bit) {
> - pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address);
> - } else {
> - pci_set_long(dev->config + msi_address_lo_off(dev), msg.address);
> - }
> - pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data);
> -}
> -
> -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector)
> -{
> - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> - unsigned int nr_vectors = msi_nr_vectors(flags);
> - MSIMessage msg;
> -
> - assert(vector < nr_vectors);
> -
> - if (msi64bit) {
> - msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev));
> - } else {
> - msg.address = pci_get_long(dev->config + msi_address_lo_off(dev));
> - }
> -
> - /* upper bit 31:16 is zero */
> - msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
> - if (nr_vectors > 1) {
> - msg.data &= ~(nr_vectors - 1);
> - msg.data |= vector;
> - }
> -
> - return msg;
> -}
> -
> -bool msi_enabled(const PCIDevice *dev)
> -{
> - return msi_present(dev) &&
> - (pci_get_word(dev->config + msi_flags_off(dev)) &
> - PCI_MSI_FLAGS_ENABLE);
> -}
> -
> -int msi_init(struct PCIDevice *dev, uint8_t offset,
> - unsigned int nr_vectors, bool msi64bit, bool
> msi_per_vector_mask)
> -{
> - unsigned int vectors_order;
> - uint16_t flags;
> - uint8_t cap_size;
> - int config_offset;
> -
> - if (!msi_supported) {
> - return -ENOTSUP;
> - }
> -
> - MSI_DEV_PRINTF(dev,
> - "init offset: 0x%"PRIx8" vector: %"PRId8
> - " 64bit %d mask %d\n",
> - offset, nr_vectors, msi64bit, msi_per_vector_mask);
> -
> - assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */
> - assert(nr_vectors > 0);
> - assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
> - /* the nr of MSI vectors is up to 32 */
> - vectors_order = ffs(nr_vectors) - 1;
> -
> - flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1);
> - if (msi64bit) {
> - flags |= PCI_MSI_FLAGS_64BIT;
> - }
> - if (msi_per_vector_mask) {
> - flags |= PCI_MSI_FLAGS_MASKBIT;
> - }
> -
> - cap_size = msi_cap_sizeof(flags);
> - config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset,
> cap_size);
> - if (config_offset < 0) {
> - return config_offset;
> - }
> -
> - dev->msi_cap = config_offset;
> - dev->cap_present |= QEMU_PCI_CAP_MSI;
> -
> - pci_set_word(dev->config + msi_flags_off(dev), flags);
> - pci_set_word(dev->wmask + msi_flags_off(dev),
> - PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
> - pci_set_long(dev->wmask + msi_address_lo_off(dev),
> - PCI_MSI_ADDRESS_LO_MASK);
> - if (msi64bit) {
> - pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff);
> - }
> - pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff);
> -
> - if (msi_per_vector_mask) {
> - /* Make mask bits 0 to nr_vectors - 1 writable. */
> - pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
> - 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
> - }
> - return config_offset;
> -}
> -
> -void msi_uninit(struct PCIDevice *dev)
> -{
> - uint16_t flags;
> - uint8_t cap_size;
> -
> - if (!msi_present(dev)) {
> - return;
> - }
> - flags = pci_get_word(dev->config + msi_flags_off(dev));
> - cap_size = msi_cap_sizeof(flags);
> - pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
> - dev->cap_present &= ~QEMU_PCI_CAP_MSI;
> -
> - MSI_DEV_PRINTF(dev, "uninit\n");
> -}
> -
> -void msi_reset(PCIDevice *dev)
> -{
> - uint16_t flags;
> - bool msi64bit;
> -
> - if (!msi_present(dev)) {
> - return;
> - }
> -
> - flags = pci_get_word(dev->config + msi_flags_off(dev));
> - flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
> - msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> -
> - pci_set_word(dev->config + msi_flags_off(dev), flags);
> - pci_set_long(dev->config + msi_address_lo_off(dev), 0);
> - if (msi64bit) {
> - pci_set_long(dev->config + msi_address_hi_off(dev), 0);
> - }
> - pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0);
> - if (flags & PCI_MSI_FLAGS_MASKBIT) {
> - pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0);
> - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0);
> - }
> - MSI_DEV_PRINTF(dev, "reset\n");
> -}
> -
> -static bool msi_is_masked(const PCIDevice *dev, unsigned int vector)
> -{
> - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> - uint32_t mask;
> - assert(vector < PCI_MSI_VECTORS_MAX);
> -
> - if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
> - return false;
> - }
> -
> - mask = pci_get_long(dev->config +
> - msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT));
> - return mask & (1U << vector);
> -}
> -
> -void msi_notify(PCIDevice *dev, unsigned int vector)
> -{
> - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> - unsigned int nr_vectors = msi_nr_vectors(flags);
> - MSIMessage msg;
> -
> - assert(vector < nr_vectors);
> - if (msi_is_masked(dev, vector)) {
> - assert(flags & PCI_MSI_FLAGS_MASKBIT);
> - pci_long_test_and_set_mask(
> - dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
> - MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector);
> - return;
> - }
> -
> - msg = msi_get_message(dev, vector);
> -
> - MSI_DEV_PRINTF(dev,
> - "notify vector 0x%x"
> - " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
> - vector, msg.address, msg.data);
> - stl_le_phys(msg.address, msg.data);
> -}
> -
> -/* Normally called by pci_default_write_config(). */
> -void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
> -{
> - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> - bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT;
> - unsigned int nr_vectors;
> - uint8_t log_num_vecs;
> - uint8_t log_max_vecs;
> - unsigned int vector;
> - uint32_t pending;
> -
> - if (!msi_present(dev) ||
> - !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
> - return;
> - }
> -
> -#ifdef MSI_DEBUG
> - MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n",
> - addr, val, len);
> - MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32,
> - flags,
> - pci_get_long(dev->config + msi_address_lo_off(dev)));
> - if (msi64bit) {
> - fprintf(stderr, " address-hi: 0x%"PRIx32,
> - pci_get_long(dev->config + msi_address_hi_off(dev)));
> - }
> - fprintf(stderr, " data: 0x%"PRIx16,
> - pci_get_word(dev->config + msi_data_off(dev, msi64bit)));
> - if (flags & PCI_MSI_FLAGS_MASKBIT) {
> - fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32,
> - pci_get_long(dev->config + msi_mask_off(dev, msi64bit)),
> - pci_get_long(dev->config + msi_pending_off(dev, msi64bit)));
> - }
> - fprintf(stderr, "\n");
> -#endif
> -
> - if (!(flags & PCI_MSI_FLAGS_ENABLE)) {
> - return;
> - }
> -
> - /*
> - * Now MSI is enabled, clear INTx# interrupts.
> - * the driver is prohibited from writing enable bit to mask
> - * a service request. But the guest OS could do this.
> - * So we just discard the interrupts as moderate fallback.
> - *
> - * 6.8.3.3. Enabling Operation
> - * While enabled for MSI or MSI-X operation, a function is prohibited
> - * from using its INTx# pin (if implemented) to request
> - * service (MSI, MSI-X, and INTx# are mutually exclusive).
> - */
> - pci_device_deassert_intx(dev);
> -
> - /*
> - * nr_vectors might be set bigger than capable. So clamp it.
> - * This is not legal by spec, so we can do anything we like,
> - * just don't crash the host
> - */
> - log_num_vecs =
> - (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
> - log_max_vecs =
> - (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1);
> - if (log_num_vecs > log_max_vecs) {
> - flags &= ~PCI_MSI_FLAGS_QSIZE;
> - flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
> - pci_set_word(dev->config + msi_flags_off(dev), flags);
> - }
> -
> - if (!msi_per_vector_mask) {
> - /* if per vector masking isn't supported,
> - there is no pending interrupt. */
> - return;
> - }
> -
> - nr_vectors = msi_nr_vectors(flags);
> -
> - /* This will discard pending interrupts, if any. */
> - pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit));
> - pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors);
> - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending);
> -
> - /* deliver pending interrupts which are unmasked */
> - for (vector = 0; vector < nr_vectors; ++vector) {
> - if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) {
> - continue;
> - }
> -
> - pci_long_test_and_clear_mask(
> - dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
> - msi_notify(dev, vector);
> - }
> -}
> -
> -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev)
> -{
> - uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> - return msi_nr_vectors(flags);
> -}
> diff --git a/hw/msi.h b/hw/msi.h
> deleted file mode 100644
> index 150b09a..0000000
> --- a/hw/msi.h
> +++ /dev/null
> @@ -1,50 +0,0 @@
> -/*
> - * msi.h
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef QEMU_MSI_H
> -#define QEMU_MSI_H
> -
> -#include "qemu-common.h"
> -#include "pci.h"
> -
> -struct MSIMessage {
> - uint64_t address;
> - uint32_t data;
> -};
> -
> -extern bool msi_supported;
> -
> -void msi_set_message(PCIDevice *dev, MSIMessage msg);
> -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector);
> -bool msi_enabled(const PCIDevice *dev);
> -int msi_init(struct PCIDevice *dev, uint8_t offset,
> - unsigned int nr_vectors, bool msi64bit, bool
> msi_per_vector_mask);
> -void msi_uninit(struct PCIDevice *dev);
> -void msi_reset(PCIDevice *dev);
> -void msi_notify(PCIDevice *dev, unsigned int vector);
> -void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
> -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
> -
> -static inline bool msi_present(const PCIDevice *dev)
> -{
> - return dev->cap_present & QEMU_PCI_CAP_MSI;
> -}
> -
> -#endif /* QEMU_MSI_H */
> diff --git a/hw/msix.c b/hw/msix.c
> deleted file mode 100644
> index 136ef09..0000000
> --- a/hw/msix.c
> +++ /dev/null
> @@ -1,562 +0,0 @@
> -/*
> - * MSI-X device support
> - *
> - * This module includes support for MSI-X in pci devices.
> - *
> - * Author: Michael S. Tsirkin <address@hidden>
> - *
> - * Copyright (c) 2009, Red Hat Inc, Michael S. Tsirkin (address@hidden)
> - *
> - * This work is licensed under the terms of the GNU GPL, version 2. See
> - * the COPYING file in the top-level directory.
> - *
> - * Contributions after 2012-01-13 are licensed under the terms of the
> - * GNU GPL, version 2 or (at your option) any later version.
> - */
> -
> -#include "hw.h"
> -#include "msi.h"
> -#include "msix.h"
> -#include "pci.h"
> -#include "range.h"
> -
> -#define MSIX_CAP_LENGTH 12
> -
> -/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
> -#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1)
> -#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
> -#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
> -
> -static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector)
> -{
> - uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE;
> - MSIMessage msg;
> -
> - msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
> - msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
> - return msg;
> -}
> -
> -/*
> - * Special API for POWER to configure the vectors through
> - * a side channel. Should never be used by devices.
> - */
> -void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg)
> -{
> - uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE;
> -
> - pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address);
> - pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data);
> - table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
> -}
> -
> -static uint8_t msix_pending_mask(int vector)
> -{
> - return 1 << (vector % 8);
> -}
> -
> -static uint8_t *msix_pending_byte(PCIDevice *dev, int vector)
> -{
> - return dev->msix_pba + vector / 8;
> -}
> -
> -static int msix_is_pending(PCIDevice *dev, int vector)
> -{
> - return *msix_pending_byte(dev, vector) & msix_pending_mask(vector);
> -}
> -
> -static void msix_set_pending(PCIDevice *dev, int vector)
> -{
> - *msix_pending_byte(dev, vector) |= msix_pending_mask(vector);
> -}
> -
> -static void msix_clr_pending(PCIDevice *dev, int vector)
> -{
> - *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
> -}
> -
> -static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask)
> -{
> - unsigned offset = vector * PCI_MSIX_ENTRY_SIZE +
> PCI_MSIX_ENTRY_VECTOR_CTRL;
> - return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
> -}
> -
> -static bool msix_is_masked(PCIDevice *dev, int vector)
> -{
> - return msix_vector_masked(dev, vector, dev->msix_function_masked);
> -}
> -
> -static void msix_fire_vector_notifier(PCIDevice *dev,
> - unsigned int vector, bool is_masked)
> -{
> - MSIMessage msg;
> - int ret;
> -
> - if (!dev->msix_vector_use_notifier) {
> - return;
> - }
> - if (is_masked) {
> - dev->msix_vector_release_notifier(dev, vector);
> - } else {
> - msg = msix_get_message(dev, vector);
> - ret = dev->msix_vector_use_notifier(dev, vector, msg);
> - assert(ret >= 0);
> - }
> -}
> -
> -static void msix_handle_mask_update(PCIDevice *dev, int vector, bool
> was_masked)
> -{
> - bool is_masked = msix_is_masked(dev, vector);
> -
> - if (is_masked == was_masked) {
> - return;
> - }
> -
> - msix_fire_vector_notifier(dev, vector, is_masked);
> -
> - if (!is_masked && msix_is_pending(dev, vector)) {
> - msix_clr_pending(dev, vector);
> - msix_notify(dev, vector);
> - }
> -}
> -
> -static void msix_update_function_masked(PCIDevice *dev)
> -{
> - dev->msix_function_masked = !msix_enabled(dev) ||
> - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
> MSIX_MASKALL_MASK);
> -}
> -
> -/* Handle MSI-X capability config write. */
> -void msix_write_config(PCIDevice *dev, uint32_t addr,
> - uint32_t val, int len)
> -{
> - unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
> - int vector;
> - bool was_masked;
> -
> - if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) {
> - return;
> - }
> -
> - was_masked = dev->msix_function_masked;
> - msix_update_function_masked(dev);
> -
> - if (!msix_enabled(dev)) {
> - return;
> - }
> -
> - pci_device_deassert_intx(dev);
> -
> - if (dev->msix_function_masked == was_masked) {
> - return;
> - }
> -
> - for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
> - msix_handle_mask_update(dev, vector,
> - msix_vector_masked(dev, vector, was_masked));
> - }
> -}
> -
> -static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr,
> - unsigned size)
> -{
> - PCIDevice *dev = opaque;
> -
> - return pci_get_long(dev->msix_table + addr);
> -}
> -
> -static void msix_table_mmio_write(void *opaque, hwaddr addr,
> - uint64_t val, unsigned size)
> -{
> - PCIDevice *dev = opaque;
> - int vector = addr / PCI_MSIX_ENTRY_SIZE;
> - bool was_masked;
> -
> - was_masked = msix_is_masked(dev, vector);
> - pci_set_long(dev->msix_table + addr, val);
> - msix_handle_mask_update(dev, vector, was_masked);
> -}
> -
> -static const MemoryRegionOps msix_table_mmio_ops = {
> - .read = msix_table_mmio_read,
> - .write = msix_table_mmio_write,
> - /* TODO: MSIX should be LITTLE_ENDIAN. */
> - .endianness = DEVICE_NATIVE_ENDIAN,
> - .valid = {
> - .min_access_size = 4,
> - .max_access_size = 4,
> - },
> -};
> -
> -static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
> - unsigned size)
> -{
> - PCIDevice *dev = opaque;
> -
> - return pci_get_long(dev->msix_pba + addr);
> -}
> -
> -static const MemoryRegionOps msix_pba_mmio_ops = {
> - .read = msix_pba_mmio_read,
> - /* TODO: MSIX should be LITTLE_ENDIAN. */
> - .endianness = DEVICE_NATIVE_ENDIAN,
> - .valid = {
> - .min_access_size = 4,
> - .max_access_size = 4,
> - },
> -};
> -
> -static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
> -{
> - int vector;
> -
> - for (vector = 0; vector < nentries; ++vector) {
> - unsigned offset =
> - vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
> - bool was_masked = msix_is_masked(dev, vector);
> -
> - dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
> - msix_handle_mask_update(dev, vector, was_masked);
> - }
> -}
> -
> -/* Initialize the MSI-X structures */
> -int msix_init(struct PCIDevice *dev, unsigned short nentries,
> - MemoryRegion *table_bar, uint8_t table_bar_nr,
> - unsigned table_offset, MemoryRegion *pba_bar,
> - uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos)
> -{
> - int cap;
> - unsigned table_size, pba_size;
> - uint8_t *config;
> -
> - /* Nothing to do if MSI is not supported by interrupt controller */
> - if (!msi_supported) {
> - return -ENOTSUP;
> - }
> -
> - if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) {
> - return -EINVAL;
> - }
> -
> - table_size = nentries * PCI_MSIX_ENTRY_SIZE;
> - pba_size = QEMU_ALIGN_UP(nentries, 64) / 8;
> -
> - /* Sanity test: table & pba don't overlap, fit within BARs, min aligned
> */
> - if ((table_bar_nr == pba_bar_nr &&
> - ranges_overlap(table_offset, table_size, pba_offset, pba_size)) ||
> - table_offset + table_size > memory_region_size(table_bar) ||
> - pba_offset + pba_size > memory_region_size(pba_bar) ||
> - (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) {
> - return -EINVAL;
> - }
> -
> - cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH);
> - if (cap < 0) {
> - return cap;
> - }
> -
> - dev->msix_cap = cap;
> - dev->cap_present |= QEMU_PCI_CAP_MSIX;
> - config = dev->config + cap;
> -
> - pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
> - dev->msix_entries_nr = nentries;
> - dev->msix_function_masked = true;
> -
> - pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr);
> - pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr);
> -
> - /* Make flags bit writable. */
> - dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
> - MSIX_MASKALL_MASK;
> -
> - dev->msix_table = g_malloc0(table_size);
> - dev->msix_pba = g_malloc0(pba_size);
> - dev->msix_entry_used = g_malloc0(nentries * sizeof
> *dev->msix_entry_used);
> -
> - msix_mask_all(dev, nentries);
> -
> - memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev,
> - "msix-table", table_size);
> - memory_region_add_subregion(table_bar, table_offset,
> &dev->msix_table_mmio);
> - memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev,
> - "msix-pba", pba_size);
> - memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio);
> -
> - return 0;
> -}
> -
> -int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
> - uint8_t bar_nr)
> -{
> - int ret;
> - char *name;
> -
> - /*
> - * Migration compatibility dictates that this remains a 4k
> - * BAR with the vector table in the lower half and PBA in
> - * the upper half. Do not use these elsewhere!
> - */
> -#define MSIX_EXCLUSIVE_BAR_SIZE 4096
> -#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0
> -#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2)
> -#define MSIX_EXCLUSIVE_CAP_OFFSET 0
> -
> - if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) {
> - return -EINVAL;
> - }
> -
> - name = g_strdup_printf("%s-msix", dev->name);
> - memory_region_init(&dev->msix_exclusive_bar, name,
> MSIX_EXCLUSIVE_BAR_SIZE);
> - g_free(name);
> -
> - ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
> - MSIX_EXCLUSIVE_BAR_TABLE_OFFSET,
> &dev->msix_exclusive_bar,
> - bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET,
> - MSIX_EXCLUSIVE_CAP_OFFSET);
> - if (ret) {
> - memory_region_destroy(&dev->msix_exclusive_bar);
> - return ret;
> - }
> -
> - pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY,
> - &dev->msix_exclusive_bar);
> -
> - return 0;
> -}
> -
> -static void msix_free_irq_entries(PCIDevice *dev)
> -{
> - int vector;
> -
> - for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
> - dev->msix_entry_used[vector] = 0;
> - msix_clr_pending(dev, vector);
> - }
> -}
> -
> -static void msix_clear_all_vectors(PCIDevice *dev)
> -{
> - int vector;
> -
> - for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
> - msix_clr_pending(dev, vector);
> - }
> -}
> -
> -/* Clean up resources for the device. */
> -void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion
> *pba_bar)
> -{
> - if (!msix_present(dev)) {
> - return;
> - }
> - pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
> - dev->msix_cap = 0;
> - msix_free_irq_entries(dev);
> - dev->msix_entries_nr = 0;
> - memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio);
> - memory_region_destroy(&dev->msix_pba_mmio);
> - g_free(dev->msix_pba);
> - dev->msix_pba = NULL;
> - memory_region_del_subregion(table_bar, &dev->msix_table_mmio);
> - memory_region_destroy(&dev->msix_table_mmio);
> - g_free(dev->msix_table);
> - dev->msix_table = NULL;
> - g_free(dev->msix_entry_used);
> - dev->msix_entry_used = NULL;
> - dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
> -}
> -
> -void msix_uninit_exclusive_bar(PCIDevice *dev)
> -{
> - if (msix_present(dev)) {
> - msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar);
> - memory_region_destroy(&dev->msix_exclusive_bar);
> - }
> -}
> -
> -void msix_save(PCIDevice *dev, QEMUFile *f)
> -{
> - unsigned n = dev->msix_entries_nr;
> -
> - if (!msix_present(dev)) {
> - return;
> - }
> -
> - qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
> - qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8);
> -}
> -
> -/* Should be called after restoring the config space. */
> -void msix_load(PCIDevice *dev, QEMUFile *f)
> -{
> - unsigned n = dev->msix_entries_nr;
> - unsigned int vector;
> -
> - if (!msix_present(dev)) {
> - return;
> - }
> -
> - msix_clear_all_vectors(dev);
> - qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
> - qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8);
> - msix_update_function_masked(dev);
> -
> - for (vector = 0; vector < n; vector++) {
> - msix_handle_mask_update(dev, vector, true);
> - }
> -}
> -
> -/* Does device support MSI-X? */
> -int msix_present(PCIDevice *dev)
> -{
> - return dev->cap_present & QEMU_PCI_CAP_MSIX;
> -}
> -
> -/* Is MSI-X enabled? */
> -int msix_enabled(PCIDevice *dev)
> -{
> - return (dev->cap_present & QEMU_PCI_CAP_MSIX) &&
> - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
> - MSIX_ENABLE_MASK);
> -}
> -
> -/* Send an MSI-X message */
> -void msix_notify(PCIDevice *dev, unsigned vector)
> -{
> - MSIMessage msg;
> -
> - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
> - return;
> - if (msix_is_masked(dev, vector)) {
> - msix_set_pending(dev, vector);
> - return;
> - }
> -
> - msg = msix_get_message(dev, vector);
> -
> - stl_le_phys(msg.address, msg.data);
> -}
> -
> -void msix_reset(PCIDevice *dev)
> -{
> - if (!msix_present(dev)) {
> - return;
> - }
> - msix_clear_all_vectors(dev);
> - dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
> - ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
> - memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE);
> - memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8);
> - msix_mask_all(dev, dev->msix_entries_nr);
> -}
> -
> -/* PCI spec suggests that devices make it possible for software to configure
> - * less vectors than supported by the device, but does not specify a standard
> - * mechanism for devices to do so.
> - *
> - * We support this by asking devices to declare vectors software is going to
> - * actually use, and checking this on the notification path. Devices that
> - * don't want to follow the spec suggestion can declare all vectors as used.
> */
> -
> -/* Mark vector as used. */
> -int msix_vector_use(PCIDevice *dev, unsigned vector)
> -{
> - if (vector >= dev->msix_entries_nr)
> - return -EINVAL;
> - dev->msix_entry_used[vector]++;
> - return 0;
> -}
> -
> -/* Mark vector as unused. */
> -void msix_vector_unuse(PCIDevice *dev, unsigned vector)
> -{
> - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) {
> - return;
> - }
> - if (--dev->msix_entry_used[vector]) {
> - return;
> - }
> - msix_clr_pending(dev, vector);
> -}
> -
> -void msix_unuse_all_vectors(PCIDevice *dev)
> -{
> - if (!msix_present(dev)) {
> - return;
> - }
> - msix_free_irq_entries(dev);
> -}
> -
> -unsigned int msix_nr_vectors_allocated(const PCIDevice *dev)
> -{
> - return dev->msix_entries_nr;
> -}
> -
> -static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector)
> -{
> - MSIMessage msg;
> -
> - if (msix_is_masked(dev, vector)) {
> - return 0;
> - }
> - msg = msix_get_message(dev, vector);
> - return dev->msix_vector_use_notifier(dev, vector, msg);
> -}
> -
> -static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int
> vector)
> -{
> - if (msix_is_masked(dev, vector)) {
> - return;
> - }
> - dev->msix_vector_release_notifier(dev, vector);
> -}
> -
> -int msix_set_vector_notifiers(PCIDevice *dev,
> - MSIVectorUseNotifier use_notifier,
> - MSIVectorReleaseNotifier release_notifier)
> -{
> - int vector, ret;
> -
> - assert(use_notifier && release_notifier);
> -
> - dev->msix_vector_use_notifier = use_notifier;
> - dev->msix_vector_release_notifier = release_notifier;
> -
> - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
> - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
> - for (vector = 0; vector < dev->msix_entries_nr; vector++) {
> - ret = msix_set_notifier_for_vector(dev, vector);
> - if (ret < 0) {
> - goto undo;
> - }
> - }
> - }
> - return 0;
> -
> -undo:
> - while (--vector >= 0) {
> - msix_unset_notifier_for_vector(dev, vector);
> - }
> - dev->msix_vector_use_notifier = NULL;
> - dev->msix_vector_release_notifier = NULL;
> - return ret;
> -}
> -
> -void msix_unset_vector_notifiers(PCIDevice *dev)
> -{
> - int vector;
> -
> - assert(dev->msix_vector_use_notifier &&
> - dev->msix_vector_release_notifier);
> -
> - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
> - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
> - for (vector = 0; vector < dev->msix_entries_nr; vector++) {
> - msix_unset_notifier_for_vector(dev, vector);
> - }
> - }
> - dev->msix_vector_use_notifier = NULL;
> - dev->msix_vector_release_notifier = NULL;
> -}
> diff --git a/hw/msix.h b/hw/msix.h
> deleted file mode 100644
> index 15211cb..0000000
> --- a/hw/msix.h
> +++ /dev/null
> @@ -1,41 +0,0 @@
> -#ifndef QEMU_MSIX_H
> -#define QEMU_MSIX_H
> -
> -#include "qemu-common.h"
> -#include "pci.h"
> -
> -void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg);
> -int msix_init(PCIDevice *dev, unsigned short nentries,
> - MemoryRegion *table_bar, uint8_t table_bar_nr,
> - unsigned table_offset, MemoryRegion *pba_bar,
> - uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos);
> -int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
> - uint8_t bar_nr);
> -
> -void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int
> len);
> -
> -void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar,
> - MemoryRegion *pba_bar);
> -void msix_uninit_exclusive_bar(PCIDevice *dev);
> -
> -unsigned int msix_nr_vectors_allocated(const PCIDevice *dev);
> -
> -void msix_save(PCIDevice *dev, QEMUFile *f);
> -void msix_load(PCIDevice *dev, QEMUFile *f);
> -
> -int msix_enabled(PCIDevice *dev);
> -int msix_present(PCIDevice *dev);
> -
> -int msix_vector_use(PCIDevice *dev, unsigned vector);
> -void msix_vector_unuse(PCIDevice *dev, unsigned vector);
> -void msix_unuse_all_vectors(PCIDevice *dev);
> -
> -void msix_notify(PCIDevice *dev, unsigned vector);
> -
> -void msix_reset(PCIDevice *dev);
> -
> -int msix_set_vector_notifiers(PCIDevice *dev,
> - MSIVectorUseNotifier use_notifier,
> - MSIVectorReleaseNotifier release_notifier);
> -void msix_unset_vector_notifiers(PCIDevice *dev);
> -#endif
> diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
> deleted file mode 100644
> index 0ca5546..0000000
> --- a/hw/pci-hotplug.c
> +++ /dev/null
> @@ -1,293 +0,0 @@
> -/*
> - * QEMU PCI hotplug support
> - *
> - * Copyright (c) 2004 Fabrice Bellard
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> - * of this software and associated documentation files (the "Software"), to
> deal
> - * in the Software without restriction, including without limitation the
> rights
> - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> - * copies of the Software, and to permit persons to whom the Software is
> - * furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM,
> - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> - * THE SOFTWARE.
> - */
> -
> -#include "hw.h"
> -#include "boards.h"
> -#include "pci.h"
> -#include "net.h"
> -#include "pc.h"
> -#include "monitor.h"
> -#include "scsi.h"
> -#include "virtio-blk.h"
> -#include "qemu-config.h"
> -#include "blockdev.h"
> -#include "error.h"
> -
> -#if defined(TARGET_I386)
> -static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
> - const char *devaddr,
> - const char *opts_str)
> -{
> - Error *local_err = NULL;
> - QemuOpts *opts;
> - PCIBus *bus;
> - int ret, devfn;
> -
> - bus = pci_get_bus_devfn(&devfn, devaddr);
> - if (!bus) {
> - monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
> - return NULL;
> - }
> - if (!((BusState*)bus)->allow_hotplug) {
> - monitor_printf(mon, "PCI bus doesn't support hotplug\n");
> - return NULL;
> - }
> -
> - opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "",
> 0);
> - if (!opts) {
> - return NULL;
> - }
> -
> - qemu_opt_set(opts, "type", "nic");
> -
> - ret = net_client_init(opts, 0, &local_err);
> - if (error_is_set(&local_err)) {
> - qerror_report_err(local_err);
> - error_free(local_err);
> - return NULL;
> - }
> - if (nd_table[ret].devaddr) {
> - monitor_printf(mon, "Parameter addr not supported\n");
> - return NULL;
> - }
> - return pci_nic_init(&nd_table[ret], "rtl8139", devaddr);
> -}
> -
> -static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
> - DriveInfo *dinfo, int printinfo)
> -{
> - SCSIBus *scsibus;
> - SCSIDevice *scsidev;
> -
> - scsibus = (SCSIBus *)
> - object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)),
> - TYPE_SCSI_BUS);
> - if (!scsibus) {
> - error_report("Device is not a SCSI adapter");
> - return -1;
> - }
> -
> - /*
> - * drive_init() tries to find a default for dinfo->unit. Doesn't
> - * work at all for hotplug though as we assign the device to a
> - * specific bus instead of the first bus with spare scsi ids.
> - *
> - * Ditch the calculated value and reload from option string (if
> - * specified).
> - */
> - dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
> - dinfo->bus = scsibus->busnr;
> - scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit,
> - false, -1);
> - if (!scsidev) {
> - return -1;
> - }
> - dinfo->unit = scsidev->id;
> -
> - if (printinfo)
> - monitor_printf(mon, "OK bus %d, unit %d\n",
> - scsibus->busnr, scsidev->id);
> - return 0;
> -}
> -
> -int pci_drive_hot_add(Monitor *mon, const QDict *qdict,
> - DriveInfo *dinfo, int type)
> -{
> - int dom, pci_bus;
> - unsigned slot;
> - PCIDevice *dev;
> - const char *pci_addr = qdict_get_str(qdict, "pci_addr");
> -
> - switch (type) {
> - case IF_SCSI:
> - if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) {
> - goto err;
> - }
> - dev = pci_find_device(pci_find_root_bus(dom), pci_bus,
> - PCI_DEVFN(slot, 0));
> - if (!dev) {
> - monitor_printf(mon, "no pci device with address %s\n", pci_addr);
> - goto err;
> - }
> - if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) {
> - goto err;
> - }
> - break;
> - default:
> - monitor_printf(mon, "Can't hot-add drive to type %d\n", type);
> - goto err;
> - }
> -
> - return 0;
> -err:
> - return -1;
> -}
> -
> -static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
> - const char *devaddr,
> - const char *opts)
> -{
> - PCIDevice *dev;
> - DriveInfo *dinfo = NULL;
> - int type = -1;
> - char buf[128];
> - PCIBus *bus;
> - int devfn;
> -
> - if (get_param_value(buf, sizeof(buf), "if", opts)) {
> - if (!strcmp(buf, "scsi"))
> - type = IF_SCSI;
> - else if (!strcmp(buf, "virtio")) {
> - type = IF_VIRTIO;
> - } else {
> - monitor_printf(mon, "type %s not a hotpluggable PCI device.\n",
> buf);
> - return NULL;
> - }
> - } else {
> - monitor_printf(mon, "no if= specified\n");
> - return NULL;
> - }
> -
> - if (get_param_value(buf, sizeof(buf), "file", opts)) {
> - dinfo = add_init_drive(opts);
> - if (!dinfo)
> - return NULL;
> - if (dinfo->devaddr) {
> - monitor_printf(mon, "Parameter addr not supported\n");
> - return NULL;
> - }
> - } else {
> - dinfo = NULL;
> - }
> -
> - bus = pci_get_bus_devfn(&devfn, devaddr);
> - if (!bus) {
> - monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
> - return NULL;
> - }
> - if (!((BusState*)bus)->allow_hotplug) {
> - monitor_printf(mon, "PCI bus doesn't support hotplug\n");
> - return NULL;
> - }
> -
> - switch (type) {
> - case IF_SCSI:
> - dev = pci_create(bus, devfn, "lsi53c895a");
> - if (qdev_init(&dev->qdev) < 0)
> - dev = NULL;
> - if (dev && dinfo) {
> - if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) {
> - qdev_unplug(&dev->qdev, NULL);
> - dev = NULL;
> - }
> - }
> - break;
> - case IF_VIRTIO:
> - if (!dinfo) {
> - monitor_printf(mon, "virtio requires a backing file/device.\n");
> - return NULL;
> - }
> - dev = pci_create(bus, devfn, "virtio-blk-pci");
> - if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
> - qdev_free(&dev->qdev);
> - dev = NULL;
> - break;
> - }
> - if (qdev_init(&dev->qdev) < 0)
> - dev = NULL;
> - break;
> - default:
> - dev = NULL;
> - }
> - return dev;
> -}
> -
> -void pci_device_hot_add(Monitor *mon, const QDict *qdict)
> -{
> - PCIDevice *dev = NULL;
> - const char *pci_addr = qdict_get_str(qdict, "pci_addr");
> - const char *type = qdict_get_str(qdict, "type");
> - const char *opts = qdict_get_try_str(qdict, "opts");
> -
> - /* strip legacy tag */
> - if (!strncmp(pci_addr, "pci_addr=", 9)) {
> - pci_addr += 9;
> - }
> -
> - if (!opts) {
> - opts = "";
> - }
> -
> - if (!strcmp(pci_addr, "auto"))
> - pci_addr = NULL;
> -
> - if (strcmp(type, "nic") == 0) {
> - dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
> - } else if (strcmp(type, "storage") == 0) {
> - dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
> - } else {
> - monitor_printf(mon, "invalid type: %s\n", type);
> - }
> -
> - if (dev) {
> - monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
> - pci_find_domain(dev->bus),
> - pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
> - PCI_FUNC(dev->devfn));
> - } else
> - monitor_printf(mon, "failed to add %s\n", opts);
> -}
> -#endif
> -
> -static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
> -{
> - PCIDevice *d;
> - int dom, bus;
> - unsigned slot;
> - Error *local_err = NULL;
> -
> - if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
> - return -1;
> - }
> -
> - d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0));
> - if (!d) {
> - monitor_printf(mon, "slot %d empty\n", slot);
> - return -1;
> - }
> -
> - qdev_unplug(&d->qdev, &local_err);
> - if (error_is_set(&local_err)) {
> - monitor_printf(mon, "%s\n", error_get_pretty(local_err));
> - error_free(local_err);
> - return -1;
> - }
> -
> - return 0;
> -}
> -
> -void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict)
> -{
> - pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
> -}
> diff --git a/hw/pci-stub.c b/hw/pci-stub.c
> deleted file mode 100644
> index 134c448..0000000
> --- a/hw/pci-stub.c
> +++ /dev/null
> @@ -1,47 +0,0 @@
> -/*
> - * PCI stubs for platforms that don't support pci bus.
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "sysemu.h"
> -#include "monitor.h"
> -#include "pci.h"
> -#include "qmp-commands.h"
> -
> -PciInfoList *qmp_query_pci(Error **errp)
> -{
> - error_set(errp, QERR_UNSUPPORTED);
> - return NULL;
> -}
> -
> -static void pci_error_message(Monitor *mon)
> -{
> - monitor_printf(mon, "PCI devices not supported\n");
> -}
> -
> -int do_pcie_aer_inject_error(Monitor *mon,
> - const QDict *qdict, QObject **ret_data)
> -{
> - pci_error_message(mon);
> - return -ENOSYS;
> -}
> -
> -void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
> -{
> - pci_error_message(mon);
> -}
> diff --git a/hw/pci.c b/hw/pci.c
> deleted file mode 100644
> index 97a0cd7..0000000
> --- a/hw/pci.c
> +++ /dev/null
> @@ -1,2168 +0,0 @@
> -/*
> - * QEMU PCI bus manager
> - *
> - * Copyright (c) 2004 Fabrice Bellard
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> - * of this software and associated documentation files (the "Software"), to
> deal
> - * in the Software without restriction, including without limitation the
> rights
> - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> - * copies of the Software, and to permit persons to whom the Software is
> - * furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM,
> - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> - * THE SOFTWARE.
> - */
> -#include "hw.h"
> -#include "pci.h"
> -#include "pci_bridge.h"
> -#include "pci_internals.h"
> -#include "monitor.h"
> -#include "net.h"
> -#include "sysemu.h"
> -#include "loader.h"
> -#include "range.h"
> -#include "qmp-commands.h"
> -#include "msi.h"
> -#include "msix.h"
> -#include "exec-memory.h"
> -
> -//#define DEBUG_PCI
> -#ifdef DEBUG_PCI
> -# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
> -#else
> -# define PCI_DPRINTF(format, ...) do { } while (0)
> -#endif
> -
> -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
> -static char *pcibus_get_dev_path(DeviceState *dev);
> -static char *pcibus_get_fw_dev_path(DeviceState *dev);
> -static int pcibus_reset(BusState *qbus);
> -
> -static Property pci_props[] = {
> - DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
> - DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
> - DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1),
> - DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
> - QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
> - DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
> - QEMU_PCI_CAP_SERR_BITNR, true),
> - DEFINE_PROP_END_OF_LIST()
> -};
> -
> -static void pci_bus_class_init(ObjectClass *klass, void *data)
> -{
> - BusClass *k = BUS_CLASS(klass);
> -
> - k->print_dev = pcibus_dev_print;
> - k->get_dev_path = pcibus_get_dev_path;
> - k->get_fw_dev_path = pcibus_get_fw_dev_path;
> - k->reset = pcibus_reset;
> -}
> -
> -static const TypeInfo pci_bus_info = {
> - .name = TYPE_PCI_BUS,
> - .parent = TYPE_BUS,
> - .instance_size = sizeof(PCIBus),
> - .class_init = pci_bus_class_init,
> -};
> -
> -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
> -static void pci_update_mappings(PCIDevice *d);
> -static void pci_set_irq(void *opaque, int irq_num, int level);
> -static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom);
> -static void pci_del_option_rom(PCIDevice *pdev);
> -
> -static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
> -static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
> -
> -struct PCIHostBus {
> - int domain;
> - struct PCIBus *bus;
> - QLIST_ENTRY(PCIHostBus) next;
> -};
> -static QLIST_HEAD(, PCIHostBus) host_buses;
> -
> -static const VMStateDescription vmstate_pcibus = {
> - .name = "PCIBUS",
> - .version_id = 1,
> - .minimum_version_id = 1,
> - .minimum_version_id_old = 1,
> - .fields = (VMStateField []) {
> - VMSTATE_INT32_EQUAL(nirq, PCIBus),
> - VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32,
> int32_t),
> - VMSTATE_END_OF_LIST()
> - }
> -};
> -static int pci_bar(PCIDevice *d, int reg)
> -{
> - uint8_t type;
> -
> - if (reg != PCI_ROM_SLOT)
> - return PCI_BASE_ADDRESS_0 + reg * 4;
> -
> - type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
> - return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 :
> PCI_ROM_ADDRESS;
> -}
> -
> -static inline int pci_irq_state(PCIDevice *d, int irq_num)
> -{
> - return (d->irq_state >> irq_num) & 0x1;
> -}
> -
> -static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level)
> -{
> - d->irq_state &= ~(0x1 << irq_num);
> - d->irq_state |= level << irq_num;
> -}
> -
> -static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
> -{
> - PCIBus *bus;
> - for (;;) {
> - bus = pci_dev->bus;
> - irq_num = bus->map_irq(pci_dev, irq_num);
> - if (bus->set_irq)
> - break;
> - pci_dev = bus->parent_dev;
> - }
> - bus->irq_count[irq_num] += change;
> - bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
> -}
> -
> -int pci_bus_get_irq_level(PCIBus *bus, int irq_num)
> -{
> - assert(irq_num >= 0);
> - assert(irq_num < bus->nirq);
> - return !!bus->irq_count[irq_num];
> -}
> -
> -/* Update interrupt status bit in config space on interrupt
> - * state change. */
> -static void pci_update_irq_status(PCIDevice *dev)
> -{
> - if (dev->irq_state) {
> - dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT;
> - } else {
> - dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
> - }
> -}
> -
> -void pci_device_deassert_intx(PCIDevice *dev)
> -{
> - int i;
> - for (i = 0; i < PCI_NUM_PINS; ++i) {
> - qemu_set_irq(dev->irq[i], 0);
> - }
> -}
> -
> -/*
> - * This function is called on #RST and FLR.
> - * FLR if PCI_EXP_DEVCTL_BCR_FLR is set
> - */
> -void pci_device_reset(PCIDevice *dev)
> -{
> - int r;
> -
> - qdev_reset_all(&dev->qdev);
> -
> - dev->irq_state = 0;
> - pci_update_irq_status(dev);
> - pci_device_deassert_intx(dev);
> - /* Clear all writable bits */
> - pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
> - pci_get_word(dev->wmask + PCI_COMMAND) |
> - pci_get_word(dev->w1cmask + PCI_COMMAND));
> - pci_word_test_and_clear_mask(dev->config + PCI_STATUS,
> - pci_get_word(dev->wmask + PCI_STATUS) |
> - pci_get_word(dev->w1cmask + PCI_STATUS));
> - dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
> - dev->config[PCI_INTERRUPT_LINE] = 0x0;
> - for (r = 0; r < PCI_NUM_REGIONS; ++r) {
> - PCIIORegion *region = &dev->io_regions[r];
> - if (!region->size) {
> - continue;
> - }
> -
> - if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) &&
> - region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
> - pci_set_quad(dev->config + pci_bar(dev, r), region->type);
> - } else {
> - pci_set_long(dev->config + pci_bar(dev, r), region->type);
> - }
> - }
> - pci_update_mappings(dev);
> -
> - msi_reset(dev);
> - msix_reset(dev);
> -}
> -
> -/*
> - * Trigger pci bus reset under a given bus.
> - * To be called on RST# assert.
> - */
> -void pci_bus_reset(PCIBus *bus)
> -{
> - int i;
> -
> - for (i = 0; i < bus->nirq; i++) {
> - bus->irq_count[i] = 0;
> - }
> - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
> - if (bus->devices[i]) {
> - pci_device_reset(bus->devices[i]);
> - }
> - }
> -}
> -
> -static int pcibus_reset(BusState *qbus)
> -{
> - pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus));
> -
> - /* topology traverse is done by pci_bus_reset().
> - Tell qbus/qdev walker not to traverse the tree */
> - return 1;
> -}
> -
> -static void pci_host_bus_register(int domain, PCIBus *bus)
> -{
> - struct PCIHostBus *host;
> - host = g_malloc0(sizeof(*host));
> - host->domain = domain;
> - host->bus = bus;
> - QLIST_INSERT_HEAD(&host_buses, host, next);
> -}
> -
> -PCIBus *pci_find_root_bus(int domain)
> -{
> - struct PCIHostBus *host;
> -
> - QLIST_FOREACH(host, &host_buses, next) {
> - if (host->domain == domain) {
> - return host->bus;
> - }
> - }
> -
> - return NULL;
> -}
> -
> -int pci_find_domain(const PCIBus *bus)
> -{
> - PCIDevice *d;
> - struct PCIHostBus *host;
> -
> - /* obtain root bus */
> - while ((d = bus->parent_dev) != NULL) {
> - bus = d->bus;
> - }
> -
> - QLIST_FOREACH(host, &host_buses, next) {
> - if (host->bus == bus) {
> - return host->domain;
> - }
> - }
> -
> - abort(); /* should not be reached */
> - return -1;
> -}
> -
> -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
> - const char *name,
> - MemoryRegion *address_space_mem,
> - MemoryRegion *address_space_io,
> - uint8_t devfn_min)
> -{
> - qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name);
> - assert(PCI_FUNC(devfn_min) == 0);
> - bus->devfn_min = devfn_min;
> - bus->address_space_mem = address_space_mem;
> - bus->address_space_io = address_space_io;
> -
> - /* host bridge */
> - QLIST_INIT(&bus->child);
> - pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported
> */
> -
> - vmstate_register(NULL, -1, &vmstate_pcibus, bus);
> -}
> -
> -PCIBus *pci_bus_new(DeviceState *parent, const char *name,
> - MemoryRegion *address_space_mem,
> - MemoryRegion *address_space_io,
> - uint8_t devfn_min)
> -{
> - PCIBus *bus;
> -
> - bus = g_malloc0(sizeof(*bus));
> - pci_bus_new_inplace(bus, parent, name, address_space_mem,
> - address_space_io, devfn_min);
> - OBJECT(bus)->free = g_free;
> - return bus;
> -}
> -
> -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn
> map_irq,
> - void *irq_opaque, int nirq)
> -{
> - bus->set_irq = set_irq;
> - bus->map_irq = map_irq;
> - bus->irq_opaque = irq_opaque;
> - bus->nirq = nirq;
> - bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0]));
> -}
> -
> -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
> -{
> - bus->qbus.allow_hotplug = 1;
> - bus->hotplug = hotplug;
> - bus->hotplug_qdev = qdev;
> -}
> -
> -PCIBus *pci_register_bus(DeviceState *parent, const char *name,
> - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
> - void *irq_opaque,
> - MemoryRegion *address_space_mem,
> - MemoryRegion *address_space_io,
> - uint8_t devfn_min, int nirq)
> -{
> - PCIBus *bus;
> -
> - bus = pci_bus_new(parent, name, address_space_mem,
> - address_space_io, devfn_min);
> - pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
> - return bus;
> -}
> -
> -int pci_bus_num(PCIBus *s)
> -{
> - if (!s->parent_dev)
> - return 0; /* pci host bridge */
> - return s->parent_dev->config[PCI_SECONDARY_BUS];
> -}
> -
> -static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
> -{
> - PCIDevice *s = container_of(pv, PCIDevice, config);
> - uint8_t *config;
> - int i;
> -
> - assert(size == pci_config_size(s));
> - config = g_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] & ~s->w1cmask[i]) {
> - g_free(config);
> - return -EINVAL;
> - }
> - }
> - memcpy(s->config, config, size);
> -
> - pci_update_mappings(s);
> -
> - memory_region_set_enabled(&s->bus_master_enable_region,
> - pci_get_word(s->config + PCI_COMMAND)
> - & PCI_COMMAND_MASTER);
> -
> - g_free(config);
> - return 0;
> -}
> -
> -/* just put buffer */
> -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);
> -}
> -
> -static VMStateInfo vmstate_info_pci_config = {
> - .name = "pci config",
> - .get = get_pci_config_device,
> - .put = put_pci_config_device,
> -};
> -
> -static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
> -{
> - PCIDevice *s = container_of(pv, PCIDevice, irq_state);
> - uint32_t irq_state[PCI_NUM_PINS];
> - int i;
> - for (i = 0; i < PCI_NUM_PINS; ++i) {
> - irq_state[i] = qemu_get_be32(f);
> - if (irq_state[i] != 0x1 && irq_state[i] != 0) {
> - fprintf(stderr, "irq state %d: must be 0 or 1.\n",
> - irq_state[i]);
> - return -EINVAL;
> - }
> - }
> -
> - for (i = 0; i < PCI_NUM_PINS; ++i) {
> - pci_set_irq_state(s, i, irq_state[i]);
> - }
> -
> - return 0;
> -}
> -
> -static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size)
> -{
> - int i;
> - PCIDevice *s = container_of(pv, PCIDevice, irq_state);
> -
> - for (i = 0; i < PCI_NUM_PINS; ++i) {
> - qemu_put_be32(f, pci_irq_state(s, i));
> - }
> -}
> -
> -static VMStateInfo vmstate_info_pci_irq_state = {
> - .name = "pci irq state",
> - .get = get_pci_irq_state,
> - .put = put_pci_irq_state,
> -};
> -
> -const VMStateDescription vmstate_pci_device = {
> - .name = "PCIDevice",
> - .version_id = 2,
> - .minimum_version_id = 1,
> - .minimum_version_id_old = 1,
> - .fields = (VMStateField []) {
> - VMSTATE_INT32_LE(version_id, PCIDevice),
> - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
> - vmstate_info_pci_config,
> - PCI_CONFIG_SPACE_SIZE),
> - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
> - vmstate_info_pci_irq_state,
> - PCI_NUM_PINS * sizeof(int32_t)),
> - VMSTATE_END_OF_LIST()
> - }
> -};
> -
> -const VMStateDescription vmstate_pcie_device = {
> - .name = "PCIEDevice",
> - .version_id = 2,
> - .minimum_version_id = 1,
> - .minimum_version_id_old = 1,
> - .fields = (VMStateField []) {
> - VMSTATE_INT32_LE(version_id, PCIDevice),
> - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
> - vmstate_info_pci_config,
> - PCIE_CONFIG_SPACE_SIZE),
> - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
> - vmstate_info_pci_irq_state,
> - PCI_NUM_PINS * sizeof(int32_t)),
> - 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)
> -{
> - /* Clear interrupt status bit: it is implicit
> - * in irq_state which we are saving.
> - * This makes us compatible with old devices
> - * which never set or clear this bit. */
> - s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
> - vmstate_save_state(f, pci_get_vmstate(s), s);
> - /* Restore the interrupt status bit. */
> - pci_update_irq_status(s);
> -}
> -
> -int pci_device_load(PCIDevice *s, QEMUFile *f)
> -{
> - int ret;
> - ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
> - /* Restore the interrupt status bit. */
> - pci_update_irq_status(s);
> - return ret;
> -}
> -
> -static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
> -{
> - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
> - pci_default_sub_vendor_id);
> - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
> - pci_default_sub_device_id);
> -}
> -
> -/*
> - * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
> - * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
> - */
> -static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
> - unsigned int *slotp, unsigned int *funcp)
> -{
> - const char *p;
> - char *e;
> - unsigned long val;
> - unsigned long dom = 0, bus = 0;
> - unsigned int slot = 0;
> - unsigned int func = 0;
> -
> - p = addr;
> - val = strtoul(p, &e, 16);
> - if (e == p)
> - return -1;
> - if (*e == ':') {
> - bus = val;
> - p = e + 1;
> - val = strtoul(p, &e, 16);
> - if (e == p)
> - return -1;
> - if (*e == ':') {
> - dom = bus;
> - bus = val;
> - p = e + 1;
> - val = strtoul(p, &e, 16);
> - if (e == p)
> - return -1;
> - }
> - }
> -
> - slot = val;
> -
> - if (funcp != NULL) {
> - if (*e != '.')
> - return -1;
> -
> - p = e + 1;
> - val = strtoul(p, &e, 16);
> - if (e == p)
> - return -1;
> -
> - func = val;
> - }
> -
> - /* if funcp == NULL func is 0 */
> - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
> - return -1;
> -
> - if (*e)
> - return -1;
> -
> - *domp = dom;
> - *busp = bus;
> - *slotp = slot;
> - if (funcp != NULL)
> - *funcp = func;
> - return 0;
> -}
> -
> -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
> - unsigned *slotp)
> -{
> - /* strip legacy tag */
> - if (!strncmp(addr, "pci_addr=", 9)) {
> - addr += 9;
> - }
> - if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) {
> - monitor_printf(mon, "Invalid pci address\n");
> - return -1;
> - }
> - return 0;
> -}
> -
> -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
> -{
> - int dom, bus;
> - unsigned slot;
> -
> - if (!devaddr) {
> - *devfnp = -1;
> - return pci_find_bus_nr(pci_find_root_bus(0), 0);
> - }
> -
> - if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
> - return NULL;
> - }
> -
> - *devfnp = PCI_DEVFN(slot, 0);
> - return pci_find_bus_nr(pci_find_root_bus(dom), bus);
> -}
> -
> -static void pci_init_cmask(PCIDevice *dev)
> -{
> - pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff);
> - pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff);
> - dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST;
> - dev->cmask[PCI_REVISION_ID] = 0xff;
> - dev->cmask[PCI_CLASS_PROG] = 0xff;
> - pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff);
> - dev->cmask[PCI_HEADER_TYPE] = 0xff;
> - dev->cmask[PCI_CAPABILITY_LIST] = 0xff;
> -}
> -
> -static void pci_init_wmask(PCIDevice *dev)
> -{
> - int config_size = pci_config_size(dev);
> -
> - dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff;
> - dev->wmask[PCI_INTERRUPT_LINE] = 0xff;
> - pci_set_word(dev->wmask + PCI_COMMAND,
> - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
> - PCI_COMMAND_INTX_DISABLE);
> - if (dev->cap_present & QEMU_PCI_CAP_SERR) {
> - pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND,
> PCI_COMMAND_SERR);
> - }
> -
> - memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
> - config_size - PCI_CONFIG_HEADER_SIZE);
> -}
> -
> -static void pci_init_w1cmask(PCIDevice *dev)
> -{
> - /*
> - * Note: It's okay to set w1cmask even for readonly bits as
> - * long as their value is hardwired to 0.
> - */
> - pci_set_word(dev->w1cmask + PCI_STATUS,
> - PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT |
> - PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT |
> - PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
> -}
> -
> -static void pci_init_mask_bridge(PCIDevice *d)
> -{
> - /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and
> - PCI_SEC_LETENCY_TIMER */
> - memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4);
> -
> - /* base and limit */
> - d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff;
> - d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff;
> - pci_set_word(d->wmask + PCI_MEMORY_BASE,
> - PCI_MEMORY_RANGE_MASK & 0xffff);
> - pci_set_word(d->wmask + PCI_MEMORY_LIMIT,
> - PCI_MEMORY_RANGE_MASK & 0xffff);
> - pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE,
> - PCI_PREF_RANGE_MASK & 0xffff);
> - pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT,
> - PCI_PREF_RANGE_MASK & 0xffff);
> -
> - /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */
> - memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);
> -
> - /* Supported memory and i/o types */
> - d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16;
> - d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16;
> - pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
> - PCI_PREF_RANGE_TYPE_64);
> - pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
> - PCI_PREF_RANGE_TYPE_64);
> -
> -/* TODO: add this define to pci_regs.h in linux and then in qemu. */
> -#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */
> -#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard
> timer */
> -#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */
> -#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */
> -#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable
> */
> - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
> - PCI_BRIDGE_CTL_PARITY |
> - PCI_BRIDGE_CTL_SERR |
> - PCI_BRIDGE_CTL_ISA |
> - PCI_BRIDGE_CTL_VGA |
> - PCI_BRIDGE_CTL_VGA_16BIT |
> - PCI_BRIDGE_CTL_MASTER_ABORT |
> - PCI_BRIDGE_CTL_BUS_RESET |
> - PCI_BRIDGE_CTL_FAST_BACK |
> - PCI_BRIDGE_CTL_DISCARD |
> - PCI_BRIDGE_CTL_SEC_DISCARD |
> - PCI_BRIDGE_CTL_DISCARD_SERR);
> - /* Below does not do anything as we never set this bit, put here for
> - * completeness. */
> - pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL,
> - PCI_BRIDGE_CTL_DISCARD_STATUS);
> - d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK;
> - d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK;
> - pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE,
> - PCI_PREF_RANGE_TYPE_MASK);
> - pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT,
> - PCI_PREF_RANGE_TYPE_MASK);
> -}
> -
> -static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
> -{
> - uint8_t slot = PCI_SLOT(dev->devfn);
> - uint8_t func;
> -
> - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
> - dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
> - }
> -
> - /*
> - * multifunction bit is interpreted in two ways as follows.
> - * - all functions must set the bit to 1.
> - * Example: Intel X53
> - * - function 0 must set the bit, but the rest function (> 0)
> - * is allowed to leave the bit to 0.
> - * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10,
> - *
> - * So OS (at least Linux) checks the bit of only function 0,
> - * and doesn't see the bit of function > 0.
> - *
> - * The below check allows both interpretation.
> - */
> - if (PCI_FUNC(dev->devfn)) {
> - PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)];
> - if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) {
> - /* function 0 should set multifunction bit */
> - error_report("PCI: single function device can't be populated "
> - "in function %x.%x", slot, PCI_FUNC(dev->devfn));
> - return -1;
> - }
> - return 0;
> - }
> -
> - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
> - return 0;
> - }
> - /* function 0 indicates single function, so function > 0 must be NULL */
> - for (func = 1; func < PCI_FUNC_MAX; ++func) {
> - if (bus->devices[PCI_DEVFN(slot, func)]) {
> - error_report("PCI: %x.0 indicates single function, "
> - "but %x.%x is already populated.",
> - slot, slot, func);
> - return -1;
> - }
> - }
> - return 0;
> -}
> -
> -static void pci_config_alloc(PCIDevice *pci_dev)
> -{
> - int config_size = pci_config_size(pci_dev);
> -
> - pci_dev->config = g_malloc0(config_size);
> - pci_dev->cmask = g_malloc0(config_size);
> - pci_dev->wmask = g_malloc0(config_size);
> - pci_dev->w1cmask = g_malloc0(config_size);
> - pci_dev->used = g_malloc0(config_size);
> -}
> -
> -static void pci_config_free(PCIDevice *pci_dev)
> -{
> - g_free(pci_dev->config);
> - g_free(pci_dev->cmask);
> - g_free(pci_dev->wmask);
> - g_free(pci_dev->w1cmask);
> - g_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)
> -{
> - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
> - PCIConfigReadFunc *config_read = pc->config_read;
> - PCIConfigWriteFunc *config_write = pc->config_write;
> -
> - if (devfn < 0) {
> - for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
> - devfn += PCI_FUNC_MAX) {
> - if (!bus->devices[devfn])
> - goto found;
> - }
> - error_report("PCI: no slot/function available for %s, all in use",
> name);
> - return NULL;
> - found: ;
> - } else if (bus->devices[devfn]) {
> - error_report("PCI: slot %d function %d not available for %s, in use
> by %s",
> - PCI_SLOT(devfn), PCI_FUNC(devfn), name,
> bus->devices[devfn]->name);
> - return NULL;
> - }
> - pci_dev->bus = bus;
> - if (bus->dma_context_fn) {
> - pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque,
> devfn);
> - } else {
> - /* FIXME: Make dma_context_fn use MemoryRegions instead, so this
> path is
> - * taken unconditionally */
> - /* FIXME: inherit memory region from bus creator */
> - memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus
> master",
> - get_system_memory(), 0,
> - memory_region_size(get_system_memory()));
> - memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
> - address_space_init(&pci_dev->bus_master_as,
> &pci_dev->bus_master_enable_region);
> - pci_dev->dma = g_new(DMAContext, 1);
> - dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL,
> NULL);
> - }
> - pci_dev->devfn = devfn;
> - pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
> - pci_dev->irq_state = 0;
> - pci_config_alloc(pci_dev);
> -
> - pci_config_set_vendor_id(pci_dev->config, pc->vendor_id);
> - pci_config_set_device_id(pci_dev->config, pc->device_id);
> - pci_config_set_revision(pci_dev->config, pc->revision);
> - pci_config_set_class(pci_dev->config, pc->class_id);
> -
> - if (!pc->is_bridge) {
> - if (pc->subsystem_vendor_id || pc->subsystem_id) {
> - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
> - pc->subsystem_vendor_id);
> - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
> - pc->subsystem_id);
> - } else {
> - pci_set_default_subsystem_id(pci_dev);
> - }
> - } else {
> - /* subsystem_vendor_id/subsystem_id are only for header type 0 */
> - assert(!pc->subsystem_vendor_id);
> - assert(!pc->subsystem_id);
> - }
> - pci_init_cmask(pci_dev);
> - pci_init_wmask(pci_dev);
> - pci_init_w1cmask(pci_dev);
> - if (pc->is_bridge) {
> - pci_init_mask_bridge(pci_dev);
> - }
> - if (pci_init_multifunction(bus, pci_dev)) {
> - pci_config_free(pci_dev);
> - return NULL;
> - }
> -
> - if (!config_read)
> - config_read = pci_default_read_config;
> - if (!config_write)
> - config_write = pci_default_write_config;
> - pci_dev->config_read = config_read;
> - pci_dev->config_write = config_write;
> - bus->devices[devfn] = pci_dev;
> - pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS);
> - pci_dev->version_id = 2; /* Current pci device vmstate version */
> - return pci_dev;
> -}
> -
> -static void do_pci_unregister_device(PCIDevice *pci_dev)
> -{
> - qemu_free_irqs(pci_dev->irq);
> - pci_dev->bus->devices[pci_dev->devfn] = NULL;
> - pci_config_free(pci_dev);
> -
> - if (!pci_dev->bus->dma_context_fn) {
> - address_space_destroy(&pci_dev->bus_master_as);
> - memory_region_destroy(&pci_dev->bus_master_enable_region);
> - g_free(pci_dev->dma);
> - pci_dev->dma = NULL;
> - }
> -}
> -
> -static void pci_unregister_io_regions(PCIDevice *pci_dev)
> -{
> - PCIIORegion *r;
> - int i;
> -
> - for(i = 0; i < PCI_NUM_REGIONS; i++) {
> - r = &pci_dev->io_regions[i];
> - if (!r->size || r->addr == PCI_BAR_UNMAPPED)
> - continue;
> - memory_region_del_subregion(r->address_space, r->memory);
> - }
> -}
> -
> -static int pci_unregister_device(DeviceState *dev)
> -{
> - PCIDevice *pci_dev = PCI_DEVICE(dev);
> - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
> -
> - pci_unregister_io_regions(pci_dev);
> - pci_del_option_rom(pci_dev);
> -
> - if (pc->exit) {
> - pc->exit(pci_dev);
> - }
> -
> - do_pci_unregister_device(pci_dev);
> - return 0;
> -}
> -
> -void pci_register_bar(PCIDevice *pci_dev, int region_num,
> - uint8_t type, MemoryRegion *memory)
> -{
> - PCIIORegion *r;
> - uint32_t addr;
> - uint64_t wmask;
> - pcibus_t size = memory_region_size(memory);
> -
> - assert(region_num >= 0);
> - assert(region_num < PCI_NUM_REGIONS);
> - if (size & (size-1)) {
> - fprintf(stderr, "ERROR: PCI region size must be pow2 "
> - "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);
> - exit(1);
> - }
> -
> - r = &pci_dev->io_regions[region_num];
> - r->addr = PCI_BAR_UNMAPPED;
> - r->size = size;
> - r->type = type;
> - r->memory = NULL;
> -
> - wmask = ~(size - 1);
> - addr = pci_bar(pci_dev, region_num);
> - if (region_num == PCI_ROM_SLOT) {
> - /* ROM enable bit is writable */
> - wmask |= PCI_ROM_ADDRESS_ENABLE;
> - }
> - pci_set_long(pci_dev->config + addr, type);
> - if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
> - r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
> - pci_set_quad(pci_dev->wmask + addr, wmask);
> - pci_set_quad(pci_dev->cmask + addr, ~0ULL);
> - } else {
> - pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
> - pci_set_long(pci_dev->cmask + addr, 0xffffffff);
> - }
> - pci_dev->io_regions[region_num].memory = memory;
> - pci_dev->io_regions[region_num].address_space
> - = type & PCI_BASE_ADDRESS_SPACE_IO
> - ? pci_dev->bus->address_space_io
> - : pci_dev->bus->address_space_mem;
> -}
> -
> -pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
> -{
> - return pci_dev->io_regions[region_num].addr;
> -}
> -
> -static pcibus_t pci_bar_address(PCIDevice *d,
> - int reg, uint8_t type, pcibus_t size)
> -{
> - pcibus_t new_addr, last_addr;
> - int bar = pci_bar(d, reg);
> - uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);
> -
> - if (type & PCI_BASE_ADDRESS_SPACE_IO) {
> - if (!(cmd & PCI_COMMAND_IO)) {
> - return PCI_BAR_UNMAPPED;
> - }
> - new_addr = pci_get_long(d->config + bar) & ~(size - 1);
> - last_addr = new_addr + size - 1;
> - /* NOTE: we have only 64K ioports on PC */
> - if (last_addr <= new_addr || new_addr == 0 || last_addr >
> UINT16_MAX) {
> - return PCI_BAR_UNMAPPED;
> - }
> - return new_addr;
> - }
> -
> - if (!(cmd & PCI_COMMAND_MEMORY)) {
> - return PCI_BAR_UNMAPPED;
> - }
> - if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
> - new_addr = pci_get_quad(d->config + bar);
> - } else {
> - new_addr = pci_get_long(d->config + bar);
> - }
> - /* the ROM slot has a specific enable bit */
> - if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) {
> - return PCI_BAR_UNMAPPED;
> - }
> - new_addr &= ~(size - 1);
> - last_addr = new_addr + size - 1;
> - /* NOTE: we do not support wrapping */
> - /* XXX: as we cannot support really dynamic
> - mappings, we handle specific values as invalid
> - mappings. */
> - if (last_addr <= new_addr || new_addr == 0 ||
> - last_addr == PCI_BAR_UNMAPPED) {
> - return PCI_BAR_UNMAPPED;
> - }
> -
> - /* Now pcibus_t is 64bit.
> - * Check if 32 bit BAR wraps around explicitly.
> - * Without this, PC ide doesn't work well.
> - * TODO: remove this work around.
> - */
> - if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) {
> - return PCI_BAR_UNMAPPED;
> - }
> -
> - /*
> - * OS is allowed to set BAR beyond its addressable
> - * bits. For example, 32 bit OS can set 64bit bar
> - * to >4G. Check it. TODO: we might need to support
> - * it in the future for e.g. PAE.
> - */
> - if (last_addr >= HWADDR_MAX) {
> - return PCI_BAR_UNMAPPED;
> - }
> -
> - return new_addr;
> -}
> -
> -static void pci_update_mappings(PCIDevice *d)
> -{
> - PCIIORegion *r;
> - int i;
> - pcibus_t new_addr;
> -
> - for(i = 0; i < PCI_NUM_REGIONS; i++) {
> - r = &d->io_regions[i];
> -
> - /* this region isn't registered */
> - if (!r->size)
> - continue;
> -
> - new_addr = pci_bar_address(d, i, r->type, r->size);
> -
> - /* This bar isn't changed */
> - if (new_addr == r->addr)
> - continue;
> -
> - /* now do the real mapping */
> - if (r->addr != PCI_BAR_UNMAPPED) {
> - memory_region_del_subregion(r->address_space, r->memory);
> - }
> - r->addr = new_addr;
> - if (r->addr != PCI_BAR_UNMAPPED) {
> - memory_region_add_subregion_overlap(r->address_space,
> - r->addr, r->memory, 1);
> - }
> - }
> -}
> -
> -static inline int pci_irq_disabled(PCIDevice *d)
> -{
> - return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE;
> -}
> -
> -/* Called after interrupt disabled field update in config space,
> - * assert/deassert interrupts if necessary.
> - * Gets original interrupt disable bit value (before update). */
> -static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled)
> -{
> - int i, disabled = pci_irq_disabled(d);
> - if (disabled == was_irq_disabled)
> - return;
> - for (i = 0; i < PCI_NUM_PINS; ++i) {
> - int state = pci_irq_state(d, i);
> - pci_change_irq_level(d, i, disabled ? -state : state);
> - }
> -}
> -
> -uint32_t pci_default_read_config(PCIDevice *d,
> - uint32_t address, int len)
> -{
> - uint32_t val = 0;
> -
> - memcpy(&val, d->config + address, len);
> - return le32_to_cpu(val);
> -}
> -
> -void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int
> l)
> -{
> - int i, was_irq_disabled = pci_irq_disabled(d);
> -
> - for (i = 0; i < l; val >>= 8, ++i) {
> - uint8_t wmask = d->wmask[addr + i];
> - uint8_t w1cmask = d->w1cmask[addr + i];
> - assert(!(wmask & w1cmask));
> - d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
> - d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
> - }
> - if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
> - ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
> - ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
> - range_covers_byte(addr, l, PCI_COMMAND))
> - pci_update_mappings(d);
> -
> - if (range_covers_byte(addr, l, PCI_COMMAND)) {
> - pci_update_irq_disabled(d, was_irq_disabled);
> - memory_region_set_enabled(&d->bus_master_enable_region,
> - pci_get_word(d->config + PCI_COMMAND)
> - & PCI_COMMAND_MASTER);
> - }
> -
> - msi_write_config(d, addr, val, l);
> - msix_write_config(d, addr, val, l);
> -}
> -
> -/***********************************************************/
> -/* generic PCI irq support */
> -
> -/* 0 <= irq_num <= 3. level must be 0 or 1 */
> -static void pci_set_irq(void *opaque, int irq_num, int level)
> -{
> - PCIDevice *pci_dev = opaque;
> - int change;
> -
> - change = level - pci_irq_state(pci_dev, irq_num);
> - if (!change)
> - return;
> -
> - pci_set_irq_state(pci_dev, irq_num, level);
> - pci_update_irq_status(pci_dev);
> - if (pci_irq_disabled(pci_dev))
> - return;
> - pci_change_irq_level(pci_dev, irq_num, change);
> -}
> -
> -/* Special hooks used by device assignment */
> -void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn
> route_intx_to_irq)
> -{
> - assert(!bus->parent_dev);
> - bus->route_intx_to_irq = route_intx_to_irq;
> -}
> -
> -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin)
> -{
> - PCIBus *bus;
> -
> - do {
> - bus = dev->bus;
> - pin = bus->map_irq(dev, pin);
> - dev = bus->parent_dev;
> - } while (dev);
> -
> - if (!bus->route_intx_to_irq) {
> - error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n",
> - object_get_typename(OBJECT(bus->qbus.parent)));
> - return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 };
> - }
> -
> - return bus->route_intx_to_irq(bus->irq_opaque, pin);
> -}
> -
> -bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new)
> -{
> - return old->mode != new->mode || old->irq != new->irq;
> -}
> -
> -void pci_bus_fire_intx_routing_notifier(PCIBus *bus)
> -{
> - PCIDevice *dev;
> - PCIBus *sec;
> - int i;
> -
> - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
> - dev = bus->devices[i];
> - if (dev && dev->intx_routing_notifier) {
> - dev->intx_routing_notifier(dev);
> - }
> - QLIST_FOREACH(sec, &bus->child, sibling) {
> - pci_bus_fire_intx_routing_notifier(sec);
> - }
> - }
> -}
> -
> -void pci_device_set_intx_routing_notifier(PCIDevice *dev,
> - PCIINTxRoutingNotifier notifier)
> -{
> - dev->intx_routing_notifier = notifier;
> -}
> -
> -/*
> - * PCI-to-PCI bridge specification
> - * 9.1: Interrupt routing. Table 9-1
> - *
> - * the PCI Express Base Specification, Revision 2.1
> - * 2.2.8.1: INTx interrutp signaling - Rules
> - * the Implementation Note
> - * Table 2-20
> - */
> -/*
> - * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD
> - * 0-origin unlike PCI interrupt pin register.
> - */
> -int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
> -{
> - return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS;
> -}
> -
> -/***********************************************************/
> -/* monitor info on PCI */
> -
> -typedef struct {
> - uint16_t class;
> - const char *desc;
> - const char *fw_name;
> - uint16_t fw_ign_bits;
> -} pci_class_desc;
> -
> -static const pci_class_desc pci_class_descriptions[] =
> -{
> - { 0x0001, "VGA controller", "display"},
> - { 0x0100, "SCSI controller", "scsi"},
> - { 0x0101, "IDE controller", "ide"},
> - { 0x0102, "Floppy controller", "fdc"},
> - { 0x0103, "IPI controller", "ipi"},
> - { 0x0104, "RAID controller", "raid"},
> - { 0x0106, "SATA controller"},
> - { 0x0107, "SAS controller"},
> - { 0x0180, "Storage controller"},
> - { 0x0200, "Ethernet controller", "ethernet"},
> - { 0x0201, "Token Ring controller", "token-ring"},
> - { 0x0202, "FDDI controller", "fddi"},
> - { 0x0203, "ATM controller", "atm"},
> - { 0x0280, "Network controller"},
> - { 0x0300, "VGA controller", "display", 0x00ff},
> - { 0x0301, "XGA controller"},
> - { 0x0302, "3D controller"},
> - { 0x0380, "Display controller"},
> - { 0x0400, "Video controller", "video"},
> - { 0x0401, "Audio controller", "sound"},
> - { 0x0402, "Phone"},
> - { 0x0403, "Audio controller", "sound"},
> - { 0x0480, "Multimedia controller"},
> - { 0x0500, "RAM controller", "memory"},
> - { 0x0501, "Flash controller", "flash"},
> - { 0x0580, "Memory controller"},
> - { 0x0600, "Host bridge", "host"},
> - { 0x0601, "ISA bridge", "isa"},
> - { 0x0602, "EISA bridge", "eisa"},
> - { 0x0603, "MC bridge", "mca"},
> - { 0x0604, "PCI bridge", "pci"},
> - { 0x0605, "PCMCIA bridge", "pcmcia"},
> - { 0x0606, "NUBUS bridge", "nubus"},
> - { 0x0607, "CARDBUS bridge", "cardbus"},
> - { 0x0608, "RACEWAY bridge"},
> - { 0x0680, "Bridge"},
> - { 0x0700, "Serial port", "serial"},
> - { 0x0701, "Parallel port", "parallel"},
> - { 0x0800, "Interrupt controller", "interrupt-controller"},
> - { 0x0801, "DMA controller", "dma-controller"},
> - { 0x0802, "Timer", "timer"},
> - { 0x0803, "RTC", "rtc"},
> - { 0x0900, "Keyboard", "keyboard"},
> - { 0x0901, "Pen", "pen"},
> - { 0x0902, "Mouse", "mouse"},
> - { 0x0A00, "Dock station", "dock", 0x00ff},
> - { 0x0B00, "i386 cpu", "cpu", 0x00ff},
> - { 0x0c00, "Fireware contorller", "fireware"},
> - { 0x0c01, "Access bus controller", "access-bus"},
> - { 0x0c02, "SSA controller", "ssa"},
> - { 0x0c03, "USB controller", "usb"},
> - { 0x0c04, "Fibre channel controller", "fibre-channel"},
> - { 0x0c05, "SMBus"},
> - { 0, NULL}
> -};
> -
> -static void pci_for_each_device_under_bus(PCIBus *bus,
> - void (*fn)(PCIBus *b, PCIDevice *d,
> - void *opaque),
> - void *opaque)
> -{
> - PCIDevice *d;
> - int devfn;
> -
> - for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
> - d = bus->devices[devfn];
> - if (d) {
> - fn(bus, d, opaque);
> - }
> - }
> -}
> -
> -void pci_for_each_device(PCIBus *bus, int bus_num,
> - void (*fn)(PCIBus *b, PCIDevice *d, void *opaque),
> - void *opaque)
> -{
> - bus = pci_find_bus_nr(bus, bus_num);
> -
> - if (bus) {
> - pci_for_each_device_under_bus(bus, fn, opaque);
> - }
> -}
> -
> -static const pci_class_desc *get_class_desc(int class)
> -{
> - const pci_class_desc *desc;
> -
> - desc = pci_class_descriptions;
> - while (desc->desc && class != desc->class) {
> - desc++;
> - }
> -
> - return desc;
> -}
> -
> -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
> -
> -static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
> -{
> - PciMemoryRegionList *head = NULL, *cur_item = NULL;
> - int i;
> -
> - for (i = 0; i < PCI_NUM_REGIONS; i++) {
> - const PCIIORegion *r = &dev->io_regions[i];
> - PciMemoryRegionList *region;
> -
> - if (!r->size) {
> - continue;
> - }
> -
> - region = g_malloc0(sizeof(*region));
> - region->value = g_malloc0(sizeof(*region->value));
> -
> - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
> - region->value->type = g_strdup("io");
> - } else {
> - region->value->type = g_strdup("memory");
> - region->value->has_prefetch = true;
> - region->value->prefetch = !!(r->type &
> PCI_BASE_ADDRESS_MEM_PREFETCH);
> - region->value->has_mem_type_64 = true;
> - region->value->mem_type_64 = !!(r->type &
> PCI_BASE_ADDRESS_MEM_TYPE_64);
> - }
> -
> - region->value->bar = i;
> - region->value->address = r->addr;
> - region->value->size = r->size;
> -
> - /* XXX: waiting for the qapi to support GSList */
> - if (!cur_item) {
> - head = cur_item = region;
> - } else {
> - cur_item->next = region;
> - cur_item = region;
> - }
> - }
> -
> - return head;
> -}
> -
> -static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
> - int bus_num)
> -{
> - PciBridgeInfo *info;
> -
> - info = g_malloc0(sizeof(*info));
> -
> - info->bus.number = dev->config[PCI_PRIMARY_BUS];
> - info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
> - info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
> -
> - info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
> - info->bus.io_range->base = pci_bridge_get_base(dev,
> PCI_BASE_ADDRESS_SPACE_IO);
> - info->bus.io_range->limit = pci_bridge_get_limit(dev,
> PCI_BASE_ADDRESS_SPACE_IO);
> -
> - info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
> - info->bus.memory_range->base = pci_bridge_get_base(dev,
> PCI_BASE_ADDRESS_SPACE_MEMORY);
> - info->bus.memory_range->limit = pci_bridge_get_limit(dev,
> PCI_BASE_ADDRESS_SPACE_MEMORY);
> -
> - info->bus.prefetchable_range =
> g_malloc0(sizeof(*info->bus.prefetchable_range));
> - info->bus.prefetchable_range->base = pci_bridge_get_base(dev,
> PCI_BASE_ADDRESS_MEM_PREFETCH);
> - info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev,
> PCI_BASE_ADDRESS_MEM_PREFETCH);
> -
> - if (dev->config[PCI_SECONDARY_BUS] != 0) {
> - PCIBus *child_bus = pci_find_bus_nr(bus,
> dev->config[PCI_SECONDARY_BUS]);
> - if (child_bus) {
> - info->has_devices = true;
> - info->devices = qmp_query_pci_devices(child_bus,
> dev->config[PCI_SECONDARY_BUS]);
> - }
> - }
> -
> - return info;
> -}
> -
> -static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
> - int bus_num)
> -{
> - const pci_class_desc *desc;
> - PciDeviceInfo *info;
> - uint8_t type;
> - int class;
> -
> - info = g_malloc0(sizeof(*info));
> - info->bus = bus_num;
> - info->slot = PCI_SLOT(dev->devfn);
> - info->function = PCI_FUNC(dev->devfn);
> -
> - class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
> - info->class_info.class = class;
> - desc = get_class_desc(class);
> - if (desc->desc) {
> - info->class_info.has_desc = true;
> - info->class_info.desc = g_strdup(desc->desc);
> - }
> -
> - info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
> - info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
> - info->regions = qmp_query_pci_regions(dev);
> - info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
> -
> - if (dev->config[PCI_INTERRUPT_PIN] != 0) {
> - info->has_irq = true;
> - info->irq = dev->config[PCI_INTERRUPT_LINE];
> - }
> -
> - type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
> - if (type == PCI_HEADER_TYPE_BRIDGE) {
> - info->has_pci_bridge = true;
> - info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
> - }
> -
> - return info;
> -}
> -
> -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
> -{
> - PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
> - PCIDevice *dev;
> - int devfn;
> -
> - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
> - dev = bus->devices[devfn];
> - if (dev) {
> - info = g_malloc0(sizeof(*info));
> - info->value = qmp_query_pci_device(dev, bus, bus_num);
> -
> - /* XXX: waiting for the qapi to support GSList */
> - if (!cur_item) {
> - head = cur_item = info;
> - } else {
> - cur_item->next = info;
> - cur_item = info;
> - }
> - }
> - }
> -
> - return head;
> -}
> -
> -static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
> -{
> - PciInfo *info = NULL;
> -
> - bus = pci_find_bus_nr(bus, bus_num);
> - if (bus) {
> - info = g_malloc0(sizeof(*info));
> - info->bus = bus_num;
> - info->devices = qmp_query_pci_devices(bus, bus_num);
> - }
> -
> - return info;
> -}
> -
> -PciInfoList *qmp_query_pci(Error **errp)
> -{
> - PciInfoList *info, *head = NULL, *cur_item = NULL;
> - struct PCIHostBus *host;
> -
> - QLIST_FOREACH(host, &host_buses, next) {
> - info = g_malloc0(sizeof(*info));
> - info->value = qmp_query_pci_bus(host->bus, 0);
> -
> - /* XXX: waiting for the qapi to support GSList */
> - if (!cur_item) {
> - head = cur_item = info;
> - } else {
> - cur_item->next = info;
> - cur_item = info;
> - }
> - }
> -
> - return head;
> -}
> -
> -static const char * const pci_nic_models[] = {
> - "ne2k_pci",
> - "i82551",
> - "i82557b",
> - "i82559er",
> - "rtl8139",
> - "e1000",
> - "pcnet",
> - "virtio",
> - NULL
> -};
> -
> -static const char * const pci_nic_names[] = {
> - "ne2k_pci",
> - "i82551",
> - "i82557b",
> - "i82559er",
> - "rtl8139",
> - "e1000",
> - "pcnet",
> - "virtio-net-pci",
> - NULL
> -};
> -
> -/* Initialize a PCI NIC. */
> -/* FIXME callers should check for failure, but don't */
> -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
> - const char *default_devaddr)
> -{
> - const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
> - PCIBus *bus;
> - int devfn;
> - PCIDevice *pci_dev;
> - DeviceState *dev;
> - int i;
> -
> - i = qemu_find_nic_model(nd, pci_nic_models, default_model);
> - if (i < 0)
> - return NULL;
> -
> - bus = pci_get_bus_devfn(&devfn, devaddr);
> - if (!bus) {
> - error_report("Invalid PCI device address %s for device %s",
> - devaddr, pci_nic_names[i]);
> - return NULL;
> - }
> -
> - pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
> - dev = &pci_dev->qdev;
> - qdev_set_nic_properties(dev, nd);
> - if (qdev_init(dev) < 0)
> - return NULL;
> - return pci_dev;
> -}
> -
> -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
> - const char *default_devaddr)
> -{
> - PCIDevice *res;
> -
> - if (qemu_show_nic_models(nd->model, pci_nic_models))
> - exit(0);
> -
> - res = pci_nic_init(nd, default_model, default_devaddr);
> - if (!res)
> - exit(1);
> - return res;
> -}
> -
> -PCIDevice *pci_vga_init(PCIBus *bus)
> -{
> - switch (vga_interface_type) {
> - case VGA_CIRRUS:
> - return pci_create_simple(bus, -1, "cirrus-vga");
> - case VGA_QXL:
> - return pci_create_simple(bus, -1, "qxl-vga");
> - case VGA_STD:
> - return pci_create_simple(bus, -1, "VGA");
> - case VGA_VMWARE:
> - return pci_create_simple(bus, -1, "vmware-svga");
> - case VGA_NONE:
> - default: /* Other non-PCI types. Checking for unsupported types is
> already
> - done in vl.c. */
> - return NULL;
> - }
> -}
> -
> -/* Whether a given bus number is in range of the secondary
> - * bus of the given bridge device. */
> -static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
> -{
> - return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) &
> - PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset.
> */ &&
> - dev->config[PCI_SECONDARY_BUS] < bus_num &&
> - bus_num <= dev->config[PCI_SUBORDINATE_BUS];
> -}
> -
> -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
> -{
> - PCIBus *sec;
> -
> - if (!bus) {
> - return NULL;
> - }
> -
> - if (pci_bus_num(bus) == bus_num) {
> - return bus;
> - }
> -
> - /* Consider all bus numbers in range for the host pci bridge. */
> - if (bus->parent_dev &&
> - !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
> - return NULL;
> - }
> -
> - /* try child bus */
> - for (; bus; bus = sec) {
> - QLIST_FOREACH(sec, &bus->child, sibling) {
> - assert(sec->parent_dev);
> - if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
> - return sec;
> - }
> - if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) {
> - break;
> - }
> - }
> - }
> -
> - return NULL;
> -}
> -
> -PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
> -{
> - bus = pci_find_bus_nr(bus, bus_num);
> -
> - if (!bus)
> - return NULL;
> -
> - return bus->devices[devfn];
> -}
> -
> -static int pci_qdev_init(DeviceState *qdev)
> -{
> - PCIDevice *pci_dev = (PCIDevice *)qdev;
> - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
> - PCIBus *bus;
> - int rc;
> - bool is_default_rom;
> -
> - /* initialize cap_present for pci_is_express() and pci_config_size() */
> - if (pc->is_express) {
> - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
> - }
> -
> - bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
> - pci_dev = do_pci_register_device(pci_dev, bus,
> - object_get_typename(OBJECT(qdev)),
> - pci_dev->devfn);
> - if (pci_dev == NULL)
> - return -1;
> - if (qdev->hotplugged && pc->no_hotplug) {
> - qerror_report(QERR_DEVICE_NO_HOTPLUG,
> object_get_typename(OBJECT(pci_dev)));
> - do_pci_unregister_device(pci_dev);
> - return -1;
> - }
> - if (pc->init) {
> - rc = pc->init(pci_dev);
> - if (rc != 0) {
> - do_pci_unregister_device(pci_dev);
> - return rc;
> - }
> - }
> -
> - /* rom loading */
> - is_default_rom = false;
> - if (pci_dev->romfile == NULL && pc->romfile != NULL) {
> - pci_dev->romfile = g_strdup(pc->romfile);
> - is_default_rom = true;
> - }
> - pci_add_option_rom(pci_dev, is_default_rom);
> -
> - if (bus->hotplug) {
> - /* Let buses differentiate between hotplug and when device is
> - * enabled during qemu machine creation. */
> - rc = bus->hotplug(bus->hotplug_qdev, pci_dev,
> - qdev->hotplugged ? PCI_HOTPLUG_ENABLED:
> - PCI_COLDPLUG_ENABLED);
> - if (rc != 0) {
> - int r = pci_unregister_device(&pci_dev->qdev);
> - assert(!r);
> - return rc;
> - }
> - }
> - return 0;
> -}
> -
> -static int pci_unplug_device(DeviceState *qdev)
> -{
> - PCIDevice *dev = PCI_DEVICE(qdev);
> - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
> -
> - if (pc->no_hotplug) {
> - qerror_report(QERR_DEVICE_NO_HOTPLUG,
> object_get_typename(OBJECT(dev)));
> - return -1;
> - }
> - return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
> - PCI_HOTPLUG_DISABLED);
> -}
> -
> -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool
> multifunction,
> - const char *name)
> -{
> - DeviceState *dev;
> -
> - dev = qdev_create(&bus->qbus, name);
> - qdev_prop_set_int32(dev, "addr", devfn);
> - qdev_prop_set_bit(dev, "multifunction", multifunction);
> - return PCI_DEVICE(dev);
> -}
> -
> -PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
> - bool multifunction,
> - const char *name)
> -{
> - PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction,
> name);
> - qdev_init_nofail(&dev->qdev);
> - return dev;
> -}
> -
> -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name)
> -{
> - return pci_create_multifunction(bus, devfn, false, name);
> -}
> -
> -PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
> -{
> - return pci_create_simple_multifunction(bus, devfn, false, name);
> -}
> -
> -static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size)
> -{
> - int offset = PCI_CONFIG_HEADER_SIZE;
> - int i;
> - for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) {
> - if (pdev->used[i])
> - offset = i + 1;
> - else if (i - offset + 1 == size)
> - return offset;
> - }
> - return 0;
> -}
> -
> -static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
> - uint8_t *prev_p)
> -{
> - uint8_t next, prev;
> -
> - if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST))
> - return 0;
> -
> - for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
> - prev = next + PCI_CAP_LIST_NEXT)
> - if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id)
> - break;
> -
> - if (prev_p)
> - *prev_p = prev;
> - return next;
> -}
> -
> -static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset)
> -{
> - uint8_t next, prev, found = 0;
> -
> - if (!(pdev->used[offset])) {
> - return 0;
> - }
> -
> - assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST);
> -
> - for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
> - prev = next + PCI_CAP_LIST_NEXT) {
> - if (next <= offset && next > found) {
> - found = next;
> - }
> - }
> - return found;
> -}
> -
> -/* Patch the PCI vendor and device ids in a PCI rom image if necessary.
> - This is needed for an option rom which is used for more than one device.
> */
> -static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size)
> -{
> - uint16_t vendor_id;
> - uint16_t device_id;
> - uint16_t rom_vendor_id;
> - uint16_t rom_device_id;
> - uint16_t rom_magic;
> - uint16_t pcir_offset;
> - uint8_t checksum;
> -
> - /* Words in rom data are little endian (like in PCI configuration),
> - so they can be read / written with pci_get_word / pci_set_word. */
> -
> - /* Only a valid rom will be patched. */
> - rom_magic = pci_get_word(ptr);
> - if (rom_magic != 0xaa55) {
> - PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic);
> - return;
> - }
> - pcir_offset = pci_get_word(ptr + 0x18);
> - if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) {
> - PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset);
> - return;
> - }
> -
> - vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
> - device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
> - rom_vendor_id = pci_get_word(ptr + pcir_offset + 4);
> - rom_device_id = pci_get_word(ptr + pcir_offset + 6);
> -
> - PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile,
> - vendor_id, device_id, rom_vendor_id, rom_device_id);
> -
> - checksum = ptr[6];
> -
> - if (vendor_id != rom_vendor_id) {
> - /* Patch vendor id and checksum (at offset 6 for etherboot roms). */
> - checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8);
> - checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8);
> - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
> - ptr[6] = checksum;
> - pci_set_word(ptr + pcir_offset + 4, vendor_id);
> - }
> -
> - if (device_id != rom_device_id) {
> - /* Patch device id and checksum (at offset 6 for etherboot roms). */
> - checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8);
> - checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8);
> - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
> - ptr[6] = checksum;
> - pci_set_word(ptr + pcir_offset + 6, device_id);
> - }
> -}
> -
> -/* Add an option rom for the device */
> -static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
> -{
> - int size;
> - char *path;
> - void *ptr;
> - char name[32];
> - const VMStateDescription *vmsd;
> -
> - if (!pdev->romfile)
> - return 0;
> - if (strlen(pdev->romfile) == 0)
> - return 0;
> -
> - if (!pdev->rom_bar) {
> - /*
> - * Load rom via fw_cfg instead of creating a rom bar,
> - * for 0.11 compatibility.
> - */
> - int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
> - if (class == 0x0300) {
> - rom_add_vga(pdev->romfile);
> - } else {
> - rom_add_option(pdev->romfile, -1);
> - }
> - return 0;
> - }
> -
> - path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
> - if (path == NULL) {
> - path = g_strdup(pdev->romfile);
> - }
> -
> - size = get_image_size(path);
> - if (size < 0) {
> - error_report("%s: failed to find romfile \"%s\"",
> - __FUNCTION__, pdev->romfile);
> - g_free(path);
> - return -1;
> - }
> - if (size & (size - 1)) {
> - size = 1 << qemu_fls(size);
> - }
> -
> - vmsd = qdev_get_vmsd(DEVICE(pdev));
> -
> - if (vmsd) {
> - snprintf(name, sizeof(name), "%s.rom", vmsd->name);
> - } else {
> - snprintf(name, sizeof(name), "%s.rom",
> object_get_typename(OBJECT(pdev)));
> - }
> - pdev->has_rom = true;
> - memory_region_init_ram(&pdev->rom, name, size);
> - vmstate_register_ram(&pdev->rom, &pdev->qdev);
> - ptr = memory_region_get_ram_ptr(&pdev->rom);
> - load_image(path, ptr);
> - g_free(path);
> -
> - if (is_default_rom) {
> - /* Only the default rom images will be patched (if needed). */
> - pci_patch_ids(pdev, ptr, size);
> - }
> -
> - qemu_put_ram_ptr(ptr);
> -
> - pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
> -
> - return 0;
> -}
> -
> -static void pci_del_option_rom(PCIDevice *pdev)
> -{
> - if (!pdev->has_rom)
> - return;
> -
> - vmstate_unregister_ram(&pdev->rom, &pdev->qdev);
> - memory_region_destroy(&pdev->rom);
> - pdev->has_rom = false;
> -}
> -
> -/*
> - * if !offset
> - * Reserve space and add capability to the linked list in pci config space
> - *
> - * if offset = 0,
> - * Find and reserve space and add capability to the linked list
> - * in pci config space */
> -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
> - uint8_t offset, uint8_t size)
> -{
> - uint8_t *config;
> - int i, overlapping_cap;
> -
> - if (!offset) {
> - offset = pci_find_space(pdev, size);
> - if (!offset) {
> - return -ENOSPC;
> - }
> - } else {
> - /* Verify that capabilities don't overlap. Note: device assignment
> - * depends on this check to verify that the device is not broken.
> - * Should never trigger for emulated devices, but it's helpful
> - * for debugging these. */
> - for (i = offset; i < offset + size; i++) {
> - overlapping_cap = pci_find_capability_at_offset(pdev, i);
> - if (overlapping_cap) {
> - fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
> - "Attempt to add PCI capability %x at offset "
> - "%x overlaps existing capability %x at offset %x\n",
> - pci_find_domain(pdev->bus), pci_bus_num(pdev->bus),
> - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
> - cap_id, offset, overlapping_cap, i);
> - return -EINVAL;
> - }
> - }
> - }
> -
> - config = pdev->config + offset;
> - config[PCI_CAP_LIST_ID] = cap_id;
> - config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
> - pdev->config[PCI_CAPABILITY_LIST] = offset;
> - pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
> - memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4));
> - /* Make capability read-only by default */
> - memset(pdev->wmask + offset, 0, size);
> - /* Check capability by default */
> - memset(pdev->cmask + offset, 0xFF, size);
> - return offset;
> -}
> -
> -/* Unlink capability from the pci config space. */
> -void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
> -{
> - uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev);
> - if (!offset)
> - return;
> - pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
> - /* Make capability writable again */
> - memset(pdev->wmask + offset, 0xff, size);
> - memset(pdev->w1cmask + offset, 0, size);
> - /* Clear cmask as device-specific registers can't be checked */
> - memset(pdev->cmask + offset, 0, size);
> - memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4));
> -
> - if (!pdev->config[PCI_CAPABILITY_LIST])
> - pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
> -}
> -
> -uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
> -{
> - return pci_find_capability_list(pdev, cap_id, NULL);
> -}
> -
> -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
> -{
> - PCIDevice *d = (PCIDevice *)dev;
> - const pci_class_desc *desc;
> - char ctxt[64];
> - PCIIORegion *r;
> - int i, class;
> -
> - class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> - desc = pci_class_descriptions;
> - while (desc->desc && class != desc->class)
> - desc++;
> - if (desc->desc) {
> - snprintf(ctxt, sizeof(ctxt), "%s", desc->desc);
> - } else {
> - snprintf(ctxt, sizeof(ctxt), "Class %04x", class);
> - }
> -
> - monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
> - "pci id %04x:%04x (sub %04x:%04x)\n",
> - indent, "", ctxt, pci_bus_num(d->bus),
> - PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
> - pci_get_word(d->config + PCI_VENDOR_ID),
> - pci_get_word(d->config + PCI_DEVICE_ID),
> - pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID),
> - pci_get_word(d->config + PCI_SUBSYSTEM_ID));
> - for (i = 0; i < PCI_NUM_REGIONS; i++) {
> - r = &d->io_regions[i];
> - if (!r->size)
> - continue;
> - monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS
> - " [0x%"FMT_PCIBUS"]\n",
> - indent, "",
> - i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" :
> "mem",
> - r->addr, r->addr + r->size - 1);
> - }
> -}
> -
> -static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
> -{
> - PCIDevice *d = (PCIDevice *)dev;
> - const char *name = NULL;
> - const pci_class_desc *desc = pci_class_descriptions;
> - int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> -
> - while (desc->desc &&
> - (class & ~desc->fw_ign_bits) !=
> - (desc->class & ~desc->fw_ign_bits)) {
> - desc++;
> - }
> -
> - if (desc->desc) {
> - name = desc->fw_name;
> - }
> -
> - if (name) {
> - pstrcpy(buf, len, name);
> - } else {
> - snprintf(buf, len, "pci%04x,%04x",
> - pci_get_word(d->config + PCI_VENDOR_ID),
> - pci_get_word(d->config + PCI_DEVICE_ID));
> - }
> -
> - return buf;
> -}
> -
> -static char *pcibus_get_fw_dev_path(DeviceState *dev)
> -{
> - PCIDevice *d = (PCIDevice *)dev;
> - char path[50], name[33];
> - int off;
> -
> - off = snprintf(path, sizeof(path), "address@hidden",
> - pci_dev_fw_name(dev, name, sizeof name),
> - PCI_SLOT(d->devfn));
> - if (PCI_FUNC(d->devfn))
> - snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
> - return g_strdup(path);
> -}
> -
> -static char *pcibus_get_dev_path(DeviceState *dev)
> -{
> - PCIDevice *d = container_of(dev, PCIDevice, qdev);
> - PCIDevice *t;
> - int slot_depth;
> - /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function.
> - * 00 is added here to make this format compatible with
> - * domain:Bus:Slot.Func for systems without nested PCI bridges.
> - * Slot.Function list specifies the slot and function numbers for all
> - * devices on the path from root to the specific device. */
> - char domain[] = "DDDD:00";
> - char slot[] = ":SS.F";
> - int domain_len = sizeof domain - 1 /* For '\0' */;
> - int slot_len = sizeof slot - 1 /* For '\0' */;
> - int path_len;
> - char *path, *p;
> - int s;
> -
> - /* Calculate # of slots on path between device and root. */;
> - slot_depth = 0;
> - for (t = d; t; t = t->bus->parent_dev) {
> - ++slot_depth;
> - }
> -
> - path_len = domain_len + slot_len * slot_depth;
> -
> - /* Allocate memory, fill in the terminating null byte. */
> - path = g_malloc(path_len + 1 /* For '\0' */);
> - path[path_len] = '\0';
> -
> - /* First field is the domain. */
> - s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus));
> - assert(s == domain_len);
> - memcpy(path, domain, domain_len);
> -
> - /* Fill in slot numbers. We walk up from device to root, so need to print
> - * them in the reverse order, last to first. */
> - p = path + path_len;
> - for (t = d; t; t = t->bus->parent_dev) {
> - p -= slot_len;
> - s = snprintf(slot, sizeof slot, ":%02x.%x",
> - PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
> - assert(s == slot_len);
> - memcpy(p, slot, slot_len);
> - }
> -
> - return path;
> -}
> -
> -static int pci_qdev_find_recursive(PCIBus *bus,
> - const char *id, PCIDevice **pdev)
> -{
> - DeviceState *qdev = qdev_find_recursive(&bus->qbus, id);
> - if (!qdev) {
> - return -ENODEV;
> - }
> -
> - /* roughly check if given qdev is pci device */
> - if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) {
> - *pdev = PCI_DEVICE(qdev);
> - return 0;
> - }
> - return -EINVAL;
> -}
> -
> -int pci_qdev_find_device(const char *id, PCIDevice **pdev)
> -{
> - struct PCIHostBus *host;
> - int rc = -ENODEV;
> -
> - QLIST_FOREACH(host, &host_buses, next) {
> - int tmp = pci_qdev_find_recursive(host->bus, id, pdev);
> - if (!tmp) {
> - rc = 0;
> - break;
> - }
> - if (tmp != -ENODEV) {
> - rc = tmp;
> - }
> - }
> -
> - return rc;
> -}
> -
> -MemoryRegion *pci_address_space(PCIDevice *dev)
> -{
> - return dev->bus->address_space_mem;
> -}
> -
> -MemoryRegion *pci_address_space_io(PCIDevice *dev)
> -{
> - return dev->bus->address_space_io;
> -}
> -
> -static void pci_device_class_init(ObjectClass *klass, void *data)
> -{
> - DeviceClass *k = DEVICE_CLASS(klass);
> - k->init = pci_qdev_init;
> - k->unplug = pci_unplug_device;
> - k->exit = pci_unregister_device;
> - k->bus_type = TYPE_PCI_BUS;
> - k->props = pci_props;
> -}
> -
> -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque)
> -{
> - bus->dma_context_fn = fn;
> - bus->dma_context_opaque = opaque;
> -}
> -
> -static TypeInfo pci_device_type_info = {
> - .name = TYPE_PCI_DEVICE,
> - .parent = TYPE_DEVICE,
> - .instance_size = sizeof(PCIDevice),
> - .abstract = true,
> - .class_size = sizeof(PCIDeviceClass),
> - .class_init = pci_device_class_init,
> -};
> -
> -static void pci_register_types(void)
> -{
> - type_register_static(&pci_bus_info);
> - type_register_static(&pci_device_type_info);
> -}
> -
> -type_init(pci_register_types)
> diff --git a/hw/pci.h b/hw/pci.h
> deleted file mode 100644
> index 4da0c2a..0000000
> --- a/hw/pci.h
> +++ /dev/null
> @@ -1,684 +0,0 @@
> -#ifndef QEMU_PCI_H
> -#define QEMU_PCI_H
> -
> -#include "qemu-common.h"
> -
> -#include "qdev.h"
> -#include "memory.h"
> -#include "dma.h"
> -
> -/* PCI includes legacy ISA access. */
> -#include "isa.h"
> -
> -#include "pcie.h"
> -
> -/* PCI bus */
> -
> -#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
> -#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
> -#define PCI_FUNC(devfn) ((devfn) & 0x07)
> -#define PCI_SLOT_MAX 32
> -#define PCI_FUNC_MAX 8
> -
> -/* Class, Vendor and Device IDs from Linux's pci_ids.h */
> -#include "pci_ids.h"
> -
> -/* QEMU-specific Vendor and Device ID definitions */
> -
> -/* IBM (0x1014) */
> -#define PCI_DEVICE_ID_IBM_440GX 0x027f
> -#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff
> -
> -/* Hitachi (0x1054) */
> -#define PCI_VENDOR_ID_HITACHI 0x1054
> -#define PCI_DEVICE_ID_HITACHI_SH7751R 0x350e
> -
> -/* Apple (0x106b) */
> -#define PCI_DEVICE_ID_APPLE_343S1201 0x0010
> -#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e
> -#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f
> -#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022
> -#define PCI_DEVICE_ID_APPLE_IPID_USB 0x003f
> -
> -/* Realtek (0x10ec) */
> -#define PCI_DEVICE_ID_REALTEK_8029 0x8029
> -
> -/* Xilinx (0x10ee) */
> -#define PCI_DEVICE_ID_XILINX_XC2VP30 0x0300
> -
> -/* Marvell (0x11ab) */
> -#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620
> -
> -/* QEMU/Bochs VGA (0x1234) */
> -#define PCI_VENDOR_ID_QEMU 0x1234
> -#define PCI_DEVICE_ID_QEMU_VGA 0x1111
> -
> -/* VMWare (0x15ad) */
> -#define PCI_VENDOR_ID_VMWARE 0x15ad
> -#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
> -#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
> -#define PCI_DEVICE_ID_VMWARE_NET 0x0720
> -#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
> -#define PCI_DEVICE_ID_VMWARE_IDE 0x1729
> -
> -/* Intel (0x8086) */
> -#define PCI_DEVICE_ID_INTEL_82551IT 0x1209
> -#define PCI_DEVICE_ID_INTEL_82557 0x1229
> -#define PCI_DEVICE_ID_INTEL_82801IR 0x2922
> -
> -/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
> -#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
> -#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
> -#define PCI_SUBDEVICE_ID_QEMU 0x1100
> -
> -#define PCI_DEVICE_ID_VIRTIO_NET 0x1000
> -#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001
> -#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
> -#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
> -#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
> -#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
> -
> -#define FMT_PCIBUS PRIx64
> -
> -typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
> - uint32_t address, uint32_t data, int len);
> -typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
> - uint32_t address, int len);
> -typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
> - pcibus_t addr, pcibus_t size, int type);
> -typedef void PCIUnregisterFunc(PCIDevice *pci_dev);
> -
> -typedef struct PCIIORegion {
> - pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
> -#define PCI_BAR_UNMAPPED (~(pcibus_t)0)
> - pcibus_t size;
> - uint8_t type;
> - MemoryRegion *memory;
> - MemoryRegion *address_space;
> -} PCIIORegion;
> -
> -#define PCI_ROM_SLOT 6
> -#define PCI_NUM_REGIONS 7
> -
> -#include "pci_regs.h"
> -
> -/* PCI HEADER_TYPE */
> -#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
> -
> -/* Size of the standard PCI config header */
> -#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_MSI = 0x1,
> - QEMU_PCI_CAP_MSIX = 0x2,
> - QEMU_PCI_CAP_EXPRESS = 0x4,
> -
> - /* multifunction capable device */
> -#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3
> - QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
> -
> - /* command register SERR bit enabled */
> -#define QEMU_PCI_CAP_SERR_BITNR 4
> - QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
> - /* Standard hot plug controller. */
> -#define QEMU_PCI_SHPC_BITNR 5
> - QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR),
> -#define QEMU_PCI_SLOTID_BITNR 6
> - QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR),
> -};
> -
> -#define TYPE_PCI_DEVICE "pci-device"
> -#define PCI_DEVICE(obj) \
> - OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE)
> -#define PCI_DEVICE_CLASS(klass) \
> - OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE)
> -#define PCI_DEVICE_GET_CLASS(obj) \
> - OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE)
> -
> -typedef struct PCIINTxRoute {
> - enum {
> - PCI_INTX_ENABLED,
> - PCI_INTX_INVERTED,
> - PCI_INTX_DISABLED,
> - } mode;
> - int irq;
> -} PCIINTxRoute;
> -
> -typedef struct PCIDeviceClass {
> - DeviceClass parent_class;
> -
> - int (*init)(PCIDevice *dev);
> - PCIUnregisterFunc *exit;
> - PCIConfigReadFunc *config_read;
> - PCIConfigWriteFunc *config_write;
> -
> - uint16_t vendor_id;
> - uint16_t device_id;
> - uint8_t revision;
> - uint16_t class_id;
> - uint16_t subsystem_vendor_id; /* only for header type = 0 */
> - uint16_t subsystem_id; /* only for header type = 0 */
> -
> - /*
> - * pci-to-pci bridge or normal device.
> - * This doesn't mean pci host switch.
> - * When card bus bridge is supported, this would be enhanced.
> - */
> - int is_bridge;
> -
> - /* pcie stuff */
> - int is_express; /* is this device pci express? */
> -
> - /* device isn't hot-pluggable */
> - int no_hotplug;
> -
> - /* rom bar */
> - const char *romfile;
> -} PCIDeviceClass;
> -
> -typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev);
> -typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector,
> - MSIMessage msg);
> -typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int
> vector);
> -
> -struct PCIDevice {
> - DeviceState qdev;
> -
> - /* PCI config space */
> - uint8_t *config;
> -
> - /* Used to enable config checks on load. Note that writable bits are
> - * never checked even if set in cmask. */
> - uint8_t *cmask;
> -
> - /* Used to implement R/W bytes */
> - uint8_t *wmask;
> -
> - /* Used to implement RW1C(Write 1 to Clear) bytes */
> - uint8_t *w1cmask;
> -
> - /* Used to allocate config space for capabilities. */
> - uint8_t *used;
> -
> - /* the following fields are read only */
> - PCIBus *bus;
> - int32_t devfn;
> - char name[64];
> - PCIIORegion io_regions[PCI_NUM_REGIONS];
> - AddressSpace bus_master_as;
> - MemoryRegion bus_master_enable_region;
> - DMAContext *dma;
> -
> - /* do not access the following fields */
> - PCIConfigReadFunc *config_read;
> - PCIConfigWriteFunc *config_write;
> -
> - /* IRQ objects for the INTA-INTD pins. */
> - qemu_irq *irq;
> -
> - /* Current IRQ levels. Used internally by the generic PCI code. */
> - uint8_t irq_state;
> -
> - /* Capability bits */
> - uint32_t cap_present;
> -
> - /* Offset of MSI-X capability in config space */
> - uint8_t msix_cap;
> -
> - /* MSI-X entries */
> - int msix_entries_nr;
> -
> - /* Space to store MSIX table & pending bit array */
> - uint8_t *msix_table;
> - uint8_t *msix_pba;
> - /* MemoryRegion container for msix exclusive BAR setup */
> - MemoryRegion msix_exclusive_bar;
> - /* Memory Regions for MSIX table and pending bit entries. */
> - MemoryRegion msix_table_mmio;
> - MemoryRegion msix_pba_mmio;
> - /* Reference-count for entries actually in use by driver. */
> - unsigned *msix_entry_used;
> - /* MSIX function mask set or MSIX disabled */
> - bool msix_function_masked;
> - /* Version id needed for VMState */
> - int32_t version_id;
> -
> - /* Offset of MSI capability in config space */
> - uint8_t msi_cap;
> -
> - /* PCI Express */
> - PCIExpressDevice exp;
> -
> - /* SHPC */
> - SHPCDevice *shpc;
> -
> - /* Location of option rom */
> - char *romfile;
> - bool has_rom;
> - MemoryRegion rom;
> - uint32_t rom_bar;
> -
> - /* INTx routing notifier */
> - PCIINTxRoutingNotifier intx_routing_notifier;
> -
> - /* MSI-X notifiers */
> - MSIVectorUseNotifier msix_vector_use_notifier;
> - MSIVectorReleaseNotifier msix_vector_release_notifier;
> -};
> -
> -void pci_register_bar(PCIDevice *pci_dev, int region_num,
> - uint8_t attr, MemoryRegion *memory);
> -pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
> -
> -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
> - uint8_t offset, uint8_t size);
> -
> -void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t
> cap_size);
> -
> -uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
> -
> -
> -uint32_t pci_default_read_config(PCIDevice *d,
> - uint32_t address, int len);
> -void pci_default_write_config(PCIDevice *d,
> - uint32_t address, uint32_t val, int len);
> -void pci_device_save(PCIDevice *s, QEMUFile *f);
> -int pci_device_load(PCIDevice *s, QEMUFile *f);
> -MemoryRegion *pci_address_space(PCIDevice *dev);
> -MemoryRegion *pci_address_space_io(PCIDevice *dev);
> -
> -typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
> -typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
> -typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
> -
> -typedef enum {
> - PCI_HOTPLUG_DISABLED,
> - PCI_HOTPLUG_ENABLED,
> - PCI_COLDPLUG_ENABLED,
> -} PCIHotplugState;
> -
> -typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
> - PCIHotplugState state);
> -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
> - const char *name,
> - MemoryRegion *address_space_mem,
> - MemoryRegion *address_space_io,
> - uint8_t devfn_min);
> -PCIBus *pci_bus_new(DeviceState *parent, const char *name,
> - MemoryRegion *address_space_mem,
> - MemoryRegion *address_space_io,
> - uint8_t devfn_min);
> -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn
> map_irq,
> - void *irq_opaque, int nirq);
> -int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
> -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
> -/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */
> -int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin);
> -PCIBus *pci_register_bus(DeviceState *parent, const char *name,
> - pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
> - void *irq_opaque,
> - MemoryRegion *address_space_mem,
> - MemoryRegion *address_space_io,
> - uint8_t devfn_min, int nirq);
> -void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
> -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
> -bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);
> -void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
> -void pci_device_set_intx_routing_notifier(PCIDevice *dev,
> - PCIINTxRoutingNotifier notifier);
> -void pci_device_reset(PCIDevice *dev);
> -void pci_bus_reset(PCIBus *bus);
> -
> -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
> - const char *default_devaddr);
> -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
> - const char *default_devaddr);
> -
> -PCIDevice *pci_vga_init(PCIBus *bus);
> -
> -int pci_bus_num(PCIBus *s);
> -void pci_for_each_device(PCIBus *bus, int bus_num,
> - void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque),
> - void *opaque);
> -PCIBus *pci_find_root_bus(int domain);
> -int pci_find_domain(const PCIBus *bus);
> -PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
> -int pci_qdev_find_device(const char *id, PCIDevice **pdev);
> -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
> -
> -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
> - unsigned *slotp);
> -
> -void pci_device_deassert_intx(PCIDevice *dev);
> -
> -typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int);
> -
> -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque);
> -
> -static inline void
> -pci_set_byte(uint8_t *config, uint8_t val)
> -{
> - *config = val;
> -}
> -
> -static inline uint8_t
> -pci_get_byte(const uint8_t *config)
> -{
> - return *config;
> -}
> -
> -static inline void
> -pci_set_word(uint8_t *config, uint16_t val)
> -{
> - cpu_to_le16wu((uint16_t *)config, val);
> -}
> -
> -static inline uint16_t
> -pci_get_word(const uint8_t *config)
> -{
> - return le16_to_cpupu((const uint16_t *)config);
> -}
> -
> -static inline void
> -pci_set_long(uint8_t *config, uint32_t val)
> -{
> - cpu_to_le32wu((uint32_t *)config, val);
> -}
> -
> -static inline uint32_t
> -pci_get_long(const uint8_t *config)
> -{
> - return le32_to_cpupu((const uint32_t *)config);
> -}
> -
> -static inline void
> -pci_set_quad(uint8_t *config, uint64_t val)
> -{
> - cpu_to_le64w((uint64_t *)config, val);
> -}
> -
> -static inline uint64_t
> -pci_get_quad(const uint8_t *config)
> -{
> - return le64_to_cpup((const uint64_t *)config);
> -}
> -
> -static inline void
> -pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
> -{
> - pci_set_word(&pci_config[PCI_VENDOR_ID], val);
> -}
> -
> -static inline void
> -pci_config_set_device_id(uint8_t *pci_config, uint16_t val)
> -{
> - pci_set_word(&pci_config[PCI_DEVICE_ID], val);
> -}
> -
> -static inline void
> -pci_config_set_revision(uint8_t *pci_config, uint8_t val)
> -{
> - pci_set_byte(&pci_config[PCI_REVISION_ID], val);
> -}
> -
> -static inline void
> -pci_config_set_class(uint8_t *pci_config, uint16_t val)
> -{
> - pci_set_word(&pci_config[PCI_CLASS_DEVICE], val);
> -}
> -
> -static inline void
> -pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val)
> -{
> - pci_set_byte(&pci_config[PCI_CLASS_PROG], val);
> -}
> -
> -static inline void
> -pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val)
> -{
> - pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val);
> -}
> -
> -/*
> - * helper functions to do bit mask operation on configuration space.
> - * Just to set bit, use test-and-set and discard returned value.
> - * Just to clear bit, use test-and-clear and discard returned value.
> - * NOTE: They aren't atomic.
> - */
> -static inline uint8_t
> -pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask)
> -{
> - uint8_t val = pci_get_byte(config);
> - pci_set_byte(config, val & ~mask);
> - return val & mask;
> -}
> -
> -static inline uint8_t
> -pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask)
> -{
> - uint8_t val = pci_get_byte(config);
> - pci_set_byte(config, val | mask);
> - return val & mask;
> -}
> -
> -static inline uint16_t
> -pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask)
> -{
> - uint16_t val = pci_get_word(config);
> - pci_set_word(config, val & ~mask);
> - return val & mask;
> -}
> -
> -static inline uint16_t
> -pci_word_test_and_set_mask(uint8_t *config, uint16_t mask)
> -{
> - uint16_t val = pci_get_word(config);
> - pci_set_word(config, val | mask);
> - return val & mask;
> -}
> -
> -static inline uint32_t
> -pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask)
> -{
> - uint32_t val = pci_get_long(config);
> - pci_set_long(config, val & ~mask);
> - return val & mask;
> -}
> -
> -static inline uint32_t
> -pci_long_test_and_set_mask(uint8_t *config, uint32_t mask)
> -{
> - uint32_t val = pci_get_long(config);
> - pci_set_long(config, val | mask);
> - return val & mask;
> -}
> -
> -static inline uint64_t
> -pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask)
> -{
> - uint64_t val = pci_get_quad(config);
> - pci_set_quad(config, val & ~mask);
> - return val & mask;
> -}
> -
> -static inline uint64_t
> -pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
> -{
> - uint64_t val = pci_get_quad(config);
> - pci_set_quad(config, val | mask);
> - return val & mask;
> -}
> -
> -/* Access a register specified by a mask */
> -static inline void
> -pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg)
> -{
> - uint8_t val = pci_get_byte(config);
> - uint8_t rval = reg << (ffs(mask) - 1);
> - pci_set_byte(config, (~mask & val) | (mask & rval));
> -}
> -
> -static inline uint8_t
> -pci_get_byte_by_mask(uint8_t *config, uint8_t mask)
> -{
> - uint8_t val = pci_get_byte(config);
> - return (val & mask) >> (ffs(mask) - 1);
> -}
> -
> -static inline void
> -pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg)
> -{
> - uint16_t val = pci_get_word(config);
> - uint16_t rval = reg << (ffs(mask) - 1);
> - pci_set_word(config, (~mask & val) | (mask & rval));
> -}
> -
> -static inline uint16_t
> -pci_get_word_by_mask(uint8_t *config, uint16_t mask)
> -{
> - uint16_t val = pci_get_word(config);
> - return (val & mask) >> (ffs(mask) - 1);
> -}
> -
> -static inline void
> -pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg)
> -{
> - uint32_t val = pci_get_long(config);
> - uint32_t rval = reg << (ffs(mask) - 1);
> - pci_set_long(config, (~mask & val) | (mask & rval));
> -}
> -
> -static inline uint32_t
> -pci_get_long_by_mask(uint8_t *config, uint32_t mask)
> -{
> - uint32_t val = pci_get_long(config);
> - return (val & mask) >> (ffs(mask) - 1);
> -}
> -
> -static inline void
> -pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg)
> -{
> - uint64_t val = pci_get_quad(config);
> - uint64_t rval = reg << (ffs(mask) - 1);
> - pci_set_quad(config, (~mask & val) | (mask & rval));
> -}
> -
> -static inline uint64_t
> -pci_get_quad_by_mask(uint8_t *config, uint64_t mask)
> -{
> - uint64_t val = pci_get_quad(config);
> - return (val & mask) >> (ffs(mask) - 1);
> -}
> -
> -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool
> multifunction,
> - const char *name);
> -PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
> - bool multifunction,
> - const char *name);
> -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(const PCIDevice *d)
> -{
> - return d->cap_present & QEMU_PCI_CAP_EXPRESS;
> -}
> -
> -static inline uint32_t pci_config_size(const PCIDevice *d)
> -{
> - return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE :
> PCI_CONFIG_SPACE_SIZE;
> -}
> -
> -/* DMA access functions */
> -static inline DMAContext *pci_dma_context(PCIDevice *dev)
> -{
> - return dev->dma;
> -}
> -
> -static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr,
> - void *buf, dma_addr_t len, DMADirection dir)
> -{
> - dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir);
> - return 0;
> -}
> -
> -static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
> - void *buf, dma_addr_t len)
> -{
> - return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
> -}
> -
> -static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
> - const void *buf, dma_addr_t len)
> -{
> - return pci_dma_rw(dev, addr, (void *) buf, len,
> DMA_DIRECTION_FROM_DEVICE);
> -}
> -
> -#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \
> - static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \
> - dma_addr_t addr) \
> - { \
> - return ld##_l##_dma(pci_dma_context(dev), addr); \
> - } \
> - static inline void st##_s##_pci_dma(PCIDevice *dev, \
> - dma_addr_t addr, uint##_bits##_t
> val) \
> - { \
> - st##_s##_dma(pci_dma_context(dev), addr, val); \
> - }
> -
> -PCI_DMA_DEFINE_LDST(ub, b, 8);
> -PCI_DMA_DEFINE_LDST(uw_le, w_le, 16)
> -PCI_DMA_DEFINE_LDST(l_le, l_le, 32);
> -PCI_DMA_DEFINE_LDST(q_le, q_le, 64);
> -PCI_DMA_DEFINE_LDST(uw_be, w_be, 16)
> -PCI_DMA_DEFINE_LDST(l_be, l_be, 32);
> -PCI_DMA_DEFINE_LDST(q_be, q_be, 64);
> -
> -#undef PCI_DMA_DEFINE_LDST
> -
> -static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr,
> - dma_addr_t *plen, DMADirection dir)
> -{
> - void *buf;
> -
> - buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir);
> - return buf;
> -}
> -
> -static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t
> len,
> - DMADirection dir, dma_addr_t access_len)
> -{
> - dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len);
> -}
> -
> -static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
> - int alloc_hint)
> -{
> - qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev));
> -}
> -
> -extern const VMStateDescription vmstate_pci_device;
> -
> -#define VMSTATE_PCI_DEVICE(_field, _state) { \
> - .name = (stringify(_field)), \
> - .size = sizeof(PCIDevice), \
> - .vmsd = &vmstate_pci_device, \
> - .flags = VMS_STRUCT, \
> - .offset = vmstate_offset_value(_state, _field, PCIDevice), \
> -}
> -
> -#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \
> - .name = (stringify(_field)), \
> - .size = sizeof(PCIDevice), \
> - .vmsd = &vmstate_pci_device, \
> - .flags = VMS_STRUCT|VMS_POINTER, \
> - .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \
> -}
> -
> -#endif
> diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs
> new file mode 100644
> index 0000000..9d21952
> --- /dev/null
> +++ b/hw/pci/Makefile.objs
> @@ -0,0 +1,6 @@
> +common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
> +common-obj-$(CONFIG_PCI) += msix.o msi.o
> +common-obj-$(CONFIG_PCI) += shpc.o
> +common-obj-$(CONFIG_PCI) += slotid_cap.o
> +common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
> +common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
> diff --git a/hw/pci/msi.c b/hw/pci/msi.c
> new file mode 100644
> index 0000000..33037a8
> --- /dev/null
> +++ b/hw/pci/msi.c
> @@ -0,0 +1,395 @@
> +/*
> + * msi.c
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "msi.h"
> +#include "range.h"
> +
> +/* Eventually those constants should go to Linux pci_regs.h */
> +#define PCI_MSI_PENDING_32 0x10
> +#define PCI_MSI_PENDING_64 0x14
> +
> +/* PCI_MSI_ADDRESS_LO */
> +#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
> +
> +/* If we get rid of cap allocator, we won't need those. */
> +#define PCI_MSI_32_SIZEOF 0x0a
> +#define PCI_MSI_64_SIZEOF 0x0e
> +#define PCI_MSI_32M_SIZEOF 0x14
> +#define PCI_MSI_64M_SIZEOF 0x18
> +
> +#define PCI_MSI_VECTORS_MAX 32
> +
> +/* Flag for interrupt controller to declare MSI/MSI-X support */
> +bool msi_supported;
> +
> +/* If we get rid of cap allocator, we won't need this. */
> +static inline uint8_t msi_cap_sizeof(uint16_t flags)
> +{
> + switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) {
> + case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT:
> + return PCI_MSI_64M_SIZEOF;
> + case PCI_MSI_FLAGS_64BIT:
> + return PCI_MSI_64_SIZEOF;
> + case PCI_MSI_FLAGS_MASKBIT:
> + return PCI_MSI_32M_SIZEOF;
> + case 0:
> + return PCI_MSI_32_SIZEOF;
> + default:
> + abort();
> + break;
> + }
> + return 0;
> +}
> +
> +//#define MSI_DEBUG
> +
> +#ifdef MSI_DEBUG
> +# define MSI_DPRINTF(fmt, ...) \
> + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
> +#else
> +# define MSI_DPRINTF(fmt, ...) do { } while (0)
> +#endif
> +#define MSI_DEV_PRINTF(dev, fmt, ...) \
> + MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
> +
> +static inline unsigned int msi_nr_vectors(uint16_t flags)
> +{
> + return 1U <<
> + ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1));
> +}
> +
> +static inline uint8_t msi_flags_off(const PCIDevice* dev)
> +{
> + return dev->msi_cap + PCI_MSI_FLAGS;
> +}
> +
> +static inline uint8_t msi_address_lo_off(const PCIDevice* dev)
> +{
> + return dev->msi_cap + PCI_MSI_ADDRESS_LO;
> +}
> +
> +static inline uint8_t msi_address_hi_off(const PCIDevice* dev)
> +{
> + return dev->msi_cap + PCI_MSI_ADDRESS_HI;
> +}
> +
> +static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit)
> +{
> + return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32);
> +}
> +
> +static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit)
> +{
> + return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32);
> +}
> +
> +static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit)
> +{
> + return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 :
> PCI_MSI_PENDING_32);
> +}
> +
> +/*
> + * Special API for POWER to configure the vectors through
> + * a side channel. Should never be used by devices.
> + */
> +void msi_set_message(PCIDevice *dev, MSIMessage msg)
> +{
> + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> +
> + if (msi64bit) {
> + pci_set_quad(dev->config + msi_address_lo_off(dev), msg.address);
> + } else {
> + pci_set_long(dev->config + msi_address_lo_off(dev), msg.address);
> + }
> + pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data);
> +}
> +
> +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector)
> +{
> + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> + unsigned int nr_vectors = msi_nr_vectors(flags);
> + MSIMessage msg;
> +
> + assert(vector < nr_vectors);
> +
> + if (msi64bit) {
> + msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev));
> + } else {
> + msg.address = pci_get_long(dev->config + msi_address_lo_off(dev));
> + }
> +
> + /* upper bit 31:16 is zero */
> + msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
> + if (nr_vectors > 1) {
> + msg.data &= ~(nr_vectors - 1);
> + msg.data |= vector;
> + }
> +
> + return msg;
> +}
> +
> +bool msi_enabled(const PCIDevice *dev)
> +{
> + return msi_present(dev) &&
> + (pci_get_word(dev->config + msi_flags_off(dev)) &
> + PCI_MSI_FLAGS_ENABLE);
> +}
> +
> +int msi_init(struct PCIDevice *dev, uint8_t offset,
> + unsigned int nr_vectors, bool msi64bit, bool
> msi_per_vector_mask)
> +{
> + unsigned int vectors_order;
> + uint16_t flags;
> + uint8_t cap_size;
> + int config_offset;
> +
> + if (!msi_supported) {
> + return -ENOTSUP;
> + }
> +
> + MSI_DEV_PRINTF(dev,
> + "init offset: 0x%"PRIx8" vector: %"PRId8
> + " 64bit %d mask %d\n",
> + offset, nr_vectors, msi64bit, msi_per_vector_mask);
> +
> + assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */
> + assert(nr_vectors > 0);
> + assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
> + /* the nr of MSI vectors is up to 32 */
> + vectors_order = ffs(nr_vectors) - 1;
> +
> + flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1);
> + if (msi64bit) {
> + flags |= PCI_MSI_FLAGS_64BIT;
> + }
> + if (msi_per_vector_mask) {
> + flags |= PCI_MSI_FLAGS_MASKBIT;
> + }
> +
> + cap_size = msi_cap_sizeof(flags);
> + config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset,
> cap_size);
> + if (config_offset < 0) {
> + return config_offset;
> + }
> +
> + dev->msi_cap = config_offset;
> + dev->cap_present |= QEMU_PCI_CAP_MSI;
> +
> + pci_set_word(dev->config + msi_flags_off(dev), flags);
> + pci_set_word(dev->wmask + msi_flags_off(dev),
> + PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
> + pci_set_long(dev->wmask + msi_address_lo_off(dev),
> + PCI_MSI_ADDRESS_LO_MASK);
> + if (msi64bit) {
> + pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff);
> + }
> + pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff);
> +
> + if (msi_per_vector_mask) {
> + /* Make mask bits 0 to nr_vectors - 1 writable. */
> + pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
> + 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
> + }
> + return config_offset;
> +}
> +
> +void msi_uninit(struct PCIDevice *dev)
> +{
> + uint16_t flags;
> + uint8_t cap_size;
> +
> + if (!msi_present(dev)) {
> + return;
> + }
> + flags = pci_get_word(dev->config + msi_flags_off(dev));
> + cap_size = msi_cap_sizeof(flags);
> + pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
> + dev->cap_present &= ~QEMU_PCI_CAP_MSI;
> +
> + MSI_DEV_PRINTF(dev, "uninit\n");
> +}
> +
> +void msi_reset(PCIDevice *dev)
> +{
> + uint16_t flags;
> + bool msi64bit;
> +
> + if (!msi_present(dev)) {
> + return;
> + }
> +
> + flags = pci_get_word(dev->config + msi_flags_off(dev));
> + flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
> + msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> +
> + pci_set_word(dev->config + msi_flags_off(dev), flags);
> + pci_set_long(dev->config + msi_address_lo_off(dev), 0);
> + if (msi64bit) {
> + pci_set_long(dev->config + msi_address_hi_off(dev), 0);
> + }
> + pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0);
> + if (flags & PCI_MSI_FLAGS_MASKBIT) {
> + pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0);
> + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0);
> + }
> + MSI_DEV_PRINTF(dev, "reset\n");
> +}
> +
> +static bool msi_is_masked(const PCIDevice *dev, unsigned int vector)
> +{
> + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> + uint32_t mask;
> + assert(vector < PCI_MSI_VECTORS_MAX);
> +
> + if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
> + return false;
> + }
> +
> + mask = pci_get_long(dev->config +
> + msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT));
> + return mask & (1U << vector);
> +}
> +
> +void msi_notify(PCIDevice *dev, unsigned int vector)
> +{
> + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> + unsigned int nr_vectors = msi_nr_vectors(flags);
> + MSIMessage msg;
> +
> + assert(vector < nr_vectors);
> + if (msi_is_masked(dev, vector)) {
> + assert(flags & PCI_MSI_FLAGS_MASKBIT);
> + pci_long_test_and_set_mask(
> + dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
> + MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector);
> + return;
> + }
> +
> + msg = msi_get_message(dev, vector);
> +
> + MSI_DEV_PRINTF(dev,
> + "notify vector 0x%x"
> + " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
> + vector, msg.address, msg.data);
> + stl_le_phys(msg.address, msg.data);
> +}
> +
> +/* Normally called by pci_default_write_config(). */
> +void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
> +{
> + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
> + bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT;
> + unsigned int nr_vectors;
> + uint8_t log_num_vecs;
> + uint8_t log_max_vecs;
> + unsigned int vector;
> + uint32_t pending;
> +
> + if (!msi_present(dev) ||
> + !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
> + return;
> + }
> +
> +#ifdef MSI_DEBUG
> + MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n",
> + addr, val, len);
> + MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32,
> + flags,
> + pci_get_long(dev->config + msi_address_lo_off(dev)));
> + if (msi64bit) {
> + fprintf(stderr, " address-hi: 0x%"PRIx32,
> + pci_get_long(dev->config + msi_address_hi_off(dev)));
> + }
> + fprintf(stderr, " data: 0x%"PRIx16,
> + pci_get_word(dev->config + msi_data_off(dev, msi64bit)));
> + if (flags & PCI_MSI_FLAGS_MASKBIT) {
> + fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32,
> + pci_get_long(dev->config + msi_mask_off(dev, msi64bit)),
> + pci_get_long(dev->config + msi_pending_off(dev, msi64bit)));
> + }
> + fprintf(stderr, "\n");
> +#endif
> +
> + if (!(flags & PCI_MSI_FLAGS_ENABLE)) {
> + return;
> + }
> +
> + /*
> + * Now MSI is enabled, clear INTx# interrupts.
> + * the driver is prohibited from writing enable bit to mask
> + * a service request. But the guest OS could do this.
> + * So we just discard the interrupts as moderate fallback.
> + *
> + * 6.8.3.3. Enabling Operation
> + * While enabled for MSI or MSI-X operation, a function is prohibited
> + * from using its INTx# pin (if implemented) to request
> + * service (MSI, MSI-X, and INTx# are mutually exclusive).
> + */
> + pci_device_deassert_intx(dev);
> +
> + /*
> + * nr_vectors might be set bigger than capable. So clamp it.
> + * This is not legal by spec, so we can do anything we like,
> + * just don't crash the host
> + */
> + log_num_vecs =
> + (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
> + log_max_vecs =
> + (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1);
> + if (log_num_vecs > log_max_vecs) {
> + flags &= ~PCI_MSI_FLAGS_QSIZE;
> + flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
> + pci_set_word(dev->config + msi_flags_off(dev), flags);
> + }
> +
> + if (!msi_per_vector_mask) {
> + /* if per vector masking isn't supported,
> + there is no pending interrupt. */
> + return;
> + }
> +
> + nr_vectors = msi_nr_vectors(flags);
> +
> + /* This will discard pending interrupts, if any. */
> + pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit));
> + pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors);
> + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending);
> +
> + /* deliver pending interrupts which are unmasked */
> + for (vector = 0; vector < nr_vectors; ++vector) {
> + if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) {
> + continue;
> + }
> +
> + pci_long_test_and_clear_mask(
> + dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
> + msi_notify(dev, vector);
> + }
> +}
> +
> +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev)
> +{
> + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
> + return msi_nr_vectors(flags);
> +}
> diff --git a/hw/pci/msi.h b/hw/pci/msi.h
> new file mode 100644
> index 0000000..150b09a
> --- /dev/null
> +++ b/hw/pci/msi.h
> @@ -0,0 +1,50 @@
> +/*
> + * msi.h
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef QEMU_MSI_H
> +#define QEMU_MSI_H
> +
> +#include "qemu-common.h"
> +#include "pci.h"
> +
> +struct MSIMessage {
> + uint64_t address;
> + uint32_t data;
> +};
> +
> +extern bool msi_supported;
> +
> +void msi_set_message(PCIDevice *dev, MSIMessage msg);
> +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector);
> +bool msi_enabled(const PCIDevice *dev);
> +int msi_init(struct PCIDevice *dev, uint8_t offset,
> + unsigned int nr_vectors, bool msi64bit, bool
> msi_per_vector_mask);
> +void msi_uninit(struct PCIDevice *dev);
> +void msi_reset(PCIDevice *dev);
> +void msi_notify(PCIDevice *dev, unsigned int vector);
> +void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
> +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
> +
> +static inline bool msi_present(const PCIDevice *dev)
> +{
> + return dev->cap_present & QEMU_PCI_CAP_MSI;
> +}
> +
> +#endif /* QEMU_MSI_H */
> diff --git a/hw/pci/msix.c b/hw/pci/msix.c
> new file mode 100644
> index 0000000..136ef09
> --- /dev/null
> +++ b/hw/pci/msix.c
> @@ -0,0 +1,562 @@
> +/*
> + * MSI-X device support
> + *
> + * This module includes support for MSI-X in pci devices.
> + *
> + * Author: Michael S. Tsirkin <address@hidden>
> + *
> + * Copyright (c) 2009, Red Hat Inc, Michael S. Tsirkin (address@hidden)
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + *
> + * Contributions after 2012-01-13 are licensed under the terms of the
> + * GNU GPL, version 2 or (at your option) any later version.
> + */
> +
> +#include "hw.h"
> +#include "msi.h"
> +#include "msix.h"
> +#include "pci.h"
> +#include "range.h"
> +
> +#define MSIX_CAP_LENGTH 12
> +
> +/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
> +#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1)
> +#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
> +#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
> +
> +static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector)
> +{
> + uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE;
> + MSIMessage msg;
> +
> + msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
> + msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
> + return msg;
> +}
> +
> +/*
> + * Special API for POWER to configure the vectors through
> + * a side channel. Should never be used by devices.
> + */
> +void msix_set_message(PCIDevice *dev, int vector, struct MSIMessage msg)
> +{
> + uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE;
> +
> + pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.address);
> + pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data);
> + table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
> +}
> +
> +static uint8_t msix_pending_mask(int vector)
> +{
> + return 1 << (vector % 8);
> +}
> +
> +static uint8_t *msix_pending_byte(PCIDevice *dev, int vector)
> +{
> + return dev->msix_pba + vector / 8;
> +}
> +
> +static int msix_is_pending(PCIDevice *dev, int vector)
> +{
> + return *msix_pending_byte(dev, vector) & msix_pending_mask(vector);
> +}
> +
> +static void msix_set_pending(PCIDevice *dev, int vector)
> +{
> + *msix_pending_byte(dev, vector) |= msix_pending_mask(vector);
> +}
> +
> +static void msix_clr_pending(PCIDevice *dev, int vector)
> +{
> + *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
> +}
> +
> +static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask)
> +{
> + unsigned offset = vector * PCI_MSIX_ENTRY_SIZE +
> PCI_MSIX_ENTRY_VECTOR_CTRL;
> + return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
> +}
> +
> +static bool msix_is_masked(PCIDevice *dev, int vector)
> +{
> + return msix_vector_masked(dev, vector, dev->msix_function_masked);
> +}
> +
> +static void msix_fire_vector_notifier(PCIDevice *dev,
> + unsigned int vector, bool is_masked)
> +{
> + MSIMessage msg;
> + int ret;
> +
> + if (!dev->msix_vector_use_notifier) {
> + return;
> + }
> + if (is_masked) {
> + dev->msix_vector_release_notifier(dev, vector);
> + } else {
> + msg = msix_get_message(dev, vector);
> + ret = dev->msix_vector_use_notifier(dev, vector, msg);
> + assert(ret >= 0);
> + }
> +}
> +
> +static void msix_handle_mask_update(PCIDevice *dev, int vector, bool
> was_masked)
> +{
> + bool is_masked = msix_is_masked(dev, vector);
> +
> + if (is_masked == was_masked) {
> + return;
> + }
> +
> + msix_fire_vector_notifier(dev, vector, is_masked);
> +
> + if (!is_masked && msix_is_pending(dev, vector)) {
> + msix_clr_pending(dev, vector);
> + msix_notify(dev, vector);
> + }
> +}
> +
> +static void msix_update_function_masked(PCIDevice *dev)
> +{
> + dev->msix_function_masked = !msix_enabled(dev) ||
> + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
> MSIX_MASKALL_MASK);
> +}
> +
> +/* Handle MSI-X capability config write. */
> +void msix_write_config(PCIDevice *dev, uint32_t addr,
> + uint32_t val, int len)
> +{
> + unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
> + int vector;
> + bool was_masked;
> +
> + if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) {
> + return;
> + }
> +
> + was_masked = dev->msix_function_masked;
> + msix_update_function_masked(dev);
> +
> + if (!msix_enabled(dev)) {
> + return;
> + }
> +
> + pci_device_deassert_intx(dev);
> +
> + if (dev->msix_function_masked == was_masked) {
> + return;
> + }
> +
> + for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
> + msix_handle_mask_update(dev, vector,
> + msix_vector_masked(dev, vector, was_masked));
> + }
> +}
> +
> +static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + PCIDevice *dev = opaque;
> +
> + return pci_get_long(dev->msix_table + addr);
> +}
> +
> +static void msix_table_mmio_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + PCIDevice *dev = opaque;
> + int vector = addr / PCI_MSIX_ENTRY_SIZE;
> + bool was_masked;
> +
> + was_masked = msix_is_masked(dev, vector);
> + pci_set_long(dev->msix_table + addr, val);
> + msix_handle_mask_update(dev, vector, was_masked);
> +}
> +
> +static const MemoryRegionOps msix_table_mmio_ops = {
> + .read = msix_table_mmio_read,
> + .write = msix_table_mmio_write,
> + /* TODO: MSIX should be LITTLE_ENDIAN. */
> + .endianness = DEVICE_NATIVE_ENDIAN,
> + .valid = {
> + .min_access_size = 4,
> + .max_access_size = 4,
> + },
> +};
> +
> +static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + PCIDevice *dev = opaque;
> +
> + return pci_get_long(dev->msix_pba + addr);
> +}
> +
> +static const MemoryRegionOps msix_pba_mmio_ops = {
> + .read = msix_pba_mmio_read,
> + /* TODO: MSIX should be LITTLE_ENDIAN. */
> + .endianness = DEVICE_NATIVE_ENDIAN,
> + .valid = {
> + .min_access_size = 4,
> + .max_access_size = 4,
> + },
> +};
> +
> +static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
> +{
> + int vector;
> +
> + for (vector = 0; vector < nentries; ++vector) {
> + unsigned offset =
> + vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
> + bool was_masked = msix_is_masked(dev, vector);
> +
> + dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
> + msix_handle_mask_update(dev, vector, was_masked);
> + }
> +}
> +
> +/* Initialize the MSI-X structures */
> +int msix_init(struct PCIDevice *dev, unsigned short nentries,
> + MemoryRegion *table_bar, uint8_t table_bar_nr,
> + unsigned table_offset, MemoryRegion *pba_bar,
> + uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos)
> +{
> + int cap;
> + unsigned table_size, pba_size;
> + uint8_t *config;
> +
> + /* Nothing to do if MSI is not supported by interrupt controller */
> + if (!msi_supported) {
> + return -ENOTSUP;
> + }
> +
> + if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) {
> + return -EINVAL;
> + }
> +
> + table_size = nentries * PCI_MSIX_ENTRY_SIZE;
> + pba_size = QEMU_ALIGN_UP(nentries, 64) / 8;
> +
> + /* Sanity test: table & pba don't overlap, fit within BARs, min aligned
> */
> + if ((table_bar_nr == pba_bar_nr &&
> + ranges_overlap(table_offset, table_size, pba_offset, pba_size)) ||
> + table_offset + table_size > memory_region_size(table_bar) ||
> + pba_offset + pba_size > memory_region_size(pba_bar) ||
> + (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) {
> + return -EINVAL;
> + }
> +
> + cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH);
> + if (cap < 0) {
> + return cap;
> + }
> +
> + dev->msix_cap = cap;
> + dev->cap_present |= QEMU_PCI_CAP_MSIX;
> + config = dev->config + cap;
> +
> + pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
> + dev->msix_entries_nr = nentries;
> + dev->msix_function_masked = true;
> +
> + pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr);
> + pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr);
> +
> + /* Make flags bit writable. */
> + dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
> + MSIX_MASKALL_MASK;
> +
> + dev->msix_table = g_malloc0(table_size);
> + dev->msix_pba = g_malloc0(pba_size);
> + dev->msix_entry_used = g_malloc0(nentries * sizeof
> *dev->msix_entry_used);
> +
> + msix_mask_all(dev, nentries);
> +
> + memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_ops, dev,
> + "msix-table", table_size);
> + memory_region_add_subregion(table_bar, table_offset,
> &dev->msix_table_mmio);
> + memory_region_init_io(&dev->msix_pba_mmio, &msix_pba_mmio_ops, dev,
> + "msix-pba", pba_size);
> + memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio);
> +
> + return 0;
> +}
> +
> +int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
> + uint8_t bar_nr)
> +{
> + int ret;
> + char *name;
> +
> + /*
> + * Migration compatibility dictates that this remains a 4k
> + * BAR with the vector table in the lower half and PBA in
> + * the upper half. Do not use these elsewhere!
> + */
> +#define MSIX_EXCLUSIVE_BAR_SIZE 4096
> +#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0
> +#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2)
> +#define MSIX_EXCLUSIVE_CAP_OFFSET 0
> +
> + if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) {
> + return -EINVAL;
> + }
> +
> + name = g_strdup_printf("%s-msix", dev->name);
> + memory_region_init(&dev->msix_exclusive_bar, name,
> MSIX_EXCLUSIVE_BAR_SIZE);
> + g_free(name);
> +
> + ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
> + MSIX_EXCLUSIVE_BAR_TABLE_OFFSET,
> &dev->msix_exclusive_bar,
> + bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET,
> + MSIX_EXCLUSIVE_CAP_OFFSET);
> + if (ret) {
> + memory_region_destroy(&dev->msix_exclusive_bar);
> + return ret;
> + }
> +
> + pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY,
> + &dev->msix_exclusive_bar);
> +
> + return 0;
> +}
> +
> +static void msix_free_irq_entries(PCIDevice *dev)
> +{
> + int vector;
> +
> + for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
> + dev->msix_entry_used[vector] = 0;
> + msix_clr_pending(dev, vector);
> + }
> +}
> +
> +static void msix_clear_all_vectors(PCIDevice *dev)
> +{
> + int vector;
> +
> + for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
> + msix_clr_pending(dev, vector);
> + }
> +}
> +
> +/* Clean up resources for the device. */
> +void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion
> *pba_bar)
> +{
> + if (!msix_present(dev)) {
> + return;
> + }
> + pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
> + dev->msix_cap = 0;
> + msix_free_irq_entries(dev);
> + dev->msix_entries_nr = 0;
> + memory_region_del_subregion(pba_bar, &dev->msix_pba_mmio);
> + memory_region_destroy(&dev->msix_pba_mmio);
> + g_free(dev->msix_pba);
> + dev->msix_pba = NULL;
> + memory_region_del_subregion(table_bar, &dev->msix_table_mmio);
> + memory_region_destroy(&dev->msix_table_mmio);
> + g_free(dev->msix_table);
> + dev->msix_table = NULL;
> + g_free(dev->msix_entry_used);
> + dev->msix_entry_used = NULL;
> + dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
> +}
> +
> +void msix_uninit_exclusive_bar(PCIDevice *dev)
> +{
> + if (msix_present(dev)) {
> + msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclusive_bar);
> + memory_region_destroy(&dev->msix_exclusive_bar);
> + }
> +}
> +
> +void msix_save(PCIDevice *dev, QEMUFile *f)
> +{
> + unsigned n = dev->msix_entries_nr;
> +
> + if (!msix_present(dev)) {
> + return;
> + }
> +
> + qemu_put_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
> + qemu_put_buffer(f, dev->msix_pba, (n + 7) / 8);
> +}
> +
> +/* Should be called after restoring the config space. */
> +void msix_load(PCIDevice *dev, QEMUFile *f)
> +{
> + unsigned n = dev->msix_entries_nr;
> + unsigned int vector;
> +
> + if (!msix_present(dev)) {
> + return;
> + }
> +
> + msix_clear_all_vectors(dev);
> + qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
> + qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8);
> + msix_update_function_masked(dev);
> +
> + for (vector = 0; vector < n; vector++) {
> + msix_handle_mask_update(dev, vector, true);
> + }
> +}
> +
> +/* Does device support MSI-X? */
> +int msix_present(PCIDevice *dev)
> +{
> + return dev->cap_present & QEMU_PCI_CAP_MSIX;
> +}
> +
> +/* Is MSI-X enabled? */
> +int msix_enabled(PCIDevice *dev)
> +{
> + return (dev->cap_present & QEMU_PCI_CAP_MSIX) &&
> + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
> + MSIX_ENABLE_MASK);
> +}
> +
> +/* Send an MSI-X message */
> +void msix_notify(PCIDevice *dev, unsigned vector)
> +{
> + MSIMessage msg;
> +
> + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
> + return;
> + if (msix_is_masked(dev, vector)) {
> + msix_set_pending(dev, vector);
> + return;
> + }
> +
> + msg = msix_get_message(dev, vector);
> +
> + stl_le_phys(msg.address, msg.data);
> +}
> +
> +void msix_reset(PCIDevice *dev)
> +{
> + if (!msix_present(dev)) {
> + return;
> + }
> + msix_clear_all_vectors(dev);
> + dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
> + ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
> + memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE);
> + memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8);
> + msix_mask_all(dev, dev->msix_entries_nr);
> +}
> +
> +/* PCI spec suggests that devices make it possible for software to configure
> + * less vectors than supported by the device, but does not specify a standard
> + * mechanism for devices to do so.
> + *
> + * We support this by asking devices to declare vectors software is going to
> + * actually use, and checking this on the notification path. Devices that
> + * don't want to follow the spec suggestion can declare all vectors as used.
> */
> +
> +/* Mark vector as used. */
> +int msix_vector_use(PCIDevice *dev, unsigned vector)
> +{
> + if (vector >= dev->msix_entries_nr)
> + return -EINVAL;
> + dev->msix_entry_used[vector]++;
> + return 0;
> +}
> +
> +/* Mark vector as unused. */
> +void msix_vector_unuse(PCIDevice *dev, unsigned vector)
> +{
> + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) {
> + return;
> + }
> + if (--dev->msix_entry_used[vector]) {
> + return;
> + }
> + msix_clr_pending(dev, vector);
> +}
> +
> +void msix_unuse_all_vectors(PCIDevice *dev)
> +{
> + if (!msix_present(dev)) {
> + return;
> + }
> + msix_free_irq_entries(dev);
> +}
> +
> +unsigned int msix_nr_vectors_allocated(const PCIDevice *dev)
> +{
> + return dev->msix_entries_nr;
> +}
> +
> +static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector)
> +{
> + MSIMessage msg;
> +
> + if (msix_is_masked(dev, vector)) {
> + return 0;
> + }
> + msg = msix_get_message(dev, vector);
> + return dev->msix_vector_use_notifier(dev, vector, msg);
> +}
> +
> +static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int
> vector)
> +{
> + if (msix_is_masked(dev, vector)) {
> + return;
> + }
> + dev->msix_vector_release_notifier(dev, vector);
> +}
> +
> +int msix_set_vector_notifiers(PCIDevice *dev,
> + MSIVectorUseNotifier use_notifier,
> + MSIVectorReleaseNotifier release_notifier)
> +{
> + int vector, ret;
> +
> + assert(use_notifier && release_notifier);
> +
> + dev->msix_vector_use_notifier = use_notifier;
> + dev->msix_vector_release_notifier = release_notifier;
> +
> + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
> + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
> + for (vector = 0; vector < dev->msix_entries_nr; vector++) {
> + ret = msix_set_notifier_for_vector(dev, vector);
> + if (ret < 0) {
> + goto undo;
> + }
> + }
> + }
> + return 0;
> +
> +undo:
> + while (--vector >= 0) {
> + msix_unset_notifier_for_vector(dev, vector);
> + }
> + dev->msix_vector_use_notifier = NULL;
> + dev->msix_vector_release_notifier = NULL;
> + return ret;
> +}
> +
> +void msix_unset_vector_notifiers(PCIDevice *dev)
> +{
> + int vector;
> +
> + assert(dev->msix_vector_use_notifier &&
> + dev->msix_vector_release_notifier);
> +
> + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
> + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
> + for (vector = 0; vector < dev->msix_entries_nr; vector++) {
> + msix_unset_notifier_for_vector(dev, vector);
> + }
> + }
> + dev->msix_vector_use_notifier = NULL;
> + dev->msix_vector_release_notifier = NULL;
> +}
> diff --git a/hw/pci/msix.h b/hw/pci/msix.h
> new file mode 100644
> index 0000000..15211cb
> --- /dev/null
> +++ b/hw/pci/msix.h
> @@ -0,0 +1,41 @@
> +#ifndef QEMU_MSIX_H
> +#define QEMU_MSIX_H
> +
> +#include "qemu-common.h"
> +#include "pci.h"
> +
> +void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg);
> +int msix_init(PCIDevice *dev, unsigned short nentries,
> + MemoryRegion *table_bar, uint8_t table_bar_nr,
> + unsigned table_offset, MemoryRegion *pba_bar,
> + uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos);
> +int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
> + uint8_t bar_nr);
> +
> +void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int
> len);
> +
> +void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar,
> + MemoryRegion *pba_bar);
> +void msix_uninit_exclusive_bar(PCIDevice *dev);
> +
> +unsigned int msix_nr_vectors_allocated(const PCIDevice *dev);
> +
> +void msix_save(PCIDevice *dev, QEMUFile *f);
> +void msix_load(PCIDevice *dev, QEMUFile *f);
> +
> +int msix_enabled(PCIDevice *dev);
> +int msix_present(PCIDevice *dev);
> +
> +int msix_vector_use(PCIDevice *dev, unsigned vector);
> +void msix_vector_unuse(PCIDevice *dev, unsigned vector);
> +void msix_unuse_all_vectors(PCIDevice *dev);
> +
> +void msix_notify(PCIDevice *dev, unsigned vector);
> +
> +void msix_reset(PCIDevice *dev);
> +
> +int msix_set_vector_notifiers(PCIDevice *dev,
> + MSIVectorUseNotifier use_notifier,
> + MSIVectorReleaseNotifier release_notifier);
> +void msix_unset_vector_notifiers(PCIDevice *dev);
> +#endif
> diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c
> new file mode 100644
> index 0000000..0ca5546
> --- /dev/null
> +++ b/hw/pci/pci-hotplug.c
> @@ -0,0 +1,293 @@
> +/*
> + * QEMU PCI hotplug support
> + *
> + * Copyright (c) 2004 Fabrice Bellard
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> + * of this software and associated documentation files (the "Software"), to
> deal
> + * in the Software without restriction, including without limitation the
> rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "hw.h"
> +#include "boards.h"
> +#include "pci.h"
> +#include "net.h"
> +#include "pc.h"
> +#include "monitor.h"
> +#include "scsi.h"
> +#include "virtio-blk.h"
> +#include "qemu-config.h"
> +#include "blockdev.h"
> +#include "error.h"
> +
> +#if defined(TARGET_I386)
> +static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
> + const char *devaddr,
> + const char *opts_str)
> +{
> + Error *local_err = NULL;
> + QemuOpts *opts;
> + PCIBus *bus;
> + int ret, devfn;
> +
> + bus = pci_get_bus_devfn(&devfn, devaddr);
> + if (!bus) {
> + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
> + return NULL;
> + }
> + if (!((BusState*)bus)->allow_hotplug) {
> + monitor_printf(mon, "PCI bus doesn't support hotplug\n");
> + return NULL;
> + }
> +
> + opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "",
> 0);
> + if (!opts) {
> + return NULL;
> + }
> +
> + qemu_opt_set(opts, "type", "nic");
> +
> + ret = net_client_init(opts, 0, &local_err);
> + if (error_is_set(&local_err)) {
> + qerror_report_err(local_err);
> + error_free(local_err);
> + return NULL;
> + }
> + if (nd_table[ret].devaddr) {
> + monitor_printf(mon, "Parameter addr not supported\n");
> + return NULL;
> + }
> + return pci_nic_init(&nd_table[ret], "rtl8139", devaddr);
> +}
> +
> +static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
> + DriveInfo *dinfo, int printinfo)
> +{
> + SCSIBus *scsibus;
> + SCSIDevice *scsidev;
> +
> + scsibus = (SCSIBus *)
> + object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)),
> + TYPE_SCSI_BUS);
> + if (!scsibus) {
> + error_report("Device is not a SCSI adapter");
> + return -1;
> + }
> +
> + /*
> + * drive_init() tries to find a default for dinfo->unit. Doesn't
> + * work at all for hotplug though as we assign the device to a
> + * specific bus instead of the first bus with spare scsi ids.
> + *
> + * Ditch the calculated value and reload from option string (if
> + * specified).
> + */
> + dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
> + dinfo->bus = scsibus->busnr;
> + scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit,
> + false, -1);
> + if (!scsidev) {
> + return -1;
> + }
> + dinfo->unit = scsidev->id;
> +
> + if (printinfo)
> + monitor_printf(mon, "OK bus %d, unit %d\n",
> + scsibus->busnr, scsidev->id);
> + return 0;
> +}
> +
> +int pci_drive_hot_add(Monitor *mon, const QDict *qdict,
> + DriveInfo *dinfo, int type)
> +{
> + int dom, pci_bus;
> + unsigned slot;
> + PCIDevice *dev;
> + const char *pci_addr = qdict_get_str(qdict, "pci_addr");
> +
> + switch (type) {
> + case IF_SCSI:
> + if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) {
> + goto err;
> + }
> + dev = pci_find_device(pci_find_root_bus(dom), pci_bus,
> + PCI_DEVFN(slot, 0));
> + if (!dev) {
> + monitor_printf(mon, "no pci device with address %s\n", pci_addr);
> + goto err;
> + }
> + if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) {
> + goto err;
> + }
> + break;
> + default:
> + monitor_printf(mon, "Can't hot-add drive to type %d\n", type);
> + goto err;
> + }
> +
> + return 0;
> +err:
> + return -1;
> +}
> +
> +static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
> + const char *devaddr,
> + const char *opts)
> +{
> + PCIDevice *dev;
> + DriveInfo *dinfo = NULL;
> + int type = -1;
> + char buf[128];
> + PCIBus *bus;
> + int devfn;
> +
> + if (get_param_value(buf, sizeof(buf), "if", opts)) {
> + if (!strcmp(buf, "scsi"))
> + type = IF_SCSI;
> + else if (!strcmp(buf, "virtio")) {
> + type = IF_VIRTIO;
> + } else {
> + monitor_printf(mon, "type %s not a hotpluggable PCI device.\n",
> buf);
> + return NULL;
> + }
> + } else {
> + monitor_printf(mon, "no if= specified\n");
> + return NULL;
> + }
> +
> + if (get_param_value(buf, sizeof(buf), "file", opts)) {
> + dinfo = add_init_drive(opts);
> + if (!dinfo)
> + return NULL;
> + if (dinfo->devaddr) {
> + monitor_printf(mon, "Parameter addr not supported\n");
> + return NULL;
> + }
> + } else {
> + dinfo = NULL;
> + }
> +
> + bus = pci_get_bus_devfn(&devfn, devaddr);
> + if (!bus) {
> + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
> + return NULL;
> + }
> + if (!((BusState*)bus)->allow_hotplug) {
> + monitor_printf(mon, "PCI bus doesn't support hotplug\n");
> + return NULL;
> + }
> +
> + switch (type) {
> + case IF_SCSI:
> + dev = pci_create(bus, devfn, "lsi53c895a");
> + if (qdev_init(&dev->qdev) < 0)
> + dev = NULL;
> + if (dev && dinfo) {
> + if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) {
> + qdev_unplug(&dev->qdev, NULL);
> + dev = NULL;
> + }
> + }
> + break;
> + case IF_VIRTIO:
> + if (!dinfo) {
> + monitor_printf(mon, "virtio requires a backing file/device.\n");
> + return NULL;
> + }
> + dev = pci_create(bus, devfn, "virtio-blk-pci");
> + if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
> + qdev_free(&dev->qdev);
> + dev = NULL;
> + break;
> + }
> + if (qdev_init(&dev->qdev) < 0)
> + dev = NULL;
> + break;
> + default:
> + dev = NULL;
> + }
> + return dev;
> +}
> +
> +void pci_device_hot_add(Monitor *mon, const QDict *qdict)
> +{
> + PCIDevice *dev = NULL;
> + const char *pci_addr = qdict_get_str(qdict, "pci_addr");
> + const char *type = qdict_get_str(qdict, "type");
> + const char *opts = qdict_get_try_str(qdict, "opts");
> +
> + /* strip legacy tag */
> + if (!strncmp(pci_addr, "pci_addr=", 9)) {
> + pci_addr += 9;
> + }
> +
> + if (!opts) {
> + opts = "";
> + }
> +
> + if (!strcmp(pci_addr, "auto"))
> + pci_addr = NULL;
> +
> + if (strcmp(type, "nic") == 0) {
> + dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
> + } else if (strcmp(type, "storage") == 0) {
> + dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
> + } else {
> + monitor_printf(mon, "invalid type: %s\n", type);
> + }
> +
> + if (dev) {
> + monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
> + pci_find_domain(dev->bus),
> + pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
> + PCI_FUNC(dev->devfn));
> + } else
> + monitor_printf(mon, "failed to add %s\n", opts);
> +}
> +#endif
> +
> +static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
> +{
> + PCIDevice *d;
> + int dom, bus;
> + unsigned slot;
> + Error *local_err = NULL;
> +
> + if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
> + return -1;
> + }
> +
> + d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0));
> + if (!d) {
> + monitor_printf(mon, "slot %d empty\n", slot);
> + return -1;
> + }
> +
> + qdev_unplug(&d->qdev, &local_err);
> + if (error_is_set(&local_err)) {
> + monitor_printf(mon, "%s\n", error_get_pretty(local_err));
> + error_free(local_err);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict)
> +{
> + pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
> +}
> diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c
> new file mode 100644
> index 0000000..134c448
> --- /dev/null
> +++ b/hw/pci/pci-stub.c
> @@ -0,0 +1,47 @@
> +/*
> + * PCI stubs for platforms that don't support pci bus.
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "sysemu.h"
> +#include "monitor.h"
> +#include "pci.h"
> +#include "qmp-commands.h"
> +
> +PciInfoList *qmp_query_pci(Error **errp)
> +{
> + error_set(errp, QERR_UNSUPPORTED);
> + return NULL;
> +}
> +
> +static void pci_error_message(Monitor *mon)
> +{
> + monitor_printf(mon, "PCI devices not supported\n");
> +}
> +
> +int do_pcie_aer_inject_error(Monitor *mon,
> + const QDict *qdict, QObject **ret_data)
> +{
> + pci_error_message(mon);
> + return -ENOSYS;
> +}
> +
> +void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
> +{
> + pci_error_message(mon);
> +}
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> new file mode 100644
> index 0000000..97a0cd7
> --- /dev/null
> +++ b/hw/pci/pci.c
> @@ -0,0 +1,2168 @@
> +/*
> + * QEMU PCI bus manager
> + *
> + * Copyright (c) 2004 Fabrice Bellard
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> + * of this software and associated documentation files (the "Software"), to
> deal
> + * in the Software without restriction, including without limitation the
> rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +#include "hw.h"
> +#include "pci.h"
> +#include "pci_bridge.h"
> +#include "pci_internals.h"
> +#include "monitor.h"
> +#include "net.h"
> +#include "sysemu.h"
> +#include "loader.h"
> +#include "range.h"
> +#include "qmp-commands.h"
> +#include "msi.h"
> +#include "msix.h"
> +#include "exec-memory.h"
> +
> +//#define DEBUG_PCI
> +#ifdef DEBUG_PCI
> +# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
> +#else
> +# define PCI_DPRINTF(format, ...) do { } while (0)
> +#endif
> +
> +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
> +static char *pcibus_get_dev_path(DeviceState *dev);
> +static char *pcibus_get_fw_dev_path(DeviceState *dev);
> +static int pcibus_reset(BusState *qbus);
> +
> +static Property pci_props[] = {
> + DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
> + DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
> + DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1),
> + DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
> + QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
> + DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
> + QEMU_PCI_CAP_SERR_BITNR, true),
> + DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static void pci_bus_class_init(ObjectClass *klass, void *data)
> +{
> + BusClass *k = BUS_CLASS(klass);
> +
> + k->print_dev = pcibus_dev_print;
> + k->get_dev_path = pcibus_get_dev_path;
> + k->get_fw_dev_path = pcibus_get_fw_dev_path;
> + k->reset = pcibus_reset;
> +}
> +
> +static const TypeInfo pci_bus_info = {
> + .name = TYPE_PCI_BUS,
> + .parent = TYPE_BUS,
> + .instance_size = sizeof(PCIBus),
> + .class_init = pci_bus_class_init,
> +};
> +
> +static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
> +static void pci_update_mappings(PCIDevice *d);
> +static void pci_set_irq(void *opaque, int irq_num, int level);
> +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom);
> +static void pci_del_option_rom(PCIDevice *pdev);
> +
> +static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
> +static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
> +
> +struct PCIHostBus {
> + int domain;
> + struct PCIBus *bus;
> + QLIST_ENTRY(PCIHostBus) next;
> +};
> +static QLIST_HEAD(, PCIHostBus) host_buses;
> +
> +static const VMStateDescription vmstate_pcibus = {
> + .name = "PCIBUS",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField []) {
> + VMSTATE_INT32_EQUAL(nirq, PCIBus),
> + VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32,
> int32_t),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +static int pci_bar(PCIDevice *d, int reg)
> +{
> + uint8_t type;
> +
> + if (reg != PCI_ROM_SLOT)
> + return PCI_BASE_ADDRESS_0 + reg * 4;
> +
> + type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
> + return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 :
> PCI_ROM_ADDRESS;
> +}
> +
> +static inline int pci_irq_state(PCIDevice *d, int irq_num)
> +{
> + return (d->irq_state >> irq_num) & 0x1;
> +}
> +
> +static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level)
> +{
> + d->irq_state &= ~(0x1 << irq_num);
> + d->irq_state |= level << irq_num;
> +}
> +
> +static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
> +{
> + PCIBus *bus;
> + for (;;) {
> + bus = pci_dev->bus;
> + irq_num = bus->map_irq(pci_dev, irq_num);
> + if (bus->set_irq)
> + break;
> + pci_dev = bus->parent_dev;
> + }
> + bus->irq_count[irq_num] += change;
> + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
> +}
> +
> +int pci_bus_get_irq_level(PCIBus *bus, int irq_num)
> +{
> + assert(irq_num >= 0);
> + assert(irq_num < bus->nirq);
> + return !!bus->irq_count[irq_num];
> +}
> +
> +/* Update interrupt status bit in config space on interrupt
> + * state change. */
> +static void pci_update_irq_status(PCIDevice *dev)
> +{
> + if (dev->irq_state) {
> + dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT;
> + } else {
> + dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
> + }
> +}
> +
> +void pci_device_deassert_intx(PCIDevice *dev)
> +{
> + int i;
> + for (i = 0; i < PCI_NUM_PINS; ++i) {
> + qemu_set_irq(dev->irq[i], 0);
> + }
> +}
> +
> +/*
> + * This function is called on #RST and FLR.
> + * FLR if PCI_EXP_DEVCTL_BCR_FLR is set
> + */
> +void pci_device_reset(PCIDevice *dev)
> +{
> + int r;
> +
> + qdev_reset_all(&dev->qdev);
> +
> + dev->irq_state = 0;
> + pci_update_irq_status(dev);
> + pci_device_deassert_intx(dev);
> + /* Clear all writable bits */
> + pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
> + pci_get_word(dev->wmask + PCI_COMMAND) |
> + pci_get_word(dev->w1cmask + PCI_COMMAND));
> + pci_word_test_and_clear_mask(dev->config + PCI_STATUS,
> + pci_get_word(dev->wmask + PCI_STATUS) |
> + pci_get_word(dev->w1cmask + PCI_STATUS));
> + dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
> + dev->config[PCI_INTERRUPT_LINE] = 0x0;
> + for (r = 0; r < PCI_NUM_REGIONS; ++r) {
> + PCIIORegion *region = &dev->io_regions[r];
> + if (!region->size) {
> + continue;
> + }
> +
> + if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) &&
> + region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
> + pci_set_quad(dev->config + pci_bar(dev, r), region->type);
> + } else {
> + pci_set_long(dev->config + pci_bar(dev, r), region->type);
> + }
> + }
> + pci_update_mappings(dev);
> +
> + msi_reset(dev);
> + msix_reset(dev);
> +}
> +
> +/*
> + * Trigger pci bus reset under a given bus.
> + * To be called on RST# assert.
> + */
> +void pci_bus_reset(PCIBus *bus)
> +{
> + int i;
> +
> + for (i = 0; i < bus->nirq; i++) {
> + bus->irq_count[i] = 0;
> + }
> + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
> + if (bus->devices[i]) {
> + pci_device_reset(bus->devices[i]);
> + }
> + }
> +}
> +
> +static int pcibus_reset(BusState *qbus)
> +{
> + pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus));
> +
> + /* topology traverse is done by pci_bus_reset().
> + Tell qbus/qdev walker not to traverse the tree */
> + return 1;
> +}
> +
> +static void pci_host_bus_register(int domain, PCIBus *bus)
> +{
> + struct PCIHostBus *host;
> + host = g_malloc0(sizeof(*host));
> + host->domain = domain;
> + host->bus = bus;
> + QLIST_INSERT_HEAD(&host_buses, host, next);
> +}
> +
> +PCIBus *pci_find_root_bus(int domain)
> +{
> + struct PCIHostBus *host;
> +
> + QLIST_FOREACH(host, &host_buses, next) {
> + if (host->domain == domain) {
> + return host->bus;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +int pci_find_domain(const PCIBus *bus)
> +{
> + PCIDevice *d;
> + struct PCIHostBus *host;
> +
> + /* obtain root bus */
> + while ((d = bus->parent_dev) != NULL) {
> + bus = d->bus;
> + }
> +
> + QLIST_FOREACH(host, &host_buses, next) {
> + if (host->bus == bus) {
> + return host->domain;
> + }
> + }
> +
> + abort(); /* should not be reached */
> + return -1;
> +}
> +
> +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
> + const char *name,
> + MemoryRegion *address_space_mem,
> + MemoryRegion *address_space_io,
> + uint8_t devfn_min)
> +{
> + qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name);
> + assert(PCI_FUNC(devfn_min) == 0);
> + bus->devfn_min = devfn_min;
> + bus->address_space_mem = address_space_mem;
> + bus->address_space_io = address_space_io;
> +
> + /* host bridge */
> + QLIST_INIT(&bus->child);
> + pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported
> */
> +
> + vmstate_register(NULL, -1, &vmstate_pcibus, bus);
> +}
> +
> +PCIBus *pci_bus_new(DeviceState *parent, const char *name,
> + MemoryRegion *address_space_mem,
> + MemoryRegion *address_space_io,
> + uint8_t devfn_min)
> +{
> + PCIBus *bus;
> +
> + bus = g_malloc0(sizeof(*bus));
> + pci_bus_new_inplace(bus, parent, name, address_space_mem,
> + address_space_io, devfn_min);
> + OBJECT(bus)->free = g_free;
> + return bus;
> +}
> +
> +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn
> map_irq,
> + void *irq_opaque, int nirq)
> +{
> + bus->set_irq = set_irq;
> + bus->map_irq = map_irq;
> + bus->irq_opaque = irq_opaque;
> + bus->nirq = nirq;
> + bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0]));
> +}
> +
> +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
> +{
> + bus->qbus.allow_hotplug = 1;
> + bus->hotplug = hotplug;
> + bus->hotplug_qdev = qdev;
> +}
> +
> +PCIBus *pci_register_bus(DeviceState *parent, const char *name,
> + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
> + void *irq_opaque,
> + MemoryRegion *address_space_mem,
> + MemoryRegion *address_space_io,
> + uint8_t devfn_min, int nirq)
> +{
> + PCIBus *bus;
> +
> + bus = pci_bus_new(parent, name, address_space_mem,
> + address_space_io, devfn_min);
> + pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
> + return bus;
> +}
> +
> +int pci_bus_num(PCIBus *s)
> +{
> + if (!s->parent_dev)
> + return 0; /* pci host bridge */
> + return s->parent_dev->config[PCI_SECONDARY_BUS];
> +}
> +
> +static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
> +{
> + PCIDevice *s = container_of(pv, PCIDevice, config);
> + uint8_t *config;
> + int i;
> +
> + assert(size == pci_config_size(s));
> + config = g_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] & ~s->w1cmask[i]) {
> + g_free(config);
> + return -EINVAL;
> + }
> + }
> + memcpy(s->config, config, size);
> +
> + pci_update_mappings(s);
> +
> + memory_region_set_enabled(&s->bus_master_enable_region,
> + pci_get_word(s->config + PCI_COMMAND)
> + & PCI_COMMAND_MASTER);
> +
> + g_free(config);
> + return 0;
> +}
> +
> +/* just put buffer */
> +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);
> +}
> +
> +static VMStateInfo vmstate_info_pci_config = {
> + .name = "pci config",
> + .get = get_pci_config_device,
> + .put = put_pci_config_device,
> +};
> +
> +static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
> +{
> + PCIDevice *s = container_of(pv, PCIDevice, irq_state);
> + uint32_t irq_state[PCI_NUM_PINS];
> + int i;
> + for (i = 0; i < PCI_NUM_PINS; ++i) {
> + irq_state[i] = qemu_get_be32(f);
> + if (irq_state[i] != 0x1 && irq_state[i] != 0) {
> + fprintf(stderr, "irq state %d: must be 0 or 1.\n",
> + irq_state[i]);
> + return -EINVAL;
> + }
> + }
> +
> + for (i = 0; i < PCI_NUM_PINS; ++i) {
> + pci_set_irq_state(s, i, irq_state[i]);
> + }
> +
> + return 0;
> +}
> +
> +static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size)
> +{
> + int i;
> + PCIDevice *s = container_of(pv, PCIDevice, irq_state);
> +
> + for (i = 0; i < PCI_NUM_PINS; ++i) {
> + qemu_put_be32(f, pci_irq_state(s, i));
> + }
> +}
> +
> +static VMStateInfo vmstate_info_pci_irq_state = {
> + .name = "pci irq state",
> + .get = get_pci_irq_state,
> + .put = put_pci_irq_state,
> +};
> +
> +const VMStateDescription vmstate_pci_device = {
> + .name = "PCIDevice",
> + .version_id = 2,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField []) {
> + VMSTATE_INT32_LE(version_id, PCIDevice),
> + VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
> + vmstate_info_pci_config,
> + PCI_CONFIG_SPACE_SIZE),
> + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
> + vmstate_info_pci_irq_state,
> + PCI_NUM_PINS * sizeof(int32_t)),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +const VMStateDescription vmstate_pcie_device = {
> + .name = "PCIEDevice",
> + .version_id = 2,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField []) {
> + VMSTATE_INT32_LE(version_id, PCIDevice),
> + VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
> + vmstate_info_pci_config,
> + PCIE_CONFIG_SPACE_SIZE),
> + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
> + vmstate_info_pci_irq_state,
> + PCI_NUM_PINS * sizeof(int32_t)),
> + 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)
> +{
> + /* Clear interrupt status bit: it is implicit
> + * in irq_state which we are saving.
> + * This makes us compatible with old devices
> + * which never set or clear this bit. */
> + s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
> + vmstate_save_state(f, pci_get_vmstate(s), s);
> + /* Restore the interrupt status bit. */
> + pci_update_irq_status(s);
> +}
> +
> +int pci_device_load(PCIDevice *s, QEMUFile *f)
> +{
> + int ret;
> + ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
> + /* Restore the interrupt status bit. */
> + pci_update_irq_status(s);
> + return ret;
> +}
> +
> +static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
> +{
> + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
> + pci_default_sub_vendor_id);
> + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
> + pci_default_sub_device_id);
> +}
> +
> +/*
> + * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
> + * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
> + */
> +static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
> + unsigned int *slotp, unsigned int *funcp)
> +{
> + const char *p;
> + char *e;
> + unsigned long val;
> + unsigned long dom = 0, bus = 0;
> + unsigned int slot = 0;
> + unsigned int func = 0;
> +
> + p = addr;
> + val = strtoul(p, &e, 16);
> + if (e == p)
> + return -1;
> + if (*e == ':') {
> + bus = val;
> + p = e + 1;
> + val = strtoul(p, &e, 16);
> + if (e == p)
> + return -1;
> + if (*e == ':') {
> + dom = bus;
> + bus = val;
> + p = e + 1;
> + val = strtoul(p, &e, 16);
> + if (e == p)
> + return -1;
> + }
> + }
> +
> + slot = val;
> +
> + if (funcp != NULL) {
> + if (*e != '.')
> + return -1;
> +
> + p = e + 1;
> + val = strtoul(p, &e, 16);
> + if (e == p)
> + return -1;
> +
> + func = val;
> + }
> +
> + /* if funcp == NULL func is 0 */
> + if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
> + return -1;
> +
> + if (*e)
> + return -1;
> +
> + *domp = dom;
> + *busp = bus;
> + *slotp = slot;
> + if (funcp != NULL)
> + *funcp = func;
> + return 0;
> +}
> +
> +int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
> + unsigned *slotp)
> +{
> + /* strip legacy tag */
> + if (!strncmp(addr, "pci_addr=", 9)) {
> + addr += 9;
> + }
> + if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) {
> + monitor_printf(mon, "Invalid pci address\n");
> + return -1;
> + }
> + return 0;
> +}
> +
> +PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
> +{
> + int dom, bus;
> + unsigned slot;
> +
> + if (!devaddr) {
> + *devfnp = -1;
> + return pci_find_bus_nr(pci_find_root_bus(0), 0);
> + }
> +
> + if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
> + return NULL;
> + }
> +
> + *devfnp = PCI_DEVFN(slot, 0);
> + return pci_find_bus_nr(pci_find_root_bus(dom), bus);
> +}
> +
> +static void pci_init_cmask(PCIDevice *dev)
> +{
> + pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff);
> + pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff);
> + dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST;
> + dev->cmask[PCI_REVISION_ID] = 0xff;
> + dev->cmask[PCI_CLASS_PROG] = 0xff;
> + pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff);
> + dev->cmask[PCI_HEADER_TYPE] = 0xff;
> + dev->cmask[PCI_CAPABILITY_LIST] = 0xff;
> +}
> +
> +static void pci_init_wmask(PCIDevice *dev)
> +{
> + int config_size = pci_config_size(dev);
> +
> + dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff;
> + dev->wmask[PCI_INTERRUPT_LINE] = 0xff;
> + pci_set_word(dev->wmask + PCI_COMMAND,
> + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
> + PCI_COMMAND_INTX_DISABLE);
> + if (dev->cap_present & QEMU_PCI_CAP_SERR) {
> + pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND,
> PCI_COMMAND_SERR);
> + }
> +
> + memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
> + config_size - PCI_CONFIG_HEADER_SIZE);
> +}
> +
> +static void pci_init_w1cmask(PCIDevice *dev)
> +{
> + /*
> + * Note: It's okay to set w1cmask even for readonly bits as
> + * long as their value is hardwired to 0.
> + */
> + pci_set_word(dev->w1cmask + PCI_STATUS,
> + PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT |
> + PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT |
> + PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
> +}
> +
> +static void pci_init_mask_bridge(PCIDevice *d)
> +{
> + /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and
> + PCI_SEC_LETENCY_TIMER */
> + memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4);
> +
> + /* base and limit */
> + d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff;
> + d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff;
> + pci_set_word(d->wmask + PCI_MEMORY_BASE,
> + PCI_MEMORY_RANGE_MASK & 0xffff);
> + pci_set_word(d->wmask + PCI_MEMORY_LIMIT,
> + PCI_MEMORY_RANGE_MASK & 0xffff);
> + pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE,
> + PCI_PREF_RANGE_MASK & 0xffff);
> + pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT,
> + PCI_PREF_RANGE_MASK & 0xffff);
> +
> + /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */
> + memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);
> +
> + /* Supported memory and i/o types */
> + d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16;
> + d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16;
> + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
> + PCI_PREF_RANGE_TYPE_64);
> + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
> + PCI_PREF_RANGE_TYPE_64);
> +
> +/* TODO: add this define to pci_regs.h in linux and then in qemu. */
> +#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */
> +#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard
> timer */
> +#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */
> +#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */
> +#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable
> */
> + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
> + PCI_BRIDGE_CTL_PARITY |
> + PCI_BRIDGE_CTL_SERR |
> + PCI_BRIDGE_CTL_ISA |
> + PCI_BRIDGE_CTL_VGA |
> + PCI_BRIDGE_CTL_VGA_16BIT |
> + PCI_BRIDGE_CTL_MASTER_ABORT |
> + PCI_BRIDGE_CTL_BUS_RESET |
> + PCI_BRIDGE_CTL_FAST_BACK |
> + PCI_BRIDGE_CTL_DISCARD |
> + PCI_BRIDGE_CTL_SEC_DISCARD |
> + PCI_BRIDGE_CTL_DISCARD_SERR);
> + /* Below does not do anything as we never set this bit, put here for
> + * completeness. */
> + pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL,
> + PCI_BRIDGE_CTL_DISCARD_STATUS);
> + d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK;
> + d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK;
> + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE,
> + PCI_PREF_RANGE_TYPE_MASK);
> + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT,
> + PCI_PREF_RANGE_TYPE_MASK);
> +}
> +
> +static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
> +{
> + uint8_t slot = PCI_SLOT(dev->devfn);
> + uint8_t func;
> +
> + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
> + dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
> + }
> +
> + /*
> + * multifunction bit is interpreted in two ways as follows.
> + * - all functions must set the bit to 1.
> + * Example: Intel X53
> + * - function 0 must set the bit, but the rest function (> 0)
> + * is allowed to leave the bit to 0.
> + * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10,
> + *
> + * So OS (at least Linux) checks the bit of only function 0,
> + * and doesn't see the bit of function > 0.
> + *
> + * The below check allows both interpretation.
> + */
> + if (PCI_FUNC(dev->devfn)) {
> + PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)];
> + if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) {
> + /* function 0 should set multifunction bit */
> + error_report("PCI: single function device can't be populated "
> + "in function %x.%x", slot, PCI_FUNC(dev->devfn));
> + return -1;
> + }
> + return 0;
> + }
> +
> + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
> + return 0;
> + }
> + /* function 0 indicates single function, so function > 0 must be NULL */
> + for (func = 1; func < PCI_FUNC_MAX; ++func) {
> + if (bus->devices[PCI_DEVFN(slot, func)]) {
> + error_report("PCI: %x.0 indicates single function, "
> + "but %x.%x is already populated.",
> + slot, slot, func);
> + return -1;
> + }
> + }
> + return 0;
> +}
> +
> +static void pci_config_alloc(PCIDevice *pci_dev)
> +{
> + int config_size = pci_config_size(pci_dev);
> +
> + pci_dev->config = g_malloc0(config_size);
> + pci_dev->cmask = g_malloc0(config_size);
> + pci_dev->wmask = g_malloc0(config_size);
> + pci_dev->w1cmask = g_malloc0(config_size);
> + pci_dev->used = g_malloc0(config_size);
> +}
> +
> +static void pci_config_free(PCIDevice *pci_dev)
> +{
> + g_free(pci_dev->config);
> + g_free(pci_dev->cmask);
> + g_free(pci_dev->wmask);
> + g_free(pci_dev->w1cmask);
> + g_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)
> +{
> + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
> + PCIConfigReadFunc *config_read = pc->config_read;
> + PCIConfigWriteFunc *config_write = pc->config_write;
> +
> + if (devfn < 0) {
> + for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
> + devfn += PCI_FUNC_MAX) {
> + if (!bus->devices[devfn])
> + goto found;
> + }
> + error_report("PCI: no slot/function available for %s, all in use",
> name);
> + return NULL;
> + found: ;
> + } else if (bus->devices[devfn]) {
> + error_report("PCI: slot %d function %d not available for %s, in use
> by %s",
> + PCI_SLOT(devfn), PCI_FUNC(devfn), name,
> bus->devices[devfn]->name);
> + return NULL;
> + }
> + pci_dev->bus = bus;
> + if (bus->dma_context_fn) {
> + pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque,
> devfn);
> + } else {
> + /* FIXME: Make dma_context_fn use MemoryRegions instead, so this
> path is
> + * taken unconditionally */
> + /* FIXME: inherit memory region from bus creator */
> + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus
> master",
> + get_system_memory(), 0,
> + memory_region_size(get_system_memory()));
> + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
> + address_space_init(&pci_dev->bus_master_as,
> &pci_dev->bus_master_enable_region);
> + pci_dev->dma = g_new(DMAContext, 1);
> + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL,
> NULL);
> + }
> + pci_dev->devfn = devfn;
> + pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
> + pci_dev->irq_state = 0;
> + pci_config_alloc(pci_dev);
> +
> + pci_config_set_vendor_id(pci_dev->config, pc->vendor_id);
> + pci_config_set_device_id(pci_dev->config, pc->device_id);
> + pci_config_set_revision(pci_dev->config, pc->revision);
> + pci_config_set_class(pci_dev->config, pc->class_id);
> +
> + if (!pc->is_bridge) {
> + if (pc->subsystem_vendor_id || pc->subsystem_id) {
> + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
> + pc->subsystem_vendor_id);
> + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
> + pc->subsystem_id);
> + } else {
> + pci_set_default_subsystem_id(pci_dev);
> + }
> + } else {
> + /* subsystem_vendor_id/subsystem_id are only for header type 0 */
> + assert(!pc->subsystem_vendor_id);
> + assert(!pc->subsystem_id);
> + }
> + pci_init_cmask(pci_dev);
> + pci_init_wmask(pci_dev);
> + pci_init_w1cmask(pci_dev);
> + if (pc->is_bridge) {
> + pci_init_mask_bridge(pci_dev);
> + }
> + if (pci_init_multifunction(bus, pci_dev)) {
> + pci_config_free(pci_dev);
> + return NULL;
> + }
> +
> + if (!config_read)
> + config_read = pci_default_read_config;
> + if (!config_write)
> + config_write = pci_default_write_config;
> + pci_dev->config_read = config_read;
> + pci_dev->config_write = config_write;
> + bus->devices[devfn] = pci_dev;
> + pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS);
> + pci_dev->version_id = 2; /* Current pci device vmstate version */
> + return pci_dev;
> +}
> +
> +static void do_pci_unregister_device(PCIDevice *pci_dev)
> +{
> + qemu_free_irqs(pci_dev->irq);
> + pci_dev->bus->devices[pci_dev->devfn] = NULL;
> + pci_config_free(pci_dev);
> +
> + if (!pci_dev->bus->dma_context_fn) {
> + address_space_destroy(&pci_dev->bus_master_as);
> + memory_region_destroy(&pci_dev->bus_master_enable_region);
> + g_free(pci_dev->dma);
> + pci_dev->dma = NULL;
> + }
> +}
> +
> +static void pci_unregister_io_regions(PCIDevice *pci_dev)
> +{
> + PCIIORegion *r;
> + int i;
> +
> + for(i = 0; i < PCI_NUM_REGIONS; i++) {
> + r = &pci_dev->io_regions[i];
> + if (!r->size || r->addr == PCI_BAR_UNMAPPED)
> + continue;
> + memory_region_del_subregion(r->address_space, r->memory);
> + }
> +}
> +
> +static int pci_unregister_device(DeviceState *dev)
> +{
> + PCIDevice *pci_dev = PCI_DEVICE(dev);
> + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
> +
> + pci_unregister_io_regions(pci_dev);
> + pci_del_option_rom(pci_dev);
> +
> + if (pc->exit) {
> + pc->exit(pci_dev);
> + }
> +
> + do_pci_unregister_device(pci_dev);
> + return 0;
> +}
> +
> +void pci_register_bar(PCIDevice *pci_dev, int region_num,
> + uint8_t type, MemoryRegion *memory)
> +{
> + PCIIORegion *r;
> + uint32_t addr;
> + uint64_t wmask;
> + pcibus_t size = memory_region_size(memory);
> +
> + assert(region_num >= 0);
> + assert(region_num < PCI_NUM_REGIONS);
> + if (size & (size-1)) {
> + fprintf(stderr, "ERROR: PCI region size must be pow2 "
> + "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);
> + exit(1);
> + }
> +
> + r = &pci_dev->io_regions[region_num];
> + r->addr = PCI_BAR_UNMAPPED;
> + r->size = size;
> + r->type = type;
> + r->memory = NULL;
> +
> + wmask = ~(size - 1);
> + addr = pci_bar(pci_dev, region_num);
> + if (region_num == PCI_ROM_SLOT) {
> + /* ROM enable bit is writable */
> + wmask |= PCI_ROM_ADDRESS_ENABLE;
> + }
> + pci_set_long(pci_dev->config + addr, type);
> + if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
> + r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
> + pci_set_quad(pci_dev->wmask + addr, wmask);
> + pci_set_quad(pci_dev->cmask + addr, ~0ULL);
> + } else {
> + pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
> + pci_set_long(pci_dev->cmask + addr, 0xffffffff);
> + }
> + pci_dev->io_regions[region_num].memory = memory;
> + pci_dev->io_regions[region_num].address_space
> + = type & PCI_BASE_ADDRESS_SPACE_IO
> + ? pci_dev->bus->address_space_io
> + : pci_dev->bus->address_space_mem;
> +}
> +
> +pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
> +{
> + return pci_dev->io_regions[region_num].addr;
> +}
> +
> +static pcibus_t pci_bar_address(PCIDevice *d,
> + int reg, uint8_t type, pcibus_t size)
> +{
> + pcibus_t new_addr, last_addr;
> + int bar = pci_bar(d, reg);
> + uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);
> +
> + if (type & PCI_BASE_ADDRESS_SPACE_IO) {
> + if (!(cmd & PCI_COMMAND_IO)) {
> + return PCI_BAR_UNMAPPED;
> + }
> + new_addr = pci_get_long(d->config + bar) & ~(size - 1);
> + last_addr = new_addr + size - 1;
> + /* NOTE: we have only 64K ioports on PC */
> + if (last_addr <= new_addr || new_addr == 0 || last_addr >
> UINT16_MAX) {
> + return PCI_BAR_UNMAPPED;
> + }
> + return new_addr;
> + }
> +
> + if (!(cmd & PCI_COMMAND_MEMORY)) {
> + return PCI_BAR_UNMAPPED;
> + }
> + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
> + new_addr = pci_get_quad(d->config + bar);
> + } else {
> + new_addr = pci_get_long(d->config + bar);
> + }
> + /* the ROM slot has a specific enable bit */
> + if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) {
> + return PCI_BAR_UNMAPPED;
> + }
> + new_addr &= ~(size - 1);
> + last_addr = new_addr + size - 1;
> + /* NOTE: we do not support wrapping */
> + /* XXX: as we cannot support really dynamic
> + mappings, we handle specific values as invalid
> + mappings. */
> + if (last_addr <= new_addr || new_addr == 0 ||
> + last_addr == PCI_BAR_UNMAPPED) {
> + return PCI_BAR_UNMAPPED;
> + }
> +
> + /* Now pcibus_t is 64bit.
> + * Check if 32 bit BAR wraps around explicitly.
> + * Without this, PC ide doesn't work well.
> + * TODO: remove this work around.
> + */
> + if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) {
> + return PCI_BAR_UNMAPPED;
> + }
> +
> + /*
> + * OS is allowed to set BAR beyond its addressable
> + * bits. For example, 32 bit OS can set 64bit bar
> + * to >4G. Check it. TODO: we might need to support
> + * it in the future for e.g. PAE.
> + */
> + if (last_addr >= HWADDR_MAX) {
> + return PCI_BAR_UNMAPPED;
> + }
> +
> + return new_addr;
> +}
> +
> +static void pci_update_mappings(PCIDevice *d)
> +{
> + PCIIORegion *r;
> + int i;
> + pcibus_t new_addr;
> +
> + for(i = 0; i < PCI_NUM_REGIONS; i++) {
> + r = &d->io_regions[i];
> +
> + /* this region isn't registered */
> + if (!r->size)
> + continue;
> +
> + new_addr = pci_bar_address(d, i, r->type, r->size);
> +
> + /* This bar isn't changed */
> + if (new_addr == r->addr)
> + continue;
> +
> + /* now do the real mapping */
> + if (r->addr != PCI_BAR_UNMAPPED) {
> + memory_region_del_subregion(r->address_space, r->memory);
> + }
> + r->addr = new_addr;
> + if (r->addr != PCI_BAR_UNMAPPED) {
> + memory_region_add_subregion_overlap(r->address_space,
> + r->addr, r->memory, 1);
> + }
> + }
> +}
> +
> +static inline int pci_irq_disabled(PCIDevice *d)
> +{
> + return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE;
> +}
> +
> +/* Called after interrupt disabled field update in config space,
> + * assert/deassert interrupts if necessary.
> + * Gets original interrupt disable bit value (before update). */
> +static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled)
> +{
> + int i, disabled = pci_irq_disabled(d);
> + if (disabled == was_irq_disabled)
> + return;
> + for (i = 0; i < PCI_NUM_PINS; ++i) {
> + int state = pci_irq_state(d, i);
> + pci_change_irq_level(d, i, disabled ? -state : state);
> + }
> +}
> +
> +uint32_t pci_default_read_config(PCIDevice *d,
> + uint32_t address, int len)
> +{
> + uint32_t val = 0;
> +
> + memcpy(&val, d->config + address, len);
> + return le32_to_cpu(val);
> +}
> +
> +void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int
> l)
> +{
> + int i, was_irq_disabled = pci_irq_disabled(d);
> +
> + for (i = 0; i < l; val >>= 8, ++i) {
> + uint8_t wmask = d->wmask[addr + i];
> + uint8_t w1cmask = d->w1cmask[addr + i];
> + assert(!(wmask & w1cmask));
> + d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
> + d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
> + }
> + if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
> + ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
> + ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
> + range_covers_byte(addr, l, PCI_COMMAND))
> + pci_update_mappings(d);
> +
> + if (range_covers_byte(addr, l, PCI_COMMAND)) {
> + pci_update_irq_disabled(d, was_irq_disabled);
> + memory_region_set_enabled(&d->bus_master_enable_region,
> + pci_get_word(d->config + PCI_COMMAND)
> + & PCI_COMMAND_MASTER);
> + }
> +
> + msi_write_config(d, addr, val, l);
> + msix_write_config(d, addr, val, l);
> +}
> +
> +/***********************************************************/
> +/* generic PCI irq support */
> +
> +/* 0 <= irq_num <= 3. level must be 0 or 1 */
> +static void pci_set_irq(void *opaque, int irq_num, int level)
> +{
> + PCIDevice *pci_dev = opaque;
> + int change;
> +
> + change = level - pci_irq_state(pci_dev, irq_num);
> + if (!change)
> + return;
> +
> + pci_set_irq_state(pci_dev, irq_num, level);
> + pci_update_irq_status(pci_dev);
> + if (pci_irq_disabled(pci_dev))
> + return;
> + pci_change_irq_level(pci_dev, irq_num, change);
> +}
> +
> +/* Special hooks used by device assignment */
> +void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn
> route_intx_to_irq)
> +{
> + assert(!bus->parent_dev);
> + bus->route_intx_to_irq = route_intx_to_irq;
> +}
> +
> +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin)
> +{
> + PCIBus *bus;
> +
> + do {
> + bus = dev->bus;
> + pin = bus->map_irq(dev, pin);
> + dev = bus->parent_dev;
> + } while (dev);
> +
> + if (!bus->route_intx_to_irq) {
> + error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n",
> + object_get_typename(OBJECT(bus->qbus.parent)));
> + return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 };
> + }
> +
> + return bus->route_intx_to_irq(bus->irq_opaque, pin);
> +}
> +
> +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new)
> +{
> + return old->mode != new->mode || old->irq != new->irq;
> +}
> +
> +void pci_bus_fire_intx_routing_notifier(PCIBus *bus)
> +{
> + PCIDevice *dev;
> + PCIBus *sec;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
> + dev = bus->devices[i];
> + if (dev && dev->intx_routing_notifier) {
> + dev->intx_routing_notifier(dev);
> + }
> + QLIST_FOREACH(sec, &bus->child, sibling) {
> + pci_bus_fire_intx_routing_notifier(sec);
> + }
> + }
> +}
> +
> +void pci_device_set_intx_routing_notifier(PCIDevice *dev,
> + PCIINTxRoutingNotifier notifier)
> +{
> + dev->intx_routing_notifier = notifier;
> +}
> +
> +/*
> + * PCI-to-PCI bridge specification
> + * 9.1: Interrupt routing. Table 9-1
> + *
> + * the PCI Express Base Specification, Revision 2.1
> + * 2.2.8.1: INTx interrutp signaling - Rules
> + * the Implementation Note
> + * Table 2-20
> + */
> +/*
> + * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD
> + * 0-origin unlike PCI interrupt pin register.
> + */
> +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
> +{
> + return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS;
> +}
> +
> +/***********************************************************/
> +/* monitor info on PCI */
> +
> +typedef struct {
> + uint16_t class;
> + const char *desc;
> + const char *fw_name;
> + uint16_t fw_ign_bits;
> +} pci_class_desc;
> +
> +static const pci_class_desc pci_class_descriptions[] =
> +{
> + { 0x0001, "VGA controller", "display"},
> + { 0x0100, "SCSI controller", "scsi"},
> + { 0x0101, "IDE controller", "ide"},
> + { 0x0102, "Floppy controller", "fdc"},
> + { 0x0103, "IPI controller", "ipi"},
> + { 0x0104, "RAID controller", "raid"},
> + { 0x0106, "SATA controller"},
> + { 0x0107, "SAS controller"},
> + { 0x0180, "Storage controller"},
> + { 0x0200, "Ethernet controller", "ethernet"},
> + { 0x0201, "Token Ring controller", "token-ring"},
> + { 0x0202, "FDDI controller", "fddi"},
> + { 0x0203, "ATM controller", "atm"},
> + { 0x0280, "Network controller"},
> + { 0x0300, "VGA controller", "display", 0x00ff},
> + { 0x0301, "XGA controller"},
> + { 0x0302, "3D controller"},
> + { 0x0380, "Display controller"},
> + { 0x0400, "Video controller", "video"},
> + { 0x0401, "Audio controller", "sound"},
> + { 0x0402, "Phone"},
> + { 0x0403, "Audio controller", "sound"},
> + { 0x0480, "Multimedia controller"},
> + { 0x0500, "RAM controller", "memory"},
> + { 0x0501, "Flash controller", "flash"},
> + { 0x0580, "Memory controller"},
> + { 0x0600, "Host bridge", "host"},
> + { 0x0601, "ISA bridge", "isa"},
> + { 0x0602, "EISA bridge", "eisa"},
> + { 0x0603, "MC bridge", "mca"},
> + { 0x0604, "PCI bridge", "pci"},
> + { 0x0605, "PCMCIA bridge", "pcmcia"},
> + { 0x0606, "NUBUS bridge", "nubus"},
> + { 0x0607, "CARDBUS bridge", "cardbus"},
> + { 0x0608, "RACEWAY bridge"},
> + { 0x0680, "Bridge"},
> + { 0x0700, "Serial port", "serial"},
> + { 0x0701, "Parallel port", "parallel"},
> + { 0x0800, "Interrupt controller", "interrupt-controller"},
> + { 0x0801, "DMA controller", "dma-controller"},
> + { 0x0802, "Timer", "timer"},
> + { 0x0803, "RTC", "rtc"},
> + { 0x0900, "Keyboard", "keyboard"},
> + { 0x0901, "Pen", "pen"},
> + { 0x0902, "Mouse", "mouse"},
> + { 0x0A00, "Dock station", "dock", 0x00ff},
> + { 0x0B00, "i386 cpu", "cpu", 0x00ff},
> + { 0x0c00, "Fireware contorller", "fireware"},
> + { 0x0c01, "Access bus controller", "access-bus"},
> + { 0x0c02, "SSA controller", "ssa"},
> + { 0x0c03, "USB controller", "usb"},
> + { 0x0c04, "Fibre channel controller", "fibre-channel"},
> + { 0x0c05, "SMBus"},
> + { 0, NULL}
> +};
> +
> +static void pci_for_each_device_under_bus(PCIBus *bus,
> + void (*fn)(PCIBus *b, PCIDevice *d,
> + void *opaque),
> + void *opaque)
> +{
> + PCIDevice *d;
> + int devfn;
> +
> + for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
> + d = bus->devices[devfn];
> + if (d) {
> + fn(bus, d, opaque);
> + }
> + }
> +}
> +
> +void pci_for_each_device(PCIBus *bus, int bus_num,
> + void (*fn)(PCIBus *b, PCIDevice *d, void *opaque),
> + void *opaque)
> +{
> + bus = pci_find_bus_nr(bus, bus_num);
> +
> + if (bus) {
> + pci_for_each_device_under_bus(bus, fn, opaque);
> + }
> +}
> +
> +static const pci_class_desc *get_class_desc(int class)
> +{
> + const pci_class_desc *desc;
> +
> + desc = pci_class_descriptions;
> + while (desc->desc && class != desc->class) {
> + desc++;
> + }
> +
> + return desc;
> +}
> +
> +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
> +
> +static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
> +{
> + PciMemoryRegionList *head = NULL, *cur_item = NULL;
> + int i;
> +
> + for (i = 0; i < PCI_NUM_REGIONS; i++) {
> + const PCIIORegion *r = &dev->io_regions[i];
> + PciMemoryRegionList *region;
> +
> + if (!r->size) {
> + continue;
> + }
> +
> + region = g_malloc0(sizeof(*region));
> + region->value = g_malloc0(sizeof(*region->value));
> +
> + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
> + region->value->type = g_strdup("io");
> + } else {
> + region->value->type = g_strdup("memory");
> + region->value->has_prefetch = true;
> + region->value->prefetch = !!(r->type &
> PCI_BASE_ADDRESS_MEM_PREFETCH);
> + region->value->has_mem_type_64 = true;
> + region->value->mem_type_64 = !!(r->type &
> PCI_BASE_ADDRESS_MEM_TYPE_64);
> + }
> +
> + region->value->bar = i;
> + region->value->address = r->addr;
> + region->value->size = r->size;
> +
> + /* XXX: waiting for the qapi to support GSList */
> + if (!cur_item) {
> + head = cur_item = region;
> + } else {
> + cur_item->next = region;
> + cur_item = region;
> + }
> + }
> +
> + return head;
> +}
> +
> +static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
> + int bus_num)
> +{
> + PciBridgeInfo *info;
> +
> + info = g_malloc0(sizeof(*info));
> +
> + info->bus.number = dev->config[PCI_PRIMARY_BUS];
> + info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
> + info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
> +
> + info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
> + info->bus.io_range->base = pci_bridge_get_base(dev,
> PCI_BASE_ADDRESS_SPACE_IO);
> + info->bus.io_range->limit = pci_bridge_get_limit(dev,
> PCI_BASE_ADDRESS_SPACE_IO);
> +
> + info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
> + info->bus.memory_range->base = pci_bridge_get_base(dev,
> PCI_BASE_ADDRESS_SPACE_MEMORY);
> + info->bus.memory_range->limit = pci_bridge_get_limit(dev,
> PCI_BASE_ADDRESS_SPACE_MEMORY);
> +
> + info->bus.prefetchable_range =
> g_malloc0(sizeof(*info->bus.prefetchable_range));
> + info->bus.prefetchable_range->base = pci_bridge_get_base(dev,
> PCI_BASE_ADDRESS_MEM_PREFETCH);
> + info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev,
> PCI_BASE_ADDRESS_MEM_PREFETCH);
> +
> + if (dev->config[PCI_SECONDARY_BUS] != 0) {
> + PCIBus *child_bus = pci_find_bus_nr(bus,
> dev->config[PCI_SECONDARY_BUS]);
> + if (child_bus) {
> + info->has_devices = true;
> + info->devices = qmp_query_pci_devices(child_bus,
> dev->config[PCI_SECONDARY_BUS]);
> + }
> + }
> +
> + return info;
> +}
> +
> +static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
> + int bus_num)
> +{
> + const pci_class_desc *desc;
> + PciDeviceInfo *info;
> + uint8_t type;
> + int class;
> +
> + info = g_malloc0(sizeof(*info));
> + info->bus = bus_num;
> + info->slot = PCI_SLOT(dev->devfn);
> + info->function = PCI_FUNC(dev->devfn);
> +
> + class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
> + info->class_info.class = class;
> + desc = get_class_desc(class);
> + if (desc->desc) {
> + info->class_info.has_desc = true;
> + info->class_info.desc = g_strdup(desc->desc);
> + }
> +
> + info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
> + info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
> + info->regions = qmp_query_pci_regions(dev);
> + info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
> +
> + if (dev->config[PCI_INTERRUPT_PIN] != 0) {
> + info->has_irq = true;
> + info->irq = dev->config[PCI_INTERRUPT_LINE];
> + }
> +
> + type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
> + if (type == PCI_HEADER_TYPE_BRIDGE) {
> + info->has_pci_bridge = true;
> + info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
> + }
> +
> + return info;
> +}
> +
> +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
> +{
> + PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
> + PCIDevice *dev;
> + int devfn;
> +
> + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
> + dev = bus->devices[devfn];
> + if (dev) {
> + info = g_malloc0(sizeof(*info));
> + info->value = qmp_query_pci_device(dev, bus, bus_num);
> +
> + /* XXX: waiting for the qapi to support GSList */
> + if (!cur_item) {
> + head = cur_item = info;
> + } else {
> + cur_item->next = info;
> + cur_item = info;
> + }
> + }
> + }
> +
> + return head;
> +}
> +
> +static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
> +{
> + PciInfo *info = NULL;
> +
> + bus = pci_find_bus_nr(bus, bus_num);
> + if (bus) {
> + info = g_malloc0(sizeof(*info));
> + info->bus = bus_num;
> + info->devices = qmp_query_pci_devices(bus, bus_num);
> + }
> +
> + return info;
> +}
> +
> +PciInfoList *qmp_query_pci(Error **errp)
> +{
> + PciInfoList *info, *head = NULL, *cur_item = NULL;
> + struct PCIHostBus *host;
> +
> + QLIST_FOREACH(host, &host_buses, next) {
> + info = g_malloc0(sizeof(*info));
> + info->value = qmp_query_pci_bus(host->bus, 0);
> +
> + /* XXX: waiting for the qapi to support GSList */
> + if (!cur_item) {
> + head = cur_item = info;
> + } else {
> + cur_item->next = info;
> + cur_item = info;
> + }
> + }
> +
> + return head;
> +}
> +
> +static const char * const pci_nic_models[] = {
> + "ne2k_pci",
> + "i82551",
> + "i82557b",
> + "i82559er",
> + "rtl8139",
> + "e1000",
> + "pcnet",
> + "virtio",
> + NULL
> +};
> +
> +static const char * const pci_nic_names[] = {
> + "ne2k_pci",
> + "i82551",
> + "i82557b",
> + "i82559er",
> + "rtl8139",
> + "e1000",
> + "pcnet",
> + "virtio-net-pci",
> + NULL
> +};
> +
> +/* Initialize a PCI NIC. */
> +/* FIXME callers should check for failure, but don't */
> +PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
> + const char *default_devaddr)
> +{
> + const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
> + PCIBus *bus;
> + int devfn;
> + PCIDevice *pci_dev;
> + DeviceState *dev;
> + int i;
> +
> + i = qemu_find_nic_model(nd, pci_nic_models, default_model);
> + if (i < 0)
> + return NULL;
> +
> + bus = pci_get_bus_devfn(&devfn, devaddr);
> + if (!bus) {
> + error_report("Invalid PCI device address %s for device %s",
> + devaddr, pci_nic_names[i]);
> + return NULL;
> + }
> +
> + pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
> + dev = &pci_dev->qdev;
> + qdev_set_nic_properties(dev, nd);
> + if (qdev_init(dev) < 0)
> + return NULL;
> + return pci_dev;
> +}
> +
> +PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
> + const char *default_devaddr)
> +{
> + PCIDevice *res;
> +
> + if (qemu_show_nic_models(nd->model, pci_nic_models))
> + exit(0);
> +
> + res = pci_nic_init(nd, default_model, default_devaddr);
> + if (!res)
> + exit(1);
> + return res;
> +}
> +
> +PCIDevice *pci_vga_init(PCIBus *bus)
> +{
> + switch (vga_interface_type) {
> + case VGA_CIRRUS:
> + return pci_create_simple(bus, -1, "cirrus-vga");
> + case VGA_QXL:
> + return pci_create_simple(bus, -1, "qxl-vga");
> + case VGA_STD:
> + return pci_create_simple(bus, -1, "VGA");
> + case VGA_VMWARE:
> + return pci_create_simple(bus, -1, "vmware-svga");
> + case VGA_NONE:
> + default: /* Other non-PCI types. Checking for unsupported types is
> already
> + done in vl.c. */
> + return NULL;
> + }
> +}
> +
> +/* Whether a given bus number is in range of the secondary
> + * bus of the given bridge device. */
> +static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
> +{
> + return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) &
> + PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset.
> */ &&
> + dev->config[PCI_SECONDARY_BUS] < bus_num &&
> + bus_num <= dev->config[PCI_SUBORDINATE_BUS];
> +}
> +
> +static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
> +{
> + PCIBus *sec;
> +
> + if (!bus) {
> + return NULL;
> + }
> +
> + if (pci_bus_num(bus) == bus_num) {
> + return bus;
> + }
> +
> + /* Consider all bus numbers in range for the host pci bridge. */
> + if (bus->parent_dev &&
> + !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
> + return NULL;
> + }
> +
> + /* try child bus */
> + for (; bus; bus = sec) {
> + QLIST_FOREACH(sec, &bus->child, sibling) {
> + assert(sec->parent_dev);
> + if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
> + return sec;
> + }
> + if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) {
> + break;
> + }
> + }
> + }
> +
> + return NULL;
> +}
> +
> +PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
> +{
> + bus = pci_find_bus_nr(bus, bus_num);
> +
> + if (!bus)
> + return NULL;
> +
> + return bus->devices[devfn];
> +}
> +
> +static int pci_qdev_init(DeviceState *qdev)
> +{
> + PCIDevice *pci_dev = (PCIDevice *)qdev;
> + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
> + PCIBus *bus;
> + int rc;
> + bool is_default_rom;
> +
> + /* initialize cap_present for pci_is_express() and pci_config_size() */
> + if (pc->is_express) {
> + pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
> + }
> +
> + bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
> + pci_dev = do_pci_register_device(pci_dev, bus,
> + object_get_typename(OBJECT(qdev)),
> + pci_dev->devfn);
> + if (pci_dev == NULL)
> + return -1;
> + if (qdev->hotplugged && pc->no_hotplug) {
> + qerror_report(QERR_DEVICE_NO_HOTPLUG,
> object_get_typename(OBJECT(pci_dev)));
> + do_pci_unregister_device(pci_dev);
> + return -1;
> + }
> + if (pc->init) {
> + rc = pc->init(pci_dev);
> + if (rc != 0) {
> + do_pci_unregister_device(pci_dev);
> + return rc;
> + }
> + }
> +
> + /* rom loading */
> + is_default_rom = false;
> + if (pci_dev->romfile == NULL && pc->romfile != NULL) {
> + pci_dev->romfile = g_strdup(pc->romfile);
> + is_default_rom = true;
> + }
> + pci_add_option_rom(pci_dev, is_default_rom);
> +
> + if (bus->hotplug) {
> + /* Let buses differentiate between hotplug and when device is
> + * enabled during qemu machine creation. */
> + rc = bus->hotplug(bus->hotplug_qdev, pci_dev,
> + qdev->hotplugged ? PCI_HOTPLUG_ENABLED:
> + PCI_COLDPLUG_ENABLED);
> + if (rc != 0) {
> + int r = pci_unregister_device(&pci_dev->qdev);
> + assert(!r);
> + return rc;
> + }
> + }
> + return 0;
> +}
> +
> +static int pci_unplug_device(DeviceState *qdev)
> +{
> + PCIDevice *dev = PCI_DEVICE(qdev);
> + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
> +
> + if (pc->no_hotplug) {
> + qerror_report(QERR_DEVICE_NO_HOTPLUG,
> object_get_typename(OBJECT(dev)));
> + return -1;
> + }
> + return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
> + PCI_HOTPLUG_DISABLED);
> +}
> +
> +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool
> multifunction,
> + const char *name)
> +{
> + DeviceState *dev;
> +
> + dev = qdev_create(&bus->qbus, name);
> + qdev_prop_set_int32(dev, "addr", devfn);
> + qdev_prop_set_bit(dev, "multifunction", multifunction);
> + return PCI_DEVICE(dev);
> +}
> +
> +PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
> + bool multifunction,
> + const char *name)
> +{
> + PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction,
> name);
> + qdev_init_nofail(&dev->qdev);
> + return dev;
> +}
> +
> +PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name)
> +{
> + return pci_create_multifunction(bus, devfn, false, name);
> +}
> +
> +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
> +{
> + return pci_create_simple_multifunction(bus, devfn, false, name);
> +}
> +
> +static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size)
> +{
> + int offset = PCI_CONFIG_HEADER_SIZE;
> + int i;
> + for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) {
> + if (pdev->used[i])
> + offset = i + 1;
> + else if (i - offset + 1 == size)
> + return offset;
> + }
> + return 0;
> +}
> +
> +static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
> + uint8_t *prev_p)
> +{
> + uint8_t next, prev;
> +
> + if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST))
> + return 0;
> +
> + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
> + prev = next + PCI_CAP_LIST_NEXT)
> + if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id)
> + break;
> +
> + if (prev_p)
> + *prev_p = prev;
> + return next;
> +}
> +
> +static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset)
> +{
> + uint8_t next, prev, found = 0;
> +
> + if (!(pdev->used[offset])) {
> + return 0;
> + }
> +
> + assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST);
> +
> + for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
> + prev = next + PCI_CAP_LIST_NEXT) {
> + if (next <= offset && next > found) {
> + found = next;
> + }
> + }
> + return found;
> +}
> +
> +/* Patch the PCI vendor and device ids in a PCI rom image if necessary.
> + This is needed for an option rom which is used for more than one device.
> */
> +static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size)
> +{
> + uint16_t vendor_id;
> + uint16_t device_id;
> + uint16_t rom_vendor_id;
> + uint16_t rom_device_id;
> + uint16_t rom_magic;
> + uint16_t pcir_offset;
> + uint8_t checksum;
> +
> + /* Words in rom data are little endian (like in PCI configuration),
> + so they can be read / written with pci_get_word / pci_set_word. */
> +
> + /* Only a valid rom will be patched. */
> + rom_magic = pci_get_word(ptr);
> + if (rom_magic != 0xaa55) {
> + PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic);
> + return;
> + }
> + pcir_offset = pci_get_word(ptr + 0x18);
> + if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) {
> + PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset);
> + return;
> + }
> +
> + vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
> + device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
> + rom_vendor_id = pci_get_word(ptr + pcir_offset + 4);
> + rom_device_id = pci_get_word(ptr + pcir_offset + 6);
> +
> + PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile,
> + vendor_id, device_id, rom_vendor_id, rom_device_id);
> +
> + checksum = ptr[6];
> +
> + if (vendor_id != rom_vendor_id) {
> + /* Patch vendor id and checksum (at offset 6 for etherboot roms). */
> + checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8);
> + checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8);
> + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
> + ptr[6] = checksum;
> + pci_set_word(ptr + pcir_offset + 4, vendor_id);
> + }
> +
> + if (device_id != rom_device_id) {
> + /* Patch device id and checksum (at offset 6 for etherboot roms). */
> + checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8);
> + checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8);
> + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
> + ptr[6] = checksum;
> + pci_set_word(ptr + pcir_offset + 6, device_id);
> + }
> +}
> +
> +/* Add an option rom for the device */
> +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
> +{
> + int size;
> + char *path;
> + void *ptr;
> + char name[32];
> + const VMStateDescription *vmsd;
> +
> + if (!pdev->romfile)
> + return 0;
> + if (strlen(pdev->romfile) == 0)
> + return 0;
> +
> + if (!pdev->rom_bar) {
> + /*
> + * Load rom via fw_cfg instead of creating a rom bar,
> + * for 0.11 compatibility.
> + */
> + int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
> + if (class == 0x0300) {
> + rom_add_vga(pdev->romfile);
> + } else {
> + rom_add_option(pdev->romfile, -1);
> + }
> + return 0;
> + }
> +
> + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
> + if (path == NULL) {
> + path = g_strdup(pdev->romfile);
> + }
> +
> + size = get_image_size(path);
> + if (size < 0) {
> + error_report("%s: failed to find romfile \"%s\"",
> + __FUNCTION__, pdev->romfile);
> + g_free(path);
> + return -1;
> + }
> + if (size & (size - 1)) {
> + size = 1 << qemu_fls(size);
> + }
> +
> + vmsd = qdev_get_vmsd(DEVICE(pdev));
> +
> + if (vmsd) {
> + snprintf(name, sizeof(name), "%s.rom", vmsd->name);
> + } else {
> + snprintf(name, sizeof(name), "%s.rom",
> object_get_typename(OBJECT(pdev)));
> + }
> + pdev->has_rom = true;
> + memory_region_init_ram(&pdev->rom, name, size);
> + vmstate_register_ram(&pdev->rom, &pdev->qdev);
> + ptr = memory_region_get_ram_ptr(&pdev->rom);
> + load_image(path, ptr);
> + g_free(path);
> +
> + if (is_default_rom) {
> + /* Only the default rom images will be patched (if needed). */
> + pci_patch_ids(pdev, ptr, size);
> + }
> +
> + qemu_put_ram_ptr(ptr);
> +
> + pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
> +
> + return 0;
> +}
> +
> +static void pci_del_option_rom(PCIDevice *pdev)
> +{
> + if (!pdev->has_rom)
> + return;
> +
> + vmstate_unregister_ram(&pdev->rom, &pdev->qdev);
> + memory_region_destroy(&pdev->rom);
> + pdev->has_rom = false;
> +}
> +
> +/*
> + * if !offset
> + * Reserve space and add capability to the linked list in pci config space
> + *
> + * if offset = 0,
> + * Find and reserve space and add capability to the linked list
> + * in pci config space */
> +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
> + uint8_t offset, uint8_t size)
> +{
> + uint8_t *config;
> + int i, overlapping_cap;
> +
> + if (!offset) {
> + offset = pci_find_space(pdev, size);
> + if (!offset) {
> + return -ENOSPC;
> + }
> + } else {
> + /* Verify that capabilities don't overlap. Note: device assignment
> + * depends on this check to verify that the device is not broken.
> + * Should never trigger for emulated devices, but it's helpful
> + * for debugging these. */
> + for (i = offset; i < offset + size; i++) {
> + overlapping_cap = pci_find_capability_at_offset(pdev, i);
> + if (overlapping_cap) {
> + fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
> + "Attempt to add PCI capability %x at offset "
> + "%x overlaps existing capability %x at offset %x\n",
> + pci_find_domain(pdev->bus), pci_bus_num(pdev->bus),
> + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
> + cap_id, offset, overlapping_cap, i);
> + return -EINVAL;
> + }
> + }
> + }
> +
> + config = pdev->config + offset;
> + config[PCI_CAP_LIST_ID] = cap_id;
> + config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
> + pdev->config[PCI_CAPABILITY_LIST] = offset;
> + pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
> + memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4));
> + /* Make capability read-only by default */
> + memset(pdev->wmask + offset, 0, size);
> + /* Check capability by default */
> + memset(pdev->cmask + offset, 0xFF, size);
> + return offset;
> +}
> +
> +/* Unlink capability from the pci config space. */
> +void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
> +{
> + uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev);
> + if (!offset)
> + return;
> + pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
> + /* Make capability writable again */
> + memset(pdev->wmask + offset, 0xff, size);
> + memset(pdev->w1cmask + offset, 0, size);
> + /* Clear cmask as device-specific registers can't be checked */
> + memset(pdev->cmask + offset, 0, size);
> + memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4));
> +
> + if (!pdev->config[PCI_CAPABILITY_LIST])
> + pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
> +}
> +
> +uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
> +{
> + return pci_find_capability_list(pdev, cap_id, NULL);
> +}
> +
> +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
> +{
> + PCIDevice *d = (PCIDevice *)dev;
> + const pci_class_desc *desc;
> + char ctxt[64];
> + PCIIORegion *r;
> + int i, class;
> +
> + class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> + desc = pci_class_descriptions;
> + while (desc->desc && class != desc->class)
> + desc++;
> + if (desc->desc) {
> + snprintf(ctxt, sizeof(ctxt), "%s", desc->desc);
> + } else {
> + snprintf(ctxt, sizeof(ctxt), "Class %04x", class);
> + }
> +
> + monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
> + "pci id %04x:%04x (sub %04x:%04x)\n",
> + indent, "", ctxt, pci_bus_num(d->bus),
> + PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
> + pci_get_word(d->config + PCI_VENDOR_ID),
> + pci_get_word(d->config + PCI_DEVICE_ID),
> + pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID),
> + pci_get_word(d->config + PCI_SUBSYSTEM_ID));
> + for (i = 0; i < PCI_NUM_REGIONS; i++) {
> + r = &d->io_regions[i];
> + if (!r->size)
> + continue;
> + monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS
> + " [0x%"FMT_PCIBUS"]\n",
> + indent, "",
> + i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" :
> "mem",
> + r->addr, r->addr + r->size - 1);
> + }
> +}
> +
> +static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
> +{
> + PCIDevice *d = (PCIDevice *)dev;
> + const char *name = NULL;
> + const pci_class_desc *desc = pci_class_descriptions;
> + int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> +
> + while (desc->desc &&
> + (class & ~desc->fw_ign_bits) !=
> + (desc->class & ~desc->fw_ign_bits)) {
> + desc++;
> + }
> +
> + if (desc->desc) {
> + name = desc->fw_name;
> + }
> +
> + if (name) {
> + pstrcpy(buf, len, name);
> + } else {
> + snprintf(buf, len, "pci%04x,%04x",
> + pci_get_word(d->config + PCI_VENDOR_ID),
> + pci_get_word(d->config + PCI_DEVICE_ID));
> + }
> +
> + return buf;
> +}
> +
> +static char *pcibus_get_fw_dev_path(DeviceState *dev)
> +{
> + PCIDevice *d = (PCIDevice *)dev;
> + char path[50], name[33];
> + int off;
> +
> + off = snprintf(path, sizeof(path), "address@hidden",
> + pci_dev_fw_name(dev, name, sizeof name),
> + PCI_SLOT(d->devfn));
> + if (PCI_FUNC(d->devfn))
> + snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
> + return g_strdup(path);
> +}
> +
> +static char *pcibus_get_dev_path(DeviceState *dev)
> +{
> + PCIDevice *d = container_of(dev, PCIDevice, qdev);
> + PCIDevice *t;
> + int slot_depth;
> + /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function.
> + * 00 is added here to make this format compatible with
> + * domain:Bus:Slot.Func for systems without nested PCI bridges.
> + * Slot.Function list specifies the slot and function numbers for all
> + * devices on the path from root to the specific device. */
> + char domain[] = "DDDD:00";
> + char slot[] = ":SS.F";
> + int domain_len = sizeof domain - 1 /* For '\0' */;
> + int slot_len = sizeof slot - 1 /* For '\0' */;
> + int path_len;
> + char *path, *p;
> + int s;
> +
> + /* Calculate # of slots on path between device and root. */;
> + slot_depth = 0;
> + for (t = d; t; t = t->bus->parent_dev) {
> + ++slot_depth;
> + }
> +
> + path_len = domain_len + slot_len * slot_depth;
> +
> + /* Allocate memory, fill in the terminating null byte. */
> + path = g_malloc(path_len + 1 /* For '\0' */);
> + path[path_len] = '\0';
> +
> + /* First field is the domain. */
> + s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus));
> + assert(s == domain_len);
> + memcpy(path, domain, domain_len);
> +
> + /* Fill in slot numbers. We walk up from device to root, so need to print
> + * them in the reverse order, last to first. */
> + p = path + path_len;
> + for (t = d; t; t = t->bus->parent_dev) {
> + p -= slot_len;
> + s = snprintf(slot, sizeof slot, ":%02x.%x",
> + PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
> + assert(s == slot_len);
> + memcpy(p, slot, slot_len);
> + }
> +
> + return path;
> +}
> +
> +static int pci_qdev_find_recursive(PCIBus *bus,
> + const char *id, PCIDevice **pdev)
> +{
> + DeviceState *qdev = qdev_find_recursive(&bus->qbus, id);
> + if (!qdev) {
> + return -ENODEV;
> + }
> +
> + /* roughly check if given qdev is pci device */
> + if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) {
> + *pdev = PCI_DEVICE(qdev);
> + return 0;
> + }
> + return -EINVAL;
> +}
> +
> +int pci_qdev_find_device(const char *id, PCIDevice **pdev)
> +{
> + struct PCIHostBus *host;
> + int rc = -ENODEV;
> +
> + QLIST_FOREACH(host, &host_buses, next) {
> + int tmp = pci_qdev_find_recursive(host->bus, id, pdev);
> + if (!tmp) {
> + rc = 0;
> + break;
> + }
> + if (tmp != -ENODEV) {
> + rc = tmp;
> + }
> + }
> +
> + return rc;
> +}
> +
> +MemoryRegion *pci_address_space(PCIDevice *dev)
> +{
> + return dev->bus->address_space_mem;
> +}
> +
> +MemoryRegion *pci_address_space_io(PCIDevice *dev)
> +{
> + return dev->bus->address_space_io;
> +}
> +
> +static void pci_device_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *k = DEVICE_CLASS(klass);
> + k->init = pci_qdev_init;
> + k->unplug = pci_unplug_device;
> + k->exit = pci_unregister_device;
> + k->bus_type = TYPE_PCI_BUS;
> + k->props = pci_props;
> +}
> +
> +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque)
> +{
> + bus->dma_context_fn = fn;
> + bus->dma_context_opaque = opaque;
> +}
> +
> +static TypeInfo pci_device_type_info = {
> + .name = TYPE_PCI_DEVICE,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(PCIDevice),
> + .abstract = true,
> + .class_size = sizeof(PCIDeviceClass),
> + .class_init = pci_device_class_init,
> +};
> +
> +static void pci_register_types(void)
> +{
> + type_register_static(&pci_bus_info);
> + type_register_static(&pci_device_type_info);
> +}
> +
> +type_init(pci_register_types)
> diff --git a/hw/pci/pci.h b/hw/pci/pci.h
> new file mode 100644
> index 0000000..4da0c2a
> --- /dev/null
> +++ b/hw/pci/pci.h
> @@ -0,0 +1,684 @@
> +#ifndef QEMU_PCI_H
> +#define QEMU_PCI_H
> +
> +#include "qemu-common.h"
> +
> +#include "qdev.h"
> +#include "memory.h"
> +#include "dma.h"
> +
> +/* PCI includes legacy ISA access. */
> +#include "isa.h"
> +
> +#include "pcie.h"
> +
> +/* PCI bus */
> +
> +#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
> +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
> +#define PCI_FUNC(devfn) ((devfn) & 0x07)
> +#define PCI_SLOT_MAX 32
> +#define PCI_FUNC_MAX 8
> +
> +/* Class, Vendor and Device IDs from Linux's pci_ids.h */
> +#include "pci_ids.h"
> +
> +/* QEMU-specific Vendor and Device ID definitions */
> +
> +/* IBM (0x1014) */
> +#define PCI_DEVICE_ID_IBM_440GX 0x027f
> +#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff
> +
> +/* Hitachi (0x1054) */
> +#define PCI_VENDOR_ID_HITACHI 0x1054
> +#define PCI_DEVICE_ID_HITACHI_SH7751R 0x350e
> +
> +/* Apple (0x106b) */
> +#define PCI_DEVICE_ID_APPLE_343S1201 0x0010
> +#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e
> +#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f
> +#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022
> +#define PCI_DEVICE_ID_APPLE_IPID_USB 0x003f
> +
> +/* Realtek (0x10ec) */
> +#define PCI_DEVICE_ID_REALTEK_8029 0x8029
> +
> +/* Xilinx (0x10ee) */
> +#define PCI_DEVICE_ID_XILINX_XC2VP30 0x0300
> +
> +/* Marvell (0x11ab) */
> +#define PCI_DEVICE_ID_MARVELL_GT6412X 0x4620
> +
> +/* QEMU/Bochs VGA (0x1234) */
> +#define PCI_VENDOR_ID_QEMU 0x1234
> +#define PCI_DEVICE_ID_QEMU_VGA 0x1111
> +
> +/* VMWare (0x15ad) */
> +#define PCI_VENDOR_ID_VMWARE 0x15ad
> +#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
> +#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
> +#define PCI_DEVICE_ID_VMWARE_NET 0x0720
> +#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
> +#define PCI_DEVICE_ID_VMWARE_IDE 0x1729
> +
> +/* Intel (0x8086) */
> +#define PCI_DEVICE_ID_INTEL_82551IT 0x1209
> +#define PCI_DEVICE_ID_INTEL_82557 0x1229
> +#define PCI_DEVICE_ID_INTEL_82801IR 0x2922
> +
> +/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
> +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
> +#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
> +#define PCI_SUBDEVICE_ID_QEMU 0x1100
> +
> +#define PCI_DEVICE_ID_VIRTIO_NET 0x1000
> +#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001
> +#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
> +#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
> +#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
> +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
> +
> +#define FMT_PCIBUS PRIx64
> +
> +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
> + uint32_t address, uint32_t data, int len);
> +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
> + uint32_t address, int len);
> +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
> + pcibus_t addr, pcibus_t size, int type);
> +typedef void PCIUnregisterFunc(PCIDevice *pci_dev);
> +
> +typedef struct PCIIORegion {
> + pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
> +#define PCI_BAR_UNMAPPED (~(pcibus_t)0)
> + pcibus_t size;
> + uint8_t type;
> + MemoryRegion *memory;
> + MemoryRegion *address_space;
> +} PCIIORegion;
> +
> +#define PCI_ROM_SLOT 6
> +#define PCI_NUM_REGIONS 7
> +
> +#include "pci_regs.h"
> +
> +/* PCI HEADER_TYPE */
> +#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
> +
> +/* Size of the standard PCI config header */
> +#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_MSI = 0x1,
> + QEMU_PCI_CAP_MSIX = 0x2,
> + QEMU_PCI_CAP_EXPRESS = 0x4,
> +
> + /* multifunction capable device */
> +#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3
> + QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
> +
> + /* command register SERR bit enabled */
> +#define QEMU_PCI_CAP_SERR_BITNR 4
> + QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
> + /* Standard hot plug controller. */
> +#define QEMU_PCI_SHPC_BITNR 5
> + QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR),
> +#define QEMU_PCI_SLOTID_BITNR 6
> + QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR),
> +};
> +
> +#define TYPE_PCI_DEVICE "pci-device"
> +#define PCI_DEVICE(obj) \
> + OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE)
> +#define PCI_DEVICE_CLASS(klass) \
> + OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE)
> +#define PCI_DEVICE_GET_CLASS(obj) \
> + OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE)
> +
> +typedef struct PCIINTxRoute {
> + enum {
> + PCI_INTX_ENABLED,
> + PCI_INTX_INVERTED,
> + PCI_INTX_DISABLED,
> + } mode;
> + int irq;
> +} PCIINTxRoute;
> +
> +typedef struct PCIDeviceClass {
> + DeviceClass parent_class;
> +
> + int (*init)(PCIDevice *dev);
> + PCIUnregisterFunc *exit;
> + PCIConfigReadFunc *config_read;
> + PCIConfigWriteFunc *config_write;
> +
> + uint16_t vendor_id;
> + uint16_t device_id;
> + uint8_t revision;
> + uint16_t class_id;
> + uint16_t subsystem_vendor_id; /* only for header type = 0 */
> + uint16_t subsystem_id; /* only for header type = 0 */
> +
> + /*
> + * pci-to-pci bridge or normal device.
> + * This doesn't mean pci host switch.
> + * When card bus bridge is supported, this would be enhanced.
> + */
> + int is_bridge;
> +
> + /* pcie stuff */
> + int is_express; /* is this device pci express? */
> +
> + /* device isn't hot-pluggable */
> + int no_hotplug;
> +
> + /* rom bar */
> + const char *romfile;
> +} PCIDeviceClass;
> +
> +typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev);
> +typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector,
> + MSIMessage msg);
> +typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int
> vector);
> +
> +struct PCIDevice {
> + DeviceState qdev;
> +
> + /* PCI config space */
> + uint8_t *config;
> +
> + /* Used to enable config checks on load. Note that writable bits are
> + * never checked even if set in cmask. */
> + uint8_t *cmask;
> +
> + /* Used to implement R/W bytes */
> + uint8_t *wmask;
> +
> + /* Used to implement RW1C(Write 1 to Clear) bytes */
> + uint8_t *w1cmask;
> +
> + /* Used to allocate config space for capabilities. */
> + uint8_t *used;
> +
> + /* the following fields are read only */
> + PCIBus *bus;
> + int32_t devfn;
> + char name[64];
> + PCIIORegion io_regions[PCI_NUM_REGIONS];
> + AddressSpace bus_master_as;
> + MemoryRegion bus_master_enable_region;
> + DMAContext *dma;
> +
> + /* do not access the following fields */
> + PCIConfigReadFunc *config_read;
> + PCIConfigWriteFunc *config_write;
> +
> + /* IRQ objects for the INTA-INTD pins. */
> + qemu_irq *irq;
> +
> + /* Current IRQ levels. Used internally by the generic PCI code. */
> + uint8_t irq_state;
> +
> + /* Capability bits */
> + uint32_t cap_present;
> +
> + /* Offset of MSI-X capability in config space */
> + uint8_t msix_cap;
> +
> + /* MSI-X entries */
> + int msix_entries_nr;
> +
> + /* Space to store MSIX table & pending bit array */
> + uint8_t *msix_table;
> + uint8_t *msix_pba;
> + /* MemoryRegion container for msix exclusive BAR setup */
> + MemoryRegion msix_exclusive_bar;
> + /* Memory Regions for MSIX table and pending bit entries. */
> + MemoryRegion msix_table_mmio;
> + MemoryRegion msix_pba_mmio;
> + /* Reference-count for entries actually in use by driver. */
> + unsigned *msix_entry_used;
> + /* MSIX function mask set or MSIX disabled */
> + bool msix_function_masked;
> + /* Version id needed for VMState */
> + int32_t version_id;
> +
> + /* Offset of MSI capability in config space */
> + uint8_t msi_cap;
> +
> + /* PCI Express */
> + PCIExpressDevice exp;
> +
> + /* SHPC */
> + SHPCDevice *shpc;
> +
> + /* Location of option rom */
> + char *romfile;
> + bool has_rom;
> + MemoryRegion rom;
> + uint32_t rom_bar;
> +
> + /* INTx routing notifier */
> + PCIINTxRoutingNotifier intx_routing_notifier;
> +
> + /* MSI-X notifiers */
> + MSIVectorUseNotifier msix_vector_use_notifier;
> + MSIVectorReleaseNotifier msix_vector_release_notifier;
> +};
> +
> +void pci_register_bar(PCIDevice *pci_dev, int region_num,
> + uint8_t attr, MemoryRegion *memory);
> +pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
> +
> +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
> + uint8_t offset, uint8_t size);
> +
> +void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t
> cap_size);
> +
> +uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
> +
> +
> +uint32_t pci_default_read_config(PCIDevice *d,
> + uint32_t address, int len);
> +void pci_default_write_config(PCIDevice *d,
> + uint32_t address, uint32_t val, int len);
> +void pci_device_save(PCIDevice *s, QEMUFile *f);
> +int pci_device_load(PCIDevice *s, QEMUFile *f);
> +MemoryRegion *pci_address_space(PCIDevice *dev);
> +MemoryRegion *pci_address_space_io(PCIDevice *dev);
> +
> +typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
> +typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
> +typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
> +
> +typedef enum {
> + PCI_HOTPLUG_DISABLED,
> + PCI_HOTPLUG_ENABLED,
> + PCI_COLDPLUG_ENABLED,
> +} PCIHotplugState;
> +
> +typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
> + PCIHotplugState state);
> +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
> + const char *name,
> + MemoryRegion *address_space_mem,
> + MemoryRegion *address_space_io,
> + uint8_t devfn_min);
> +PCIBus *pci_bus_new(DeviceState *parent, const char *name,
> + MemoryRegion *address_space_mem,
> + MemoryRegion *address_space_io,
> + uint8_t devfn_min);
> +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn
> map_irq,
> + void *irq_opaque, int nirq);
> +int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
> +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
> +/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */
> +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin);
> +PCIBus *pci_register_bus(DeviceState *parent, const char *name,
> + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
> + void *irq_opaque,
> + MemoryRegion *address_space_mem,
> + MemoryRegion *address_space_io,
> + uint8_t devfn_min, int nirq);
> +void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
> +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
> +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);
> +void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
> +void pci_device_set_intx_routing_notifier(PCIDevice *dev,
> + PCIINTxRoutingNotifier notifier);
> +void pci_device_reset(PCIDevice *dev);
> +void pci_bus_reset(PCIBus *bus);
> +
> +PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
> + const char *default_devaddr);
> +PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
> + const char *default_devaddr);
> +
> +PCIDevice *pci_vga_init(PCIBus *bus);
> +
> +int pci_bus_num(PCIBus *s);
> +void pci_for_each_device(PCIBus *bus, int bus_num,
> + void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque),
> + void *opaque);
> +PCIBus *pci_find_root_bus(int domain);
> +int pci_find_domain(const PCIBus *bus);
> +PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
> +int pci_qdev_find_device(const char *id, PCIDevice **pdev);
> +PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
> +
> +int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
> + unsigned *slotp);
> +
> +void pci_device_deassert_intx(PCIDevice *dev);
> +
> +typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int);
> +
> +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque);
> +
> +static inline void
> +pci_set_byte(uint8_t *config, uint8_t val)
> +{
> + *config = val;
> +}
> +
> +static inline uint8_t
> +pci_get_byte(const uint8_t *config)
> +{
> + return *config;
> +}
> +
> +static inline void
> +pci_set_word(uint8_t *config, uint16_t val)
> +{
> + cpu_to_le16wu((uint16_t *)config, val);
> +}
> +
> +static inline uint16_t
> +pci_get_word(const uint8_t *config)
> +{
> + return le16_to_cpupu((const uint16_t *)config);
> +}
> +
> +static inline void
> +pci_set_long(uint8_t *config, uint32_t val)
> +{
> + cpu_to_le32wu((uint32_t *)config, val);
> +}
> +
> +static inline uint32_t
> +pci_get_long(const uint8_t *config)
> +{
> + return le32_to_cpupu((const uint32_t *)config);
> +}
> +
> +static inline void
> +pci_set_quad(uint8_t *config, uint64_t val)
> +{
> + cpu_to_le64w((uint64_t *)config, val);
> +}
> +
> +static inline uint64_t
> +pci_get_quad(const uint8_t *config)
> +{
> + return le64_to_cpup((const uint64_t *)config);
> +}
> +
> +static inline void
> +pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
> +{
> + pci_set_word(&pci_config[PCI_VENDOR_ID], val);
> +}
> +
> +static inline void
> +pci_config_set_device_id(uint8_t *pci_config, uint16_t val)
> +{
> + pci_set_word(&pci_config[PCI_DEVICE_ID], val);
> +}
> +
> +static inline void
> +pci_config_set_revision(uint8_t *pci_config, uint8_t val)
> +{
> + pci_set_byte(&pci_config[PCI_REVISION_ID], val);
> +}
> +
> +static inline void
> +pci_config_set_class(uint8_t *pci_config, uint16_t val)
> +{
> + pci_set_word(&pci_config[PCI_CLASS_DEVICE], val);
> +}
> +
> +static inline void
> +pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val)
> +{
> + pci_set_byte(&pci_config[PCI_CLASS_PROG], val);
> +}
> +
> +static inline void
> +pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val)
> +{
> + pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val);
> +}
> +
> +/*
> + * helper functions to do bit mask operation on configuration space.
> + * Just to set bit, use test-and-set and discard returned value.
> + * Just to clear bit, use test-and-clear and discard returned value.
> + * NOTE: They aren't atomic.
> + */
> +static inline uint8_t
> +pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask)
> +{
> + uint8_t val = pci_get_byte(config);
> + pci_set_byte(config, val & ~mask);
> + return val & mask;
> +}
> +
> +static inline uint8_t
> +pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask)
> +{
> + uint8_t val = pci_get_byte(config);
> + pci_set_byte(config, val | mask);
> + return val & mask;
> +}
> +
> +static inline uint16_t
> +pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask)
> +{
> + uint16_t val = pci_get_word(config);
> + pci_set_word(config, val & ~mask);
> + return val & mask;
> +}
> +
> +static inline uint16_t
> +pci_word_test_and_set_mask(uint8_t *config, uint16_t mask)
> +{
> + uint16_t val = pci_get_word(config);
> + pci_set_word(config, val | mask);
> + return val & mask;
> +}
> +
> +static inline uint32_t
> +pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask)
> +{
> + uint32_t val = pci_get_long(config);
> + pci_set_long(config, val & ~mask);
> + return val & mask;
> +}
> +
> +static inline uint32_t
> +pci_long_test_and_set_mask(uint8_t *config, uint32_t mask)
> +{
> + uint32_t val = pci_get_long(config);
> + pci_set_long(config, val | mask);
> + return val & mask;
> +}
> +
> +static inline uint64_t
> +pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask)
> +{
> + uint64_t val = pci_get_quad(config);
> + pci_set_quad(config, val & ~mask);
> + return val & mask;
> +}
> +
> +static inline uint64_t
> +pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
> +{
> + uint64_t val = pci_get_quad(config);
> + pci_set_quad(config, val | mask);
> + return val & mask;
> +}
> +
> +/* Access a register specified by a mask */
> +static inline void
> +pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg)
> +{
> + uint8_t val = pci_get_byte(config);
> + uint8_t rval = reg << (ffs(mask) - 1);
> + pci_set_byte(config, (~mask & val) | (mask & rval));
> +}
> +
> +static inline uint8_t
> +pci_get_byte_by_mask(uint8_t *config, uint8_t mask)
> +{
> + uint8_t val = pci_get_byte(config);
> + return (val & mask) >> (ffs(mask) - 1);
> +}
> +
> +static inline void
> +pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg)
> +{
> + uint16_t val = pci_get_word(config);
> + uint16_t rval = reg << (ffs(mask) - 1);
> + pci_set_word(config, (~mask & val) | (mask & rval));
> +}
> +
> +static inline uint16_t
> +pci_get_word_by_mask(uint8_t *config, uint16_t mask)
> +{
> + uint16_t val = pci_get_word(config);
> + return (val & mask) >> (ffs(mask) - 1);
> +}
> +
> +static inline void
> +pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg)
> +{
> + uint32_t val = pci_get_long(config);
> + uint32_t rval = reg << (ffs(mask) - 1);
> + pci_set_long(config, (~mask & val) | (mask & rval));
> +}
> +
> +static inline uint32_t
> +pci_get_long_by_mask(uint8_t *config, uint32_t mask)
> +{
> + uint32_t val = pci_get_long(config);
> + return (val & mask) >> (ffs(mask) - 1);
> +}
> +
> +static inline void
> +pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg)
> +{
> + uint64_t val = pci_get_quad(config);
> + uint64_t rval = reg << (ffs(mask) - 1);
> + pci_set_quad(config, (~mask & val) | (mask & rval));
> +}
> +
> +static inline uint64_t
> +pci_get_quad_by_mask(uint8_t *config, uint64_t mask)
> +{
> + uint64_t val = pci_get_quad(config);
> + return (val & mask) >> (ffs(mask) - 1);
> +}
> +
> +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool
> multifunction,
> + const char *name);
> +PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
> + bool multifunction,
> + const char *name);
> +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(const PCIDevice *d)
> +{
> + return d->cap_present & QEMU_PCI_CAP_EXPRESS;
> +}
> +
> +static inline uint32_t pci_config_size(const PCIDevice *d)
> +{
> + return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE :
> PCI_CONFIG_SPACE_SIZE;
> +}
> +
> +/* DMA access functions */
> +static inline DMAContext *pci_dma_context(PCIDevice *dev)
> +{
> + return dev->dma;
> +}
> +
> +static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr,
> + void *buf, dma_addr_t len, DMADirection dir)
> +{
> + dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir);
> + return 0;
> +}
> +
> +static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
> + void *buf, dma_addr_t len)
> +{
> + return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
> +}
> +
> +static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
> + const void *buf, dma_addr_t len)
> +{
> + return pci_dma_rw(dev, addr, (void *) buf, len,
> DMA_DIRECTION_FROM_DEVICE);
> +}
> +
> +#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \
> + static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev, \
> + dma_addr_t addr) \
> + { \
> + return ld##_l##_dma(pci_dma_context(dev), addr); \
> + } \
> + static inline void st##_s##_pci_dma(PCIDevice *dev, \
> + dma_addr_t addr, uint##_bits##_t
> val) \
> + { \
> + st##_s##_dma(pci_dma_context(dev), addr, val); \
> + }
> +
> +PCI_DMA_DEFINE_LDST(ub, b, 8);
> +PCI_DMA_DEFINE_LDST(uw_le, w_le, 16)
> +PCI_DMA_DEFINE_LDST(l_le, l_le, 32);
> +PCI_DMA_DEFINE_LDST(q_le, q_le, 64);
> +PCI_DMA_DEFINE_LDST(uw_be, w_be, 16)
> +PCI_DMA_DEFINE_LDST(l_be, l_be, 32);
> +PCI_DMA_DEFINE_LDST(q_be, q_be, 64);
> +
> +#undef PCI_DMA_DEFINE_LDST
> +
> +static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr,
> + dma_addr_t *plen, DMADirection dir)
> +{
> + void *buf;
> +
> + buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir);
> + return buf;
> +}
> +
> +static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t
> len,
> + DMADirection dir, dma_addr_t access_len)
> +{
> + dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len);
> +}
> +
> +static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
> + int alloc_hint)
> +{
> + qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev));
> +}
> +
> +extern const VMStateDescription vmstate_pci_device;
> +
> +#define VMSTATE_PCI_DEVICE(_field, _state) { \
> + .name = (stringify(_field)), \
> + .size = sizeof(PCIDevice), \
> + .vmsd = &vmstate_pci_device, \
> + .flags = VMS_STRUCT, \
> + .offset = vmstate_offset_value(_state, _field, PCIDevice), \
> +}
> +
> +#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \
> + .name = (stringify(_field)), \
> + .size = sizeof(PCIDevice), \
> + .vmsd = &vmstate_pci_device, \
> + .flags = VMS_STRUCT|VMS_POINTER, \
> + .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \
> +}
> +
> +#endif
> diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
> new file mode 100644
> index 0000000..4680501
> --- /dev/null
> +++ b/hw/pci/pci_bridge.c
> @@ -0,0 +1,363 @@
> +/*
> + * QEMU PCI bus manager
> + *
> + * Copyright (c) 2004 Fabrice Bellard
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> + * of this software and associated documentation files (the "Software"), to
> dea
> +
> + * in the Software without restriction, including without limitation the
> rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM
> +
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +/*
> + * split out from pci.c
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * VA Linux Systems Japan K.K.
> + */
> +
> +#include "pci_bridge.h"
> +#include "pci_internals.h"
> +#include "range.h"
> +
> +/* PCI bridge subsystem vendor ID helper functions */
> +#define PCI_SSVID_SIZEOF 8
> +#define PCI_SSVID_SVID 4
> +#define PCI_SSVID_SSID 6
> +
> +int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
> + uint16_t svid, uint16_t ssid)
> +{
> + int pos;
> + pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset,
> PCI_SSVID_SIZEOF);
> + if (pos < 0) {
> + return pos;
> + }
> +
> + pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid);
> + pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid);
> + return pos;
> +}
> +
> +/* Accessor function to get parent bridge device from pci bus. */
> +PCIDevice *pci_bridge_get_device(PCIBus *bus)
> +{
> + return bus->parent_dev;
> +}
> +
> +/* Accessor function to get secondary bus from pci-to-pci bridge device */
> +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
> +{
> + return &br->sec_bus;
> +}
> +
> +static uint32_t pci_config_get_io_base(const PCIDevice *d,
> + uint32_t base, uint32_t base_upper16)
> +{
> + uint32_t val;
> +
> + val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
> + if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
> + val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
> + }
> + return val;
> +}
> +
> +static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base)
> +{
> + return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
> + << 16;
> +}
> +
> +static pcibus_t pci_config_get_pref_base(const PCIDevice *d,
> + uint32_t base, uint32_t upper)
> +{
> + pcibus_t tmp;
> + pcibus_t val;
> +
> + tmp = (pcibus_t)pci_get_word(d->config + base);
> + val = (tmp & PCI_PREF_RANGE_MASK) << 16;
> + if (tmp & PCI_PREF_RANGE_TYPE_64) {
> + val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
> + }
> + return val;
> +}
> +
> +/* accessor function to get bridge filtering base address */
> +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type)
> +{
> + pcibus_t base;
> + if (type & PCI_BASE_ADDRESS_SPACE_IO) {
> + base = pci_config_get_io_base(bridge,
> + PCI_IO_BASE, PCI_IO_BASE_UPPER16);
> + } else {
> + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
> + base = pci_config_get_pref_base(
> + bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
> + } else {
> + base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
> + }
> + }
> +
> + return base;
> +}
> +
> +/* accessor funciton to get bridge filtering limit */
> +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
> +{
> + pcibus_t limit;
> + if (type & PCI_BASE_ADDRESS_SPACE_IO) {
> + limit = pci_config_get_io_base(bridge,
> + PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
> + limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */
> + } else {
> + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
> + limit = pci_config_get_pref_base(
> + bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
> + } else {
> + limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
> + }
> + limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */
> + }
> + return limit;
> +}
> +
> +static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
> + uint8_t type, const char *name,
> + MemoryRegion *space,
> + MemoryRegion *parent_space,
> + bool enabled)
> +{
> + pcibus_t base = pci_bridge_get_base(&bridge->dev, type);
> + pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type);
> + /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly.
> + * Apparently no way to do this with existing memory APIs. */
> + pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0;
> +
> + memory_region_init_alias(alias, name, space, base, size);
> + memory_region_add_subregion_overlap(parent_space, base, alias, 1);
> +}
> +
> +static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
> +{
> + PCIBus *parent = br->dev.bus;
> + PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1);
> + uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND);
> +
> + pci_bridge_init_alias(br, &w->alias_pref_mem,
> + PCI_BASE_ADDRESS_MEM_PREFETCH,
> + "pci_bridge_pref_mem",
> + &br->address_space_mem,
> + parent->address_space_mem,
> + cmd & PCI_COMMAND_MEMORY);
> + pci_bridge_init_alias(br, &w->alias_mem,
> + PCI_BASE_ADDRESS_SPACE_MEMORY,
> + "pci_bridge_mem",
> + &br->address_space_mem,
> + parent->address_space_mem,
> + cmd & PCI_COMMAND_MEMORY);
> + pci_bridge_init_alias(br, &w->alias_io,
> + PCI_BASE_ADDRESS_SPACE_IO,
> + "pci_bridge_io",
> + &br->address_space_io,
> + parent->address_space_io,
> + cmd & PCI_COMMAND_IO);
> + /* TODO: optinal VGA and VGA palette snooping support. */
> +
> + return w;
> +}
> +
> +static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w)
> +{
> + PCIBus *parent = br->dev.bus;
> +
> + memory_region_del_subregion(parent->address_space_io, &w->alias_io);
> + memory_region_del_subregion(parent->address_space_mem, &w->alias_mem);
> + memory_region_del_subregion(parent->address_space_mem,
> &w->alias_pref_mem);
> +}
> +
> +static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
> +{
> + memory_region_destroy(&w->alias_io);
> + memory_region_destroy(&w->alias_mem);
> + memory_region_destroy(&w->alias_pref_mem);
> + g_free(w);
> +}
> +
> +static void pci_bridge_update_mappings(PCIBridge *br)
> +{
> + PCIBridgeWindows *w = br->windows;
> +
> + /* Make updates atomic to: handle the case of one VCPU updating the
> bridge
> + * while another accesses an unaffected region. */
> + memory_region_transaction_begin();
> + pci_bridge_region_del(br, br->windows);
> + br->windows = pci_bridge_region_init(br);
> + memory_region_transaction_commit();
> + pci_bridge_region_cleanup(br, w);
> +}
> +
> +/* default write_config function for PCI-to-PCI bridge */
> +void pci_bridge_write_config(PCIDevice *d,
> + uint32_t address, uint32_t val, int len)
> +{
> + PCIBridge *s = container_of(d, PCIBridge, dev);
> + uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
> + uint16_t newctl;
> +
> + pci_default_write_config(d, address, val, len);
> +
> + if (ranges_overlap(address, len, PCI_COMMAND, 2) ||
> +
> + /* io base/limit */
> + ranges_overlap(address, len, PCI_IO_BASE, 2) ||
> +
> + /* memory base/limit, prefetchable base/limit and
> + io base/limit upper 16 */
> + ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
> + pci_bridge_update_mappings(s);
> + }
> +
> + newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
> + if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) {
> + /* Trigger hot reset on 0->1 transition. */
> + pci_bus_reset(&s->sec_bus);
> + }
> +}
> +
> +void pci_bridge_disable_base_limit(PCIDevice *dev)
> +{
> + uint8_t *conf = dev->config;
> +
> + pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
> + PCI_IO_RANGE_MASK & 0xff);
> + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
> + PCI_IO_RANGE_MASK & 0xff);
> + pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE,
> + PCI_MEMORY_RANGE_MASK & 0xffff);
> + pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
> + PCI_MEMORY_RANGE_MASK & 0xffff);
> + pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE,
> + PCI_PREF_RANGE_MASK & 0xffff);
> + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
> + PCI_PREF_RANGE_MASK & 0xffff);
> + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0);
> + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0);
> +}
> +
> +/* reset bridge specific configuration registers */
> +void pci_bridge_reset(DeviceState *qdev)
> +{
> + PCIDevice *dev = PCI_DEVICE(qdev);
> + uint8_t *conf = dev->config;
> +
> + conf[PCI_PRIMARY_BUS] = 0;
> + conf[PCI_SECONDARY_BUS] = 0;
> + conf[PCI_SUBORDINATE_BUS] = 0;
> + conf[PCI_SEC_LATENCY_TIMER] = 0;
> +
> + /*
> + * the default values for base/limit registers aren't specified
> + * in the PCI-to-PCI-bridge spec. So we don't thouch them here.
> + * Each implementation can override it.
> + * typical implementation does
> + * zero base/limit registers or
> + * disable forwarding: pci_bridge_disable_base_limit()
> + * If disable forwarding is wanted, call pci_bridge_disable_base_limit()
> + * after this function.
> + */
> + pci_byte_test_and_clear_mask(conf + PCI_IO_BASE,
> + PCI_IO_RANGE_MASK & 0xff);
> + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
> + PCI_IO_RANGE_MASK & 0xff);
> + pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE,
> + PCI_MEMORY_RANGE_MASK & 0xffff);
> + pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
> + PCI_MEMORY_RANGE_MASK & 0xffff);
> + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE,
> + PCI_PREF_RANGE_MASK & 0xffff);
> + pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
> + PCI_PREF_RANGE_MASK & 0xffff);
> + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0);
> + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0);
> +
> + pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
> +}
> +
> +/* default qdev initialization function for PCI-to-PCI bridge */
> +int pci_bridge_initfn(PCIDevice *dev)
> +{
> + PCIBus *parent = dev->bus;
> + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
> + PCIBus *sec_bus = &br->sec_bus;
> +
> + pci_word_test_and_set_mask(dev->config + PCI_STATUS,
> + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
> + pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
> + dev->config[PCI_HEADER_TYPE] =
> + (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
> + PCI_HEADER_TYPE_BRIDGE;
> + pci_set_word(dev->config + PCI_SEC_STATUS,
> + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
> +
> + /*
> + * If we don't specify the name, the bus will be addressed as <id>.0,
> where
> + * id is the device id.
> + * Since PCI Bridge devices have a single bus each, we don't need the
> index:
> + * let users address the bus using the device name.
> + */
> + if (!br->bus_name && dev->qdev.id && *dev->qdev.id) {
> + br->bus_name = dev->qdev.id;
> + }
> +
> + qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev,
> + br->bus_name);
> + sec_bus->parent_dev = dev;
> + sec_bus->map_irq = br->map_irq;
> + sec_bus->address_space_mem = &br->address_space_mem;
> + memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
> + sec_bus->address_space_io = &br->address_space_io;
> + memory_region_init(&br->address_space_io, "pci_bridge_io", 65536);
> + br->windows = pci_bridge_region_init(br);
> + QLIST_INIT(&sec_bus->child);
> + QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
> + return 0;
> +}
> +
> +/* default qdev clean up function for PCI-to-PCI bridge */
> +void pci_bridge_exitfn(PCIDevice *pci_dev)
> +{
> + PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
> + assert(QLIST_EMPTY(&s->sec_bus.child));
> + QLIST_REMOVE(&s->sec_bus, sibling);
> + pci_bridge_region_del(s, s->windows);
> + pci_bridge_region_cleanup(s, s->windows);
> + memory_region_destroy(&s->address_space_mem);
> + memory_region_destroy(&s->address_space_io);
> + /* qbus_free() is called automatically by qdev_free() */
> +}
> +
> +/*
> + * before qdev initialization(qdev_init()), this function sets bus_name and
> + * map_irq callback which are necessry for pci_bridge_initfn() to
> + * initialize bus.
> + */
> +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
> + pci_map_irq_fn map_irq)
> +{
> + br->map_irq = map_irq;
> + br->bus_name = bus_name;
> +}
> diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h
> new file mode 100644
> index 0000000..a00accc
> --- /dev/null
> +++ b/hw/pci/pci_bridge.h
> @@ -0,0 +1,66 @@
> +/*
> + * QEMU PCI bridge
> + *
> + * Copyright (c) 2004 Fabrice Bellard
> + *
> + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc]
> + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> + * VA Linux Systems Japan K.K.
> + *
> + */
> +
> +#ifndef QEMU_PCI_BRIDGE_H
> +#define QEMU_PCI_BRIDGE_H
> +
> +#include "pci.h"
> +
> +int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
> + uint16_t svid, uint16_t ssid);
> +
> +PCIDevice *pci_bridge_get_device(PCIBus *bus);
> +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
> +
> +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
> +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
> +
> +void pci_bridge_write_config(PCIDevice *d,
> + uint32_t address, uint32_t val, int len);
> +void pci_bridge_disable_base_limit(PCIDevice *dev);
> +void pci_bridge_reset_reg(PCIDevice *dev);
> +void pci_bridge_reset(DeviceState *qdev);
> +
> +int pci_bridge_initfn(PCIDevice *pci_dev);
> +void pci_bridge_exitfn(PCIDevice *pci_dev);
> +
> +
> +/*
> + * before qdev initialization(qdev_init()), this function sets bus_name and
> + * map_irq callback which are necessry for pci_bridge_initfn() to
> + * initialize bus.
> + */
> +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
> + pci_map_irq_fn map_irq);
> +
> +#endif /* QEMU_PCI_BRIDGE_H */
> +/*
> + * Local variables:
> + * c-indent-level: 4
> + * c-basic-offset: 4
> + * tab-width: 8
> + * indent-tab-mode: nil
> + * End:
> + */
> diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c
> new file mode 100644
> index 0000000..68e328c
> --- /dev/null
> +++ b/hw/pci/pci_host.c
> @@ -0,0 +1,180 @@
> +/*
> + * pci_host.c
> + *
> + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "pci.h"
> +#include "pci_host.h"
> +
> +/* debug PCI */
> +//#define DEBUG_PCI
> +
> +#ifdef DEBUG_PCI
> +#define PCI_DPRINTF(fmt, ...) \
> +do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define PCI_DPRINTF(fmt, ...)
> +#endif
> +
> +/*
> + * PCI address
> + * bit 16 - 24: bus number
> + * bit 8 - 15: devfun number
> + * bit 0 - 7: offset in configuration space of a given pci device
> + */
> +
> +/* the helper functio to get a PCIDeice* for a given pci address */
> +static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
> +{
> + uint8_t bus_num = addr >> 16;
> + uint8_t devfn = addr >> 8;
> +
> + return pci_find_device(bus, bus_num, devfn);
> +}
> +
> +void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
> + uint32_t limit, uint32_t val, uint32_t len)
> +{
> + assert(len <= 4);
> + pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
> +}
> +
> +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
> + uint32_t limit, uint32_t len)
> +{
> + assert(len <= 4);
> + return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
> +}
> +
> +void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
> +{
> + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
> + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
> +
> + if (!pci_dev) {
> + return;
> + }
> +
> + PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
> + __func__, pci_dev->name, config_addr, val, len);
> + pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
> + val, len);
> +}
> +
> +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
> +{
> + PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
> + uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
> + uint32_t val;
> +
> + if (!pci_dev) {
> + return ~0x0;
> + }
> +
> + val = pci_host_config_read_common(pci_dev, config_addr,
> + PCI_CONFIG_SPACE_SIZE, len);
> + PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
> + __func__, pci_dev->name, config_addr, val, len);
> +
> + return val;
> +}
> +
> +static void pci_host_config_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned len)
> +{
> + PCIHostState *s = opaque;
> +
> + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
> + __func__, addr, len, val);
> + if (addr != 0 || len != 4) {
> + return;
> + }
> + s->config_reg = val;
> +}
> +
> +static uint64_t pci_host_config_read(void *opaque, hwaddr addr,
> + unsigned len)
> +{
> + PCIHostState *s = opaque;
> + uint32_t val = s->config_reg;
> +
> + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n",
> + __func__, addr, len, val);
> + return val;
> +}
> +
> +static void pci_host_data_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned len)
> +{
> + PCIHostState *s = opaque;
> + PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n",
> + addr, len, (unsigned)val);
> + if (s->config_reg & (1u << 31))
> + pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
> +}
> +
> +static uint64_t pci_host_data_read(void *opaque,
> + hwaddr addr, unsigned len)
> +{
> + PCIHostState *s = opaque;
> + uint32_t val;
> + if (!(s->config_reg & (1 << 31)))
> + return 0xffffffff;
> + val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
> + PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
> + addr, len, val);
> + return val;
> +}
> +
> +const MemoryRegionOps pci_host_conf_le_ops = {
> + .read = pci_host_config_read,
> + .write = pci_host_config_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +const MemoryRegionOps pci_host_conf_be_ops = {
> + .read = pci_host_config_read,
> + .write = pci_host_config_write,
> + .endianness = DEVICE_BIG_ENDIAN,
> +};
> +
> +const MemoryRegionOps pci_host_data_le_ops = {
> + .read = pci_host_data_read,
> + .write = pci_host_data_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +const MemoryRegionOps pci_host_data_be_ops = {
> + .read = pci_host_data_read,
> + .write = pci_host_data_write,
> + .endianness = DEVICE_BIG_ENDIAN,
> +};
> +
> +static const TypeInfo pci_host_type_info = {
> + .name = TYPE_PCI_HOST_BRIDGE,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .abstract = true,
> + .instance_size = sizeof(PCIHostState),
> +};
> +
> +static void pci_host_register_types(void)
> +{
> + type_register_static(&pci_host_type_info);
> +}
> +
> +type_init(pci_host_register_types)
> diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h
> new file mode 100644
> index 0000000..4b9c300
> --- /dev/null
> +++ b/hw/pci/pci_host.h
> @@ -0,0 +1,62 @@
> +/*
> + * QEMU Common PCI Host bridge configuration data space access routines.
> + *
> + * Copyright (c) 2006 Fabrice Bellard
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> + * of this software and associated documentation files (the "Software"), to
> deal
> + * in the Software without restriction, including without limitation the
> rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +/* Worker routines for a PCI host controller that uses an {address,data}
> + register pair to access PCI configuration space. */
> +
> +#ifndef PCI_HOST_H
> +#define PCI_HOST_H
> +
> +#include "sysbus.h"
> +
> +#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
> +#define PCI_HOST_BRIDGE(obj) \
> + OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
> +
> +struct PCIHostState {
> + SysBusDevice busdev;
> +
> + MemoryRegion conf_mem;
> + MemoryRegion data_mem;
> + MemoryRegion mmcfg;
> + MemoryRegion *address_space;
> + uint32_t config_reg;
> + PCIBus *bus;
> +};
> +
> +/* common internal helpers for PCI/PCIe hosts, cut off overflows */
> +void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
> + uint32_t limit, uint32_t val, uint32_t
> len);
> +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
> + uint32_t limit, uint32_t len);
> +
> +void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len);
> +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len);
> +
> +extern const MemoryRegionOps pci_host_conf_le_ops;
> +extern const MemoryRegionOps pci_host_conf_be_ops;
> +extern const MemoryRegionOps pci_host_data_le_ops;
> +extern const MemoryRegionOps pci_host_data_be_ops;
> +
> +#endif /* PCI_HOST_H */
> diff --git a/hw/pci/pci_ids.h b/hw/pci/pci_ids.h
> new file mode 100644
> index 0000000..5df7245
> --- /dev/null
> +++ b/hw/pci/pci_ids.h
> @@ -0,0 +1,147 @@
> +/*
> + * PCI Class, Vendor and Device IDs
> + *
> + * Please keep sorted.
> + *
> + * Abbreviated version of linux/pci_ids.h
> + *
> + * QEMU-specific definitions belong in pci.h
> + */
> +
> +/* Device classes and subclasses */
> +
> +#define PCI_BASE_CLASS_STORAGE 0x01
> +#define PCI_BASE_CLASS_NETWORK 0x02
> +
> +#define PCI_CLASS_STORAGE_SCSI 0x0100
> +#define PCI_CLASS_STORAGE_IDE 0x0101
> +#define PCI_CLASS_STORAGE_RAID 0x0104
> +#define PCI_CLASS_STORAGE_SATA 0x0106
> +#define PCI_CLASS_STORAGE_OTHER 0x0180
> +
> +#define PCI_CLASS_NETWORK_ETHERNET 0x0200
> +
> +#define PCI_CLASS_DISPLAY_VGA 0x0300
> +#define PCI_CLASS_DISPLAY_OTHER 0x0380
> +
> +#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
> +
> +#define PCI_CLASS_MEMORY_RAM 0x0500
> +
> +#define PCI_CLASS_SYSTEM_OTHER 0x0880
> +
> +#define PCI_CLASS_SERIAL_USB 0x0c03
> +#define PCI_CLASS_SERIAL_SMBUS 0x0c05
> +
> +#define PCI_CLASS_BRIDGE_HOST 0x0600
> +#define PCI_CLASS_BRIDGE_ISA 0x0601
> +#define PCI_CLASS_BRIDGE_PCI 0x0604
> +#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01
> +#define PCI_CLASS_BRIDGE_OTHER 0x0680
> +
> +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
> +#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
> +
> +#define PCI_CLASS_PROCESSOR_CO 0x0b40
> +#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
> +
> +#define PCI_CLASS_OTHERS 0xff
> +
> +/* Vendors and devices. Sort key: vendor first, device next. */
> +
> +#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
> +#define PCI_DEVICE_ID_LSI_53C895A 0x0012
> +#define PCI_DEVICE_ID_LSI_SAS1078 0x0060
> +
> +#define PCI_VENDOR_ID_DEC 0x1011
> +#define PCI_DEVICE_ID_DEC_21154 0x0026
> +
> +#define PCI_VENDOR_ID_CIRRUS 0x1013
> +
> +#define PCI_VENDOR_ID_IBM 0x1014
> +
> +#define PCI_VENDOR_ID_AMD 0x1022
> +#define PCI_DEVICE_ID_AMD_LANCE 0x2000
> +#define PCI_DEVICE_ID_AMD_SCSI 0x2020
> +
> +#define PCI_VENDOR_ID_TI 0x104c
> +
> +#define PCI_VENDOR_ID_MOTOROLA 0x1057
> +#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
> +#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
> +
> +#define PCI_VENDOR_ID_APPLE 0x106b
> +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
> +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b
> +
> +#define PCI_VENDOR_ID_SUN 0x108e
> +#define PCI_DEVICE_ID_SUN_EBUS 0x1000
> +#define PCI_DEVICE_ID_SUN_SIMBA 0x5000
> +#define PCI_DEVICE_ID_SUN_SABRE 0xa000
> +
> +#define PCI_VENDOR_ID_CMD 0x1095
> +#define PCI_DEVICE_ID_CMD_646 0x0646
> +
> +#define PCI_VENDOR_ID_REALTEK 0x10ec
> +#define PCI_DEVICE_ID_REALTEK_8139 0x8139
> +
> +#define PCI_VENDOR_ID_XILINX 0x10ee
> +
> +#define PCI_VENDOR_ID_VIA 0x1106
> +#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686
> +#define PCI_DEVICE_ID_VIA_IDE 0x0571
> +#define PCI_DEVICE_ID_VIA_UHCI 0x3038
> +#define PCI_DEVICE_ID_VIA_ACPI 0x3057
> +#define PCI_DEVICE_ID_VIA_AC97 0x3058
> +#define PCI_DEVICE_ID_VIA_MC97 0x3068
> +
> +#define PCI_VENDOR_ID_MARVELL 0x11ab
> +
> +#define PCI_VENDOR_ID_ENSONIQ 0x1274
> +#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
> +
> +#define PCI_VENDOR_ID_FREESCALE 0x1957
> +#define PCI_DEVICE_ID_MPC8533E 0x0030
> +
> +#define PCI_VENDOR_ID_INTEL 0x8086
> +#define PCI_DEVICE_ID_INTEL_82378 0x0484
> +#define PCI_DEVICE_ID_INTEL_82441 0x1237
> +#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
> +#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e
> +#define PCI_DEVICE_ID_INTEL_82801D 0x24CD
> +#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
> +#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
> +#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
> +#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
> +#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
> +#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
> +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
> +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
> +
> +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910
> +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917
> +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912
> +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913
> +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914
> +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919
> +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930
> +#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916
> +#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918
> +
> +#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
> +#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
> +#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
> +#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
> +#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
> +#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
> +#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
> +#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
> +#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed
> +
> +#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0
> +
> +#define PCI_VENDOR_ID_XEN 0x5853
> +#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
> +
> +#define PCI_VENDOR_ID_NEC 0x1033
> +#define PCI_DEVICE_ID_NEC_UPD720200 0x0194
> diff --git a/hw/pci/pci_internals.h b/hw/pci/pci_internals.h
> new file mode 100644
> index 0000000..21d0ce6
> --- /dev/null
> +++ b/hw/pci/pci_internals.h
> @@ -0,0 +1,78 @@
> +#ifndef QEMU_PCI_INTERNALS_H
> +#define QEMU_PCI_INTERNALS_H
> +
> +/*
> + * This header files is private to pci.c and pci_bridge.c
> + * So following structures are opaque to others and shouldn't be
> + * accessed.
> + *
> + * For pci-to-pci bridge needs to include this header file to embed
> + * PCIBridge in its structure or to get sizeof(PCIBridge),
> + * However, they shouldn't access those following members directly.
> + * Use accessor function in pci.h, pci_bridge.h
> + */
> +
> +#define TYPE_PCI_BUS "PCI"
> +#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
> +
> +struct PCIBus {
> + BusState qbus;
> + PCIDMAContextFunc dma_context_fn;
> + void *dma_context_opaque;
> + uint8_t devfn_min;
> + pci_set_irq_fn set_irq;
> + pci_map_irq_fn map_irq;
> + pci_route_irq_fn route_intx_to_irq;
> + pci_hotplug_fn hotplug;
> + DeviceState *hotplug_qdev;
> + void *irq_opaque;
> + PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
> + PCIDevice *parent_dev;
> + MemoryRegion *address_space_mem;
> + MemoryRegion *address_space_io;
> +
> + QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
> + QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
> +
> + /* The bus IRQ state is the logical OR of the connected devices.
> + Keep a count of the number of devices with raised IRQs. */
> + int nirq;
> + int *irq_count;
> +};
> +
> +typedef struct PCIBridgeWindows PCIBridgeWindows;
> +
> +/*
> + * Aliases for each of the address space windows that the bridge
> + * can forward. Mapped into the bridge's parent's address space,
> + * as subregions.
> + */
> +struct PCIBridgeWindows {
> + MemoryRegion alias_pref_mem;
> + MemoryRegion alias_mem;
> + MemoryRegion alias_io;
> +};
> +
> +struct PCIBridge {
> + PCIDevice dev;
> +
> + /* private member */
> + PCIBus sec_bus;
> + /*
> + * Memory regions for the bridge's address spaces. These regions are not
> + * directly added to system_memory/system_io or its descendants.
> + * Bridge's secondary bus points to these, so that devices
> + * under the bridge see these regions as its address spaces.
> + * The regions are as large as the entire address space -
> + * they don't take into account any windows.
> + */
> + MemoryRegion address_space_mem;
> + MemoryRegion address_space_io;
> +
> + PCIBridgeWindows *windows;
> +
> + pci_map_irq_fn map_irq;
> + const char *bus_name;
> +};
> +
> +#endif /* QEMU_PCI_INTERNALS_H */
> diff --git a/hw/pci/pci_regs.h b/hw/pci/pci_regs.h
> new file mode 100644
> index 0000000..56a404b
> --- /dev/null
> +++ b/hw/pci/pci_regs.h
> @@ -0,0 +1,717 @@
> +/*
> + * pci_regs.h
> + *
> + * PCI standard defines
> + * Copyright 1994, Drew Eckhardt
> + * Copyright 1997--1999 Martin Mares <address@hidden>
> + *
> + * For more information, please consult the following manuals (look at
> + * http://www.pcisig.com/ for how to get them):
> + *
> + * PCI BIOS Specification
> + * PCI Local Bus Specification
> + * PCI to PCI Bridge Specification
> + * PCI System Design Guide
> + *
> + * For hypertransport information, please consult the following manuals
> + * from http://www.hypertransport.org
> + *
> + * The Hypertransport I/O Link Specification
> + */
> +
> +#ifndef LINUX_PCI_REGS_H
> +#define LINUX_PCI_REGS_H
> +
> +/*
> + * Under PCI, each device has 256 bytes of configuration address space,
> + * of which the first 64 bytes are standardized as follows:
> + */
> +#define PCI_VENDOR_ID 0x00 /* 16 bits */
> +#define PCI_DEVICE_ID 0x02 /* 16 bits */
> +#define PCI_COMMAND 0x04 /* 16 bits */
> +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O
> space */
> +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
> +#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
> +#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles
> */
> +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and
> invalidate */
> +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
> +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
> +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
> +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
> +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
> +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
> +
> +#define PCI_STATUS 0x06 /* 16 bits */
> +#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */
> +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
> +#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
> +#define PCI_STATUS_UDF 0x40 /* Support User Definable
> Features [obsolete] */
> +#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
> +#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
> +#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
> +#define PCI_STATUS_DEVSEL_FAST 0x000
> +#define PCI_STATUS_DEVSEL_MEDIUM 0x200
> +#define PCI_STATUS_DEVSEL_SLOW 0x400
> +#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
> +#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
> +#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
> +#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
> +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
> +
> +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8
> revision */
> +#define PCI_REVISION_ID 0x08 /* Revision ID */
> +#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
> +#define PCI_CLASS_DEVICE 0x0a /* Device class */
> +
> +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
> +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
> +#define PCI_HEADER_TYPE 0x0e /* 8 bits */
> +#define PCI_HEADER_TYPE_NORMAL 0
> +#define PCI_HEADER_TYPE_BRIDGE 1
> +#define PCI_HEADER_TYPE_CARDBUS 2
> +
> +#define PCI_BIST 0x0f /* 8 bits */
> +#define PCI_BIST_CODE_MASK 0x0f /* Return result */
> +#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or
> less */
> +#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
> +
> +/*
> + * Base addresses specify locations in memory or I/O space.
> + * Decoded size can be determined by writing a value of
> + * 0xffffffff to the register, and reading it back. Only
> + * 1 bits are decoded.
> + */
> +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
> +#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
> +#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
> +#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
> +#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
> +#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
> +#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 =
> I/O */
> +#define PCI_BASE_ADDRESS_SPACE_IO 0x01
> +#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
> +#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
> +#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
> +#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
> +#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
> +#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
> +#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
> +#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
> +/* bit 1 is reserved if address_space = 1 */
> +
> +/* Header type 0 (normal devices) */
> +#define PCI_CARDBUS_CIS 0x28
> +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
> +#define PCI_SUBSYSTEM_ID 0x2e
> +#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address,
> 10..1 reserved */
> +#define PCI_ROM_ADDRESS_ENABLE 0x01
> +#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
> +
> +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list
> entry */
> +
> +/* 0x35-0x3b are reserved */
> +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
> +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
> +#define PCI_MIN_GNT 0x3e /* 8 bits */
> +#define PCI_MAX_LAT 0x3f /* 8 bits */
> +
> +/* Header type 1 (PCI-to-PCI bridges) */
> +#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
> +#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
> +#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the
> bridge */
> +#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary
> interface */
> +#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
> +#define PCI_IO_LIMIT 0x1d
> +#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */
> +#define PCI_IO_RANGE_TYPE_16 0x00
> +#define PCI_IO_RANGE_TYPE_32 0x01
> +#define PCI_IO_RANGE_MASK (~0x0fUL)
> +#define PCI_SEC_STATUS 0x1e /* Secondary status register, only
> bit 14 used */
> +#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
> +#define PCI_MEMORY_LIMIT 0x22
> +#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
> +#define PCI_MEMORY_RANGE_MASK (~0x0fUL)
> +#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
> +#define PCI_PREF_MEMORY_LIMIT 0x26
> +#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL
> +#define PCI_PREF_RANGE_TYPE_32 0x00
> +#define PCI_PREF_RANGE_TYPE_64 0x01
> +#define PCI_PREF_RANGE_MASK (~0x0fUL)
> +#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory
> range */
> +#define PCI_PREF_LIMIT_UPPER32 0x2c
> +#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
> +#define PCI_IO_LIMIT_UPPER16 0x32
> +/* 0x34 same as for htype 0 */
> +/* 0x35-0x3b is reserved */
> +#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for
> htype 1 */
> +/* 0x3c-0x3d are same as for htype 0 */
> +#define PCI_BRIDGE_CONTROL 0x3e
> +#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on
> secondary interface */
> +#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
> +#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */
> +#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
> +#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
> +#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
> +#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on
> secondary interface */
> +
> +/* Header type 2 (CardBus bridges) */
> +#define PCI_CB_CAPABILITY_LIST 0x14
> +/* 0x15 reserved */
> +#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
> +#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
> +#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
> +#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
> +#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
> +#define PCI_CB_MEMORY_BASE_0 0x1c
> +#define PCI_CB_MEMORY_LIMIT_0 0x20
> +#define PCI_CB_MEMORY_BASE_1 0x24
> +#define PCI_CB_MEMORY_LIMIT_1 0x28
> +#define PCI_CB_IO_BASE_0 0x2c
> +#define PCI_CB_IO_BASE_0_HI 0x2e
> +#define PCI_CB_IO_LIMIT_0 0x30
> +#define PCI_CB_IO_LIMIT_0_HI 0x32
> +#define PCI_CB_IO_BASE_1 0x34
> +#define PCI_CB_IO_BASE_1_HI 0x36
> +#define PCI_CB_IO_LIMIT_1 0x38
> +#define PCI_CB_IO_LIMIT_1_HI 0x3a
> +#define PCI_CB_IO_RANGE_MASK (~0x03UL)
> +/* 0x3c-0x3d are same as for htype 0 */
> +#define PCI_CB_BRIDGE_CONTROL 0x3e
> +#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge
> control register */
> +#define PCI_CB_BRIDGE_CTL_SERR 0x02
> +#define PCI_CB_BRIDGE_CTL_ISA 0x04
> +#define PCI_CB_BRIDGE_CTL_VGA 0x08
> +#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
> +#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
> +#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for
> 16-bit cards */
> +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both
> memory regions */
> +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
> +#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
> +#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
> +#define PCI_CB_SUBSYSTEM_ID 0x42
> +#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card
> legacy mode base address (ExCa) */
> +/* 0x48-0x7f reserved */
> +
> +/* Capability lists */
> +
> +#define PCI_CAP_LIST_ID 0 /* Capability ID */
> +#define PCI_CAP_ID_PM 0x01 /* Power Management */
> +#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port
> */
> +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */
> +#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */
> +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled
> Interrupts */
> +#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
> +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
> +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
> +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */
> +#define PCI_CAP_ID_DBG 0x0A /* Debug port */
> +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource
> Control */
> +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
> +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID
> */
> +#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */
> +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
> +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
> +#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */
> +#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */
> +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
> +#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits)
> */
> +#define PCI_CAP_SIZEOF 4
> +
> +/* Power Management Registers */
> +
> +#define PCI_PM_PMC 2 /* PM Capabilities Register */
> +#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */
> +#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */
> +#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */
> +#define PCI_PM_CAP_DSI 0x0020 /* Device specific
> initialization */
> +#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */
> +#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */
> +#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */
> +#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */
> +#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */
> +#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */
> +#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */
> +#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */
> +#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */
> +#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */
> +#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */
> +#define PCI_PM_CTRL 4 /* PM control and status register */
> +#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to
> D3) */
> +#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */
> +#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */
> +#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */
> +#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */
> +#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */
> +#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */
> +#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */
> +#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable
> (??) */
> +#define PCI_PM_DATA_REGISTER 7 /* (??) */
> +#define PCI_PM_SIZEOF 8
> +
> +/* AGP registers */
> +
> +#define PCI_AGP_VERSION 2 /* BCD version number */
> +#define PCI_AGP_RFU 3 /* Rest of capability flags */
> +#define PCI_AGP_STATUS 4 /* Status register */
> +#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of
> requests - 1 */
> +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */
> +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */
> +#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */
> +#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */
> +#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */
> +#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */
> +#define PCI_AGP_COMMAND 8 /* Control register */
> +#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of
> requests */
> +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */
> +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP
> transactions */
> +#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit
> addresses */
> +#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */
> +#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */
> +#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */
> +#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */
> +#define PCI_AGP_SIZEOF 12
> +
> +/* Vital Product Data */
> +
> +#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */
> +#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */
> +#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates
> completion */
> +#define PCI_VPD_DATA 4 /* 32-bits of data returned here */
> +
> +/* Slot Identification */
> +
> +#define PCI_SID_ESR 2 /* Expansion Slot Register */
> +#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots
> available */
> +#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */
> +#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */
> +
> +/* Message Signalled Interrupts registers */
> +
> +#define PCI_MSI_FLAGS 2 /* Various flags */
> +#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */
> +#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */
> +#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */
> +#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */
> +#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */
> +#define PCI_MSI_RFU 3 /* Rest of capability flags */
> +#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
> +#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if
> PCI_MSI_FLAGS_64BIT set) */
> +#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit
> devices */
> +#define PCI_MSI_MASK_32 12 /* Mask bits register for
> 32-bit devices */
> +#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit
> devices */
> +#define PCI_MSI_MASK_64 16 /* Mask bits register for
> 64-bit devices */
> +
> +/* MSI-X registers */
> +#define PCI_MSIX_FLAGS 2
> +#define PCI_MSIX_FLAGS_QSIZE 0x7FF
> +#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
> +#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
> +#define PCI_MSIX_TABLE 4
> +#define PCI_MSIX_PBA 8
> +#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
> +
> +/* MSI-X entry's format */
> +#define PCI_MSIX_ENTRY_SIZE 16
> +#define PCI_MSIX_ENTRY_LOWER_ADDR 0
> +#define PCI_MSIX_ENTRY_UPPER_ADDR 4
> +#define PCI_MSIX_ENTRY_DATA 8
> +#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
> +#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1
> +
> +/* CompactPCI Hotswap Register */
> +
> +#define PCI_CHSWP_CSR 2 /* Control and Status Register */
> +#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */
> +#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */
> +#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */
> +#define PCI_CHSWP_LOO 0x08 /* LED On / Off */
> +#define PCI_CHSWP_PI 0x30 /* Programming Interface */
> +#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */
> +#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */
> +
> +/* PCI Advanced Feature registers */
> +
> +#define PCI_AF_LENGTH 2
> +#define PCI_AF_CAP 3
> +#define PCI_AF_CAP_TP 0x01
> +#define PCI_AF_CAP_FLR 0x02
> +#define PCI_AF_CTRL 4
> +#define PCI_AF_CTRL_FLR 0x01
> +#define PCI_AF_STATUS 5
> +#define PCI_AF_STATUS_TP 0x01
> +
> +/* PCI-X registers */
> +
> +#define PCI_X_CMD 2 /* Modes & Features */
> +#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable
> */
> +#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */
> +#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */
> +#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */
> +#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */
> +#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */
> +#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */
> + /* Max # of outstanding split transactions */
> +#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */
> +#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */
> +#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */
> +#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */
> +#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */
> +#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */
> +#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */
> +#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */
> +#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions
> */
> +#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */
> +#define PCI_X_STATUS 4 /* PCI-X capabilities */
> +#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */
> +#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */
> +#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */
> +#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */
> +#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded
> */
> +#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split
> Completion */
> +#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */
> +#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read
> Count */
> +#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max
> Outstanding Split Transactions */
> +#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative
> Read Size */
> +#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion
> Error Msg */
> +#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */
> +#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */
> +
> +/* PCI Bridge Subsystem ID registers */
> +
> +#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id
> register */
> +#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id
> register */
> +
> +/* PCI Express capability registers */
> +
> +#define PCI_EXP_FLAGS 2 /* Capabilities register */
> +#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */
> +#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */
> +#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */
> +#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */
> +#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */
> +#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
> +#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
> +#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */
> +#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */
> +#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */
> +#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */
> +#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */
> +#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */
> +#define PCI_EXP_DEVCAP 4 /* Device capabilities */
> +#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */
> +#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */
> +#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */
> +#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */
> +#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */
> +#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */
> +#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator
> Present */
> +#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */
> +#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */
> +#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */
> +#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */
> +#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */
> +#define PCI_EXP_DEVCTL 8 /* Device Control */
> +#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */
> +#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */
> +#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */
> +#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En.
> */
> +#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
> +#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
> +#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable
> */
> +#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */
> +#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable
> */
> +#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */
> +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */
> +#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR
> */
> +#define PCI_EXP_DEVSTA 10 /* Device Status */
> +#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */
> +#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */
> +#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */
> +#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */
> +#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */
> +#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */
> +#define PCI_EXP_LNKCAP 12 /* Link Capabilities */
> +#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */
> +#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
> +#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
> +#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */
> +#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */
> +#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* L1 Clock Power Management */
> +#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting
> Capable */
> +#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link
> Active Reporting Capable */
> +#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification
> Capability */
> +#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */
> +#define PCI_EXP_LNKCTL 16 /* Link Control */
> +#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */
> +#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */
> +#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */
> +#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */
> +#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */
> +#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */
> +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */
> +#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable
> */
> +#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management
> Interrupt Enable */
> +#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Lnk Autonomous Bandwidth Interrupt
> Enable */
> +#define PCI_EXP_LNKSTA 18 /* Link Status */
> +#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */
> +#define PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */
> +#define PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */
> +#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */
> +#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */
> +#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */
> +#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */
> +#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */
> +#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */
> +#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */
> +#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */
> +#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */
> +#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */
> +#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */
> +#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */
> +#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */
> +#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */
> +#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */
> +#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */
> +#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */
> +#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock
> Present */
> +#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */
> +#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */
> +#define PCI_EXP_SLTCTL 24 /* Slot Control */
> +#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */
> +#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */
> +#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */
> +#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */
> +#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable
> */
> +#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */
> +#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */
> +#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */
> +#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */
> +#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock
> Control */
> +#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed
> Enable */
> +#define PCI_EXP_SLTSTA 26 /* Slot Status */
> +#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */
> +#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */
> +#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */
> +#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */
> +#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */
> +#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */
> +#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */
> +#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status
> */
> +#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */
> +#define PCI_EXP_RTCTL 28 /* Root Control */
> +#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error
> */
> +#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */
> +#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */
> +#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */
> +#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */
> +#define PCI_EXP_RTCAP 30 /* Root Capabilities */
> +#define PCI_EXP_RTSTA 32 /* Root Status */
> +#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */
> +#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */
> +#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */
> +#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */
> +#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */
> +#define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */
> +#define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */
> +#define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */
> +#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
> +#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */
> +#define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */
> +#define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion
> enable */
> +#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance
> reporting */
> +#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */
> +#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */
> +#define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */
> +#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */
> +#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */
> +
> +/* Extended Capabilities (PCI-X 2.0 and Express) */
> +#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff)
> +#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf)
> +#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc)
> +
> +#define PCI_EXT_CAP_ID_ERR 1
> +#define PCI_EXT_CAP_ID_VC 2
> +#define PCI_EXT_CAP_ID_DSN 3
> +#define PCI_EXT_CAP_ID_PWR 4
> +#define PCI_EXT_CAP_ID_VNDR 11
> +#define PCI_EXT_CAP_ID_ACS 13
> +#define PCI_EXT_CAP_ID_ARI 14
> +#define PCI_EXT_CAP_ID_ATS 15
> +#define PCI_EXT_CAP_ID_SRIOV 16
> +#define PCI_EXT_CAP_ID_LTR 24
> +
> +/* Advanced Error Reporting */
> +#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */
> +#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */
> +#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */
> +#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */
> +#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */
> +#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */
> +#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */
> +#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */
> +#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */
> +#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */
> +#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */
> +#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */
> +#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */
> + /* Same bits as above */
> +#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */
> + /* Same bits as above */
> +#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */
> +#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */
> +#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */
> +#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */
> +#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */
> +#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */
> +#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */
> + /* Same bits as above */
> +#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */
> +#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */
> +#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */
> +#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */
> +#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
> +#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
> +#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */
> +#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */
> +/* Correctable Err Reporting Enable */
> +#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001
> +/* Non-fatal Err Reporting Enable */
> +#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002
> +/* Fatal Err Reporting Enable */
> +#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004
> +#define PCI_ERR_ROOT_STATUS 48
> +#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */
> +/* Multi ERR_COR Received */
> +#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002
> +/* ERR_FATAL/NONFATAL Recevied */
> +#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004
> +/* Multi ERR_FATAL/NONFATAL Recevied */
> +#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008
> +#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */
> +#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received
> */
> +#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */
> +#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */
> +
> +/* Virtual Channel */
> +#define PCI_VC_PORT_REG1 4
> +#define PCI_VC_PORT_REG2 8
> +#define PCI_VC_PORT_CTRL 12
> +#define PCI_VC_PORT_STATUS 14
> +#define PCI_VC_RES_CAP 16
> +#define PCI_VC_RES_CTRL 20
> +#define PCI_VC_RES_STATUS 26
> +
> +/* Power Budgeting */
> +#define PCI_PWR_DSR 4 /* Data Select Register */
> +#define PCI_PWR_DATA 8 /* Data Register */
> +#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */
> +#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */
> +#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */
> +#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
> +#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */
> +#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */
> +#define PCI_PWR_CAP 12 /* Capability */
> +#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget
> */
> +
> +/*
> + * Hypertransport sub capability types
> + *
> + * Unfortunately there are both 3 bit and 5 bit capability types defined
> + * in the HT spec, catering for that is a little messy. You probably don't
> + * want to use these directly, just use pci_find_ht_capability() and it
> + * will do the right thing for you.
> + */
> +#define HT_3BIT_CAP_MASK 0xE0
> +#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
> +#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link
> configuration */
> +
> +#define HT_5BIT_CAP_MASK 0xF8
> +#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */
> +#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */
> +#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */
> +#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */
> +#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space
> Access */
> +#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */
> +#define HT_MSI_FLAGS 0x02 /* Offset to flags */
> +#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */
> +#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */
> +#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */
> +#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr
> bits */
> +#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */
> +#define HT_MSI_ADDR_HI 0x08 /* Offset to high
> addr bits */
> +#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing
> configuration */
> +#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */
> +#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */
> +#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3
> hypertransport configuration */
> +#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement
> configuration */
> +
> +/* Alternative Routing-ID Interpretation */
> +#define PCI_ARI_CAP 0x04 /* ARI Capability Register */
> +#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */
> +#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */
> +#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */
> +#define PCI_ARI_CTRL 0x06 /* ARI Control Register */
> +#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */
> +#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */
> +#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */
> +
> +/* Address Translation Service */
> +#define PCI_ATS_CAP 0x04 /* ATS Capability Register */
> +#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */
> +#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */
> +#define PCI_ATS_CTRL 0x06 /* ATS Control Register */
> +#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */
> +#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit
> */
> +#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */
> +
> +/* Single Root I/O Virtualization */
> +#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */
> +#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */
> +#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */
> +#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */
> +#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */
> +#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */
> +#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */
> +#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */
> +#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */
> +#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */
> +#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */
> +#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */
> +#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */
> +#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */
> +#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */
> +#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */
> +#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */
> +#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */
> +#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */
> +#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */
> +#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */
> +#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */
> +#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/
> +#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */
> +#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */
> +#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */
> +#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */
> +#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */
> +#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */
> +
> +#define PCI_LTR_MAX_SNOOP_LAT 0x4
> +#define PCI_LTR_MAX_NOSNOOP_LAT 0x6
> +#define PCI_LTR_VALUE_MASK 0x000003ff
> +#define PCI_LTR_SCALE_MASK 0x00001c00
> +#define PCI_LTR_SCALE_SHIFT 10
> +
> +/* Access Control Service */
> +#define PCI_ACS_CAP 0x04 /* ACS Capability Register */
> +#define PCI_ACS_SV 0x01 /* Source Validation */
> +#define PCI_ACS_TB 0x02 /* Translation Blocking */
> +#define PCI_ACS_RR 0x04 /* P2P Request Redirect */
> +#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */
> +#define PCI_ACS_UF 0x10 /* Upstream Forwarding */
> +#define PCI_ACS_EC 0x20 /* P2P Egress Control */
> +#define PCI_ACS_DT 0x40 /* Direct Translated P2P */
> +#define PCI_ACS_CTRL 0x06 /* ACS Control Register */
> +#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */
> +
> +#endif /* LINUX_PCI_REGS_H */
> diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
> new file mode 100644
> index 0000000..7c92f19
> --- /dev/null
> +++ b/hw/pci/pcie.c
> @@ -0,0 +1,555 @@
> +/*
> + * pcie.c
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu-common.h"
> +#include "pci_bridge.h"
> +#include "pcie.h"
> +#include "msix.h"
> +#include "msi.h"
> +#include "pci_internals.h"
> +#include "pcie_regs.h"
> +#include "range.h"
> +
> +//#define DEBUG_PCIE
> +#ifdef DEBUG_PCIE
> +# define PCIE_DPRINTF(fmt, ...) \
> + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
> +#else
> +# define PCIE_DPRINTF(fmt, ...) do {} while (0)
> +#endif
> +#define PCIE_DEV_PRINTF(dev, fmt, ...) \
> + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
> +
> +
> +/***************************************************************************
> + * pci express capability helper functions
> + */
> +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
> +{
> + int pos;
> + uint8_t *exp_cap;
> +
> + assert(pci_is_express(dev));
> +
> + pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
> + PCI_EXP_VER2_SIZEOF);
> + if (pos < 0) {
> + return pos;
> + }
> + dev->exp.exp_cap = pos;
> + exp_cap = dev->config + pos;
> +
> + /* capability register
> + interrupt message number defaults to 0 */
> + pci_set_word(exp_cap + PCI_EXP_FLAGS,
> + ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) |
> + PCI_EXP_FLAGS_VER2);
> +
> + /* device capability register
> + * table 7-12:
> + * roll based error reporting bit must be set by all
> + * Functions conforming to the ECN, PCI Express Base
> + * Specification, Revision 1.1., or subsequent PCI Express Base
> + * Specification revisions.
> + */
> + pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);
> +
> + pci_set_long(exp_cap + PCI_EXP_LNKCAP,
> + (port << PCI_EXP_LNKCAP_PN_SHIFT) |
> + PCI_EXP_LNKCAP_ASPMS_0S |
> + PCI_EXP_LNK_MLW_1 |
> + PCI_EXP_LNK_LS_25);
> +
> + pci_set_word(exp_cap + PCI_EXP_LNKSTA,
> + PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
> +
> + pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
> + PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
> +
> + pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB);
> + return pos;
> +}
> +
> +void pcie_cap_exit(PCIDevice *dev)
> +{
> + pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
> +}
> +
> +uint8_t pcie_cap_get_type(const PCIDevice *dev)
> +{
> + uint32_t pos = dev->exp.exp_cap;
> + assert(pos > 0);
> + return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) &
> + PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT;
> +}
> +
> +/* MSI/MSI-X */
> +/* pci express interrupt message number */
> +/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */
> +void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector)
> +{
> + uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
> + assert(vector < 32);
> + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ);
> + pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
> + vector << PCI_EXP_FLAGS_IRQ_SHIFT);
> +}
> +
> +uint8_t pcie_cap_flags_get_vector(PCIDevice *dev)
> +{
> + return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
> + PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT;
> +}
> +
> +void pcie_cap_deverr_init(PCIDevice *dev)
> +{
> + uint32_t pos = dev->exp.exp_cap;
> + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP,
> + PCI_EXP_DEVCAP_RBER);
> + pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL,
> + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
> + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
> + pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA,
> + PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
> + PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD);
> +}
> +
> +void pcie_cap_deverr_reset(PCIDevice *dev)
> +{
> + uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
> + pci_long_test_and_clear_mask(devctl,
> + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
> + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
> +}
> +
> +static void hotplug_event_update_event_status(PCIDevice *dev)
> +{
> + uint32_t pos = dev->exp.exp_cap;
> + uint8_t *exp_cap = dev->config + pos;
> + uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
> + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
> +
> + dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) &&
> + (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED);
> +}
> +
> +static void hotplug_event_notify(PCIDevice *dev)
> +{
> + bool prev = dev->exp.hpev_notified;
> +
> + hotplug_event_update_event_status(dev);
> +
> + if (prev == dev->exp.hpev_notified) {
> + return;
> + }
> +
> + /* Note: the logic above does not take into account whether interrupts
> + * are masked. The result is that interrupt will be sent when it is
> + * subsequently unmasked. This appears to be legal: Section 6.7.3.4:
> + * The Port may optionally send an MSI when there are hot-plug events
> that
> + * occur while interrupt generation is disabled, and interrupt
> generation is
> + * subsequently enabled. */
> + if (msix_enabled(dev)) {
> + msix_notify(dev, pcie_cap_flags_get_vector(dev));
> + } else if (msi_enabled(dev)) {
> + msi_notify(dev, pcie_cap_flags_get_vector(dev));
> + } else {
> + qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
> + }
> +}
> +
> +static void hotplug_event_clear(PCIDevice *dev)
> +{
> + hotplug_event_update_event_status(dev);
> + if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) {
> + qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0);
> + }
> +}
> +
> +/*
> + * A PCI Express Hot-Plug Event has occurred, so update slot status register
> + * and notify OS of the event if necessary.
> + *
> + * 6.7.3 PCI Express Hot-Plug Events
> + * 6.7.3.4 Software Notification of Hot-Plug Events
> + */
> +static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
> +{
> + /* Minor optimization: if nothing changed - no event is needed. */
> + if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
> + PCI_EXP_SLTSTA, event)) {
> + return;
> + }
> + hotplug_event_notify(dev);
> +}
> +
> +static int pcie_cap_slot_hotplug(DeviceState *qdev,
> + PCIDevice *pci_dev, PCIHotplugState state)
> +{
> + PCIDevice *d = PCI_DEVICE(qdev);
> + uint8_t *exp_cap = d->config + d->exp.exp_cap;
> + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
> +
> + /* Don't send event when device is enabled during qemu machine creation:
> + * it is present on boot, no hotplug event is necessary. We do send an
> + * event when the device is disabled later. */
> + if (state == PCI_COLDPLUG_ENABLED) {
> + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
> + PCI_EXP_SLTSTA_PDS);
> + return 0;
> + }
> +
> + PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
> + if (sltsta & PCI_EXP_SLTSTA_EIS) {
> + /* the slot is electromechanically locked.
> + * This error is propagated up to qdev and then to HMP/QMP.
> + */
> + return -EBUSY;
> + }
> +
> + /* TODO: multifunction hot-plug.
> + * Right now, only a device of function = 0 is allowed to be
> + * hot plugged/unplugged.
> + */
> + assert(PCI_FUNC(pci_dev->devfn) == 0);
> +
> + if (state == PCI_HOTPLUG_ENABLED) {
> + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
> + PCI_EXP_SLTSTA_PDS);
> + pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
> + } else {
> + qdev_free(&pci_dev->qdev);
> + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
> + PCI_EXP_SLTSTA_PDS);
> + pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
> + }
> + return 0;
> +}
> +
> +/* pci express slot for pci express root/downstream port
> + PCI express capability slot registers */
> +void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
> +{
> + uint32_t pos = dev->exp.exp_cap;
> +
> + pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS,
> + PCI_EXP_FLAGS_SLOT);
> +
> + pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP,
> + ~PCI_EXP_SLTCAP_PSN);
> + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
> + (slot << PCI_EXP_SLTCAP_PSN_SHIFT) |
> + PCI_EXP_SLTCAP_EIP |
> + PCI_EXP_SLTCAP_HPS |
> + PCI_EXP_SLTCAP_HPC |
> + PCI_EXP_SLTCAP_PIP |
> + PCI_EXP_SLTCAP_AIP |
> + PCI_EXP_SLTCAP_ABP);
> +
> + pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
> + PCI_EXP_SLTCTL_PIC |
> + PCI_EXP_SLTCTL_AIC);
> + pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL,
> + PCI_EXP_SLTCTL_PIC_OFF |
> + PCI_EXP_SLTCTL_AIC_OFF);
> + pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
> + PCI_EXP_SLTCTL_PIC |
> + PCI_EXP_SLTCTL_AIC |
> + PCI_EXP_SLTCTL_HPIE |
> + PCI_EXP_SLTCTL_CCIE |
> + PCI_EXP_SLTCTL_PDCE |
> + PCI_EXP_SLTCTL_ABPE);
> + /* Although reading PCI_EXP_SLTCTL_EIC returns always 0,
> + * make the bit writable here in order to detect 1b is written.
> + * pcie_cap_slot_write_config() test-and-clear the bit, so
> + * this bit always returns 0 to the guest.
> + */
> + pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
> + PCI_EXP_SLTCTL_EIC);
> +
> + pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
> + PCI_EXP_HP_EV_SUPPORTED);
> +
> + dev->exp.hpev_notified = false;
> +
> + pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)),
> + pcie_cap_slot_hotplug, &dev->qdev);
> +}
> +
> +void pcie_cap_slot_reset(PCIDevice *dev)
> +{
> + uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
> +
> + PCIE_DEV_PRINTF(dev, "reset\n");
> +
> + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
> + PCI_EXP_SLTCTL_EIC |
> + PCI_EXP_SLTCTL_PIC |
> + PCI_EXP_SLTCTL_AIC |
> + PCI_EXP_SLTCTL_HPIE |
> + PCI_EXP_SLTCTL_CCIE |
> + PCI_EXP_SLTCTL_PDCE |
> + PCI_EXP_SLTCTL_ABPE);
> + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
> + PCI_EXP_SLTCTL_PIC_OFF |
> + PCI_EXP_SLTCTL_AIC_OFF);
> +
> + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
> + PCI_EXP_SLTSTA_EIS |/* on reset,
> + the lock is released
> */
> + PCI_EXP_SLTSTA_CC |
> + PCI_EXP_SLTSTA_PDC |
> + PCI_EXP_SLTSTA_ABP);
> +
> + hotplug_event_update_event_status(dev);
> +}
> +
> +void pcie_cap_slot_write_config(PCIDevice *dev,
> + uint32_t addr, uint32_t val, int len)
> +{
> + uint32_t pos = dev->exp.exp_cap;
> + uint8_t *exp_cap = dev->config + pos;
> + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
> +
> + if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
> + hotplug_event_clear(dev);
> + }
> +
> + if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
> + return;
> + }
> +
> + if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
> + PCI_EXP_SLTCTL_EIC)) {
> + sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
> + pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
> + PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
> + "sltsta -> 0x%02"PRIx16"\n",
> + sltsta);
> + }
> +
> + hotplug_event_notify(dev);
> +
> + /*
> + * 6.7.3.2 Command Completed Events
> + *
> + * Software issues a command to a hot-plug capable Downstream Port by
> + * issuing a write transaction that targets any portion of the Port’s
> Slot
> + * Control register. A single write to the Slot Control register is
> + * considered to be a single command, even if the write affects more than
> + * one field in the Slot Control register. In response to this
> transaction,
> + * the Port must carry out the requested actions and then set the
> + * associated status field for the command completed event. */
> +
> + /* Real hardware might take a while to complete requested command because
> + * physical movement would be involved like locking the electromechanical
> + * lock. However in our case, command is completed instantaneously
> above,
> + * so send a command completion event right now.
> + */
> + pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
> +}
> +
> +int pcie_cap_slot_post_load(void *opaque, int version_id)
> +{
> + PCIDevice *dev = opaque;
> + hotplug_event_update_event_status(dev);
> + return 0;
> +}
> +
> +void pcie_cap_slot_push_attention_button(PCIDevice *dev)
> +{
> + pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
> +}
> +
> +/* root control/capabilities/status. PME isn't emulated for now */
> +void pcie_cap_root_init(PCIDevice *dev)
> +{
> + pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL,
> + PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
> + PCI_EXP_RTCTL_SEFEE);
> +}
> +
> +void pcie_cap_root_reset(PCIDevice *dev)
> +{
> + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0);
> +}
> +
> +/* function level reset(FLR) */
> +void pcie_cap_flr_init(PCIDevice *dev)
> +{
> + pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap +
> PCI_EXP_DEVCAP,
> + PCI_EXP_DEVCAP_FLR);
> +
> + /* Although reading BCR_FLR returns always 0,
> + * the bit is made writable here in order to detect the 1b is written
> + * pcie_cap_flr_write_config() test-and-clear the bit, so
> + * this bit always returns 0 to the guest.
> + */
> + pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap +
> PCI_EXP_DEVCTL,
> + PCI_EXP_DEVCTL_BCR_FLR);
> +}
> +
> +void pcie_cap_flr_write_config(PCIDevice *dev,
> + uint32_t addr, uint32_t val, int len)
> +{
> + uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
> + if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) {
> + /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler
> + so the handler can detect FLR by looking at this bit. */
> + pci_device_reset(dev);
> + pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR);
> + }
> +}
> +
> +/* Alternative Routing-ID Interpretation (ARI) */
> +/* ari forwarding support for down stream port */
> +void pcie_cap_ari_init(PCIDevice *dev)
> +{
> + uint32_t pos = dev->exp.exp_cap;
> + pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2,
> + PCI_EXP_DEVCAP2_ARI);
> + pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2,
> + PCI_EXP_DEVCTL2_ARI);
> +}
> +
> +void pcie_cap_ari_reset(PCIDevice *dev)
> +{
> + uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2;
> + pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI);
> +}
> +
> +bool pcie_cap_is_ari_enabled(const PCIDevice *dev)
> +{
> + if (!pci_is_express(dev)) {
> + return false;
> + }
> + if (!dev->exp.exp_cap) {
> + return false;
> + }
> +
> + return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
> + PCI_EXP_DEVCTL2_ARI;
> +}
> +
> +/**************************************************************************
> + * pci express extended capability allocation functions
> + * uint16_t ext_cap_id (16 bit)
> + * uint8_t cap_ver (4 bit)
> + * uint16_t cap_offset (12 bit)
> + * uint16_t ext_cap_size
> + */
> +
> +static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id,
> + uint16_t *prev_p)
> +{
> + uint16_t prev = 0;
> + uint16_t next;
> + uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE);
> +
> + if (!header) {
> + /* no extended capability */
> + next = 0;
> + goto out;
> + }
> + for (next = PCI_CONFIG_SPACE_SIZE; next;
> + prev = next, next = PCI_EXT_CAP_NEXT(header)) {
> +
> + assert(next >= PCI_CONFIG_SPACE_SIZE);
> + assert(next <= PCIE_CONFIG_SPACE_SIZE - 8);
> +
> + header = pci_get_long(dev->config + next);
> + if (PCI_EXT_CAP_ID(header) == cap_id) {
> + break;
> + }
> + }
> +
> +out:
> + if (prev_p) {
> + *prev_p = prev;
> + }
> + return next;
> +}
> +
> +uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id)
> +{
> + return pcie_find_capability_list(dev, cap_id, NULL);
> +}
> +
> +static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t
> next)
> +{
> + uint16_t header = pci_get_long(dev->config + pos);
> + assert(!(next & (PCI_EXT_CAP_ALIGN - 1)));
> + header = (header & ~PCI_EXT_CAP_NEXT_MASK) |
> + ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK);
> + pci_set_long(dev->config + pos, header);
> +}
> +
> +/*
> + * caller must supply valid (offset, size) * such that the range shouldn't
> + * overlap with other capability or other registers.
> + * This function doesn't check it.
> + */
> +void pcie_add_capability(PCIDevice *dev,
> + uint16_t cap_id, uint8_t cap_ver,
> + uint16_t offset, uint16_t size)
> +{
> + uint32_t header;
> + uint16_t next;
> +
> + assert(offset >= PCI_CONFIG_SPACE_SIZE);
> + assert(offset < offset + size);
> + assert(offset + size < PCIE_CONFIG_SPACE_SIZE);
> + assert(size >= 8);
> + assert(pci_is_express(dev));
> +
> + if (offset == PCI_CONFIG_SPACE_SIZE) {
> + header = pci_get_long(dev->config + offset);
> + next = PCI_EXT_CAP_NEXT(header);
> + } else {
> + uint16_t prev;
> +
> + /* 0 is reserved cap id. use internally to find the last capability
> + in the linked list */
> + next = pcie_find_capability_list(dev, 0, &prev);
> +
> + assert(prev >= PCI_CONFIG_SPACE_SIZE);
> + assert(next == 0);
> + pcie_ext_cap_set_next(dev, prev, offset);
> + }
> + pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next));
> +
> + /* Make capability read-only by default */
> + memset(dev->wmask + offset, 0, size);
> + memset(dev->w1cmask + offset, 0, size);
> + /* Check capability by default */
> + memset(dev->cmask + offset, 0xFF, size);
> +}
> +
> +/**************************************************************************
> + * pci express extended capability helper functions
> + */
> +
> +/* ARI */
> +void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn)
> +{
> + pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER,
> + offset, PCI_ARI_SIZEOF);
> + pci_set_long(dev->config + offset + PCI_ARI_CAP,
> PCI_ARI_CAP_NFN(nextfn));
> +}
> diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h
> new file mode 100644
> index 0000000..4889194
> --- /dev/null
> +++ b/hw/pci/pcie.h
> @@ -0,0 +1,142 @@
> +/*
> + * pcie.h
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef QEMU_PCIE_H
> +#define QEMU_PCIE_H
> +
> +#include "hw.h"
> +#include "pci_regs.h"
> +#include "pcie_regs.h"
> +#include "pcie_aer.h"
> +
> +typedef enum {
> + /* for attention and power indicator */
> + PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED,
> + PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON,
> + PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK,
> + PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF,
> +} PCIExpressIndicator;
> +
> +typedef enum {
> + /* these bits must match the bits in Slot Control/Status registers.
> + * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx
> + *
> + * Not all the bits of slot control register match with the ones of
> + * slot status. Not some bits of slot status register is used to
> + * show status, not to report event occurrence.
> + * So such bits must be masked out when checking the software
> + * notification condition.
> + */
> + PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE,
> + /* attention button pressed */
> + PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE,
> + /* presence detect changed */
> + PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE,
> + /* command completed */
> +
> + PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP |
> + PCI_EXP_HP_EV_PDC |
> + PCI_EXP_HP_EV_CCI,
> + /* supported event mask */
> +
> + /* events not listed aren't supported */
> +} PCIExpressHotPlugEvent;
> +
> +struct PCIExpressDevice {
> + /* Offset of express capability in config space */
> + uint8_t exp_cap;
> +
> + /* SLOT */
> + unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#)
> + * default is 0 = INTA#
> + * If the chip wants to use other interrupt
> + * line, initialize this member with the
> + * desired number.
> + * If the chip dynamically changes this
> member,
> + * also initialize it when loaded as
> + * appropreately.
> + */
> + bool hpev_notified; /* Logical AND of conditions for hot plug event.
> + Following 6.7.3.4:
> + Software Notification of Hot-Plug Events, an
> interrupt
> + is sent whenever the logical and of these conditions
> + transitions from false to true. */
> +
> + /* AER */
> + uint16_t aer_cap;
> + PCIEAERLog aer_log;
> + unsigned int aer_intx; /* INTx for error reporting
> + * default is 0 = INTA#
> + * If the chip wants to use other interrupt
> + * line, initialize this member with the
> + * desired number.
> + * If the chip dynamically changes this
> member,
> + * also initialize it when loaded as
> + * appropreately.
> + */
> +};
> +
> +/* PCI express capability helper functions */
> +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t
> port);
> +void pcie_cap_exit(PCIDevice *dev);
> +uint8_t pcie_cap_get_type(const PCIDevice *dev);
> +void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
> +uint8_t pcie_cap_flags_get_vector(PCIDevice *dev);
> +
> +void pcie_cap_deverr_init(PCIDevice *dev);
> +void pcie_cap_deverr_reset(PCIDevice *dev);
> +
> +void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
> +void pcie_cap_slot_reset(PCIDevice *dev);
> +void pcie_cap_slot_write_config(PCIDevice *dev,
> + uint32_t addr, uint32_t val, int len);
> +int pcie_cap_slot_post_load(void *opaque, int version_id);
> +void pcie_cap_slot_push_attention_button(PCIDevice *dev);
> +
> +void pcie_cap_root_init(PCIDevice *dev);
> +void pcie_cap_root_reset(PCIDevice *dev);
> +
> +void pcie_cap_flr_init(PCIDevice *dev);
> +void pcie_cap_flr_write_config(PCIDevice *dev,
> + uint32_t addr, uint32_t val, int len);
> +
> +void pcie_cap_ari_init(PCIDevice *dev);
> +void pcie_cap_ari_reset(PCIDevice *dev);
> +bool pcie_cap_is_ari_enabled(const PCIDevice *dev);
> +
> +/* PCI express extended capability helper functions */
> +uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
> +void pcie_add_capability(PCIDevice *dev,
> + uint16_t cap_id, uint8_t cap_ver,
> + uint16_t offset, uint16_t size);
> +
> +void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
> +
> +extern const VMStateDescription vmstate_pcie_device;
> +
> +#define VMSTATE_PCIE_DEVICE(_field, _state) { \
> + .name = (stringify(_field)), \
> + .size = sizeof(PCIDevice), \
> + .vmsd = &vmstate_pcie_device, \
> + .flags = VMS_STRUCT, \
> + .offset = vmstate_offset_value(_state, _field, PCIDevice), \
> +}
> +
> +#endif /* QEMU_PCIE_H */
> diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
> new file mode 100644
> index 0000000..b04c164
> --- /dev/null
> +++ b/hw/pci/pcie_aer.c
> @@ -0,0 +1,1032 @@
> +/*
> + * pcie_aer.c
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "sysemu.h"
> +#include "qemu-objects.h"
> +#include "monitor.h"
> +#include "pci_bridge.h"
> +#include "pcie.h"
> +#include "msix.h"
> +#include "msi.h"
> +#include "pci_internals.h"
> +#include "pcie_regs.h"
> +
> +//#define DEBUG_PCIE
> +#ifdef DEBUG_PCIE
> +# define PCIE_DPRINTF(fmt, ...) \
> + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
> +#else
> +# define PCIE_DPRINTF(fmt, ...) do {} while (0)
> +#endif
> +#define PCIE_DEV_PRINTF(dev, fmt, ...) \
> + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
> +
> +#define PCI_ERR_SRC_COR_OFFS 0
> +#define PCI_ERR_SRC_UNCOR_OFFS 2
> +
> +/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
> +static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
> +{
> + switch (status) {
> + case PCI_ERR_UNC_INTN:
> + case PCI_ERR_UNC_DLP:
> + case PCI_ERR_UNC_SDN:
> + case PCI_ERR_UNC_RX_OVER:
> + case PCI_ERR_UNC_FCP:
> + case PCI_ERR_UNC_MALF_TLP:
> + return PCI_ERR_ROOT_CMD_FATAL_EN;
> + case PCI_ERR_UNC_POISON_TLP:
> + case PCI_ERR_UNC_ECRC:
> + case PCI_ERR_UNC_UNSUP:
> + case PCI_ERR_UNC_COMP_TIME:
> + case PCI_ERR_UNC_COMP_ABORT:
> + case PCI_ERR_UNC_UNX_COMP:
> + case PCI_ERR_UNC_ACSV:
> + case PCI_ERR_UNC_MCBTLP:
> + case PCI_ERR_UNC_ATOP_EBLOCKED:
> + case PCI_ERR_UNC_TLP_PRF_BLOCKED:
> + return PCI_ERR_ROOT_CMD_NONFATAL_EN;
> + default:
> + abort();
> + break;
> + }
> + return PCI_ERR_ROOT_CMD_FATAL_EN;
> +}
> +
> +static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err)
> +{
> + if (aer_log->log_num == aer_log->log_max) {
> + return -1;
> + }
> + memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err);
> + aer_log->log_num++;
> + return 0;
> +}
> +
> +static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err)
> +{
> + assert(aer_log->log_num);
> + *err = aer_log->log[0];
> + aer_log->log_num--;
> + memmove(&aer_log->log[0], &aer_log->log[1],
> + aer_log->log_num * sizeof *err);
> +}
> +
> +static void aer_log_clear_all_err(PCIEAERLog *aer_log)
> +{
> + aer_log->log_num = 0;
> +}
> +
> +int pcie_aer_init(PCIDevice *dev, uint16_t offset)
> +{
> + PCIExpressDevice *exp;
> +
> + pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER,
> + offset, PCI_ERR_SIZEOF);
> + exp = &dev->exp;
> + exp->aer_cap = offset;
> +
> + /* log_max is property */
> + if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) {
> + dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT;
> + }
> + /* clip down the value to avoid unreasobale memory usage */
> + if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
> + return -EINVAL;
> + }
> + dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] *
> + dev->exp.aer_log.log_max);
> +
> + pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
> + PCI_ERR_UNC_SUPPORTED);
> +
> + pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
> + PCI_ERR_UNC_SEVERITY_DEFAULT);
> + pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER,
> + PCI_ERR_UNC_SUPPORTED);
> +
> + pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS,
> + PCI_ERR_COR_STATUS);
> +
> + pci_set_long(dev->config + offset + PCI_ERR_COR_MASK,
> + PCI_ERR_COR_MASK_DEFAULT);
> + pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK,
> + PCI_ERR_COR_SUPPORTED);
> +
> + /* capabilities and control. multiple header logging is supported */
> + if (dev->exp.aer_log.log_max > 0) {
> + pci_set_long(dev->config + offset + PCI_ERR_CAP,
> + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC |
> + PCI_ERR_CAP_MHRC);
> + pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
> + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE |
> + PCI_ERR_CAP_MHRE);
> + } else {
> + pci_set_long(dev->config + offset + PCI_ERR_CAP,
> + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC);
> + pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
> + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
> + }
> +
> + switch (pcie_cap_get_type(dev)) {
> + case PCI_EXP_TYPE_ROOT_PORT:
> + /* this case will be set by pcie_aer_root_init() */
> + /* fallthrough */
> + case PCI_EXP_TYPE_DOWNSTREAM:
> + case PCI_EXP_TYPE_UPSTREAM:
> + pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL,
> + PCI_BRIDGE_CTL_SERR);
> + pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS,
> + PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
> + break;
> + default:
> + /* nothing */
> + break;
> + }
> + return 0;
> +}
> +
> +void pcie_aer_exit(PCIDevice *dev)
> +{
> + g_free(dev->exp.aer_log.log);
> +}
> +
> +static void pcie_aer_update_uncor_status(PCIDevice *dev)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> + PCIEAERLog *aer_log = &dev->exp.aer_log;
> +
> + uint16_t i;
> + for (i = 0; i < aer_log->log_num; i++) {
> + pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS,
> + dev->exp.aer_log.log[i].status);
> + }
> +}
> +
> +/*
> + * return value:
> + * true: error message needs to be sent up
> + * false: error message is masked
> + *
> + * 6.2.6 Error Message Control
> + * Figure 6-3
> + * all pci express devices part
> + */
> +static bool
> +pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg)
> +{
> + if (!(pcie_aer_msg_is_uncor(msg) &&
> + (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) {
> + return false;
> + }
> +
> + /* Signaled System Error
> + *
> + * 7.5.1.1 Command register
> + * Bit 8 SERR# Enable
> + *
> + * When Set, this bit enables reporting of Non-fatal and Fatal
> + * errors detected by the Function to the Root Complex. Note that
> + * errors are reported if enabled either through this bit or through
> + * the PCI Express specific bits in the Device Control register (see
> + * Section 7.8.4).
> + */
> + pci_word_test_and_set_mask(dev->config + PCI_STATUS,
> + PCI_STATUS_SIG_SYSTEM_ERROR);
> +
> + if (!(msg->severity &
> + pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) {
> + return false;
> + }
> +
> + /* send up error message */
> + return true;
> +}
> +
> +/*
> + * return value:
> + * true: error message is sent up
> + * false: error message is masked
> + *
> + * 6.2.6 Error Message Control
> + * Figure 6-3
> + * virtual pci bridge part
> + */
> +static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg)
> +{
> + uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL);
> +
> + if (pcie_aer_msg_is_uncor(msg)) {
> + /* Received System Error */
> + pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS,
> + PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
> + }
> +
> + if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) {
> + return false;
> + }
> + return true;
> +}
> +
> +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> + assert(vector < PCI_ERR_ROOT_IRQ_MAX);
> + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS,
> + PCI_ERR_ROOT_IRQ);
> + pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS,
> + vector << PCI_ERR_ROOT_IRQ_SHIFT);
> +}
> +
> +static unsigned int pcie_aer_root_get_vector(PCIDevice *dev)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
> + return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
> +}
> +
> +/* Given a status register, get corresponding bits in the command register */
> +static uint32_t pcie_aer_status_to_cmd(uint32_t status)
> +{
> + uint32_t cmd = 0;
> + if (status & PCI_ERR_ROOT_COR_RCV) {
> + cmd |= PCI_ERR_ROOT_CMD_COR_EN;
> + }
> + if (status & PCI_ERR_ROOT_NONFATAL_RCV) {
> + cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN;
> + }
> + if (status & PCI_ERR_ROOT_FATAL_RCV) {
> + cmd |= PCI_ERR_ROOT_CMD_FATAL_EN;
> + }
> + return cmd;
> +}
> +
> +static void pcie_aer_root_notify(PCIDevice *dev)
> +{
> + if (msix_enabled(dev)) {
> + msix_notify(dev, pcie_aer_root_get_vector(dev));
> + } else if (msi_enabled(dev)) {
> + msi_notify(dev, pcie_aer_root_get_vector(dev));
> + } else {
> + qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
> + }
> +}
> +
> +/*
> + * 6.2.6 Error Message Control
> + * Figure 6-3
> + * root port part
> + */
> +static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
> +{
> + uint16_t cmd;
> + uint8_t *aer_cap;
> + uint32_t root_cmd;
> + uint32_t root_status, prev_status;
> +
> + cmd = pci_get_word(dev->config + PCI_COMMAND);
> + aer_cap = dev->config + dev->exp.aer_cap;
> + root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
> + prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
> +
> + if (cmd & PCI_COMMAND_SERR) {
> + /* System Error.
> + *
> + * The way to report System Error is platform specific and
> + * it isn't implemented in qemu right now.
> + * So just discard the error for now.
> + * OS which cares of aer would receive errors via
> + * native aer mechanims, so this wouldn't matter.
> + */
> + }
> +
> + /* Errro Message Received: Root Error Status register */
> + switch (msg->severity) {
> + case PCI_ERR_ROOT_CMD_COR_EN:
> + if (root_status & PCI_ERR_ROOT_COR_RCV) {
> + root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
> + } else {
> + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
> PCI_ERR_SRC_COR_OFFS,
> + msg->source_id);
> + }
> + root_status |= PCI_ERR_ROOT_COR_RCV;
> + break;
> + case PCI_ERR_ROOT_CMD_NONFATAL_EN:
> + root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
> + break;
> + case PCI_ERR_ROOT_CMD_FATAL_EN:
> + if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) {
> + root_status |= PCI_ERR_ROOT_FIRST_FATAL;
> + }
> + root_status |= PCI_ERR_ROOT_FATAL_RCV;
> + break;
> + default:
> + abort();
> + break;
> + }
> + if (pcie_aer_msg_is_uncor(msg)) {
> + if (root_status & PCI_ERR_ROOT_UNCOR_RCV) {
> + root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
> + } else {
> + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
> + PCI_ERR_SRC_UNCOR_OFFS, msg->source_id);
> + }
> + root_status |= PCI_ERR_ROOT_UNCOR_RCV;
> + }
> + pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
> +
> + /* 6.2.4.1.2 Interrupt Generation */
> + /* All the above did was set some bits in the status register.
> + * Specifically these that match message severity.
> + * The below code relies on this fact. */
> + if (!(root_cmd & msg->severity) ||
> + (pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
> + /* Condition is not being set or was already true so nothing to do.
> */
> + return;
> + }
> +
> + pcie_aer_root_notify(dev);
> +}
> +
> +/*
> + * 6.2.6 Error Message Control Figure 6-3
> + *
> + * Walk up the bus tree from the device, propagate the error message.
> + */
> +static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
> +{
> + uint8_t type;
> +
> + while (dev) {
> + if (!pci_is_express(dev)) {
> + /* just ignore it */
> + /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR?
> + * Consider e.g. a PCI bridge above a PCI Express device. */
> + return;
> + }
> +
> + type = pcie_cap_get_type(dev);
> + if ((type == PCI_EXP_TYPE_ROOT_PORT ||
> + type == PCI_EXP_TYPE_UPSTREAM ||
> + type == PCI_EXP_TYPE_DOWNSTREAM) &&
> + !pcie_aer_msg_vbridge(dev, msg)) {
> + return;
> + }
> + if (!pcie_aer_msg_alldev(dev, msg)) {
> + return;
> + }
> + if (type == PCI_EXP_TYPE_ROOT_PORT) {
> + pcie_aer_msg_root_port(dev, msg);
> + /* Root port can notify system itself,
> + or send the error message to root complex event collector. */
> + /*
> + * if root port is associated with an event collector,
> + * return the root complex event collector here.
> + * For now root complex event collector isn't supported.
> + */
> + return;
> + }
> + dev = pci_bridge_get_device(dev->bus);
> + }
> +}
> +
> +static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> + uint8_t first_bit = ffs(err->status) - 1;
> + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
> + int i;
> +
> + assert(err->status);
> + assert(!(err->status & (err->status - 1)));
> +
> + errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
> + errcap |= PCI_ERR_CAP_FEP(first_bit);
> +
> + if (err->flags & PCIE_AER_ERR_HEADER_VALID) {
> + for (i = 0; i < ARRAY_SIZE(err->header); ++i) {
> + /* 7.10.8 Header Log Register */
> + uint8_t *header_log =
> + aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0];
> + cpu_to_be32wu((uint32_t*)header_log, err->header[i]);
> + }
> + } else {
> + assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT));
> + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
> + }
> +
> + if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) &&
> + (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
> + PCI_EXP_DEVCAP2_EETLPP)) {
> + for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) {
> + /* 7.10.12 tlp prefix log register */
> + uint8_t *prefix_log =
> + aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0];
> + cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]);
> + }
> + errcap |= PCI_ERR_CAP_TLP;
> + } else {
> + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0,
> + PCI_ERR_TLP_PREFIX_LOG_SIZE);
> + }
> + pci_set_long(aer_cap + PCI_ERR_CAP, errcap);
> +}
> +
> +static void pcie_aer_clear_log(PCIDevice *dev)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> +
> + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP,
> + PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
> +
> + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
> + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE);
> +}
> +
> +static void pcie_aer_clear_error(PCIDevice *dev)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
> + PCIEAERLog *aer_log = &dev->exp.aer_log;
> + PCIEAERErr err;
> +
> + if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) {
> + pcie_aer_clear_log(dev);
> + return;
> + }
> +
> + /*
> + * If more errors are queued, set corresponding bits in uncorrectable
> + * error status.
> + * We emulate uncorrectable error status register as W1CS.
> + * So set bit in uncorrectable error status here again for multiple
> + * error recording support.
> + *
> + * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability)
> + */
> + pcie_aer_update_uncor_status(dev);
> +
> + aer_log_del_err(aer_log, &err);
> + pcie_aer_update_log(dev, &err);
> +}
> +
> +static int pcie_aer_record_error(PCIDevice *dev,
> + const PCIEAERErr *err)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
> + int fep = PCI_ERR_CAP_FEP(errcap);
> +
> + assert(err->status);
> + assert(!(err->status & (err->status - 1)));
> +
> + if (errcap & PCI_ERR_CAP_MHRE &&
> + (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) {
> + /* Not first error. queue error */
> + if (aer_log_add_err(&dev->exp.aer_log, err) < 0) {
> + /* overflow */
> + return -1;
> + }
> + return 0;
> + }
> +
> + pcie_aer_update_log(dev, err);
> + return 0;
> +}
> +
> +typedef struct PCIEAERInject {
> + PCIDevice *dev;
> + uint8_t *aer_cap;
> + const PCIEAERErr *err;
> + uint16_t devctl;
> + uint16_t devsta;
> + uint32_t error_status;
> + bool unsupported_request;
> + bool log_overflow;
> + PCIEAERMsg msg;
> +} PCIEAERInject;
> +
> +static bool pcie_aer_inject_cor_error(PCIEAERInject *inj,
> + uint32_t uncor_status,
> + bool is_advisory_nonfatal)
> +{
> + PCIDevice *dev = inj->dev;
> +
> + inj->devsta |= PCI_EXP_DEVSTA_CED;
> + if (inj->unsupported_request) {
> + inj->devsta |= PCI_EXP_DEVSTA_URD;
> + }
> + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA,
> inj->devsta);
> +
> + if (inj->aer_cap) {
> + uint32_t mask;
> + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS,
> + inj->error_status);
> + mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK);
> + if (mask & inj->error_status) {
> + return false;
> + }
> + if (is_advisory_nonfatal) {
> + uint32_t uncor_mask =
> + pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
> + if (!(uncor_mask & uncor_status)) {
> + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
> + }
> + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
> + uncor_status);
> + }
> + }
> +
> + if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) {
> + return false;
> + }
> + if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) {
> + return false;
> + }
> +
> + inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN;
> + return true;
> +}
> +
> +static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
> +{
> + PCIDevice *dev = inj->dev;
> + uint16_t cmd;
> +
> + if (is_fatal) {
> + inj->devsta |= PCI_EXP_DEVSTA_FED;
> + } else {
> + inj->devsta |= PCI_EXP_DEVSTA_NFED;
> + }
> + if (inj->unsupported_request) {
> + inj->devsta |= PCI_EXP_DEVSTA_URD;
> + }
> + pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA,
> inj->devsta);
> +
> + if (inj->aer_cap) {
> + uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
> + if (mask & inj->error_status) {
> + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
> + inj->error_status);
> + return false;
> + }
> +
> + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
> + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
> + inj->error_status);
> + }
> +
> + cmd = pci_get_word(dev->config + PCI_COMMAND);
> + if (inj->unsupported_request &&
> + !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) {
> + return false;
> + }
> + if (is_fatal) {
> + if (!((cmd & PCI_COMMAND_SERR) ||
> + (inj->devctl & PCI_EXP_DEVCTL_FERE))) {
> + return false;
> + }
> + inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN;
> + } else {
> + if (!((cmd & PCI_COMMAND_SERR) ||
> + (inj->devctl & PCI_EXP_DEVCTL_NFERE))) {
> + return false;
> + }
> + inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN;
> + }
> + return true;
> +}
> +
> +/*
> + * non-Function specific error must be recorded in all functions.
> + * It is the responsibility of the caller of this function.
> + * It is also caller's responsibility to determine which function should
> + * report the rerror.
> + *
> + * 6.2.4 Error Logging
> + * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations
> + * table 6-2: Flowchard Showing Sequence of Device Error Signaling and
> Logging
> + * Operations
> + */
> +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
> +{
> + uint8_t *aer_cap = NULL;
> + uint16_t devctl = 0;
> + uint16_t devsta = 0;
> + uint32_t error_status = err->status;
> + PCIEAERInject inj;
> +
> + if (!pci_is_express(dev)) {
> + return -ENOSYS;
> + }
> +
> + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
> + error_status &= PCI_ERR_COR_SUPPORTED;
> + } else {
> + error_status &= PCI_ERR_UNC_SUPPORTED;
> + }
> +
> + /* invalid status bit. one and only one bit must be set */
> + if (!error_status || (error_status & (error_status - 1))) {
> + return -EINVAL;
> + }
> +
> + if (dev->exp.aer_cap) {
> + uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
> + aer_cap = dev->config + dev->exp.aer_cap;
> + devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL);
> + devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA);
> + }
> +
> + inj.dev = dev;
> + inj.aer_cap = aer_cap;
> + inj.err = err;
> + inj.devctl = devctl;
> + inj.devsta = devsta;
> + inj.error_status = error_status;
> + inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) &&
> + err->status == PCI_ERR_UNC_UNSUP;
> + inj.log_overflow = false;
> +
> + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
> + if (!pcie_aer_inject_cor_error(&inj, 0, false)) {
> + return 0;
> + }
> + } else {
> + bool is_fatal =
> + pcie_aer_uncor_default_severity(error_status) ==
> + PCI_ERR_ROOT_CMD_FATAL_EN;
> + if (aer_cap) {
> + is_fatal =
> + error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER);
> + }
> + if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) {
> + inj.error_status = PCI_ERR_COR_ADV_NONFATAL;
> + if (!pcie_aer_inject_cor_error(&inj, error_status, true)) {
> + return 0;
> + }
> + } else {
> + if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) {
> + return 0;
> + }
> + }
> + }
> +
> + /* send up error message */
> + inj.msg.source_id = err->source_id;
> + pcie_aer_msg(dev, &inj.msg);
> +
> + if (inj.log_overflow) {
> + PCIEAERErr header_log_overflow = {
> + .status = PCI_ERR_COR_HL_OVERFLOW,
> + .flags = PCIE_AER_ERR_IS_CORRECTABLE,
> + };
> + int ret = pcie_aer_inject_error(dev, &header_log_overflow);
> + assert(!ret);
> + }
> + return 0;
> +}
> +
> +void pcie_aer_write_config(PCIDevice *dev,
> + uint32_t addr, uint32_t val, int len)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
> + uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap);
> + uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS);
> +
> + /* uncorrectable error */
> + if (!(uncorsta & first_error)) {
> + /* the bit that corresponds to the first error is cleared */
> + pcie_aer_clear_error(dev);
> + } else if (errcap & PCI_ERR_CAP_MHRE) {
> + /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared
> + * nothing should happen. So we have to revert the modification to
> + * the register.
> + */
> + pcie_aer_update_uncor_status(dev);
> + } else {
> + /* capability & control
> + * PCI_ERR_CAP_MHRE might be cleared, so clear of header log.
> + */
> + aer_log_clear_all_err(&dev->exp.aer_log);
> + }
> +}
> +
> +void pcie_aer_root_init(PCIDevice *dev)
> +{
> + uint16_t pos = dev->exp.aer_cap;
> +
> + pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND,
> + PCI_ERR_ROOT_CMD_EN_MASK);
> + pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
> + PCI_ERR_ROOT_STATUS_REPORT_MASK);
> + /* PCI_ERR_ROOT_IRQ is RO but devices change it using a
> + * device-specific method.
> + */
> + pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS,
> + ~PCI_ERR_ROOT_IRQ);
> +}
> +
> +void pcie_aer_root_reset(PCIDevice *dev)
> +{
> + uint8_t* aer_cap = dev->config + dev->exp.aer_cap;
> +
> + pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0);
> +
> + /*
> + * Advanced Error Interrupt Message Number in Root Error Status Register
> + * must be updated by chip dependent code because it's chip dependent
> + * which number is used.
> + */
> +}
> +
> +void pcie_aer_root_write_config(PCIDevice *dev,
> + uint32_t addr, uint32_t val, int len,
> + uint32_t root_cmd_prev)
> +{
> + uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
> + uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status);
> + uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
> + /* 6.2.4.1.2 Interrupt Generation */
> + if (!msix_enabled(dev) && !msi_enabled(dev)) {
> + qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd &
> enabled_cmd));
> + return;
> + }
> +
> + if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) {
> + /* Send MSI on transition from false to true. */
> + return;
> + }
> +
> + pcie_aer_root_notify(dev);
> +}
> +
> +static const VMStateDescription vmstate_pcie_aer_err = {
> + .name = "PCIE_AER_ERROR",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32(status, PCIEAERErr),
> + VMSTATE_UINT16(source_id, PCIEAERErr),
> + VMSTATE_UINT16(flags, PCIEAERErr),
> + VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4),
> + VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +const VMStateDescription vmstate_pcie_aer_log = {
> + .name = "PCIE_AER_ERROR_LOG",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT16(log_num, PCIEAERLog),
> + VMSTATE_UINT16(log_max, PCIEAERLog),
> + VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
> + vmstate_pcie_aer_err, PCIEAERErr),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
> +{
> + QDict *qdict;
> + int devfn;
> + assert(qobject_type(data) == QTYPE_QDICT);
> + qdict = qobject_to_qdict(data);
> +
> + devfn = (int)qdict_get_int(qdict, "devfn");
> + monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n",
> + qdict_get_str(qdict, "id"),
> + (int) qdict_get_int(qdict, "domain"),
> + (int) qdict_get_int(qdict, "bus"),
> + PCI_SLOT(devfn), PCI_FUNC(devfn));
> +}
> +
> +typedef struct PCIEAERErrorName {
> + const char *name;
> + uint32_t val;
> + bool correctable;
> +} PCIEAERErrorName;
> +
> +/*
> + * AER error name -> value conversion table
> + * This naming scheme is same to linux aer-injection tool.
> + */
> +static const struct PCIEAERErrorName pcie_aer_error_list[] = {
> + {
> + .name = "TRAIN",
> + .val = PCI_ERR_UNC_TRAIN,
> + .correctable = false,
> + }, {
> + .name = "DLP",
> + .val = PCI_ERR_UNC_DLP,
> + .correctable = false,
> + }, {
> + .name = "SDN",
> + .val = PCI_ERR_UNC_SDN,
> + .correctable = false,
> + }, {
> + .name = "POISON_TLP",
> + .val = PCI_ERR_UNC_POISON_TLP,
> + .correctable = false,
> + }, {
> + .name = "FCP",
> + .val = PCI_ERR_UNC_FCP,
> + .correctable = false,
> + }, {
> + .name = "COMP_TIME",
> + .val = PCI_ERR_UNC_COMP_TIME,
> + .correctable = false,
> + }, {
> + .name = "COMP_ABORT",
> + .val = PCI_ERR_UNC_COMP_ABORT,
> + .correctable = false,
> + }, {
> + .name = "UNX_COMP",
> + .val = PCI_ERR_UNC_UNX_COMP,
> + .correctable = false,
> + }, {
> + .name = "RX_OVER",
> + .val = PCI_ERR_UNC_RX_OVER,
> + .correctable = false,
> + }, {
> + .name = "MALF_TLP",
> + .val = PCI_ERR_UNC_MALF_TLP,
> + .correctable = false,
> + }, {
> + .name = "ECRC",
> + .val = PCI_ERR_UNC_ECRC,
> + .correctable = false,
> + }, {
> + .name = "UNSUP",
> + .val = PCI_ERR_UNC_UNSUP,
> + .correctable = false,
> + }, {
> + .name = "ACSV",
> + .val = PCI_ERR_UNC_ACSV,
> + .correctable = false,
> + }, {
> + .name = "INTN",
> + .val = PCI_ERR_UNC_INTN,
> + .correctable = false,
> + }, {
> + .name = "MCBTLP",
> + .val = PCI_ERR_UNC_MCBTLP,
> + .correctable = false,
> + }, {
> + .name = "ATOP_EBLOCKED",
> + .val = PCI_ERR_UNC_ATOP_EBLOCKED,
> + .correctable = false,
> + }, {
> + .name = "TLP_PRF_BLOCKED",
> + .val = PCI_ERR_UNC_TLP_PRF_BLOCKED,
> + .correctable = false,
> + }, {
> + .name = "RCVR",
> + .val = PCI_ERR_COR_RCVR,
> + .correctable = true,
> + }, {
> + .name = "BAD_TLP",
> + .val = PCI_ERR_COR_BAD_TLP,
> + .correctable = true,
> + }, {
> + .name = "BAD_DLLP",
> + .val = PCI_ERR_COR_BAD_DLLP,
> + .correctable = true,
> + }, {
> + .name = "REP_ROLL",
> + .val = PCI_ERR_COR_REP_ROLL,
> + .correctable = true,
> + }, {
> + .name = "REP_TIMER",
> + .val = PCI_ERR_COR_REP_TIMER,
> + .correctable = true,
> + }, {
> + .name = "ADV_NONFATAL",
> + .val = PCI_ERR_COR_ADV_NONFATAL,
> + .correctable = true,
> + }, {
> + .name = "INTERNAL",
> + .val = PCI_ERR_COR_INTERNAL,
> + .correctable = true,
> + }, {
> + .name = "HL_OVERFLOW",
> + .val = PCI_ERR_COR_HL_OVERFLOW,
> + .correctable = true,
> + },
> +};
> +
> +static int pcie_aer_parse_error_string(const char *error_name,
> + uint32_t *status, bool *correctable)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) {
> + const PCIEAERErrorName *e = &pcie_aer_error_list[i];
> + if (strcmp(error_name, e->name)) {
> + continue;
> + }
> +
> + *status = e->val;
> + *correctable = e->correctable;
> + return 0;
> + }
> + return -EINVAL;
> +}
> +
> +int do_pcie_aer_inject_error(Monitor *mon,
> + const QDict *qdict, QObject **ret_data)
> +{
> + const char *id = qdict_get_str(qdict, "id");
> + const char *error_name;
> + uint32_t error_status;
> + bool correctable;
> + PCIDevice *dev;
> + PCIEAERErr err;
> + int ret;
> +
> + ret = pci_qdev_find_device(id, &dev);
> + if (ret < 0) {
> + monitor_printf(mon,
> + "id or pci device path is invalid or device not "
> + "found. %s\n", id);
> + return ret;
> + }
> + if (!pci_is_express(dev)) {
> + monitor_printf(mon, "the device doesn't support pci express. %s\n",
> + id);
> + return -ENOSYS;
> + }
> +
> + error_name = qdict_get_str(qdict, "error_status");
> + if (pcie_aer_parse_error_string(error_name, &error_status,
> &correctable)) {
> + char *e = NULL;
> + error_status = strtoul(error_name, &e, 0);
> + correctable = qdict_get_try_bool(qdict, "correctable", 0);
> + if (!e || *e != '\0') {
> + monitor_printf(mon, "invalid error status value. \"%s\"",
> + error_name);
> + return -EINVAL;
> + }
> + }
> + err.status = error_status;
> + err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn;
> +
> + err.flags = 0;
> + if (correctable) {
> + err.flags |= PCIE_AER_ERR_IS_CORRECTABLE;
> + }
> + if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) {
> + err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY;
> + }
> + if (qdict_haskey(qdict, "header0")) {
> + err.flags |= PCIE_AER_ERR_HEADER_VALID;
> + }
> + if (qdict_haskey(qdict, "prefix0")) {
> + err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT;
> + }
> +
> + err.header[0] = qdict_get_try_int(qdict, "header0", 0);
> + err.header[1] = qdict_get_try_int(qdict, "header1", 0);
> + err.header[2] = qdict_get_try_int(qdict, "header2", 0);
> + err.header[3] = qdict_get_try_int(qdict, "header3", 0);
> +
> + err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0);
> + err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0);
> + err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0);
> + err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0);
> +
> + ret = pcie_aer_inject_error(dev, &err);
> + *ret_data = qobject_from_jsonf("{'id': %s, "
> + "'domain': %d, 'bus': %d, 'devfn': %d, "
> + "'ret': %d}",
> + id,
> + pci_find_domain(dev->bus),
> + pci_bus_num(dev->bus), dev->devfn,
> + ret);
> + assert(*ret_data);
> +
> + return 0;
> +}
> diff --git a/hw/pci/pcie_aer.h b/hw/pci/pcie_aer.h
> new file mode 100644
> index 0000000..7539500
> --- /dev/null
> +++ b/hw/pci/pcie_aer.h
> @@ -0,0 +1,106 @@
> +/*
> + * pcie_aer.h
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef QEMU_PCIE_AER_H
> +#define QEMU_PCIE_AER_H
> +
> +#include "hw.h"
> +
> +/* definitions which PCIExpressDevice uses */
> +
> +/* AER log */
> +struct PCIEAERLog {
> + /* This structure is saved/loaded.
> + So explicitly size them instead of unsigned int */
> +
> + /* the number of currently recorded log in log member */
> + uint16_t log_num;
> +
> + /*
> + * The maximum number of the log. Errors can be logged up to this.
> + *
> + * This is configurable property.
> + * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT
> + * to avoid unreasonable memory usage.
> + * I bet that 128 log size would be big enough, otherwise too many errors
> + * for system to function normaly. But could consecutive errors occur?
> + */
> +#define PCIE_AER_LOG_MAX_DEFAULT 8
> +#define PCIE_AER_LOG_MAX_LIMIT 128
> +#define PCIE_AER_LOG_MAX_UNSET 0xffff
> + uint16_t log_max;
> +
> + /* Error log. log_max-sized array */
> + PCIEAERErr *log;
> +};
> +
> +/* aer error message: error signaling message has only error sevirity and
> + source id. See 2.2.8.3 error signaling messages */
> +struct PCIEAERMsg {
> + /*
> + * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN
> + * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE}
> + */
> + uint32_t severity;
> +
> + uint16_t source_id; /* bdf */
> +};
> +
> +static inline bool
> +pcie_aer_msg_is_uncor(const PCIEAERMsg *msg)
> +{
> + return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN ||
> + msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN;
> +}
> +
> +/* error */
> +struct PCIEAERErr {
> + uint32_t status; /* error status bits */
> + uint16_t source_id; /* bdf */
> +
> +#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable
> */
> +#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal
> */
> +#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */
> +#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */
> + uint16_t flags;
> +
> + uint32_t header[4]; /* TLP header */
> + uint32_t prefix[4]; /* TLP header prefix */
> +};
> +
> +extern const VMStateDescription vmstate_pcie_aer_log;
> +
> +int pcie_aer_init(PCIDevice *dev, uint16_t offset);
> +void pcie_aer_exit(PCIDevice *dev);
> +void pcie_aer_write_config(PCIDevice *dev,
> + uint32_t addr, uint32_t val, int len);
> +
> +/* aer root port */
> +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector);
> +void pcie_aer_root_init(PCIDevice *dev);
> +void pcie_aer_root_reset(PCIDevice *dev);
> +void pcie_aer_root_write_config(PCIDevice *dev,
> + uint32_t addr, uint32_t val, int len,
> + uint32_t root_cmd_prev);
> +
> +/* error injection */
> +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err);
> +
> +#endif /* QEMU_PCIE_AER_H */
> diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c
> new file mode 100644
> index 0000000..c257fb4
> --- /dev/null
> +++ b/hw/pci/pcie_host.c
> @@ -0,0 +1,161 @@
> +/*
> + * pcie_host.c
> + * utility functions for pci express host bridge.
> + *
> + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "hw.h"
> +#include "pci.h"
> +#include "pcie_host.h"
> +#include "exec-memory.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_dev_find_by_mmcfg_addr(PCIBus *s,
> + uint32_t mmcfg_addr)
> +{
> + return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr),
> + PCIE_MMCFG_DEVFN(mmcfg_addr));
> +}
> +
> +static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr,
> + uint64_t val, unsigned len)
> +{
> + PCIExpressHost *e = opaque;
> + PCIBus *s = e->pci.bus;
> + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
> + uint32_t addr;
> + uint32_t limit;
> +
> + if (!pci_dev) {
> + return;
> + }
> + addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
> + limit = pci_config_size(pci_dev);
> + if (limit <= addr) {
> + /* conventional pci device can be behind pcie-to-pci bridge.
> + 256 <= addr < 4K has no effects. */
> + return;
> + }
> + pci_host_config_write_common(pci_dev, addr, limit, val, len);
> +}
> +
> +static uint64_t pcie_mmcfg_data_read(void *opaque,
> + hwaddr mmcfg_addr,
> + unsigned len)
> +{
> + PCIExpressHost *e = opaque;
> + PCIBus *s = e->pci.bus;
> + PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
> + uint32_t addr;
> + uint32_t limit;
> +
> + if (!pci_dev) {
> + return ~0x0;
> + }
> + addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
> + limit = pci_config_size(pci_dev);
> + if (limit <= addr) {
> + /* conventional pci device can be behind pcie-to-pci bridge.
> + 256 <= addr < 4K has no effects. */
> + return ~0x0;
> + }
> + return pci_host_config_read_common(pci_dev, addr, limit, len);
> +}
> +
> +static const MemoryRegionOps pcie_mmcfg_ops = {
> + .read = pcie_mmcfg_data_read,
> + .write = pcie_mmcfg_data_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */
> +#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL)
> +
> +int pcie_host_init(PCIExpressHost *e)
> +{
> + e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
> +
> + return 0;
> +}
> +
> +void pcie_host_mmcfg_unmap(PCIExpressHost *e)
> +{
> + if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
> + memory_region_del_subregion(get_system_memory(), &e->mmio);
> + memory_region_destroy(&e->mmio);
> + e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
> + }
> +}
> +
> +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr,
> + uint32_t size)
> +{
> + assert(!(size & (size - 1))); /* power of 2 */
> + assert(size >= PCIE_MMCFG_SIZE_MIN);
> + assert(size <= PCIE_MMCFG_SIZE_MAX);
> + e->size = size;
> + memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg",
> e->size);
> + e->base_addr = addr;
> + memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
> +}
> +
> +void pcie_host_mmcfg_update(PCIExpressHost *e,
> + int enable,
> + hwaddr addr,
> + uint32_t size)
> +{
> + pcie_host_mmcfg_unmap(e);
> + if (enable) {
> + pcie_host_mmcfg_map(e, addr, size);
> + }
> +}
> +
> +static const TypeInfo pcie_host_type_info = {
> + .name = TYPE_PCIE_HOST_BRIDGE,
> + .parent = TYPE_PCI_HOST_BRIDGE,
> + .abstract = true,
> + .instance_size = sizeof(PCIExpressHost),
> +};
> +
> +static void pcie_host_register_types(void)
> +{
> + type_register_static(&pcie_host_type_info);
> +}
> +
> +type_init(pcie_host_register_types)
> diff --git a/hw/pci/pcie_host.h b/hw/pci/pcie_host.h
> new file mode 100644
> index 0000000..3921935
> --- /dev/null
> +++ b/hw/pci/pcie_host.h
> @@ -0,0 +1,54 @@
> +/*
> + * pcie_host.h
> + *
> + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef PCIE_HOST_H
> +#define PCIE_HOST_H
> +
> +#include "pci_host.h"
> +#include "memory.h"
> +
> +#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge"
> +#define PCIE_HOST_BRIDGE(obj) \
> + OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE)
> +
> +struct PCIExpressHost {
> + PCIHostState pci;
> +
> + /* express part */
> +
> + /* base address where MMCONFIG area is mapped. */
> + hwaddr base_addr;
> +
> + /* the size of MMCONFIG area. It's host bridge dependent */
> + hwaddr size;
> +
> + /* MMCONFIG mmio area */
> + MemoryRegion mmio;
> +};
> +
> +int pcie_host_init(PCIExpressHost *e);
> +void pcie_host_mmcfg_unmap(PCIExpressHost *e);
> +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size);
> +void pcie_host_mmcfg_update(PCIExpressHost *e,
> + int enable,
> + hwaddr addr,
> + uint32_t size);
> +
> +#endif /* PCIE_HOST_H */
> diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
> new file mode 100644
> index 0000000..d6350e5
> --- /dev/null
> +++ b/hw/pci/pcie_port.c
> @@ -0,0 +1,114 @@
> +/*
> + * pcie_port.c
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "pcie_port.h"
> +
> +void pcie_port_init_reg(PCIDevice *d)
> +{
> + /* Unlike pci bridge,
> + 66MHz and fast back to back don't apply to pci express port. */
> + pci_set_word(d->config + PCI_STATUS, 0);
> + pci_set_word(d->config + PCI_SEC_STATUS, 0);
> +
> + /* Unlike conventional pci bridge, some bits are hardwired to 0. */
> + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
> + PCI_BRIDGE_CTL_PARITY |
> + PCI_BRIDGE_CTL_ISA |
> + PCI_BRIDGE_CTL_VGA |
> + PCI_BRIDGE_CTL_SERR |
> + PCI_BRIDGE_CTL_BUS_RESET);
> +}
> +
> +/**************************************************************************
> + * (chassis number, pcie physical slot number) -> pcie slot conversion
> + */
> +struct PCIEChassis {
> + uint8_t number;
> +
> + QLIST_HEAD(, PCIESlot) slots;
> + QLIST_ENTRY(PCIEChassis) next;
> +};
> +
> +static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
> +
> +static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
> +{
> + struct PCIEChassis *c;
> + QLIST_FOREACH(c, &chassis, next) {
> + if (c->number == chassis_number) {
> + break;
> + }
> + }
> + return c;
> +}
> +
> +void pcie_chassis_create(uint8_t chassis_number)
> +{
> + struct PCIEChassis *c;
> + c = pcie_chassis_find(chassis_number);
> + if (c) {
> + return;
> + }
> + c = g_malloc0(sizeof(*c));
> + c->number = chassis_number;
> + QLIST_INIT(&c->slots);
> + QLIST_INSERT_HEAD(&chassis, c, next);
> +}
> +
> +static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
> + uint8_t slot)
> +{
> + PCIESlot *s;
> + QLIST_FOREACH(s, &c->slots, next) {
> + if (s->slot == slot) {
> + break;
> + }
> + }
> + return s;
> +}
> +
> +PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
> +{
> + struct PCIEChassis *c;
> + c = pcie_chassis_find(chassis_number);
> + if (!c) {
> + return NULL;
> + }
> + return pcie_chassis_find_slot_with_chassis(c, slot);
> +}
> +
> +int pcie_chassis_add_slot(struct PCIESlot *slot)
> +{
> + struct PCIEChassis *c;
> + c = pcie_chassis_find(slot->chassis);
> + if (!c) {
> + return -ENODEV;
> + }
> + if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
> + return -EBUSY;
> + }
> + QLIST_INSERT_HEAD(&c->slots, slot, next);
> + return 0;
> +}
> +
> +void pcie_chassis_del_slot(PCIESlot *s)
> +{
> + QLIST_REMOVE(s, next);
> +}
> diff --git a/hw/pci/pcie_port.h b/hw/pci/pcie_port.h
> new file mode 100644
> index 0000000..3709583
> --- /dev/null
> +++ b/hw/pci/pcie_port.h
> @@ -0,0 +1,51 @@
> +/*
> + * pcie_port.h
> + *
> + * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef QEMU_PCIE_PORT_H
> +#define QEMU_PCIE_PORT_H
> +
> +#include "pci_bridge.h"
> +#include "pci_internals.h"
> +
> +struct PCIEPort {
> + PCIBridge br;
> +
> + /* pci express switch port */
> + uint8_t port;
> +};
> +
> +void pcie_port_init_reg(PCIDevice *d);
> +
> +struct PCIESlot {
> + PCIEPort port;
> +
> + /* pci express switch port with slot */
> + uint8_t chassis;
> + uint16_t slot;
> + QLIST_ENTRY(PCIESlot) next;
> +};
> +
> +void pcie_chassis_create(uint8_t chassis_number);
> +void pcie_main_chassis_create(void);
> +PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
> +int pcie_chassis_add_slot(struct PCIESlot *slot);
> +void pcie_chassis_del_slot(PCIESlot *s);
> +
> +#endif /* QEMU_PCIE_PORT_H */
> diff --git a/hw/pci/pcie_regs.h b/hw/pci/pcie_regs.h
> new file mode 100644
> index 0000000..4d123d9
> --- /dev/null
> +++ b/hw/pci/pcie_regs.h
> @@ -0,0 +1,156 @@
> +/*
> + * constants for pcie configurations space from pci express spec.
> + *
> + * TODO:
> + * Those constants and macros should go to Linux pci_regs.h
> + * Once they're merged, they will go away.
> + */
> +#ifndef QEMU_PCIE_REGS_H
> +#define QEMU_PCIE_REGS_H
> +
> +
> +/* express capability */
> +
> +#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2
> */
> +#define PCI_EXT_CAP_VER_SHIFT 16
> +#define PCI_EXT_CAP_NEXT_SHIFT 20
> +#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT)
> +
> +#define PCI_EXT_CAP(id, ver, next) \
> + ((id) | \
> + ((ver) << PCI_EXT_CAP_VER_SHIFT) | \
> + ((next) << PCI_EXT_CAP_NEXT_SHIFT))
> +
> +#define PCI_EXT_CAP_ALIGN 4
> +#define PCI_EXT_CAP_ALIGNUP(x) \
> + (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1))
> +
> +/* PCI_EXP_FLAGS */
> +#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */
> +#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1)
> +#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1)
> +
> +
> +/* PCI_EXP_LINK{CAP, STA} */
> +/* link speed */
> +#define PCI_EXP_LNK_LS_25 1
> +
> +#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1)
> +#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT)
> +
> +/* PCI_EXP_LINKCAP */
> +#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1)
> +#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
> +
> +#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1)
> +
> +#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1)
> +
> +#define PCI_EXP_SLTCTL_IND_RESERVED 0x0
> +#define PCI_EXP_SLTCTL_IND_ON 0x1
> +#define PCI_EXP_SLTCTL_IND_BLINK 0x2
> +#define PCI_EXP_SLTCTL_IND_OFF 0x3
> +#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1)
> +#define PCI_EXP_SLTCTL_AIC_OFF \
> + (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT)
> +
> +#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1)
> +#define PCI_EXP_SLTCTL_PIC_OFF \
> + (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT)
> +
> +#define PCI_EXP_SLTCTL_SUPPORTED \
> + (PCI_EXP_SLTCTL_ABPE | \
> + PCI_EXP_SLTCTL_PDCE | \
> + PCI_EXP_SLTCTL_CCIE | \
> + PCI_EXP_SLTCTL_HPIE | \
> + PCI_EXP_SLTCTL_AIC | \
> + PCI_EXP_SLTCTL_PCC | \
> + PCI_EXP_SLTCTL_EIC)
> +
> +#define PCI_EXP_DEVCAP2_EFF 0x100000
> +#define PCI_EXP_DEVCAP2_EETLPP 0x200000
> +
> +#define PCI_EXP_DEVCTL2_EETLPPB 0x80
> +
> +/* ARI */
> +#define PCI_ARI_VER 1
> +#define PCI_ARI_SIZEOF 8
> +
> +/* AER */
> +#define PCI_ERR_VER 2
> +#define PCI_ERR_SIZEOF 0x48
> +
> +#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */
> +#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */
> +#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */
> +#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */
> +#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress
> blocked */
> +#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix
> Blocked */
> +#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory
> Non-Fatal */
> +#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected
> Internal */
> +#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long
> Overflow */
> +#define PCI_ERR_CAP_FEP_MASK 0x0000001f
> +#define PCI_ERR_CAP_MHRC 0x00000200
> +#define PCI_ERR_CAP_MHRE 0x00000400
> +#define PCI_ERR_CAP_TLP 0x00000800
> +
> +#define PCI_ERR_HEADER_LOG_SIZE 16
> +#define PCI_ERR_TLP_PREFIX_LOG 0x38
> +#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16
> +
> +#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000
> +
> +/* aer root error command/status */
> +#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \
> + PCI_ERR_ROOT_CMD_NONFATAL_EN | \
> + PCI_ERR_ROOT_CMD_FATAL_EN)
> +
> +#define PCI_ERR_ROOT_IRQ_MAX 32
> +#define PCI_ERR_ROOT_IRQ 0xf8000000
> +#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1)
> +#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \
> + PCI_ERR_ROOT_MULTI_COR_RCV | \
> + PCI_ERR_ROOT_UNCOR_RCV | \
> + PCI_ERR_ROOT_MULTI_UNCOR_RCV | \
> + PCI_ERR_ROOT_FIRST_FATAL | \
> + PCI_ERR_ROOT_NONFATAL_RCV | \
> + PCI_ERR_ROOT_FATAL_RCV)
> +
> +#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \
> + PCI_ERR_UNC_SDN | \
> + PCI_ERR_UNC_POISON_TLP | \
> + PCI_ERR_UNC_FCP | \
> + PCI_ERR_UNC_COMP_TIME | \
> + PCI_ERR_UNC_COMP_ABORT | \
> + PCI_ERR_UNC_UNX_COMP | \
> + PCI_ERR_UNC_RX_OVER | \
> + PCI_ERR_UNC_MALF_TLP | \
> + PCI_ERR_UNC_ECRC | \
> + PCI_ERR_UNC_UNSUP | \
> + PCI_ERR_UNC_ACSV | \
> + PCI_ERR_UNC_INTN | \
> + PCI_ERR_UNC_MCBTLP | \
> + PCI_ERR_UNC_ATOP_EBLOCKED | \
> + PCI_ERR_UNC_TLP_PRF_BLOCKED)
> +
> +#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \
> + PCI_ERR_UNC_SDN | \
> + PCI_ERR_UNC_FCP | \
> + PCI_ERR_UNC_RX_OVER | \
> + PCI_ERR_UNC_MALF_TLP | \
> + PCI_ERR_UNC_INTN)
> +
> +#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \
> + PCI_ERR_COR_BAD_TLP | \
> + PCI_ERR_COR_BAD_DLLP | \
> + PCI_ERR_COR_REP_ROLL | \
> + PCI_ERR_COR_REP_TIMER | \
> + PCI_ERR_COR_ADV_NONFATAL | \
> + PCI_ERR_COR_INTERNAL | \
> + PCI_ERR_COR_HL_OVERFLOW)
> +
> +#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \
> + PCI_ERR_COR_INTERNAL | \
> + PCI_ERR_COR_HL_OVERFLOW)
> +
> +#endif /* QEMU_PCIE_REGS_H */
> diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
> new file mode 100644
> index 0000000..4597bbd
> --- /dev/null
> +++ b/hw/pci/shpc.c
> @@ -0,0 +1,681 @@
> +#include <strings.h>
> +#include <stdint.h>
> +#include "range.h"
> +#include "range.h"
> +#include "shpc.h"
> +#include "pci.h"
> +#include "pci_internals.h"
> +#include "msi.h"
> +
> +/* TODO: model power only and disabled slot states. */
> +/* TODO: handle SERR and wakeups */
> +/* TODO: consider enabling 66MHz support */
> +
> +/* TODO: remove fully only on state DISABLED and LED off.
> + * track state to properly record this. */
> +
> +/* SHPC Working Register Set */
> +#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */
> +#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */
> +#define SHPC_SLOTS_66 0x08 /* 4 bytes. */
> +#define SHPC_NSLOTS 0x0C /* 1 byte */
> +#define SHPC_FIRST_DEV 0x0D /* 1 byte */
> +#define SHPC_PHYS_SLOT 0x0E /* 2 byte */
> +#define SHPC_PHYS_NUM_MAX 0x7ff
> +#define SHPC_PHYS_NUM_UP 0x2000
> +#define SHPC_PHYS_MRL 0x4000
> +#define SHPC_PHYS_BUTTON 0x8000
> +#define SHPC_SEC_BUS 0x10 /* 2 bytes */
> +#define SHPC_SEC_BUS_33 0x0
> +#define SHPC_SEC_BUS_66 0x1 /* Unused */
> +#define SHPC_SEC_BUS_MASK 0x7
> +#define SHPC_MSI_CTL 0x12 /* 1 byte */
> +#define SHPC_PROG_IFC 0x13 /* 1 byte */
> +#define SHPC_PROG_IFC_1_0 0x1
> +#define SHPC_CMD_CODE 0x14 /* 1 byte */
> +#define SHPC_CMD_TRGT 0x15 /* 1 byte */
> +#define SHPC_CMD_TRGT_MIN 0x1
> +#define SHPC_CMD_TRGT_MAX 0x1f
> +#define SHPC_CMD_STATUS 0x16 /* 2 bytes */
> +#define SHPC_CMD_STATUS_BUSY 0x1
> +#define SHPC_CMD_STATUS_MRL_OPEN 0x2
> +#define SHPC_CMD_STATUS_INVALID_CMD 0x4
> +#define SHPC_CMD_STATUS_INVALID_MODE 0x8
> +#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */
> +#define SHPC_INT_COMMAND 0x1
> +#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */
> +#define SHPC_SERR_INT 0x20 /* 4 bytes */
> +#define SHPC_INT_DIS 0x1
> +#define SHPC_SERR_DIS 0x2
> +#define SHPC_CMD_INT_DIS 0x4
> +#define SHPC_ARB_SERR_DIS 0x8
> +#define SHPC_CMD_DETECTED 0x10000
> +#define SHPC_ARB_DETECTED 0x20000
> + /* 4 bytes * slot # (start from 0) */
> +#define SHPC_SLOT_REG(s) (0x24 + (s) * 4)
> + /* 2 bytes */
> +#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s))
> +
> +/* Same slot state masks are used for command and status registers */
> +#define SHPC_SLOT_STATE_MASK 0x03
> +#define SHPC_SLOT_STATE_SHIFT \
> + (ffs(SHPC_SLOT_STATE_MASK) - 1)
> +
> +#define SHPC_STATE_NO 0x0
> +#define SHPC_STATE_PWRONLY 0x1
> +#define SHPC_STATE_ENABLED 0x2
> +#define SHPC_STATE_DISABLED 0x3
> +
> +#define SHPC_SLOT_PWR_LED_MASK 0xC
> +#define SHPC_SLOT_PWR_LED_SHIFT \
> + (ffs(SHPC_SLOT_PWR_LED_MASK) - 1)
> +#define SHPC_SLOT_ATTN_LED_MASK 0x30
> +#define SHPC_SLOT_ATTN_LED_SHIFT \
> + (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1)
> +
> +#define SHPC_LED_NO 0x0
> +#define SHPC_LED_ON 0x1
> +#define SHPC_LED_BLINK 0x2
> +#define SHPC_LED_OFF 0x3
> +
> +#define SHPC_SLOT_STATUS_PWR_FAULT 0x40
> +#define SHPC_SLOT_STATUS_BUTTON 0x80
> +#define SHPC_SLOT_STATUS_MRL_OPEN 0x100
> +#define SHPC_SLOT_STATUS_66 0x200
> +#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00
> +#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3
> +#define SHPC_SLOT_STATUS_PRSNT_25W 0x1
> +#define SHPC_SLOT_STATUS_PRSNT_15W 0x2
> +#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0
> +
> +#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000
> +
> +
> + /* 1 byte */
> +#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s))
> + /* 1 byte */
> +#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s))
> +#define SHPC_SLOT_EVENT_PRESENCE 0x01
> +#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02
> +#define SHPC_SLOT_EVENT_BUTTON 0x04
> +#define SHPC_SLOT_EVENT_MRL 0x08
> +#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10
> +/* Bits below are used for Serr/Int disable only */
> +#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20
> +#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40
> +
> +#define SHPC_MIN_SLOTS 1
> +#define SHPC_MAX_SLOTS 31
> +#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots)
> +
> +/* SHPC Slot identifiers */
> +
> +/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0,
> + and give the rest of them physical *and* pci numbers starting from 1, so
> + they match logical numbers. Note: this means that multiple slots must
> have
> + different chassis number values, to make chassis+physical slot unique.
> + TODO: make this configurable? */
> +#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1)
> +#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1)
> +#define SHPC_IDX_TO_PCI(slot) ((slot) + 1)
> +#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1)
> +#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1)
> +
> +static int roundup_pow_of_two(int x)
> +{
> + x |= (x >> 1);
> + x |= (x >> 2);
> + x |= (x >> 4);
> + x |= (x >> 8);
> + x |= (x >> 16);
> + return x + 1;
> +}
> +
> +static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk)
> +{
> + uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
> + return (pci_get_word(status) & msk) >> (ffs(msk) - 1);
> +}
> +
> +static void shpc_set_status(SHPCDevice *shpc,
> + int slot, uint8_t value, uint16_t msk)
> +{
> + uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
> + pci_word_test_and_clear_mask(status, msk);
> + pci_word_test_and_set_mask(status, value << (ffs(msk) - 1));
> +}
> +
> +static void shpc_interrupt_update(PCIDevice *d)
> +{
> + SHPCDevice *shpc = d->shpc;
> + int slot;
> + int level = 0;
> + uint32_t serr_int;
> + uint32_t int_locator = 0;
> +
> + /* Update interrupt locator register */
> + for (slot = 0; slot < shpc->nslots; ++slot) {
> + uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)];
> + uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d,
> slot)];
> + uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot);
> + if (event & ~disable) {
> + int_locator |= mask;
> + }
> + }
> + serr_int = pci_get_long(shpc->config + SHPC_SERR_INT);
> + if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) {
> + int_locator |= SHPC_INT_COMMAND;
> + }
> + pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator);
> + level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0;
> + if (msi_enabled(d) && shpc->msi_requested != level)
> + msi_notify(d, 0);
> + else
> + qemu_set_irq(d->irq[0], level);
> + shpc->msi_requested = level;
> +}
> +
> +static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed)
> +{
> + switch (speed) {
> + case SHPC_SEC_BUS_33:
> + shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK;
> + shpc->config[SHPC_SEC_BUS] |= speed;
> + break;
> + default:
> + pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
> + SHPC_CMD_STATUS_INVALID_MODE);
> + }
> +}
> +
> +void shpc_reset(PCIDevice *d)
> +{
> + SHPCDevice *shpc = d->shpc;
> + int nslots = shpc->nslots;
> + int i;
> + memset(shpc->config, 0, SHPC_SIZEOF(d));
> + pci_set_byte(shpc->config + SHPC_NSLOTS, nslots);
> + pci_set_long(shpc->config + SHPC_SLOTS_33, nslots);
> + pci_set_long(shpc->config + SHPC_SLOTS_66, 0);
> + pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0));
> + pci_set_word(shpc->config + SHPC_PHYS_SLOT,
> + SHPC_IDX_TO_PHYSICAL(0) |
> + SHPC_PHYS_NUM_UP |
> + SHPC_PHYS_MRL |
> + SHPC_PHYS_BUTTON);
> + pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS |
> + SHPC_SERR_DIS |
> + SHPC_CMD_INT_DIS |
> + SHPC_ARB_SERR_DIS);
> + pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0);
> + pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33);
> + for (i = 0; i < shpc->nslots; ++i) {
> + pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
> + SHPC_SLOT_EVENT_PRESENCE |
> + SHPC_SLOT_EVENT_ISOLATED_FAULT |
> + SHPC_SLOT_EVENT_BUTTON |
> + SHPC_SLOT_EVENT_MRL |
> + SHPC_SLOT_EVENT_CONNECTED_FAULT |
> + SHPC_SLOT_EVENT_MRL_SERR_DIS |
> + SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
> + if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) {
> + shpc_set_status(shpc, i, SHPC_STATE_ENABLED,
> SHPC_SLOT_STATE_MASK);
> + shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN);
> + shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W,
> + SHPC_SLOT_STATUS_PRSNT_MASK);
> + shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK);
> + } else {
> + shpc_set_status(shpc, i, SHPC_STATE_DISABLED,
> SHPC_SLOT_STATE_MASK);
> + shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN);
> + shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY,
> + SHPC_SLOT_STATUS_PRSNT_MASK);
> + shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK);
> + }
> + shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66);
> + }
> + shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33);
> + shpc->msi_requested = 0;
> + shpc_interrupt_update(d);
> +}
> +
> +static void shpc_invalid_command(SHPCDevice *shpc)
> +{
> + pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
> + SHPC_CMD_STATUS_INVALID_CMD);
> +}
> +
> +static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
> +{
> + int devfn;
> + int pci_slot = SHPC_IDX_TO_PCI(slot);
> + for (devfn = PCI_DEVFN(pci_slot, 0);
> + devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1);
> + ++devfn) {
> + PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
> + if (affected_dev) {
> + qdev_free(&affected_dev->qdev);
> + }
> + }
> +}
> +
> +static void shpc_slot_command(SHPCDevice *shpc, uint8_t target,
> + uint8_t state, uint8_t power, uint8_t attn)
> +{
> + uint8_t current_state;
> + int slot = SHPC_LOGICAL_TO_IDX(target);
> + if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) {
> + shpc_invalid_command(shpc);
> + return;
> + }
> + current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
> + if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) {
> + shpc_invalid_command(shpc);
> + return;
> + }
> +
> + switch (power) {
> + case SHPC_LED_NO:
> + break;
> + default:
> + /* TODO: send event to monitor */
> + shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK);
> + }
> + switch (attn) {
> + case SHPC_LED_NO:
> + break;
> + default:
> + /* TODO: send event to monitor */
> + shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK);
> + }
> +
> + if ((current_state == SHPC_STATE_DISABLED && state ==
> SHPC_STATE_PWRONLY) ||
> + (current_state == SHPC_STATE_DISABLED && state ==
> SHPC_STATE_ENABLED)) {
> + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
> + } else if ((current_state == SHPC_STATE_ENABLED ||
> + current_state == SHPC_STATE_PWRONLY) &&
> + state == SHPC_STATE_DISABLED) {
> + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
> + power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
> + /* TODO: track what monitor requested. */
> + /* Look at LED to figure out whether it's ok to remove the device. */
> + if (power == SHPC_LED_OFF) {
> + shpc_free_devices_in_slot(shpc, slot);
> + shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
> + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
> + SHPC_SLOT_STATUS_PRSNT_MASK);
> + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
> + SHPC_SLOT_EVENT_BUTTON |
> + SHPC_SLOT_EVENT_MRL |
> + SHPC_SLOT_EVENT_PRESENCE;
> + }
> + }
> +}
> +
> +static void shpc_command(SHPCDevice *shpc)
> +{
> + uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE);
> + uint8_t speed;
> + uint8_t target;
> + uint8_t attn;
> + uint8_t power;
> + uint8_t state;
> + int i;
> +
> + /* Clear status from the previous command. */
> + pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS,
> + SHPC_CMD_STATUS_BUSY |
> + SHPC_CMD_STATUS_MRL_OPEN |
> + SHPC_CMD_STATUS_INVALID_CMD |
> + SHPC_CMD_STATUS_INVALID_MODE);
> + switch (code) {
> + case 0x00 ... 0x3f:
> + target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX;
> + state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT;
> + power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT;
> + attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT;
> + shpc_slot_command(shpc, target, state, power, attn);
> + break;
> + case 0x40 ... 0x47:
> + speed = code & SHPC_SEC_BUS_MASK;
> + shpc_set_sec_bus_speed(shpc, speed);
> + break;
> + case 0x48:
> + /* Power only all slots */
> + /* first verify no slots are enabled */
> + for (i = 0; i < shpc->nslots; ++i) {
> + state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
> + if (state == SHPC_STATE_ENABLED) {
> + shpc_invalid_command(shpc);
> + goto done;
> + }
> + }
> + for (i = 0; i < shpc->nslots; ++i) {
> + if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
> + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
> + SHPC_STATE_PWRONLY, SHPC_LED_ON,
> SHPC_LED_NO);
> + } else {
> + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
> + SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
> + }
> + }
> + break;
> + case 0x49:
> + /* Enable all slots */
> + /* TODO: Spec says this shall fail if some are already enabled.
> + * This doesn't make sense - why not? a spec bug? */
> + for (i = 0; i < shpc->nslots; ++i) {
> + state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
> + if (state == SHPC_STATE_ENABLED) {
> + shpc_invalid_command(shpc);
> + goto done;
> + }
> + }
> + for (i = 0; i < shpc->nslots; ++i) {
> + if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
> + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
> + SHPC_STATE_ENABLED, SHPC_LED_ON,
> SHPC_LED_NO);
> + } else {
> + shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
> + SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
> + }
> + }
> + break;
> + default:
> + shpc_invalid_command(shpc);
> + break;
> + }
> +done:
> + pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT,
> SHPC_CMD_DETECTED);
> +}
> +
> +static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l)
> +{
> + SHPCDevice *shpc = d->shpc;
> + int i;
> + if (addr >= SHPC_SIZEOF(d)) {
> + return;
> + }
> + l = MIN(l, SHPC_SIZEOF(d) - addr);
> +
> + /* TODO: code duplicated from pci.c */
> + for (i = 0; i < l; val >>= 8, ++i) {
> + unsigned a = addr + i;
> + uint8_t wmask = shpc->wmask[a];
> + uint8_t w1cmask = shpc->w1cmask[a];
> + assert(!(wmask & w1cmask));
> + shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask);
> + shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
> + }
> + if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) {
> + shpc_command(shpc);
> + }
> + shpc_interrupt_update(d);
> +}
> +
> +static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l)
> +{
> + uint64_t val = 0x0;
> + if (addr >= SHPC_SIZEOF(d)) {
> + return val;
> + }
> + l = MIN(l, SHPC_SIZEOF(d) - addr);
> + memcpy(&val, d->shpc->config + addr, l);
> + return val;
> +}
> +
> +/* SHPC Bridge Capability */
> +#define SHPC_CAP_LENGTH 0x08
> +#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */
> +#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */
> +#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */
> +#define SHPC_CAP_CSP_MASK 0x4
> +#define SHPC_CAP_CIP_MASK 0x8
> +
> +static uint8_t shpc_cap_dword(PCIDevice *d)
> +{
> + return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT);
> +}
> +
> +/* Update dword data capability register */
> +static void shpc_cap_update_dword(PCIDevice *d)
> +{
> + unsigned data;
> + data = shpc_read(d, shpc_cap_dword(d) * 4, 4);
> + pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data);
> +}
> +
> +/* Add SHPC capability to the config space for the device. */
> +static int shpc_cap_add_config(PCIDevice *d)
> +{
> + uint8_t *config;
> + int config_offset;
> + config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC,
> + 0, SHPC_CAP_LENGTH);
> + if (config_offset < 0) {
> + return config_offset;
> + }
> + config = d->config + config_offset;
> +
> + pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0);
> + pci_set_byte(config + SHPC_CAP_CxP, 0);
> + pci_set_long(config + SHPC_CAP_DWORD_DATA, 0);
> + d->shpc->cap = config_offset;
> + /* Make dword select and data writeable. */
> + pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
> + pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
> + return 0;
> +}
> +
> +static uint64_t shpc_mmio_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + return shpc_read(opaque, addr, size);
> +}
> +
> +static void shpc_mmio_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + shpc_write(opaque, addr, val, size);
> +}
> +
> +static const MemoryRegionOps shpc_mmio_ops = {
> + .read = shpc_mmio_read,
> + .write = shpc_mmio_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + .valid = {
> + /* SHPC ECN requires dword accesses, but the original 1.0 spec
> doesn't.
> + * It's easier to suppport all sizes than worry about it. */
> + .min_access_size = 1,
> + .max_access_size = 4,
> + },
> +};
> +
> +static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev,
> + PCIHotplugState hotplug_state)
> +{
> + int pci_slot = PCI_SLOT(affected_dev->devfn);
> + uint8_t state;
> + uint8_t led;
> + PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
> + SHPCDevice *shpc = d->shpc;
> + int slot = SHPC_PCI_TO_IDX(pci_slot);
> + if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) {
> + error_report("Unsupported PCI slot %d for standard hotplug "
> + "controller. Valid slots are between %d and %d.",
> + pci_slot, SHPC_IDX_TO_PCI(0),
> + SHPC_IDX_TO_PCI(shpc->nslots) - 1);
> + return -1;
> + }
> + /* Don't send event when device is enabled during qemu machine creation:
> + * it is present on boot, no hotplug event is necessary. We do send an
> + * event when the device is disabled later. */
> + if (hotplug_state == PCI_COLDPLUG_ENABLED) {
> + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
> + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
> + SHPC_SLOT_STATUS_PRSNT_MASK);
> + return 0;
> + }
> + if (hotplug_state == PCI_HOTPLUG_DISABLED) {
> + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
> + state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
> + led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
> + if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
> + shpc_free_devices_in_slot(shpc, slot);
> + shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
> + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
> + SHPC_SLOT_STATUS_PRSNT_MASK);
> + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
> + SHPC_SLOT_EVENT_MRL |
> + SHPC_SLOT_EVENT_PRESENCE;
> + }
> + } else {
> + /* This could be a cancellation of the previous removal.
> + * We check MRL state to figure out. */
> + if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
> + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
> + shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
> + SHPC_SLOT_STATUS_PRSNT_MASK);
> + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
> + SHPC_SLOT_EVENT_BUTTON |
> + SHPC_SLOT_EVENT_MRL |
> + SHPC_SLOT_EVENT_PRESENCE;
> + } else {
> + /* Press attention button to cancel removal */
> + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
> + SHPC_SLOT_EVENT_BUTTON;
> + }
> + }
> + shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
> + shpc_interrupt_update(d);
> + return 0;
> +}
> +
> +/* Initialize the SHPC structure in bridge's BAR. */
> +int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned
> offset)
> +{
> + int i, ret;
> + int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */
> + SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc));
> + shpc->sec_bus = sec_bus;
> + ret = shpc_cap_add_config(d);
> + if (ret) {
> + g_free(d->shpc);
> + return ret;
> + }
> + if (nslots < SHPC_MIN_SLOTS) {
> + return 0;
> + }
> + if (nslots > SHPC_MAX_SLOTS ||
> + SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) {
> + /* TODO: report an error mesage that makes sense. */
> + return -EINVAL;
> + }
> + shpc->nslots = nslots;
> + shpc->config = g_malloc0(SHPC_SIZEOF(d));
> + shpc->cmask = g_malloc0(SHPC_SIZEOF(d));
> + shpc->wmask = g_malloc0(SHPC_SIZEOF(d));
> + shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d));
> +
> + shpc_reset(d);
> +
> + pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset);
> +
> + pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff);
> + pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
> + pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
> + pci_set_long(shpc->wmask + SHPC_SERR_INT,
> + SHPC_INT_DIS |
> + SHPC_SERR_DIS |
> + SHPC_CMD_INT_DIS |
> + SHPC_ARB_SERR_DIS);
> + pci_set_long(shpc->w1cmask + SHPC_SERR_INT,
> + SHPC_CMD_DETECTED |
> + SHPC_ARB_DETECTED);
> + for (i = 0; i < nslots; ++i) {
> + pci_set_byte(shpc->wmask +
> + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
> + SHPC_SLOT_EVENT_PRESENCE |
> + SHPC_SLOT_EVENT_ISOLATED_FAULT |
> + SHPC_SLOT_EVENT_BUTTON |
> + SHPC_SLOT_EVENT_MRL |
> + SHPC_SLOT_EVENT_CONNECTED_FAULT |
> + SHPC_SLOT_EVENT_MRL_SERR_DIS |
> + SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
> + pci_set_byte(shpc->w1cmask +
> + SHPC_SLOT_EVENT_LATCH(i),
> + SHPC_SLOT_EVENT_PRESENCE |
> + SHPC_SLOT_EVENT_ISOLATED_FAULT |
> + SHPC_SLOT_EVENT_BUTTON |
> + SHPC_SLOT_EVENT_MRL |
> + SHPC_SLOT_EVENT_CONNECTED_FAULT);
> + }
> +
> + /* TODO: init cmask */
> + memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio",
> + SHPC_SIZEOF(d));
> + shpc_cap_update_dword(d);
> + memory_region_add_subregion(bar, offset, &shpc->mmio);
> + pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev);
> +
> + d->cap_present |= QEMU_PCI_CAP_SHPC;
> + return 0;
> +}
> +
> +int shpc_bar_size(PCIDevice *d)
> +{
> + return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS));
> +}
> +
> +void shpc_cleanup(PCIDevice *d, MemoryRegion *bar)
> +{
> + SHPCDevice *shpc = d->shpc;
> + d->cap_present &= ~QEMU_PCI_CAP_SHPC;
> + memory_region_del_subregion(bar, &shpc->mmio);
> + /* TODO: cleanup config space changes? */
> + g_free(shpc->config);
> + g_free(shpc->cmask);
> + g_free(shpc->wmask);
> + g_free(shpc->w1cmask);
> + memory_region_destroy(&shpc->mmio);
> + g_free(shpc);
> +}
> +
> +void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
> +{
> + if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) {
> + return;
> + }
> + if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) {
> + unsigned dword_data;
> + dword_data = pci_get_long(d->shpc->config + d->shpc->cap
> + + SHPC_CAP_DWORD_DATA);
> + shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4);
> + }
> + /* Update cap dword data in case guest is going to read it. */
> + shpc_cap_update_dword(d);
> +}
> +
> +static void shpc_save(QEMUFile *f, void *pv, size_t size)
> +{
> + PCIDevice *d = container_of(pv, PCIDevice, shpc);
> + qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
> +}
> +
> +static int shpc_load(QEMUFile *f, void *pv, size_t size)
> +{
> + PCIDevice *d = container_of(pv, PCIDevice, shpc);
> + int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
> + if (ret != SHPC_SIZEOF(d)) {
> + return -EINVAL;
> + }
> + /* Make sure we don't lose notifications. An extra interrupt is
> harmless. */
> + d->shpc->msi_requested = 0;
> + shpc_interrupt_update(d);
> + return 0;
> +}
> +
> +VMStateInfo shpc_vmstate_info = {
> + .name = "shpc",
> + .get = shpc_load,
> + .put = shpc_save,
> +};
> diff --git a/hw/pci/shpc.h b/hw/pci/shpc.h
> new file mode 100644
> index 0000000..130b71d
> --- /dev/null
> +++ b/hw/pci/shpc.h
> @@ -0,0 +1,48 @@
> +#ifndef SHPC_H
> +#define SHPC_H
> +
> +#include "qemu-common.h"
> +#include "memory.h"
> +#include "vmstate.h"
> +
> +struct SHPCDevice {
> + /* Capability offset in device's config space */
> + int cap;
> +
> + /* # of hot-pluggable slots */
> + int nslots;
> +
> + /* SHPC WRS: working register set */
> + uint8_t *config;
> +
> + /* Used to enable checks on load. Note that writable bits are
> + * never checked even if set in cmask. */
> + uint8_t *cmask;
> +
> + /* Used to implement R/W bytes */
> + uint8_t *wmask;
> +
> + /* Used to implement RW1C(Write 1 to Clear) bytes */
> + uint8_t *w1cmask;
> +
> + /* MMIO for the SHPC BAR */
> + MemoryRegion mmio;
> +
> + /* Bus controlled by this SHPC */
> + PCIBus *sec_bus;
> +
> + /* MSI already requested for this event */
> + int msi_requested;
> +};
> +
> +void shpc_reset(PCIDevice *d);
> +int shpc_bar_size(PCIDevice *dev);
> +int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned
> off);
> +void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar);
> +void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int
> len);
> +
> +extern VMStateInfo shpc_vmstate_info;
> +#define SHPC_VMSTATE(_field, _type) \
> + VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0)
> +
> +#endif
> diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c
> new file mode 100644
> index 0000000..0106452
> --- /dev/null
> +++ b/hw/pci/slotid_cap.c
> @@ -0,0 +1,44 @@
> +#include "slotid_cap.h"
> +#include "pci.h"
> +
> +#define SLOTID_CAP_LENGTH 4
> +#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1)
> +
> +int slotid_cap_init(PCIDevice *d, int nslots,
> + uint8_t chassis,
> + unsigned offset)
> +{
> + int cap;
> + if (!chassis) {
> + error_report("Bridge chassis not specified. Each bridge is required "
> + "to be assigned a unique chassis id > 0.");
> + return -EINVAL;
> + }
> + if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) {
> + /* TODO: error report? */
> + return -EINVAL;
> + }
> +
> + cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset,
> SLOTID_CAP_LENGTH);
> + if (cap < 0) {
> + return cap;
> + }
> + /* We make each chassis unique, this way each bridge is First in Chassis
> */
> + d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC |
> + (nslots << SLOTID_NSLOTS_SHIFT);
> + d->cmask[cap + PCI_SID_ESR] = 0xff;
> + d->config[cap + PCI_SID_CHASSIS_NR] = chassis;
> + /* Note: Chassis number register is non-volatile,
> + so we don't reset it. */
> + /* TODO: store in eeprom? */
> + d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff;
> +
> + d->cap_present |= QEMU_PCI_CAP_SLOTID;
> + return 0;
> +}
> +
> +void slotid_cap_cleanup(PCIDevice *d)
> +{
> + /* TODO: cleanup config space? */
> + d->cap_present &= ~QEMU_PCI_CAP_SLOTID;
> +}
> diff --git a/hw/pci/slotid_cap.h b/hw/pci/slotid_cap.h
> new file mode 100644
> index 0000000..70db047
> --- /dev/null
> +++ b/hw/pci/slotid_cap.h
> @@ -0,0 +1,11 @@
> +#ifndef PCI_SLOTID_CAP_H
> +#define PCI_SLOTID_CAP_H
> +
> +#include "qemu-common.h"
> +
> +int slotid_cap_init(PCIDevice *dev, int nslots,
> + uint8_t chassis,
> + unsigned offset);
> +void slotid_cap_cleanup(PCIDevice *dev);
> +
> +#endif
> diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
> deleted file mode 100644
> index 4680501..0000000
> --- a/hw/pci_bridge.c
> +++ /dev/null
> @@ -1,363 +0,0 @@
> -/*
> - * QEMU PCI bus manager
> - *
> - * Copyright (c) 2004 Fabrice Bellard
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> - * of this software and associated documentation files (the "Software"), to
> dea
> -
> - * in the Software without restriction, including without limitation the
> rights
> - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> - * copies of the Software, and to permit persons to whom the Software is
> - * furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM
> -
> - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> - * THE SOFTWARE.
> - */
> -/*
> - * split out from pci.c
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * VA Linux Systems Japan K.K.
> - */
> -
> -#include "pci_bridge.h"
> -#include "pci_internals.h"
> -#include "range.h"
> -
> -/* PCI bridge subsystem vendor ID helper functions */
> -#define PCI_SSVID_SIZEOF 8
> -#define PCI_SSVID_SVID 4
> -#define PCI_SSVID_SSID 6
> -
> -int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
> - uint16_t svid, uint16_t ssid)
> -{
> - int pos;
> - pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset,
> PCI_SSVID_SIZEOF);
> - if (pos < 0) {
> - return pos;
> - }
> -
> - pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid);
> - pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid);
> - return pos;
> -}
> -
> -/* Accessor function to get parent bridge device from pci bus. */
> -PCIDevice *pci_bridge_get_device(PCIBus *bus)
> -{
> - return bus->parent_dev;
> -}
> -
> -/* Accessor function to get secondary bus from pci-to-pci bridge device */
> -PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
> -{
> - return &br->sec_bus;
> -}
> -
> -static uint32_t pci_config_get_io_base(const PCIDevice *d,
> - uint32_t base, uint32_t base_upper16)
> -{
> - uint32_t val;
> -
> - val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
> - if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
> - val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
> - }
> - return val;
> -}
> -
> -static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base)
> -{
> - return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
> - << 16;
> -}
> -
> -static pcibus_t pci_config_get_pref_base(const PCIDevice *d,
> - uint32_t base, uint32_t upper)
> -{
> - pcibus_t tmp;
> - pcibus_t val;
> -
> - tmp = (pcibus_t)pci_get_word(d->config + base);
> - val = (tmp & PCI_PREF_RANGE_MASK) << 16;
> - if (tmp & PCI_PREF_RANGE_TYPE_64) {
> - val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
> - }
> - return val;
> -}
> -
> -/* accessor function to get bridge filtering base address */
> -pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type)
> -{
> - pcibus_t base;
> - if (type & PCI_BASE_ADDRESS_SPACE_IO) {
> - base = pci_config_get_io_base(bridge,
> - PCI_IO_BASE, PCI_IO_BASE_UPPER16);
> - } else {
> - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
> - base = pci_config_get_pref_base(
> - bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
> - } else {
> - base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
> - }
> - }
> -
> - return base;
> -}
> -
> -/* accessor funciton to get bridge filtering limit */
> -pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
> -{
> - pcibus_t limit;
> - if (type & PCI_BASE_ADDRESS_SPACE_IO) {
> - limit = pci_config_get_io_base(bridge,
> - PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
> - limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */
> - } else {
> - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
> - limit = pci_config_get_pref_base(
> - bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
> - } else {
> - limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
> - }
> - limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */
> - }
> - return limit;
> -}
> -
> -static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
> - uint8_t type, const char *name,
> - MemoryRegion *space,
> - MemoryRegion *parent_space,
> - bool enabled)
> -{
> - pcibus_t base = pci_bridge_get_base(&bridge->dev, type);
> - pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type);
> - /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly.
> - * Apparently no way to do this with existing memory APIs. */
> - pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0;
> -
> - memory_region_init_alias(alias, name, space, base, size);
> - memory_region_add_subregion_overlap(parent_space, base, alias, 1);
> -}
> -
> -static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
> -{
> - PCIBus *parent = br->dev.bus;
> - PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1);
> - uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND);
> -
> - pci_bridge_init_alias(br, &w->alias_pref_mem,
> - PCI_BASE_ADDRESS_MEM_PREFETCH,
> - "pci_bridge_pref_mem",
> - &br->address_space_mem,
> - parent->address_space_mem,
> - cmd & PCI_COMMAND_MEMORY);
> - pci_bridge_init_alias(br, &w->alias_mem,
> - PCI_BASE_ADDRESS_SPACE_MEMORY,
> - "pci_bridge_mem",
> - &br->address_space_mem,
> - parent->address_space_mem,
> - cmd & PCI_COMMAND_MEMORY);
> - pci_bridge_init_alias(br, &w->alias_io,
> - PCI_BASE_ADDRESS_SPACE_IO,
> - "pci_bridge_io",
> - &br->address_space_io,
> - parent->address_space_io,
> - cmd & PCI_COMMAND_IO);
> - /* TODO: optinal VGA and VGA palette snooping support. */
> -
> - return w;
> -}
> -
> -static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w)
> -{
> - PCIBus *parent = br->dev.bus;
> -
> - memory_region_del_subregion(parent->address_space_io, &w->alias_io);
> - memory_region_del_subregion(parent->address_space_mem, &w->alias_mem);
> - memory_region_del_subregion(parent->address_space_mem,
> &w->alias_pref_mem);
> -}
> -
> -static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
> -{
> - memory_region_destroy(&w->alias_io);
> - memory_region_destroy(&w->alias_mem);
> - memory_region_destroy(&w->alias_pref_mem);
> - g_free(w);
> -}
> -
> -static void pci_bridge_update_mappings(PCIBridge *br)
> -{
> - PCIBridgeWindows *w = br->windows;
> -
> - /* Make updates atomic to: handle the case of one VCPU updating the
> bridge
> - * while another accesses an unaffected region. */
> - memory_region_transaction_begin();
> - pci_bridge_region_del(br, br->windows);
> - br->windows = pci_bridge_region_init(br);
> - memory_region_transaction_commit();
> - pci_bridge_region_cleanup(br, w);
> -}
> -
> -/* default write_config function for PCI-to-PCI bridge */
> -void pci_bridge_write_config(PCIDevice *d,
> - uint32_t address, uint32_t val, int len)
> -{
> - PCIBridge *s = container_of(d, PCIBridge, dev);
> - uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
> - uint16_t newctl;
> -
> - pci_default_write_config(d, address, val, len);
> -
> - if (ranges_overlap(address, len, PCI_COMMAND, 2) ||
> -
> - /* io base/limit */
> - ranges_overlap(address, len, PCI_IO_BASE, 2) ||
> -
> - /* memory base/limit, prefetchable base/limit and
> - io base/limit upper 16 */
> - ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
> - pci_bridge_update_mappings(s);
> - }
> -
> - newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
> - if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) {
> - /* Trigger hot reset on 0->1 transition. */
> - pci_bus_reset(&s->sec_bus);
> - }
> -}
> -
> -void pci_bridge_disable_base_limit(PCIDevice *dev)
> -{
> - uint8_t *conf = dev->config;
> -
> - pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
> - PCI_IO_RANGE_MASK & 0xff);
> - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
> - PCI_IO_RANGE_MASK & 0xff);
> - pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE,
> - PCI_MEMORY_RANGE_MASK & 0xffff);
> - pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
> - PCI_MEMORY_RANGE_MASK & 0xffff);
> - pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE,
> - PCI_PREF_RANGE_MASK & 0xffff);
> - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
> - PCI_PREF_RANGE_MASK & 0xffff);
> - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0);
> - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0);
> -}
> -
> -/* reset bridge specific configuration registers */
> -void pci_bridge_reset(DeviceState *qdev)
> -{
> - PCIDevice *dev = PCI_DEVICE(qdev);
> - uint8_t *conf = dev->config;
> -
> - conf[PCI_PRIMARY_BUS] = 0;
> - conf[PCI_SECONDARY_BUS] = 0;
> - conf[PCI_SUBORDINATE_BUS] = 0;
> - conf[PCI_SEC_LATENCY_TIMER] = 0;
> -
> - /*
> - * the default values for base/limit registers aren't specified
> - * in the PCI-to-PCI-bridge spec. So we don't thouch them here.
> - * Each implementation can override it.
> - * typical implementation does
> - * zero base/limit registers or
> - * disable forwarding: pci_bridge_disable_base_limit()
> - * If disable forwarding is wanted, call pci_bridge_disable_base_limit()
> - * after this function.
> - */
> - pci_byte_test_and_clear_mask(conf + PCI_IO_BASE,
> - PCI_IO_RANGE_MASK & 0xff);
> - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
> - PCI_IO_RANGE_MASK & 0xff);
> - pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE,
> - PCI_MEMORY_RANGE_MASK & 0xffff);
> - pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
> - PCI_MEMORY_RANGE_MASK & 0xffff);
> - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE,
> - PCI_PREF_RANGE_MASK & 0xffff);
> - pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
> - PCI_PREF_RANGE_MASK & 0xffff);
> - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0);
> - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0);
> -
> - pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
> -}
> -
> -/* default qdev initialization function for PCI-to-PCI bridge */
> -int pci_bridge_initfn(PCIDevice *dev)
> -{
> - PCIBus *parent = dev->bus;
> - PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
> - PCIBus *sec_bus = &br->sec_bus;
> -
> - pci_word_test_and_set_mask(dev->config + PCI_STATUS,
> - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
> - pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
> - dev->config[PCI_HEADER_TYPE] =
> - (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
> - PCI_HEADER_TYPE_BRIDGE;
> - pci_set_word(dev->config + PCI_SEC_STATUS,
> - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
> -
> - /*
> - * If we don't specify the name, the bus will be addressed as <id>.0,
> where
> - * id is the device id.
> - * Since PCI Bridge devices have a single bus each, we don't need the
> index:
> - * let users address the bus using the device name.
> - */
> - if (!br->bus_name && dev->qdev.id && *dev->qdev.id) {
> - br->bus_name = dev->qdev.id;
> - }
> -
> - qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev,
> - br->bus_name);
> - sec_bus->parent_dev = dev;
> - sec_bus->map_irq = br->map_irq;
> - sec_bus->address_space_mem = &br->address_space_mem;
> - memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
> - sec_bus->address_space_io = &br->address_space_io;
> - memory_region_init(&br->address_space_io, "pci_bridge_io", 65536);
> - br->windows = pci_bridge_region_init(br);
> - QLIST_INIT(&sec_bus->child);
> - QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
> - return 0;
> -}
> -
> -/* default qdev clean up function for PCI-to-PCI bridge */
> -void pci_bridge_exitfn(PCIDevice *pci_dev)
> -{
> - PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
> - assert(QLIST_EMPTY(&s->sec_bus.child));
> - QLIST_REMOVE(&s->sec_bus, sibling);
> - pci_bridge_region_del(s, s->windows);
> - pci_bridge_region_cleanup(s, s->windows);
> - memory_region_destroy(&s->address_space_mem);
> - memory_region_destroy(&s->address_space_io);
> - /* qbus_free() is called automatically by qdev_free() */
> -}
> -
> -/*
> - * before qdev initialization(qdev_init()), this function sets bus_name and
> - * map_irq callback which are necessry for pci_bridge_initfn() to
> - * initialize bus.
> - */
> -void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
> - pci_map_irq_fn map_irq)
> -{
> - br->map_irq = map_irq;
> - br->bus_name = bus_name;
> -}
> diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h
> deleted file mode 100644
> index a00accc..0000000
> --- a/hw/pci_bridge.h
> +++ /dev/null
> @@ -1,66 +0,0 @@
> -/*
> - * QEMU PCI bridge
> - *
> - * Copyright (c) 2004 Fabrice Bellard
> - *
> - * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> - *
> - * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc]
> - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> - * VA Linux Systems Japan K.K.
> - *
> - */
> -
> -#ifndef QEMU_PCI_BRIDGE_H
> -#define QEMU_PCI_BRIDGE_H
> -
> -#include "pci.h"
> -
> -int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
> - uint16_t svid, uint16_t ssid);
> -
> -PCIDevice *pci_bridge_get_device(PCIBus *bus);
> -PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
> -
> -pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
> -pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
> -
> -void pci_bridge_write_config(PCIDevice *d,
> - uint32_t address, uint32_t val, int len);
> -void pci_bridge_disable_base_limit(PCIDevice *dev);
> -void pci_bridge_reset_reg(PCIDevice *dev);
> -void pci_bridge_reset(DeviceState *qdev);
> -
> -int pci_bridge_initfn(PCIDevice *pci_dev);
> -void pci_bridge_exitfn(PCIDevice *pci_dev);
> -
> -
> -/*
> - * before qdev initialization(qdev_init()), this function sets bus_name and
> - * map_irq callback which are necessry for pci_bridge_initfn() to
> - * initialize bus.
> - */
> -void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
> - pci_map_irq_fn map_irq);
> -
> -#endif /* QEMU_PCI_BRIDGE_H */
> -/*
> - * Local variables:
> - * c-indent-level: 4
> - * c-basic-offset: 4
> - * tab-width: 8
> - * indent-tab-mode: nil
> - * End:
> - */
> diff --git a/hw/pci_host.c b/hw/pci_host.c
> deleted file mode 100644
> index 68e328c..0000000
> --- a/hw/pci_host.c
> +++ /dev/null
> @@ -1,180 +0,0 @@
> -/*
> - * pci_host.c
> - *
> - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "pci.h"
> -#include "pci_host.h"
> -
> -/* debug PCI */
> -//#define DEBUG_PCI
> -
> -#ifdef DEBUG_PCI
> -#define PCI_DPRINTF(fmt, ...) \
> -do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
> -#else
> -#define PCI_DPRINTF(fmt, ...)
> -#endif
> -
> -/*
> - * PCI address
> - * bit 16 - 24: bus number
> - * bit 8 - 15: devfun number
> - * bit 0 - 7: offset in configuration space of a given pci device
> - */
> -
> -/* the helper functio to get a PCIDeice* for a given pci address */
> -static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
> -{
> - uint8_t bus_num = addr >> 16;
> - uint8_t devfn = addr >> 8;
> -
> - return pci_find_device(bus, bus_num, devfn);
> -}
> -
> -void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
> - uint32_t limit, uint32_t val, uint32_t len)
> -{
> - assert(len <= 4);
> - pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
> -}
> -
> -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
> - uint32_t limit, uint32_t len)
> -{
> - assert(len <= 4);
> - return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
> -}
> -
> -void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
> -{
> - PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
> - uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
> -
> - if (!pci_dev) {
> - return;
> - }
> -
> - PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
> - __func__, pci_dev->name, config_addr, val, len);
> - pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
> - val, len);
> -}
> -
> -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
> -{
> - PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
> - uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
> - uint32_t val;
> -
> - if (!pci_dev) {
> - return ~0x0;
> - }
> -
> - val = pci_host_config_read_common(pci_dev, config_addr,
> - PCI_CONFIG_SPACE_SIZE, len);
> - PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
> - __func__, pci_dev->name, config_addr, val, len);
> -
> - return val;
> -}
> -
> -static void pci_host_config_write(void *opaque, hwaddr addr,
> - uint64_t val, unsigned len)
> -{
> - PCIHostState *s = opaque;
> -
> - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
> - __func__, addr, len, val);
> - if (addr != 0 || len != 4) {
> - return;
> - }
> - s->config_reg = val;
> -}
> -
> -static uint64_t pci_host_config_read(void *opaque, hwaddr addr,
> - unsigned len)
> -{
> - PCIHostState *s = opaque;
> - uint32_t val = s->config_reg;
> -
> - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n",
> - __func__, addr, len, val);
> - return val;
> -}
> -
> -static void pci_host_data_write(void *opaque, hwaddr addr,
> - uint64_t val, unsigned len)
> -{
> - PCIHostState *s = opaque;
> - PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n",
> - addr, len, (unsigned)val);
> - if (s->config_reg & (1u << 31))
> - pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
> -}
> -
> -static uint64_t pci_host_data_read(void *opaque,
> - hwaddr addr, unsigned len)
> -{
> - PCIHostState *s = opaque;
> - uint32_t val;
> - if (!(s->config_reg & (1 << 31)))
> - return 0xffffffff;
> - val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
> - PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
> - addr, len, val);
> - return val;
> -}
> -
> -const MemoryRegionOps pci_host_conf_le_ops = {
> - .read = pci_host_config_read,
> - .write = pci_host_config_write,
> - .endianness = DEVICE_LITTLE_ENDIAN,
> -};
> -
> -const MemoryRegionOps pci_host_conf_be_ops = {
> - .read = pci_host_config_read,
> - .write = pci_host_config_write,
> - .endianness = DEVICE_BIG_ENDIAN,
> -};
> -
> -const MemoryRegionOps pci_host_data_le_ops = {
> - .read = pci_host_data_read,
> - .write = pci_host_data_write,
> - .endianness = DEVICE_LITTLE_ENDIAN,
> -};
> -
> -const MemoryRegionOps pci_host_data_be_ops = {
> - .read = pci_host_data_read,
> - .write = pci_host_data_write,
> - .endianness = DEVICE_BIG_ENDIAN,
> -};
> -
> -static const TypeInfo pci_host_type_info = {
> - .name = TYPE_PCI_HOST_BRIDGE,
> - .parent = TYPE_SYS_BUS_DEVICE,
> - .abstract = true,
> - .instance_size = sizeof(PCIHostState),
> -};
> -
> -static void pci_host_register_types(void)
> -{
> - type_register_static(&pci_host_type_info);
> -}
> -
> -type_init(pci_host_register_types)
> diff --git a/hw/pci_host.h b/hw/pci_host.h
> deleted file mode 100644
> index 4b9c300..0000000
> --- a/hw/pci_host.h
> +++ /dev/null
> @@ -1,62 +0,0 @@
> -/*
> - * QEMU Common PCI Host bridge configuration data space access routines.
> - *
> - * Copyright (c) 2006 Fabrice Bellard
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> - * of this software and associated documentation files (the "Software"), to
> deal
> - * in the Software without restriction, including without limitation the
> rights
> - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> - * copies of the Software, and to permit persons to whom the Software is
> - * furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM,
> - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> - * THE SOFTWARE.
> - */
> -
> -/* Worker routines for a PCI host controller that uses an {address,data}
> - register pair to access PCI configuration space. */
> -
> -#ifndef PCI_HOST_H
> -#define PCI_HOST_H
> -
> -#include "sysbus.h"
> -
> -#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
> -#define PCI_HOST_BRIDGE(obj) \
> - OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
> -
> -struct PCIHostState {
> - SysBusDevice busdev;
> -
> - MemoryRegion conf_mem;
> - MemoryRegion data_mem;
> - MemoryRegion mmcfg;
> - MemoryRegion *address_space;
> - uint32_t config_reg;
> - PCIBus *bus;
> -};
> -
> -/* common internal helpers for PCI/PCIe hosts, cut off overflows */
> -void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
> - uint32_t limit, uint32_t val, uint32_t
> len);
> -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
> - uint32_t limit, uint32_t len);
> -
> -void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len);
> -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len);
> -
> -extern const MemoryRegionOps pci_host_conf_le_ops;
> -extern const MemoryRegionOps pci_host_conf_be_ops;
> -extern const MemoryRegionOps pci_host_data_le_ops;
> -extern const MemoryRegionOps pci_host_data_be_ops;
> -
> -#endif /* PCI_HOST_H */
> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> deleted file mode 100644
> index 5df7245..0000000
> --- a/hw/pci_ids.h
> +++ /dev/null
> @@ -1,147 +0,0 @@
> -/*
> - * PCI Class, Vendor and Device IDs
> - *
> - * Please keep sorted.
> - *
> - * Abbreviated version of linux/pci_ids.h
> - *
> - * QEMU-specific definitions belong in pci.h
> - */
> -
> -/* Device classes and subclasses */
> -
> -#define PCI_BASE_CLASS_STORAGE 0x01
> -#define PCI_BASE_CLASS_NETWORK 0x02
> -
> -#define PCI_CLASS_STORAGE_SCSI 0x0100
> -#define PCI_CLASS_STORAGE_IDE 0x0101
> -#define PCI_CLASS_STORAGE_RAID 0x0104
> -#define PCI_CLASS_STORAGE_SATA 0x0106
> -#define PCI_CLASS_STORAGE_OTHER 0x0180
> -
> -#define PCI_CLASS_NETWORK_ETHERNET 0x0200
> -
> -#define PCI_CLASS_DISPLAY_VGA 0x0300
> -#define PCI_CLASS_DISPLAY_OTHER 0x0380
> -
> -#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
> -
> -#define PCI_CLASS_MEMORY_RAM 0x0500
> -
> -#define PCI_CLASS_SYSTEM_OTHER 0x0880
> -
> -#define PCI_CLASS_SERIAL_USB 0x0c03
> -#define PCI_CLASS_SERIAL_SMBUS 0x0c05
> -
> -#define PCI_CLASS_BRIDGE_HOST 0x0600
> -#define PCI_CLASS_BRIDGE_ISA 0x0601
> -#define PCI_CLASS_BRIDGE_PCI 0x0604
> -#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01
> -#define PCI_CLASS_BRIDGE_OTHER 0x0680
> -
> -#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
> -#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
> -
> -#define PCI_CLASS_PROCESSOR_CO 0x0b40
> -#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
> -
> -#define PCI_CLASS_OTHERS 0xff
> -
> -/* Vendors and devices. Sort key: vendor first, device next. */
> -
> -#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
> -#define PCI_DEVICE_ID_LSI_53C895A 0x0012
> -#define PCI_DEVICE_ID_LSI_SAS1078 0x0060
> -
> -#define PCI_VENDOR_ID_DEC 0x1011
> -#define PCI_DEVICE_ID_DEC_21154 0x0026
> -
> -#define PCI_VENDOR_ID_CIRRUS 0x1013
> -
> -#define PCI_VENDOR_ID_IBM 0x1014
> -
> -#define PCI_VENDOR_ID_AMD 0x1022
> -#define PCI_DEVICE_ID_AMD_LANCE 0x2000
> -#define PCI_DEVICE_ID_AMD_SCSI 0x2020
> -
> -#define PCI_VENDOR_ID_TI 0x104c
> -
> -#define PCI_VENDOR_ID_MOTOROLA 0x1057
> -#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
> -#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
> -
> -#define PCI_VENDOR_ID_APPLE 0x106b
> -#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
> -#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b
> -
> -#define PCI_VENDOR_ID_SUN 0x108e
> -#define PCI_DEVICE_ID_SUN_EBUS 0x1000
> -#define PCI_DEVICE_ID_SUN_SIMBA 0x5000
> -#define PCI_DEVICE_ID_SUN_SABRE 0xa000
> -
> -#define PCI_VENDOR_ID_CMD 0x1095
> -#define PCI_DEVICE_ID_CMD_646 0x0646
> -
> -#define PCI_VENDOR_ID_REALTEK 0x10ec
> -#define PCI_DEVICE_ID_REALTEK_8139 0x8139
> -
> -#define PCI_VENDOR_ID_XILINX 0x10ee
> -
> -#define PCI_VENDOR_ID_VIA 0x1106
> -#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686
> -#define PCI_DEVICE_ID_VIA_IDE 0x0571
> -#define PCI_DEVICE_ID_VIA_UHCI 0x3038
> -#define PCI_DEVICE_ID_VIA_ACPI 0x3057
> -#define PCI_DEVICE_ID_VIA_AC97 0x3058
> -#define PCI_DEVICE_ID_VIA_MC97 0x3068
> -
> -#define PCI_VENDOR_ID_MARVELL 0x11ab
> -
> -#define PCI_VENDOR_ID_ENSONIQ 0x1274
> -#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
> -
> -#define PCI_VENDOR_ID_FREESCALE 0x1957
> -#define PCI_DEVICE_ID_MPC8533E 0x0030
> -
> -#define PCI_VENDOR_ID_INTEL 0x8086
> -#define PCI_DEVICE_ID_INTEL_82378 0x0484
> -#define PCI_DEVICE_ID_INTEL_82441 0x1237
> -#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
> -#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e
> -#define PCI_DEVICE_ID_INTEL_82801D 0x24CD
> -#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
> -#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
> -#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
> -#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
> -#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
> -#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
> -#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
> -#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
> -
> -#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910
> -#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917
> -#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912
> -#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913
> -#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914
> -#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919
> -#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930
> -#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916
> -#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918
> -
> -#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
> -#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
> -#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
> -#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
> -#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
> -#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
> -#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
> -#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
> -#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed
> -
> -#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0
> -
> -#define PCI_VENDOR_ID_XEN 0x5853
> -#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
> -
> -#define PCI_VENDOR_ID_NEC 0x1033
> -#define PCI_DEVICE_ID_NEC_UPD720200 0x0194
> diff --git a/hw/pci_internals.h b/hw/pci_internals.h
> deleted file mode 100644
> index 21d0ce6..0000000
> --- a/hw/pci_internals.h
> +++ /dev/null
> @@ -1,78 +0,0 @@
> -#ifndef QEMU_PCI_INTERNALS_H
> -#define QEMU_PCI_INTERNALS_H
> -
> -/*
> - * This header files is private to pci.c and pci_bridge.c
> - * So following structures are opaque to others and shouldn't be
> - * accessed.
> - *
> - * For pci-to-pci bridge needs to include this header file to embed
> - * PCIBridge in its structure or to get sizeof(PCIBridge),
> - * However, they shouldn't access those following members directly.
> - * Use accessor function in pci.h, pci_bridge.h
> - */
> -
> -#define TYPE_PCI_BUS "PCI"
> -#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
> -
> -struct PCIBus {
> - BusState qbus;
> - PCIDMAContextFunc dma_context_fn;
> - void *dma_context_opaque;
> - uint8_t devfn_min;
> - pci_set_irq_fn set_irq;
> - pci_map_irq_fn map_irq;
> - pci_route_irq_fn route_intx_to_irq;
> - pci_hotplug_fn hotplug;
> - DeviceState *hotplug_qdev;
> - void *irq_opaque;
> - PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
> - PCIDevice *parent_dev;
> - MemoryRegion *address_space_mem;
> - MemoryRegion *address_space_io;
> -
> - QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
> - QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
> -
> - /* The bus IRQ state is the logical OR of the connected devices.
> - Keep a count of the number of devices with raised IRQs. */
> - int nirq;
> - int *irq_count;
> -};
> -
> -typedef struct PCIBridgeWindows PCIBridgeWindows;
> -
> -/*
> - * Aliases for each of the address space windows that the bridge
> - * can forward. Mapped into the bridge's parent's address space,
> - * as subregions.
> - */
> -struct PCIBridgeWindows {
> - MemoryRegion alias_pref_mem;
> - MemoryRegion alias_mem;
> - MemoryRegion alias_io;
> -};
> -
> -struct PCIBridge {
> - PCIDevice dev;
> -
> - /* private member */
> - PCIBus sec_bus;
> - /*
> - * Memory regions for the bridge's address spaces. These regions are not
> - * directly added to system_memory/system_io or its descendants.
> - * Bridge's secondary bus points to these, so that devices
> - * under the bridge see these regions as its address spaces.
> - * The regions are as large as the entire address space -
> - * they don't take into account any windows.
> - */
> - MemoryRegion address_space_mem;
> - MemoryRegion address_space_io;
> -
> - PCIBridgeWindows *windows;
> -
> - pci_map_irq_fn map_irq;
> - const char *bus_name;
> -};
> -
> -#endif /* QEMU_PCI_INTERNALS_H */
> diff --git a/hw/pci_regs.h b/hw/pci_regs.h
> deleted file mode 100644
> index 56a404b..0000000
> --- a/hw/pci_regs.h
> +++ /dev/null
> @@ -1,717 +0,0 @@
> -/*
> - * pci_regs.h
> - *
> - * PCI standard defines
> - * Copyright 1994, Drew Eckhardt
> - * Copyright 1997--1999 Martin Mares <address@hidden>
> - *
> - * For more information, please consult the following manuals (look at
> - * http://www.pcisig.com/ for how to get them):
> - *
> - * PCI BIOS Specification
> - * PCI Local Bus Specification
> - * PCI to PCI Bridge Specification
> - * PCI System Design Guide
> - *
> - * For hypertransport information, please consult the following manuals
> - * from http://www.hypertransport.org
> - *
> - * The Hypertransport I/O Link Specification
> - */
> -
> -#ifndef LINUX_PCI_REGS_H
> -#define LINUX_PCI_REGS_H
> -
> -/*
> - * Under PCI, each device has 256 bytes of configuration address space,
> - * of which the first 64 bytes are standardized as follows:
> - */
> -#define PCI_VENDOR_ID 0x00 /* 16 bits */
> -#define PCI_DEVICE_ID 0x02 /* 16 bits */
> -#define PCI_COMMAND 0x04 /* 16 bits */
> -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O
> space */
> -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
> -#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
> -#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles
> */
> -#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and
> invalidate */
> -#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
> -#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
> -#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
> -#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
> -#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
> -#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
> -
> -#define PCI_STATUS 0x06 /* 16 bits */
> -#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */
> -#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
> -#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
> -#define PCI_STATUS_UDF 0x40 /* Support User Definable
> Features [obsolete] */
> -#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
> -#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
> -#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
> -#define PCI_STATUS_DEVSEL_FAST 0x000
> -#define PCI_STATUS_DEVSEL_MEDIUM 0x200
> -#define PCI_STATUS_DEVSEL_SLOW 0x400
> -#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
> -#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
> -#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
> -#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
> -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
> -
> -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8
> revision */
> -#define PCI_REVISION_ID 0x08 /* Revision ID */
> -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
> -#define PCI_CLASS_DEVICE 0x0a /* Device class */
> -
> -#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
> -#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
> -#define PCI_HEADER_TYPE 0x0e /* 8 bits */
> -#define PCI_HEADER_TYPE_NORMAL 0
> -#define PCI_HEADER_TYPE_BRIDGE 1
> -#define PCI_HEADER_TYPE_CARDBUS 2
> -
> -#define PCI_BIST 0x0f /* 8 bits */
> -#define PCI_BIST_CODE_MASK 0x0f /* Return result */
> -#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or
> less */
> -#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
> -
> -/*
> - * Base addresses specify locations in memory or I/O space.
> - * Decoded size can be determined by writing a value of
> - * 0xffffffff to the register, and reading it back. Only
> - * 1 bits are decoded.
> - */
> -#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
> -#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
> -#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
> -#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
> -#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
> -#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
> -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 =
> I/O */
> -#define PCI_BASE_ADDRESS_SPACE_IO 0x01
> -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
> -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
> -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
> -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
> -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
> -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
> -#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
> -#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
> -/* bit 1 is reserved if address_space = 1 */
> -
> -/* Header type 0 (normal devices) */
> -#define PCI_CARDBUS_CIS 0x28
> -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
> -#define PCI_SUBSYSTEM_ID 0x2e
> -#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address,
> 10..1 reserved */
> -#define PCI_ROM_ADDRESS_ENABLE 0x01
> -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
> -
> -#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list
> entry */
> -
> -/* 0x35-0x3b are reserved */
> -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
> -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
> -#define PCI_MIN_GNT 0x3e /* 8 bits */
> -#define PCI_MAX_LAT 0x3f /* 8 bits */
> -
> -/* Header type 1 (PCI-to-PCI bridges) */
> -#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
> -#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
> -#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the
> bridge */
> -#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary
> interface */
> -#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
> -#define PCI_IO_LIMIT 0x1d
> -#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */
> -#define PCI_IO_RANGE_TYPE_16 0x00
> -#define PCI_IO_RANGE_TYPE_32 0x01
> -#define PCI_IO_RANGE_MASK (~0x0fUL)
> -#define PCI_SEC_STATUS 0x1e /* Secondary status register, only
> bit 14 used */
> -#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
> -#define PCI_MEMORY_LIMIT 0x22
> -#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
> -#define PCI_MEMORY_RANGE_MASK (~0x0fUL)
> -#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
> -#define PCI_PREF_MEMORY_LIMIT 0x26
> -#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL
> -#define PCI_PREF_RANGE_TYPE_32 0x00
> -#define PCI_PREF_RANGE_TYPE_64 0x01
> -#define PCI_PREF_RANGE_MASK (~0x0fUL)
> -#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory
> range */
> -#define PCI_PREF_LIMIT_UPPER32 0x2c
> -#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
> -#define PCI_IO_LIMIT_UPPER16 0x32
> -/* 0x34 same as for htype 0 */
> -/* 0x35-0x3b is reserved */
> -#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for
> htype 1 */
> -/* 0x3c-0x3d are same as for htype 0 */
> -#define PCI_BRIDGE_CONTROL 0x3e
> -#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on
> secondary interface */
> -#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
> -#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */
> -#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
> -#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
> -#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
> -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on
> secondary interface */
> -
> -/* Header type 2 (CardBus bridges) */
> -#define PCI_CB_CAPABILITY_LIST 0x14
> -/* 0x15 reserved */
> -#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
> -#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
> -#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
> -#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
> -#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
> -#define PCI_CB_MEMORY_BASE_0 0x1c
> -#define PCI_CB_MEMORY_LIMIT_0 0x20
> -#define PCI_CB_MEMORY_BASE_1 0x24
> -#define PCI_CB_MEMORY_LIMIT_1 0x28
> -#define PCI_CB_IO_BASE_0 0x2c
> -#define PCI_CB_IO_BASE_0_HI 0x2e
> -#define PCI_CB_IO_LIMIT_0 0x30
> -#define PCI_CB_IO_LIMIT_0_HI 0x32
> -#define PCI_CB_IO_BASE_1 0x34
> -#define PCI_CB_IO_BASE_1_HI 0x36
> -#define PCI_CB_IO_LIMIT_1 0x38
> -#define PCI_CB_IO_LIMIT_1_HI 0x3a
> -#define PCI_CB_IO_RANGE_MASK (~0x03UL)
> -/* 0x3c-0x3d are same as for htype 0 */
> -#define PCI_CB_BRIDGE_CONTROL 0x3e
> -#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge
> control register */
> -#define PCI_CB_BRIDGE_CTL_SERR 0x02
> -#define PCI_CB_BRIDGE_CTL_ISA 0x04
> -#define PCI_CB_BRIDGE_CTL_VGA 0x08
> -#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
> -#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
> -#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for
> 16-bit cards */
> -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both
> memory regions */
> -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
> -#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
> -#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
> -#define PCI_CB_SUBSYSTEM_ID 0x42
> -#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card
> legacy mode base address (ExCa) */
> -/* 0x48-0x7f reserved */
> -
> -/* Capability lists */
> -
> -#define PCI_CAP_LIST_ID 0 /* Capability ID */
> -#define PCI_CAP_ID_PM 0x01 /* Power Management */
> -#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port
> */
> -#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */
> -#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */
> -#define PCI_CAP_ID_MSI 0x05 /* Message Signalled
> Interrupts */
> -#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
> -#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
> -#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
> -#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */
> -#define PCI_CAP_ID_DBG 0x0A /* Debug port */
> -#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource
> Control */
> -#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
> -#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID
> */
> -#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */
> -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
> -#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
> -#define PCI_CAP_ID_SATA 0x12 /* Serial ATA */
> -#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */
> -#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
> -#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits)
> */
> -#define PCI_CAP_SIZEOF 4
> -
> -/* Power Management Registers */
> -
> -#define PCI_PM_PMC 2 /* PM Capabilities Register */
> -#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */
> -#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */
> -#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */
> -#define PCI_PM_CAP_DSI 0x0020 /* Device specific
> initialization */
> -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */
> -#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */
> -#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */
> -#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */
> -#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */
> -#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */
> -#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */
> -#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */
> -#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */
> -#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */
> -#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */
> -#define PCI_PM_CTRL 4 /* PM control and status register */
> -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to
> D3) */
> -#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */
> -#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */
> -#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */
> -#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */
> -#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */
> -#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */
> -#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */
> -#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable
> (??) */
> -#define PCI_PM_DATA_REGISTER 7 /* (??) */
> -#define PCI_PM_SIZEOF 8
> -
> -/* AGP registers */
> -
> -#define PCI_AGP_VERSION 2 /* BCD version number */
> -#define PCI_AGP_RFU 3 /* Rest of capability flags */
> -#define PCI_AGP_STATUS 4 /* Status register */
> -#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of
> requests - 1 */
> -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */
> -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */
> -#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */
> -#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */
> -#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */
> -#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */
> -#define PCI_AGP_COMMAND 8 /* Control register */
> -#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of
> requests */
> -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */
> -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP
> transactions */
> -#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit
> addresses */
> -#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */
> -#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */
> -#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */
> -#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */
> -#define PCI_AGP_SIZEOF 12
> -
> -/* Vital Product Data */
> -
> -#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */
> -#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */
> -#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates
> completion */
> -#define PCI_VPD_DATA 4 /* 32-bits of data returned here */
> -
> -/* Slot Identification */
> -
> -#define PCI_SID_ESR 2 /* Expansion Slot Register */
> -#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots
> available */
> -#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */
> -#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */
> -
> -/* Message Signalled Interrupts registers */
> -
> -#define PCI_MSI_FLAGS 2 /* Various flags */
> -#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */
> -#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */
> -#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */
> -#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */
> -#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */
> -#define PCI_MSI_RFU 3 /* Rest of capability flags */
> -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
> -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if
> PCI_MSI_FLAGS_64BIT set) */
> -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit
> devices */
> -#define PCI_MSI_MASK_32 12 /* Mask bits register for
> 32-bit devices */
> -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit
> devices */
> -#define PCI_MSI_MASK_64 16 /* Mask bits register for
> 64-bit devices */
> -
> -/* MSI-X registers */
> -#define PCI_MSIX_FLAGS 2
> -#define PCI_MSIX_FLAGS_QSIZE 0x7FF
> -#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
> -#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
> -#define PCI_MSIX_TABLE 4
> -#define PCI_MSIX_PBA 8
> -#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
> -
> -/* MSI-X entry's format */
> -#define PCI_MSIX_ENTRY_SIZE 16
> -#define PCI_MSIX_ENTRY_LOWER_ADDR 0
> -#define PCI_MSIX_ENTRY_UPPER_ADDR 4
> -#define PCI_MSIX_ENTRY_DATA 8
> -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
> -#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1
> -
> -/* CompactPCI Hotswap Register */
> -
> -#define PCI_CHSWP_CSR 2 /* Control and Status Register */
> -#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */
> -#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */
> -#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */
> -#define PCI_CHSWP_LOO 0x08 /* LED On / Off */
> -#define PCI_CHSWP_PI 0x30 /* Programming Interface */
> -#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */
> -#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */
> -
> -/* PCI Advanced Feature registers */
> -
> -#define PCI_AF_LENGTH 2
> -#define PCI_AF_CAP 3
> -#define PCI_AF_CAP_TP 0x01
> -#define PCI_AF_CAP_FLR 0x02
> -#define PCI_AF_CTRL 4
> -#define PCI_AF_CTRL_FLR 0x01
> -#define PCI_AF_STATUS 5
> -#define PCI_AF_STATUS_TP 0x01
> -
> -/* PCI-X registers */
> -
> -#define PCI_X_CMD 2 /* Modes & Features */
> -#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable
> */
> -#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */
> -#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */
> -#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */
> -#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */
> -#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */
> -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */
> - /* Max # of outstanding split transactions */
> -#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */
> -#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */
> -#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */
> -#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */
> -#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */
> -#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */
> -#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */
> -#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */
> -#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions
> */
> -#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */
> -#define PCI_X_STATUS 4 /* PCI-X capabilities */
> -#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */
> -#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */
> -#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */
> -#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */
> -#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded
> */
> -#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split
> Completion */
> -#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */
> -#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read
> Count */
> -#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max
> Outstanding Split Transactions */
> -#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative
> Read Size */
> -#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion
> Error Msg */
> -#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */
> -#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */
> -
> -/* PCI Bridge Subsystem ID registers */
> -
> -#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id
> register */
> -#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id
> register */
> -
> -/* PCI Express capability registers */
> -
> -#define PCI_EXP_FLAGS 2 /* Capabilities register */
> -#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */
> -#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */
> -#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */
> -#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */
> -#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */
> -#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
> -#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
> -#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */
> -#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */
> -#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */
> -#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */
> -#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */
> -#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */
> -#define PCI_EXP_DEVCAP 4 /* Device capabilities */
> -#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */
> -#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */
> -#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */
> -#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */
> -#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */
> -#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */
> -#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator
> Present */
> -#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */
> -#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */
> -#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */
> -#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */
> -#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */
> -#define PCI_EXP_DEVCTL 8 /* Device Control */
> -#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */
> -#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */
> -#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */
> -#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En.
> */
> -#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
> -#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
> -#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable
> */
> -#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */
> -#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable
> */
> -#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */
> -#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */
> -#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR
> */
> -#define PCI_EXP_DEVSTA 10 /* Device Status */
> -#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */
> -#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */
> -#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */
> -#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */
> -#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */
> -#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */
> -#define PCI_EXP_LNKCAP 12 /* Link Capabilities */
> -#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */
> -#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
> -#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
> -#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */
> -#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */
> -#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* L1 Clock Power Management */
> -#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting
> Capable */
> -#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link
> Active Reporting Capable */
> -#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification
> Capability */
> -#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */
> -#define PCI_EXP_LNKCTL 16 /* Link Control */
> -#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */
> -#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */
> -#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */
> -#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */
> -#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */
> -#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */
> -#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */
> -#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable
> */
> -#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management
> Interrupt Enable */
> -#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Lnk Autonomous Bandwidth Interrupt
> Enable */
> -#define PCI_EXP_LNKSTA 18 /* Link Status */
> -#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */
> -#define PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */
> -#define PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */
> -#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */
> -#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */
> -#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */
> -#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */
> -#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */
> -#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */
> -#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */
> -#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */
> -#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */
> -#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */
> -#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */
> -#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */
> -#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */
> -#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */
> -#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */
> -#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */
> -#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */
> -#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock
> Present */
> -#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */
> -#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */
> -#define PCI_EXP_SLTCTL 24 /* Slot Control */
> -#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */
> -#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */
> -#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */
> -#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */
> -#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable
> */
> -#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */
> -#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */
> -#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */
> -#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */
> -#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock
> Control */
> -#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed
> Enable */
> -#define PCI_EXP_SLTSTA 26 /* Slot Status */
> -#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */
> -#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */
> -#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */
> -#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */
> -#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */
> -#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */
> -#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */
> -#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status
> */
> -#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */
> -#define PCI_EXP_RTCTL 28 /* Root Control */
> -#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error
> */
> -#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */
> -#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */
> -#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */
> -#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */
> -#define PCI_EXP_RTCAP 30 /* Root Capabilities */
> -#define PCI_EXP_RTSTA 32 /* Root Status */
> -#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */
> -#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */
> -#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */
> -#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */
> -#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reporting */
> -#define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */
> -#define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */
> -#define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */
> -#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
> -#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */
> -#define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */
> -#define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion
> enable */
> -#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance
> reporting */
> -#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */
> -#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */
> -#define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */
> -#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */
> -#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */
> -
> -/* Extended Capabilities (PCI-X 2.0 and Express) */
> -#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff)
> -#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf)
> -#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc)
> -
> -#define PCI_EXT_CAP_ID_ERR 1
> -#define PCI_EXT_CAP_ID_VC 2
> -#define PCI_EXT_CAP_ID_DSN 3
> -#define PCI_EXT_CAP_ID_PWR 4
> -#define PCI_EXT_CAP_ID_VNDR 11
> -#define PCI_EXT_CAP_ID_ACS 13
> -#define PCI_EXT_CAP_ID_ARI 14
> -#define PCI_EXT_CAP_ID_ATS 15
> -#define PCI_EXT_CAP_ID_SRIOV 16
> -#define PCI_EXT_CAP_ID_LTR 24
> -
> -/* Advanced Error Reporting */
> -#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */
> -#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */
> -#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */
> -#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */
> -#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */
> -#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */
> -#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */
> -#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */
> -#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */
> -#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */
> -#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */
> -#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */
> -#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */
> - /* Same bits as above */
> -#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */
> - /* Same bits as above */
> -#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */
> -#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */
> -#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */
> -#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */
> -#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */
> -#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */
> -#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */
> - /* Same bits as above */
> -#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */
> -#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */
> -#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */
> -#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */
> -#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
> -#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
> -#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */
> -#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */
> -/* Correctable Err Reporting Enable */
> -#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001
> -/* Non-fatal Err Reporting Enable */
> -#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002
> -/* Fatal Err Reporting Enable */
> -#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004
> -#define PCI_ERR_ROOT_STATUS 48
> -#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */
> -/* Multi ERR_COR Received */
> -#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002
> -/* ERR_FATAL/NONFATAL Recevied */
> -#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004
> -/* Multi ERR_FATAL/NONFATAL Recevied */
> -#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008
> -#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */
> -#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received
> */
> -#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */
> -#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */
> -
> -/* Virtual Channel */
> -#define PCI_VC_PORT_REG1 4
> -#define PCI_VC_PORT_REG2 8
> -#define PCI_VC_PORT_CTRL 12
> -#define PCI_VC_PORT_STATUS 14
> -#define PCI_VC_RES_CAP 16
> -#define PCI_VC_RES_CTRL 20
> -#define PCI_VC_RES_STATUS 26
> -
> -/* Power Budgeting */
> -#define PCI_PWR_DSR 4 /* Data Select Register */
> -#define PCI_PWR_DATA 8 /* Data Register */
> -#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */
> -#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */
> -#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */
> -#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
> -#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */
> -#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */
> -#define PCI_PWR_CAP 12 /* Capability */
> -#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget
> */
> -
> -/*
> - * Hypertransport sub capability types
> - *
> - * Unfortunately there are both 3 bit and 5 bit capability types defined
> - * in the HT spec, catering for that is a little messy. You probably don't
> - * want to use these directly, just use pci_find_ht_capability() and it
> - * will do the right thing for you.
> - */
> -#define HT_3BIT_CAP_MASK 0xE0
> -#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
> -#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link
> configuration */
> -
> -#define HT_5BIT_CAP_MASK 0xF8
> -#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */
> -#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */
> -#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */
> -#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */
> -#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space
> Access */
> -#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */
> -#define HT_MSI_FLAGS 0x02 /* Offset to flags */
> -#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */
> -#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */
> -#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */
> -#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr
> bits */
> -#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */
> -#define HT_MSI_ADDR_HI 0x08 /* Offset to high
> addr bits */
> -#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing
> configuration */
> -#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */
> -#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */
> -#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3
> hypertransport configuration */
> -#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement
> configuration */
> -
> -/* Alternative Routing-ID Interpretation */
> -#define PCI_ARI_CAP 0x04 /* ARI Capability Register */
> -#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */
> -#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */
> -#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */
> -#define PCI_ARI_CTRL 0x06 /* ARI Control Register */
> -#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */
> -#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */
> -#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */
> -
> -/* Address Translation Service */
> -#define PCI_ATS_CAP 0x04 /* ATS Capability Register */
> -#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */
> -#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */
> -#define PCI_ATS_CTRL 0x06 /* ATS Control Register */
> -#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */
> -#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit
> */
> -#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */
> -
> -/* Single Root I/O Virtualization */
> -#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */
> -#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */
> -#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */
> -#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */
> -#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */
> -#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */
> -#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */
> -#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */
> -#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */
> -#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */
> -#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */
> -#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */
> -#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */
> -#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */
> -#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */
> -#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */
> -#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */
> -#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */
> -#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */
> -#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */
> -#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */
> -#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */
> -#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/
> -#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */
> -#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */
> -#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */
> -#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */
> -#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */
> -#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */
> -
> -#define PCI_LTR_MAX_SNOOP_LAT 0x4
> -#define PCI_LTR_MAX_NOSNOOP_LAT 0x6
> -#define PCI_LTR_VALUE_MASK 0x000003ff
> -#define PCI_LTR_SCALE_MASK 0x00001c00
> -#define PCI_LTR_SCALE_SHIFT 10
> -
> -/* Access Control Service */
> -#define PCI_ACS_CAP 0x04 /* ACS Capability Register */
> -#define PCI_ACS_SV 0x01 /* Source Validation */
> -#define PCI_ACS_TB 0x02 /* Translation Blocking */
> -#define PCI_ACS_RR 0x04 /* P2P Request Redirect */
> -#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */
> -#define PCI_ACS_UF 0x10 /* Upstream Forwarding */
> -#define PCI_ACS_EC 0x20 /* P2P Egress Control */
> -#define PCI_ACS_DT 0x40 /* Direct Translated P2P */
> -#define PCI_ACS_CTRL 0x06 /* ACS Control Register */
> -#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */
> -
> -#endif /* LINUX_PCI_REGS_H */
> diff --git a/hw/pcie.c b/hw/pcie.c
> deleted file mode 100644
> index 7c92f19..0000000
> --- a/hw/pcie.c
> +++ /dev/null
> @@ -1,555 +0,0 @@
> -/*
> - * pcie.c
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "qemu-common.h"
> -#include "pci_bridge.h"
> -#include "pcie.h"
> -#include "msix.h"
> -#include "msi.h"
> -#include "pci_internals.h"
> -#include "pcie_regs.h"
> -#include "range.h"
> -
> -//#define DEBUG_PCIE
> -#ifdef DEBUG_PCIE
> -# define PCIE_DPRINTF(fmt, ...) \
> - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
> -#else
> -# define PCIE_DPRINTF(fmt, ...) do {} while (0)
> -#endif
> -#define PCIE_DEV_PRINTF(dev, fmt, ...) \
> - PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
> -
> -
> -/***************************************************************************
> - * pci express capability helper functions
> - */
> -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
> -{
> - int pos;
> - uint8_t *exp_cap;
> -
> - assert(pci_is_express(dev));
> -
> - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
> - PCI_EXP_VER2_SIZEOF);
> - if (pos < 0) {
> - return pos;
> - }
> - dev->exp.exp_cap = pos;
> - exp_cap = dev->config + pos;
> -
> - /* capability register
> - interrupt message number defaults to 0 */
> - pci_set_word(exp_cap + PCI_EXP_FLAGS,
> - ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) |
> - PCI_EXP_FLAGS_VER2);
> -
> - /* device capability register
> - * table 7-12:
> - * roll based error reporting bit must be set by all
> - * Functions conforming to the ECN, PCI Express Base
> - * Specification, Revision 1.1., or subsequent PCI Express Base
> - * Specification revisions.
> - */
> - pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);
> -
> - pci_set_long(exp_cap + PCI_EXP_LNKCAP,
> - (port << PCI_EXP_LNKCAP_PN_SHIFT) |
> - PCI_EXP_LNKCAP_ASPMS_0S |
> - PCI_EXP_LNK_MLW_1 |
> - PCI_EXP_LNK_LS_25);
> -
> - pci_set_word(exp_cap + PCI_EXP_LNKSTA,
> - PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
> -
> - pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
> - PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
> -
> - pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB);
> - return pos;
> -}
> -
> -void pcie_cap_exit(PCIDevice *dev)
> -{
> - pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
> -}
> -
> -uint8_t pcie_cap_get_type(const PCIDevice *dev)
> -{
> - uint32_t pos = dev->exp.exp_cap;
> - assert(pos > 0);
> - return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) &
> - PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT;
> -}
> -
> -/* MSI/MSI-X */
> -/* pci express interrupt message number */
> -/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */
> -void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector)
> -{
> - uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
> - assert(vector < 32);
> - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ);
> - pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
> - vector << PCI_EXP_FLAGS_IRQ_SHIFT);
> -}
> -
> -uint8_t pcie_cap_flags_get_vector(PCIDevice *dev)
> -{
> - return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
> - PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT;
> -}
> -
> -void pcie_cap_deverr_init(PCIDevice *dev)
> -{
> - uint32_t pos = dev->exp.exp_cap;
> - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP,
> - PCI_EXP_DEVCAP_RBER);
> - pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL,
> - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
> - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
> - pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA,
> - PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
> - PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD);
> -}
> -
> -void pcie_cap_deverr_reset(PCIDevice *dev)
> -{
> - uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
> - pci_long_test_and_clear_mask(devctl,
> - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
> - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
> -}
> -
> -static void hotplug_event_update_event_status(PCIDevice *dev)
> -{
> - uint32_t pos = dev->exp.exp_cap;
> - uint8_t *exp_cap = dev->config + pos;
> - uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
> - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
> -
> - dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) &&
> - (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED);
> -}
> -
> -static void hotplug_event_notify(PCIDevice *dev)
> -{
> - bool prev = dev->exp.hpev_notified;
> -
> - hotplug_event_update_event_status(dev);
> -
> - if (prev == dev->exp.hpev_notified) {
> - return;
> - }
> -
> - /* Note: the logic above does not take into account whether interrupts
> - * are masked. The result is that interrupt will be sent when it is
> - * subsequently unmasked. This appears to be legal: Section 6.7.3.4:
> - * The Port may optionally send an MSI when there are hot-plug events
> that
> - * occur while interrupt generation is disabled, and interrupt
> generation is
> - * subsequently enabled. */
> - if (msix_enabled(dev)) {
> - msix_notify(dev, pcie_cap_flags_get_vector(dev));
> - } else if (msi_enabled(dev)) {
> - msi_notify(dev, pcie_cap_flags_get_vector(dev));
> - } else {
> - qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
> - }
> -}
> -
> -static void hotplug_event_clear(PCIDevice *dev)
> -{
> - hotplug_event_update_event_status(dev);
> - if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) {
> - qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0);
> - }
> -}
> -
> -/*
> - * A PCI Express Hot-Plug Event has occurred, so update slot status register
> - * and notify OS of the event if necessary.
> - *
> - * 6.7.3 PCI Express Hot-Plug Events
> - * 6.7.3.4 Software Notification of Hot-Plug Events
> - */
> -static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
> -{
> - /* Minor optimization: if nothing changed - no event is needed. */
> - if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
> - PCI_EXP_SLTSTA, event)) {
> - return;
> - }
> - hotplug_event_notify(dev);
> -}
> -
> -static int pcie_cap_slot_hotplug(DeviceState *qdev,
> - PCIDevice *pci_dev, PCIHotplugState state)
> -{
> - PCIDevice *d = PCI_DEVICE(qdev);
> - uint8_t *exp_cap = d->config + d->exp.exp_cap;
> - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
> -
> - /* Don't send event when device is enabled during qemu machine creation:
> - * it is present on boot, no hotplug event is necessary. We do send an
> - * event when the device is disabled later. */
> - if (state == PCI_COLDPLUG_ENABLED) {
> - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
> - PCI_EXP_SLTSTA_PDS);
> - return 0;
> - }
> -
> - PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
> - if (sltsta & PCI_EXP_SLTSTA_EIS) {
> - /* the slot is electromechanically locked.
> - * This error is propagated up to qdev and then to HMP/QMP.
> - */
> - return -EBUSY;
> - }
> -
> - /* TODO: multifunction hot-plug.
> - * Right now, only a device of function = 0 is allowed to be
> - * hot plugged/unplugged.
> - */
> - assert(PCI_FUNC(pci_dev->devfn) == 0);
> -
> - if (state == PCI_HOTPLUG_ENABLED) {
> - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
> - PCI_EXP_SLTSTA_PDS);
> - pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
> - } else {
> - qdev_free(&pci_dev->qdev);
> - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
> - PCI_EXP_SLTSTA_PDS);
> - pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
> - }
> - return 0;
> -}
> -
> -/* pci express slot for pci express root/downstream port
> - PCI express capability slot registers */
> -void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
> -{
> - uint32_t pos = dev->exp.exp_cap;
> -
> - pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS,
> - PCI_EXP_FLAGS_SLOT);
> -
> - pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP,
> - ~PCI_EXP_SLTCAP_PSN);
> - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
> - (slot << PCI_EXP_SLTCAP_PSN_SHIFT) |
> - PCI_EXP_SLTCAP_EIP |
> - PCI_EXP_SLTCAP_HPS |
> - PCI_EXP_SLTCAP_HPC |
> - PCI_EXP_SLTCAP_PIP |
> - PCI_EXP_SLTCAP_AIP |
> - PCI_EXP_SLTCAP_ABP);
> -
> - pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
> - PCI_EXP_SLTCTL_PIC |
> - PCI_EXP_SLTCTL_AIC);
> - pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL,
> - PCI_EXP_SLTCTL_PIC_OFF |
> - PCI_EXP_SLTCTL_AIC_OFF);
> - pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
> - PCI_EXP_SLTCTL_PIC |
> - PCI_EXP_SLTCTL_AIC |
> - PCI_EXP_SLTCTL_HPIE |
> - PCI_EXP_SLTCTL_CCIE |
> - PCI_EXP_SLTCTL_PDCE |
> - PCI_EXP_SLTCTL_ABPE);
> - /* Although reading PCI_EXP_SLTCTL_EIC returns always 0,
> - * make the bit writable here in order to detect 1b is written.
> - * pcie_cap_slot_write_config() test-and-clear the bit, so
> - * this bit always returns 0 to the guest.
> - */
> - pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
> - PCI_EXP_SLTCTL_EIC);
> -
> - pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
> - PCI_EXP_HP_EV_SUPPORTED);
> -
> - dev->exp.hpev_notified = false;
> -
> - pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)),
> - pcie_cap_slot_hotplug, &dev->qdev);
> -}
> -
> -void pcie_cap_slot_reset(PCIDevice *dev)
> -{
> - uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
> -
> - PCIE_DEV_PRINTF(dev, "reset\n");
> -
> - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
> - PCI_EXP_SLTCTL_EIC |
> - PCI_EXP_SLTCTL_PIC |
> - PCI_EXP_SLTCTL_AIC |
> - PCI_EXP_SLTCTL_HPIE |
> - PCI_EXP_SLTCTL_CCIE |
> - PCI_EXP_SLTCTL_PDCE |
> - PCI_EXP_SLTCTL_ABPE);
> - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
> - PCI_EXP_SLTCTL_PIC_OFF |
> - PCI_EXP_SLTCTL_AIC_OFF);
> -
> - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
> - PCI_EXP_SLTSTA_EIS |/* on reset,
> - the lock is released
> */
> - PCI_EXP_SLTSTA_CC |
> - PCI_EXP_SLTSTA_PDC |
> - PCI_EXP_SLTSTA_ABP);
> -
> - hotplug_event_update_event_status(dev);
> -}
> -
> -void pcie_cap_slot_write_config(PCIDevice *dev,
> - uint32_t addr, uint32_t val, int len)
> -{
> - uint32_t pos = dev->exp.exp_cap;
> - uint8_t *exp_cap = dev->config + pos;
> - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
> -
> - if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
> - hotplug_event_clear(dev);
> - }
> -
> - if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
> - return;
> - }
> -
> - if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
> - PCI_EXP_SLTCTL_EIC)) {
> - sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
> - pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
> - PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
> - "sltsta -> 0x%02"PRIx16"\n",
> - sltsta);
> - }
> -
> - hotplug_event_notify(dev);
> -
> - /*
> - * 6.7.3.2 Command Completed Events
> - *
> - * Software issues a command to a hot-plug capable Downstream Port by
> - * issuing a write transaction that targets any portion of the Port’s
> Slot
> - * Control register. A single write to the Slot Control register is
> - * considered to be a single command, even if the write affects more than
> - * one field in the Slot Control register. In response to this
> transaction,
> - * the Port must carry out the requested actions and then set the
> - * associated status field for the command completed event. */
> -
> - /* Real hardware might take a while to complete requested command because
> - * physical movement would be involved like locking the electromechanical
> - * lock. However in our case, command is completed instantaneously
> above,
> - * so send a command completion event right now.
> - */
> - pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
> -}
> -
> -int pcie_cap_slot_post_load(void *opaque, int version_id)
> -{
> - PCIDevice *dev = opaque;
> - hotplug_event_update_event_status(dev);
> - return 0;
> -}
> -
> -void pcie_cap_slot_push_attention_button(PCIDevice *dev)
> -{
> - pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
> -}
> -
> -/* root control/capabilities/status. PME isn't emulated for now */
> -void pcie_cap_root_init(PCIDevice *dev)
> -{
> - pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL,
> - PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
> - PCI_EXP_RTCTL_SEFEE);
> -}
> -
> -void pcie_cap_root_reset(PCIDevice *dev)
> -{
> - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0);
> -}
> -
> -/* function level reset(FLR) */
> -void pcie_cap_flr_init(PCIDevice *dev)
> -{
> - pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap +
> PCI_EXP_DEVCAP,
> - PCI_EXP_DEVCAP_FLR);
> -
> - /* Although reading BCR_FLR returns always 0,
> - * the bit is made writable here in order to detect the 1b is written
> - * pcie_cap_flr_write_config() test-and-clear the bit, so
> - * this bit always returns 0 to the guest.
> - */
> - pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap +
> PCI_EXP_DEVCTL,
> - PCI_EXP_DEVCTL_BCR_FLR);
> -}
> -
> -void pcie_cap_flr_write_config(PCIDevice *dev,
> - uint32_t addr, uint32_t val, int len)
> -{
> - uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
> - if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) {
> - /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler
> - so the handler can detect FLR by looking at this bit. */
> - pci_device_reset(dev);
> - pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR);
> - }
> -}
> -
> -/* Alternative Routing-ID Interpretation (ARI) */
> -/* ari forwarding support for down stream port */
> -void pcie_cap_ari_init(PCIDevice *dev)
> -{
> - uint32_t pos = dev->exp.exp_cap;
> - pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2,
> - PCI_EXP_DEVCAP2_ARI);
> - pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2,
> - PCI_EXP_DEVCTL2_ARI);
> -}
> -
> -void pcie_cap_ari_reset(PCIDevice *dev)
> -{
> - uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2;
> - pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI);
> -}
> -
> -bool pcie_cap_is_ari_enabled(const PCIDevice *dev)
> -{
> - if (!pci_is_express(dev)) {
> - return false;
> - }
> - if (!dev->exp.exp_cap) {
> - return false;
> - }
> -
> - return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
> - PCI_EXP_DEVCTL2_ARI;
> -}
> -
> -/**************************************************************************
> - * pci express extended capability allocation functions
> - * uint16_t ext_cap_id (16 bit)
> - * uint8_t cap_ver (4 bit)
> - * uint16_t cap_offset (12 bit)
> - * uint16_t ext_cap_size
> - */
> -
> -static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id,
> - uint16_t *prev_p)
> -{
> - uint16_t prev = 0;
> - uint16_t next;
> - uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE);
> -
> - if (!header) {
> - /* no extended capability */
> - next = 0;
> - goto out;
> - }
> - for (next = PCI_CONFIG_SPACE_SIZE; next;
> - prev = next, next = PCI_EXT_CAP_NEXT(header)) {
> -
> - assert(next >= PCI_CONFIG_SPACE_SIZE);
> - assert(next <= PCIE_CONFIG_SPACE_SIZE - 8);
> -
> - header = pci_get_long(dev->config + next);
> - if (PCI_EXT_CAP_ID(header) == cap_id) {
> - break;
> - }
> - }
> -
> -out:
> - if (prev_p) {
> - *prev_p = prev;
> - }
> - return next;
> -}
> -
> -uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id)
> -{
> - return pcie_find_capability_list(dev, cap_id, NULL);
> -}
> -
> -static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t
> next)
> -{
> - uint16_t header = pci_get_long(dev->config + pos);
> - assert(!(next & (PCI_EXT_CAP_ALIGN - 1)));
> - header = (header & ~PCI_EXT_CAP_NEXT_MASK) |
> - ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK);
> - pci_set_long(dev->config + pos, header);
> -}
> -
> -/*
> - * caller must supply valid (offset, size) * such that the range shouldn't
> - * overlap with other capability or other registers.
> - * This function doesn't check it.
> - */
> -void pcie_add_capability(PCIDevice *dev,
> - uint16_t cap_id, uint8_t cap_ver,
> - uint16_t offset, uint16_t size)
> -{
> - uint32_t header;
> - uint16_t next;
> -
> - assert(offset >= PCI_CONFIG_SPACE_SIZE);
> - assert(offset < offset + size);
> - assert(offset + size < PCIE_CONFIG_SPACE_SIZE);
> - assert(size >= 8);
> - assert(pci_is_express(dev));
> -
> - if (offset == PCI_CONFIG_SPACE_SIZE) {
> - header = pci_get_long(dev->config + offset);
> - next = PCI_EXT_CAP_NEXT(header);
> - } else {
> - uint16_t prev;
> -
> - /* 0 is reserved cap id. use internally to find the last capability
> - in the linked list */
> - next = pcie_find_capability_list(dev, 0, &prev);
> -
> - assert(prev >= PCI_CONFIG_SPACE_SIZE);
> - assert(next == 0);
> - pcie_ext_cap_set_next(dev, prev, offset);
> - }
> - pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next));
> -
> - /* Make capability read-only by default */
> - memset(dev->wmask + offset, 0, size);
> - memset(dev->w1cmask + offset, 0, size);
> - /* Check capability by default */
> - memset(dev->cmask + offset, 0xFF, size);
> -}
> -
> -/**************************************************************************
> - * pci express extended capability helper functions
> - */
> -
> -/* ARI */
> -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn)
> -{
> - pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER,
> - offset, PCI_ARI_SIZEOF);
> - pci_set_long(dev->config + offset + PCI_ARI_CAP,
> PCI_ARI_CAP_NFN(nextfn));
> -}
> diff --git a/hw/pcie.h b/hw/pcie.h
> deleted file mode 100644
> index 4889194..0000000
> --- a/hw/pcie.h
> +++ /dev/null
> @@ -1,142 +0,0 @@
> -/*
> - * pcie.h
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef QEMU_PCIE_H
> -#define QEMU_PCIE_H
> -
> -#include "hw.h"
> -#include "pci_regs.h"
> -#include "pcie_regs.h"
> -#include "pcie_aer.h"
> -
> -typedef enum {
> - /* for attention and power indicator */
> - PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED,
> - PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON,
> - PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK,
> - PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF,
> -} PCIExpressIndicator;
> -
> -typedef enum {
> - /* these bits must match the bits in Slot Control/Status registers.
> - * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx
> - *
> - * Not all the bits of slot control register match with the ones of
> - * slot status. Not some bits of slot status register is used to
> - * show status, not to report event occurrence.
> - * So such bits must be masked out when checking the software
> - * notification condition.
> - */
> - PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE,
> - /* attention button pressed */
> - PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE,
> - /* presence detect changed */
> - PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE,
> - /* command completed */
> -
> - PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP |
> - PCI_EXP_HP_EV_PDC |
> - PCI_EXP_HP_EV_CCI,
> - /* supported event mask */
> -
> - /* events not listed aren't supported */
> -} PCIExpressHotPlugEvent;
> -
> -struct PCIExpressDevice {
> - /* Offset of express capability in config space */
> - uint8_t exp_cap;
> -
> - /* SLOT */
> - unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#)
> - * default is 0 = INTA#
> - * If the chip wants to use other interrupt
> - * line, initialize this member with the
> - * desired number.
> - * If the chip dynamically changes this
> member,
> - * also initialize it when loaded as
> - * appropreately.
> - */
> - bool hpev_notified; /* Logical AND of conditions for hot plug event.
> - Following 6.7.3.4:
> - Software Notification of Hot-Plug Events, an
> interrupt
> - is sent whenever the logical and of these conditions
> - transitions from false to true. */
> -
> - /* AER */
> - uint16_t aer_cap;
> - PCIEAERLog aer_log;
> - unsigned int aer_intx; /* INTx for error reporting
> - * default is 0 = INTA#
> - * If the chip wants to use other interrupt
> - * line, initialize this member with the
> - * desired number.
> - * If the chip dynamically changes this
> member,
> - * also initialize it when loaded as
> - * appropreately.
> - */
> -};
> -
> -/* PCI express capability helper functions */
> -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t
> port);
> -void pcie_cap_exit(PCIDevice *dev);
> -uint8_t pcie_cap_get_type(const PCIDevice *dev);
> -void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
> -uint8_t pcie_cap_flags_get_vector(PCIDevice *dev);
> -
> -void pcie_cap_deverr_init(PCIDevice *dev);
> -void pcie_cap_deverr_reset(PCIDevice *dev);
> -
> -void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
> -void pcie_cap_slot_reset(PCIDevice *dev);
> -void pcie_cap_slot_write_config(PCIDevice *dev,
> - uint32_t addr, uint32_t val, int len);
> -int pcie_cap_slot_post_load(void *opaque, int version_id);
> -void pcie_cap_slot_push_attention_button(PCIDevice *dev);
> -
> -void pcie_cap_root_init(PCIDevice *dev);
> -void pcie_cap_root_reset(PCIDevice *dev);
> -
> -void pcie_cap_flr_init(PCIDevice *dev);
> -void pcie_cap_flr_write_config(PCIDevice *dev,
> - uint32_t addr, uint32_t val, int len);
> -
> -void pcie_cap_ari_init(PCIDevice *dev);
> -void pcie_cap_ari_reset(PCIDevice *dev);
> -bool pcie_cap_is_ari_enabled(const PCIDevice *dev);
> -
> -/* PCI express extended capability helper functions */
> -uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
> -void pcie_add_capability(PCIDevice *dev,
> - uint16_t cap_id, uint8_t cap_ver,
> - uint16_t offset, uint16_t size);
> -
> -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
> -
> -extern const VMStateDescription vmstate_pcie_device;
> -
> -#define VMSTATE_PCIE_DEVICE(_field, _state) { \
> - .name = (stringify(_field)), \
> - .size = sizeof(PCIDevice), \
> - .vmsd = &vmstate_pcie_device, \
> - .flags = VMS_STRUCT, \
> - .offset = vmstate_offset_value(_state, _field, PCIDevice), \
> -}
> -
> -#endif /* QEMU_PCIE_H */
> diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c
> deleted file mode 100644
> index b04c164..0000000
> --- a/hw/pcie_aer.c
> +++ /dev/null
> @@ -1,1032 +0,0 @@
> -/*
> - * pcie_aer.c
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "sysemu.h"
> -#include "qemu-objects.h"
> -#include "monitor.h"
> -#include "pci_bridge.h"
> -#include "pcie.h"
> -#include "msix.h"
> -#include "msi.h"
> -#include "pci_internals.h"
> -#include "pcie_regs.h"
> -
> -//#define DEBUG_PCIE
> -#ifdef DEBUG_PCIE
> -# define PCIE_DPRINTF(fmt, ...) \
> - fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
> -#else
> -# define PCIE_DPRINTF(fmt, ...) do {} while (0)
> -#endif
> -#define PCIE_DEV_PRINTF(dev, fmt, ...) \
> - PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
> -
> -#define PCI_ERR_SRC_COR_OFFS 0
> -#define PCI_ERR_SRC_UNCOR_OFFS 2
> -
> -/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
> -static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
> -{
> - switch (status) {
> - case PCI_ERR_UNC_INTN:
> - case PCI_ERR_UNC_DLP:
> - case PCI_ERR_UNC_SDN:
> - case PCI_ERR_UNC_RX_OVER:
> - case PCI_ERR_UNC_FCP:
> - case PCI_ERR_UNC_MALF_TLP:
> - return PCI_ERR_ROOT_CMD_FATAL_EN;
> - case PCI_ERR_UNC_POISON_TLP:
> - case PCI_ERR_UNC_ECRC:
> - case PCI_ERR_UNC_UNSUP:
> - case PCI_ERR_UNC_COMP_TIME:
> - case PCI_ERR_UNC_COMP_ABORT:
> - case PCI_ERR_UNC_UNX_COMP:
> - case PCI_ERR_UNC_ACSV:
> - case PCI_ERR_UNC_MCBTLP:
> - case PCI_ERR_UNC_ATOP_EBLOCKED:
> - case PCI_ERR_UNC_TLP_PRF_BLOCKED:
> - return PCI_ERR_ROOT_CMD_NONFATAL_EN;
> - default:
> - abort();
> - break;
> - }
> - return PCI_ERR_ROOT_CMD_FATAL_EN;
> -}
> -
> -static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err)
> -{
> - if (aer_log->log_num == aer_log->log_max) {
> - return -1;
> - }
> - memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err);
> - aer_log->log_num++;
> - return 0;
> -}
> -
> -static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err)
> -{
> - assert(aer_log->log_num);
> - *err = aer_log->log[0];
> - aer_log->log_num--;
> - memmove(&aer_log->log[0], &aer_log->log[1],
> - aer_log->log_num * sizeof *err);
> -}
> -
> -static void aer_log_clear_all_err(PCIEAERLog *aer_log)
> -{
> - aer_log->log_num = 0;
> -}
> -
> -int pcie_aer_init(PCIDevice *dev, uint16_t offset)
> -{
> - PCIExpressDevice *exp;
> -
> - pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER,
> - offset, PCI_ERR_SIZEOF);
> - exp = &dev->exp;
> - exp->aer_cap = offset;
> -
> - /* log_max is property */
> - if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) {
> - dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT;
> - }
> - /* clip down the value to avoid unreasobale memory usage */
> - if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
> - return -EINVAL;
> - }
> - dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] *
> - dev->exp.aer_log.log_max);
> -
> - pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
> - PCI_ERR_UNC_SUPPORTED);
> -
> - pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
> - PCI_ERR_UNC_SEVERITY_DEFAULT);
> - pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER,
> - PCI_ERR_UNC_SUPPORTED);
> -
> - pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS,
> - PCI_ERR_COR_STATUS);
> -
> - pci_set_long(dev->config + offset + PCI_ERR_COR_MASK,
> - PCI_ERR_COR_MASK_DEFAULT);
> - pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK,
> - PCI_ERR_COR_SUPPORTED);
> -
> - /* capabilities and control. multiple header logging is supported */
> - if (dev->exp.aer_log.log_max > 0) {
> - pci_set_long(dev->config + offset + PCI_ERR_CAP,
> - PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC |
> - PCI_ERR_CAP_MHRC);
> - pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
> - PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE |
> - PCI_ERR_CAP_MHRE);
> - } else {
> - pci_set_long(dev->config + offset + PCI_ERR_CAP,
> - PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC);
> - pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
> - PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
> - }
> -
> - switch (pcie_cap_get_type(dev)) {
> - case PCI_EXP_TYPE_ROOT_PORT:
> - /* this case will be set by pcie_aer_root_init() */
> - /* fallthrough */
> - case PCI_EXP_TYPE_DOWNSTREAM:
> - case PCI_EXP_TYPE_UPSTREAM:
> - pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL,
> - PCI_BRIDGE_CTL_SERR);
> - pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS,
> - PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
> - break;
> - default:
> - /* nothing */
> - break;
> - }
> - return 0;
> -}
> -
> -void pcie_aer_exit(PCIDevice *dev)
> -{
> - g_free(dev->exp.aer_log.log);
> -}
> -
> -static void pcie_aer_update_uncor_status(PCIDevice *dev)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> - PCIEAERLog *aer_log = &dev->exp.aer_log;
> -
> - uint16_t i;
> - for (i = 0; i < aer_log->log_num; i++) {
> - pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS,
> - dev->exp.aer_log.log[i].status);
> - }
> -}
> -
> -/*
> - * return value:
> - * true: error message needs to be sent up
> - * false: error message is masked
> - *
> - * 6.2.6 Error Message Control
> - * Figure 6-3
> - * all pci express devices part
> - */
> -static bool
> -pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg)
> -{
> - if (!(pcie_aer_msg_is_uncor(msg) &&
> - (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) {
> - return false;
> - }
> -
> - /* Signaled System Error
> - *
> - * 7.5.1.1 Command register
> - * Bit 8 SERR# Enable
> - *
> - * When Set, this bit enables reporting of Non-fatal and Fatal
> - * errors detected by the Function to the Root Complex. Note that
> - * errors are reported if enabled either through this bit or through
> - * the PCI Express specific bits in the Device Control register (see
> - * Section 7.8.4).
> - */
> - pci_word_test_and_set_mask(dev->config + PCI_STATUS,
> - PCI_STATUS_SIG_SYSTEM_ERROR);
> -
> - if (!(msg->severity &
> - pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) {
> - return false;
> - }
> -
> - /* send up error message */
> - return true;
> -}
> -
> -/*
> - * return value:
> - * true: error message is sent up
> - * false: error message is masked
> - *
> - * 6.2.6 Error Message Control
> - * Figure 6-3
> - * virtual pci bridge part
> - */
> -static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg)
> -{
> - uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL);
> -
> - if (pcie_aer_msg_is_uncor(msg)) {
> - /* Received System Error */
> - pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS,
> - PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
> - }
> -
> - if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) {
> - return false;
> - }
> - return true;
> -}
> -
> -void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> - assert(vector < PCI_ERR_ROOT_IRQ_MAX);
> - pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS,
> - PCI_ERR_ROOT_IRQ);
> - pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS,
> - vector << PCI_ERR_ROOT_IRQ_SHIFT);
> -}
> -
> -static unsigned int pcie_aer_root_get_vector(PCIDevice *dev)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> - uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
> - return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
> -}
> -
> -/* Given a status register, get corresponding bits in the command register */
> -static uint32_t pcie_aer_status_to_cmd(uint32_t status)
> -{
> - uint32_t cmd = 0;
> - if (status & PCI_ERR_ROOT_COR_RCV) {
> - cmd |= PCI_ERR_ROOT_CMD_COR_EN;
> - }
> - if (status & PCI_ERR_ROOT_NONFATAL_RCV) {
> - cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN;
> - }
> - if (status & PCI_ERR_ROOT_FATAL_RCV) {
> - cmd |= PCI_ERR_ROOT_CMD_FATAL_EN;
> - }
> - return cmd;
> -}
> -
> -static void pcie_aer_root_notify(PCIDevice *dev)
> -{
> - if (msix_enabled(dev)) {
> - msix_notify(dev, pcie_aer_root_get_vector(dev));
> - } else if (msi_enabled(dev)) {
> - msi_notify(dev, pcie_aer_root_get_vector(dev));
> - } else {
> - qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
> - }
> -}
> -
> -/*
> - * 6.2.6 Error Message Control
> - * Figure 6-3
> - * root port part
> - */
> -static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
> -{
> - uint16_t cmd;
> - uint8_t *aer_cap;
> - uint32_t root_cmd;
> - uint32_t root_status, prev_status;
> -
> - cmd = pci_get_word(dev->config + PCI_COMMAND);
> - aer_cap = dev->config + dev->exp.aer_cap;
> - root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
> - prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
> -
> - if (cmd & PCI_COMMAND_SERR) {
> - /* System Error.
> - *
> - * The way to report System Error is platform specific and
> - * it isn't implemented in qemu right now.
> - * So just discard the error for now.
> - * OS which cares of aer would receive errors via
> - * native aer mechanims, so this wouldn't matter.
> - */
> - }
> -
> - /* Errro Message Received: Root Error Status register */
> - switch (msg->severity) {
> - case PCI_ERR_ROOT_CMD_COR_EN:
> - if (root_status & PCI_ERR_ROOT_COR_RCV) {
> - root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
> - } else {
> - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
> PCI_ERR_SRC_COR_OFFS,
> - msg->source_id);
> - }
> - root_status |= PCI_ERR_ROOT_COR_RCV;
> - break;
> - case PCI_ERR_ROOT_CMD_NONFATAL_EN:
> - root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
> - break;
> - case PCI_ERR_ROOT_CMD_FATAL_EN:
> - if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) {
> - root_status |= PCI_ERR_ROOT_FIRST_FATAL;
> - }
> - root_status |= PCI_ERR_ROOT_FATAL_RCV;
> - break;
> - default:
> - abort();
> - break;
> - }
> - if (pcie_aer_msg_is_uncor(msg)) {
> - if (root_status & PCI_ERR_ROOT_UNCOR_RCV) {
> - root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
> - } else {
> - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
> - PCI_ERR_SRC_UNCOR_OFFS, msg->source_id);
> - }
> - root_status |= PCI_ERR_ROOT_UNCOR_RCV;
> - }
> - pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
> -
> - /* 6.2.4.1.2 Interrupt Generation */
> - /* All the above did was set some bits in the status register.
> - * Specifically these that match message severity.
> - * The below code relies on this fact. */
> - if (!(root_cmd & msg->severity) ||
> - (pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
> - /* Condition is not being set or was already true so nothing to do.
> */
> - return;
> - }
> -
> - pcie_aer_root_notify(dev);
> -}
> -
> -/*
> - * 6.2.6 Error Message Control Figure 6-3
> - *
> - * Walk up the bus tree from the device, propagate the error message.
> - */
> -static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
> -{
> - uint8_t type;
> -
> - while (dev) {
> - if (!pci_is_express(dev)) {
> - /* just ignore it */
> - /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR?
> - * Consider e.g. a PCI bridge above a PCI Express device. */
> - return;
> - }
> -
> - type = pcie_cap_get_type(dev);
> - if ((type == PCI_EXP_TYPE_ROOT_PORT ||
> - type == PCI_EXP_TYPE_UPSTREAM ||
> - type == PCI_EXP_TYPE_DOWNSTREAM) &&
> - !pcie_aer_msg_vbridge(dev, msg)) {
> - return;
> - }
> - if (!pcie_aer_msg_alldev(dev, msg)) {
> - return;
> - }
> - if (type == PCI_EXP_TYPE_ROOT_PORT) {
> - pcie_aer_msg_root_port(dev, msg);
> - /* Root port can notify system itself,
> - or send the error message to root complex event collector. */
> - /*
> - * if root port is associated with an event collector,
> - * return the root complex event collector here.
> - * For now root complex event collector isn't supported.
> - */
> - return;
> - }
> - dev = pci_bridge_get_device(dev->bus);
> - }
> -}
> -
> -static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> - uint8_t first_bit = ffs(err->status) - 1;
> - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
> - int i;
> -
> - assert(err->status);
> - assert(!(err->status & (err->status - 1)));
> -
> - errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
> - errcap |= PCI_ERR_CAP_FEP(first_bit);
> -
> - if (err->flags & PCIE_AER_ERR_HEADER_VALID) {
> - for (i = 0; i < ARRAY_SIZE(err->header); ++i) {
> - /* 7.10.8 Header Log Register */
> - uint8_t *header_log =
> - aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0];
> - cpu_to_be32wu((uint32_t*)header_log, err->header[i]);
> - }
> - } else {
> - assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT));
> - memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
> - }
> -
> - if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) &&
> - (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
> - PCI_EXP_DEVCAP2_EETLPP)) {
> - for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) {
> - /* 7.10.12 tlp prefix log register */
> - uint8_t *prefix_log =
> - aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0];
> - cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]);
> - }
> - errcap |= PCI_ERR_CAP_TLP;
> - } else {
> - memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0,
> - PCI_ERR_TLP_PREFIX_LOG_SIZE);
> - }
> - pci_set_long(aer_cap + PCI_ERR_CAP, errcap);
> -}
> -
> -static void pcie_aer_clear_log(PCIDevice *dev)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> -
> - pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP,
> - PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
> -
> - memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
> - memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE);
> -}
> -
> -static void pcie_aer_clear_error(PCIDevice *dev)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
> - PCIEAERLog *aer_log = &dev->exp.aer_log;
> - PCIEAERErr err;
> -
> - if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) {
> - pcie_aer_clear_log(dev);
> - return;
> - }
> -
> - /*
> - * If more errors are queued, set corresponding bits in uncorrectable
> - * error status.
> - * We emulate uncorrectable error status register as W1CS.
> - * So set bit in uncorrectable error status here again for multiple
> - * error recording support.
> - *
> - * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability)
> - */
> - pcie_aer_update_uncor_status(dev);
> -
> - aer_log_del_err(aer_log, &err);
> - pcie_aer_update_log(dev, &err);
> -}
> -
> -static int pcie_aer_record_error(PCIDevice *dev,
> - const PCIEAERErr *err)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
> - int fep = PCI_ERR_CAP_FEP(errcap);
> -
> - assert(err->status);
> - assert(!(err->status & (err->status - 1)));
> -
> - if (errcap & PCI_ERR_CAP_MHRE &&
> - (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) {
> - /* Not first error. queue error */
> - if (aer_log_add_err(&dev->exp.aer_log, err) < 0) {
> - /* overflow */
> - return -1;
> - }
> - return 0;
> - }
> -
> - pcie_aer_update_log(dev, err);
> - return 0;
> -}
> -
> -typedef struct PCIEAERInject {
> - PCIDevice *dev;
> - uint8_t *aer_cap;
> - const PCIEAERErr *err;
> - uint16_t devctl;
> - uint16_t devsta;
> - uint32_t error_status;
> - bool unsupported_request;
> - bool log_overflow;
> - PCIEAERMsg msg;
> -} PCIEAERInject;
> -
> -static bool pcie_aer_inject_cor_error(PCIEAERInject *inj,
> - uint32_t uncor_status,
> - bool is_advisory_nonfatal)
> -{
> - PCIDevice *dev = inj->dev;
> -
> - inj->devsta |= PCI_EXP_DEVSTA_CED;
> - if (inj->unsupported_request) {
> - inj->devsta |= PCI_EXP_DEVSTA_URD;
> - }
> - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA,
> inj->devsta);
> -
> - if (inj->aer_cap) {
> - uint32_t mask;
> - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS,
> - inj->error_status);
> - mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK);
> - if (mask & inj->error_status) {
> - return false;
> - }
> - if (is_advisory_nonfatal) {
> - uint32_t uncor_mask =
> - pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
> - if (!(uncor_mask & uncor_status)) {
> - inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
> - }
> - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
> - uncor_status);
> - }
> - }
> -
> - if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) {
> - return false;
> - }
> - if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) {
> - return false;
> - }
> -
> - inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN;
> - return true;
> -}
> -
> -static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
> -{
> - PCIDevice *dev = inj->dev;
> - uint16_t cmd;
> -
> - if (is_fatal) {
> - inj->devsta |= PCI_EXP_DEVSTA_FED;
> - } else {
> - inj->devsta |= PCI_EXP_DEVSTA_NFED;
> - }
> - if (inj->unsupported_request) {
> - inj->devsta |= PCI_EXP_DEVSTA_URD;
> - }
> - pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA,
> inj->devsta);
> -
> - if (inj->aer_cap) {
> - uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
> - if (mask & inj->error_status) {
> - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
> - inj->error_status);
> - return false;
> - }
> -
> - inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
> - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
> - inj->error_status);
> - }
> -
> - cmd = pci_get_word(dev->config + PCI_COMMAND);
> - if (inj->unsupported_request &&
> - !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) {
> - return false;
> - }
> - if (is_fatal) {
> - if (!((cmd & PCI_COMMAND_SERR) ||
> - (inj->devctl & PCI_EXP_DEVCTL_FERE))) {
> - return false;
> - }
> - inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN;
> - } else {
> - if (!((cmd & PCI_COMMAND_SERR) ||
> - (inj->devctl & PCI_EXP_DEVCTL_NFERE))) {
> - return false;
> - }
> - inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN;
> - }
> - return true;
> -}
> -
> -/*
> - * non-Function specific error must be recorded in all functions.
> - * It is the responsibility of the caller of this function.
> - * It is also caller's responsibility to determine which function should
> - * report the rerror.
> - *
> - * 6.2.4 Error Logging
> - * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations
> - * table 6-2: Flowchard Showing Sequence of Device Error Signaling and
> Logging
> - * Operations
> - */
> -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
> -{
> - uint8_t *aer_cap = NULL;
> - uint16_t devctl = 0;
> - uint16_t devsta = 0;
> - uint32_t error_status = err->status;
> - PCIEAERInject inj;
> -
> - if (!pci_is_express(dev)) {
> - return -ENOSYS;
> - }
> -
> - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
> - error_status &= PCI_ERR_COR_SUPPORTED;
> - } else {
> - error_status &= PCI_ERR_UNC_SUPPORTED;
> - }
> -
> - /* invalid status bit. one and only one bit must be set */
> - if (!error_status || (error_status & (error_status - 1))) {
> - return -EINVAL;
> - }
> -
> - if (dev->exp.aer_cap) {
> - uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
> - aer_cap = dev->config + dev->exp.aer_cap;
> - devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL);
> - devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA);
> - }
> -
> - inj.dev = dev;
> - inj.aer_cap = aer_cap;
> - inj.err = err;
> - inj.devctl = devctl;
> - inj.devsta = devsta;
> - inj.error_status = error_status;
> - inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) &&
> - err->status == PCI_ERR_UNC_UNSUP;
> - inj.log_overflow = false;
> -
> - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
> - if (!pcie_aer_inject_cor_error(&inj, 0, false)) {
> - return 0;
> - }
> - } else {
> - bool is_fatal =
> - pcie_aer_uncor_default_severity(error_status) ==
> - PCI_ERR_ROOT_CMD_FATAL_EN;
> - if (aer_cap) {
> - is_fatal =
> - error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER);
> - }
> - if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) {
> - inj.error_status = PCI_ERR_COR_ADV_NONFATAL;
> - if (!pcie_aer_inject_cor_error(&inj, error_status, true)) {
> - return 0;
> - }
> - } else {
> - if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) {
> - return 0;
> - }
> - }
> - }
> -
> - /* send up error message */
> - inj.msg.source_id = err->source_id;
> - pcie_aer_msg(dev, &inj.msg);
> -
> - if (inj.log_overflow) {
> - PCIEAERErr header_log_overflow = {
> - .status = PCI_ERR_COR_HL_OVERFLOW,
> - .flags = PCIE_AER_ERR_IS_CORRECTABLE,
> - };
> - int ret = pcie_aer_inject_error(dev, &header_log_overflow);
> - assert(!ret);
> - }
> - return 0;
> -}
> -
> -void pcie_aer_write_config(PCIDevice *dev,
> - uint32_t addr, uint32_t val, int len)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> - uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
> - uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap);
> - uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS);
> -
> - /* uncorrectable error */
> - if (!(uncorsta & first_error)) {
> - /* the bit that corresponds to the first error is cleared */
> - pcie_aer_clear_error(dev);
> - } else if (errcap & PCI_ERR_CAP_MHRE) {
> - /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared
> - * nothing should happen. So we have to revert the modification to
> - * the register.
> - */
> - pcie_aer_update_uncor_status(dev);
> - } else {
> - /* capability & control
> - * PCI_ERR_CAP_MHRE might be cleared, so clear of header log.
> - */
> - aer_log_clear_all_err(&dev->exp.aer_log);
> - }
> -}
> -
> -void pcie_aer_root_init(PCIDevice *dev)
> -{
> - uint16_t pos = dev->exp.aer_cap;
> -
> - pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND,
> - PCI_ERR_ROOT_CMD_EN_MASK);
> - pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
> - PCI_ERR_ROOT_STATUS_REPORT_MASK);
> - /* PCI_ERR_ROOT_IRQ is RO but devices change it using a
> - * device-specific method.
> - */
> - pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS,
> - ~PCI_ERR_ROOT_IRQ);
> -}
> -
> -void pcie_aer_root_reset(PCIDevice *dev)
> -{
> - uint8_t* aer_cap = dev->config + dev->exp.aer_cap;
> -
> - pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0);
> -
> - /*
> - * Advanced Error Interrupt Message Number in Root Error Status Register
> - * must be updated by chip dependent code because it's chip dependent
> - * which number is used.
> - */
> -}
> -
> -void pcie_aer_root_write_config(PCIDevice *dev,
> - uint32_t addr, uint32_t val, int len,
> - uint32_t root_cmd_prev)
> -{
> - uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
> - uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
> - uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status);
> - uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
> - /* 6.2.4.1.2 Interrupt Generation */
> - if (!msix_enabled(dev) && !msi_enabled(dev)) {
> - qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd &
> enabled_cmd));
> - return;
> - }
> -
> - if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) {
> - /* Send MSI on transition from false to true. */
> - return;
> - }
> -
> - pcie_aer_root_notify(dev);
> -}
> -
> -static const VMStateDescription vmstate_pcie_aer_err = {
> - .name = "PCIE_AER_ERROR",
> - .version_id = 1,
> - .minimum_version_id = 1,
> - .minimum_version_id_old = 1,
> - .fields = (VMStateField[]) {
> - VMSTATE_UINT32(status, PCIEAERErr),
> - VMSTATE_UINT16(source_id, PCIEAERErr),
> - VMSTATE_UINT16(flags, PCIEAERErr),
> - VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4),
> - VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4),
> - VMSTATE_END_OF_LIST()
> - }
> -};
> -
> -const VMStateDescription vmstate_pcie_aer_log = {
> - .name = "PCIE_AER_ERROR_LOG",
> - .version_id = 1,
> - .minimum_version_id = 1,
> - .minimum_version_id_old = 1,
> - .fields = (VMStateField[]) {
> - VMSTATE_UINT16(log_num, PCIEAERLog),
> - VMSTATE_UINT16(log_max, PCIEAERLog),
> - VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
> - vmstate_pcie_aer_err, PCIEAERErr),
> - VMSTATE_END_OF_LIST()
> - }
> -};
> -
> -void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
> -{
> - QDict *qdict;
> - int devfn;
> - assert(qobject_type(data) == QTYPE_QDICT);
> - qdict = qobject_to_qdict(data);
> -
> - devfn = (int)qdict_get_int(qdict, "devfn");
> - monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n",
> - qdict_get_str(qdict, "id"),
> - (int) qdict_get_int(qdict, "domain"),
> - (int) qdict_get_int(qdict, "bus"),
> - PCI_SLOT(devfn), PCI_FUNC(devfn));
> -}
> -
> -typedef struct PCIEAERErrorName {
> - const char *name;
> - uint32_t val;
> - bool correctable;
> -} PCIEAERErrorName;
> -
> -/*
> - * AER error name -> value conversion table
> - * This naming scheme is same to linux aer-injection tool.
> - */
> -static const struct PCIEAERErrorName pcie_aer_error_list[] = {
> - {
> - .name = "TRAIN",
> - .val = PCI_ERR_UNC_TRAIN,
> - .correctable = false,
> - }, {
> - .name = "DLP",
> - .val = PCI_ERR_UNC_DLP,
> - .correctable = false,
> - }, {
> - .name = "SDN",
> - .val = PCI_ERR_UNC_SDN,
> - .correctable = false,
> - }, {
> - .name = "POISON_TLP",
> - .val = PCI_ERR_UNC_POISON_TLP,
> - .correctable = false,
> - }, {
> - .name = "FCP",
> - .val = PCI_ERR_UNC_FCP,
> - .correctable = false,
> - }, {
> - .name = "COMP_TIME",
> - .val = PCI_ERR_UNC_COMP_TIME,
> - .correctable = false,
> - }, {
> - .name = "COMP_ABORT",
> - .val = PCI_ERR_UNC_COMP_ABORT,
> - .correctable = false,
> - }, {
> - .name = "UNX_COMP",
> - .val = PCI_ERR_UNC_UNX_COMP,
> - .correctable = false,
> - }, {
> - .name = "RX_OVER",
> - .val = PCI_ERR_UNC_RX_OVER,
> - .correctable = false,
> - }, {
> - .name = "MALF_TLP",
> - .val = PCI_ERR_UNC_MALF_TLP,
> - .correctable = false,
> - }, {
> - .name = "ECRC",
> - .val = PCI_ERR_UNC_ECRC,
> - .correctable = false,
> - }, {
> - .name = "UNSUP",
> - .val = PCI_ERR_UNC_UNSUP,
> - .correctable = false,
> - }, {
> - .name = "ACSV",
> - .val = PCI_ERR_UNC_ACSV,
> - .correctable = false,
> - }, {
> - .name = "INTN",
> - .val = PCI_ERR_UNC_INTN,
> - .correctable = false,
> - }, {
> - .name = "MCBTLP",
> - .val = PCI_ERR_UNC_MCBTLP,
> - .correctable = false,
> - }, {
> - .name = "ATOP_EBLOCKED",
> - .val = PCI_ERR_UNC_ATOP_EBLOCKED,
> - .correctable = false,
> - }, {
> - .name = "TLP_PRF_BLOCKED",
> - .val = PCI_ERR_UNC_TLP_PRF_BLOCKED,
> - .correctable = false,
> - }, {
> - .name = "RCVR",
> - .val = PCI_ERR_COR_RCVR,
> - .correctable = true,
> - }, {
> - .name = "BAD_TLP",
> - .val = PCI_ERR_COR_BAD_TLP,
> - .correctable = true,
> - }, {
> - .name = "BAD_DLLP",
> - .val = PCI_ERR_COR_BAD_DLLP,
> - .correctable = true,
> - }, {
> - .name = "REP_ROLL",
> - .val = PCI_ERR_COR_REP_ROLL,
> - .correctable = true,
> - }, {
> - .name = "REP_TIMER",
> - .val = PCI_ERR_COR_REP_TIMER,
> - .correctable = true,
> - }, {
> - .name = "ADV_NONFATAL",
> - .val = PCI_ERR_COR_ADV_NONFATAL,
> - .correctable = true,
> - }, {
> - .name = "INTERNAL",
> - .val = PCI_ERR_COR_INTERNAL,
> - .correctable = true,
> - }, {
> - .name = "HL_OVERFLOW",
> - .val = PCI_ERR_COR_HL_OVERFLOW,
> - .correctable = true,
> - },
> -};
> -
> -static int pcie_aer_parse_error_string(const char *error_name,
> - uint32_t *status, bool *correctable)
> -{
> - int i;
> -
> - for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) {
> - const PCIEAERErrorName *e = &pcie_aer_error_list[i];
> - if (strcmp(error_name, e->name)) {
> - continue;
> - }
> -
> - *status = e->val;
> - *correctable = e->correctable;
> - return 0;
> - }
> - return -EINVAL;
> -}
> -
> -int do_pcie_aer_inject_error(Monitor *mon,
> - const QDict *qdict, QObject **ret_data)
> -{
> - const char *id = qdict_get_str(qdict, "id");
> - const char *error_name;
> - uint32_t error_status;
> - bool correctable;
> - PCIDevice *dev;
> - PCIEAERErr err;
> - int ret;
> -
> - ret = pci_qdev_find_device(id, &dev);
> - if (ret < 0) {
> - monitor_printf(mon,
> - "id or pci device path is invalid or device not "
> - "found. %s\n", id);
> - return ret;
> - }
> - if (!pci_is_express(dev)) {
> - monitor_printf(mon, "the device doesn't support pci express. %s\n",
> - id);
> - return -ENOSYS;
> - }
> -
> - error_name = qdict_get_str(qdict, "error_status");
> - if (pcie_aer_parse_error_string(error_name, &error_status,
> &correctable)) {
> - char *e = NULL;
> - error_status = strtoul(error_name, &e, 0);
> - correctable = qdict_get_try_bool(qdict, "correctable", 0);
> - if (!e || *e != '\0') {
> - monitor_printf(mon, "invalid error status value. \"%s\"",
> - error_name);
> - return -EINVAL;
> - }
> - }
> - err.status = error_status;
> - err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn;
> -
> - err.flags = 0;
> - if (correctable) {
> - err.flags |= PCIE_AER_ERR_IS_CORRECTABLE;
> - }
> - if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) {
> - err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY;
> - }
> - if (qdict_haskey(qdict, "header0")) {
> - err.flags |= PCIE_AER_ERR_HEADER_VALID;
> - }
> - if (qdict_haskey(qdict, "prefix0")) {
> - err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT;
> - }
> -
> - err.header[0] = qdict_get_try_int(qdict, "header0", 0);
> - err.header[1] = qdict_get_try_int(qdict, "header1", 0);
> - err.header[2] = qdict_get_try_int(qdict, "header2", 0);
> - err.header[3] = qdict_get_try_int(qdict, "header3", 0);
> -
> - err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0);
> - err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0);
> - err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0);
> - err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0);
> -
> - ret = pcie_aer_inject_error(dev, &err);
> - *ret_data = qobject_from_jsonf("{'id': %s, "
> - "'domain': %d, 'bus': %d, 'devfn': %d, "
> - "'ret': %d}",
> - id,
> - pci_find_domain(dev->bus),
> - pci_bus_num(dev->bus), dev->devfn,
> - ret);
> - assert(*ret_data);
> -
> - return 0;
> -}
> diff --git a/hw/pcie_aer.h b/hw/pcie_aer.h
> deleted file mode 100644
> index 7539500..0000000
> --- a/hw/pcie_aer.h
> +++ /dev/null
> @@ -1,106 +0,0 @@
> -/*
> - * pcie_aer.h
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef QEMU_PCIE_AER_H
> -#define QEMU_PCIE_AER_H
> -
> -#include "hw.h"
> -
> -/* definitions which PCIExpressDevice uses */
> -
> -/* AER log */
> -struct PCIEAERLog {
> - /* This structure is saved/loaded.
> - So explicitly size them instead of unsigned int */
> -
> - /* the number of currently recorded log in log member */
> - uint16_t log_num;
> -
> - /*
> - * The maximum number of the log. Errors can be logged up to this.
> - *
> - * This is configurable property.
> - * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT
> - * to avoid unreasonable memory usage.
> - * I bet that 128 log size would be big enough, otherwise too many errors
> - * for system to function normaly. But could consecutive errors occur?
> - */
> -#define PCIE_AER_LOG_MAX_DEFAULT 8
> -#define PCIE_AER_LOG_MAX_LIMIT 128
> -#define PCIE_AER_LOG_MAX_UNSET 0xffff
> - uint16_t log_max;
> -
> - /* Error log. log_max-sized array */
> - PCIEAERErr *log;
> -};
> -
> -/* aer error message: error signaling message has only error sevirity and
> - source id. See 2.2.8.3 error signaling messages */
> -struct PCIEAERMsg {
> - /*
> - * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN
> - * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE}
> - */
> - uint32_t severity;
> -
> - uint16_t source_id; /* bdf */
> -};
> -
> -static inline bool
> -pcie_aer_msg_is_uncor(const PCIEAERMsg *msg)
> -{
> - return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN ||
> - msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN;
> -}
> -
> -/* error */
> -struct PCIEAERErr {
> - uint32_t status; /* error status bits */
> - uint16_t source_id; /* bdf */
> -
> -#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable
> */
> -#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal
> */
> -#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */
> -#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */
> - uint16_t flags;
> -
> - uint32_t header[4]; /* TLP header */
> - uint32_t prefix[4]; /* TLP header prefix */
> -};
> -
> -extern const VMStateDescription vmstate_pcie_aer_log;
> -
> -int pcie_aer_init(PCIDevice *dev, uint16_t offset);
> -void pcie_aer_exit(PCIDevice *dev);
> -void pcie_aer_write_config(PCIDevice *dev,
> - uint32_t addr, uint32_t val, int len);
> -
> -/* aer root port */
> -void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector);
> -void pcie_aer_root_init(PCIDevice *dev);
> -void pcie_aer_root_reset(PCIDevice *dev);
> -void pcie_aer_root_write_config(PCIDevice *dev,
> - uint32_t addr, uint32_t val, int len,
> - uint32_t root_cmd_prev);
> -
> -/* error injection */
> -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err);
> -
> -#endif /* QEMU_PCIE_AER_H */
> diff --git a/hw/pcie_host.c b/hw/pcie_host.c
> deleted file mode 100644
> index c257fb4..0000000
> --- a/hw/pcie_host.c
> +++ /dev/null
> @@ -1,161 +0,0 @@
> -/*
> - * pcie_host.c
> - * utility functions for pci express host bridge.
> - *
> - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "hw.h"
> -#include "pci.h"
> -#include "pcie_host.h"
> -#include "exec-memory.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_dev_find_by_mmcfg_addr(PCIBus *s,
> - uint32_t mmcfg_addr)
> -{
> - return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr),
> - PCIE_MMCFG_DEVFN(mmcfg_addr));
> -}
> -
> -static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr,
> - uint64_t val, unsigned len)
> -{
> - PCIExpressHost *e = opaque;
> - PCIBus *s = e->pci.bus;
> - PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
> - uint32_t addr;
> - uint32_t limit;
> -
> - if (!pci_dev) {
> - return;
> - }
> - addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
> - limit = pci_config_size(pci_dev);
> - if (limit <= addr) {
> - /* conventional pci device can be behind pcie-to-pci bridge.
> - 256 <= addr < 4K has no effects. */
> - return;
> - }
> - pci_host_config_write_common(pci_dev, addr, limit, val, len);
> -}
> -
> -static uint64_t pcie_mmcfg_data_read(void *opaque,
> - hwaddr mmcfg_addr,
> - unsigned len)
> -{
> - PCIExpressHost *e = opaque;
> - PCIBus *s = e->pci.bus;
> - PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
> - uint32_t addr;
> - uint32_t limit;
> -
> - if (!pci_dev) {
> - return ~0x0;
> - }
> - addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
> - limit = pci_config_size(pci_dev);
> - if (limit <= addr) {
> - /* conventional pci device can be behind pcie-to-pci bridge.
> - 256 <= addr < 4K has no effects. */
> - return ~0x0;
> - }
> - return pci_host_config_read_common(pci_dev, addr, limit, len);
> -}
> -
> -static const MemoryRegionOps pcie_mmcfg_ops = {
> - .read = pcie_mmcfg_data_read,
> - .write = pcie_mmcfg_data_write,
> - .endianness = DEVICE_NATIVE_ENDIAN,
> -};
> -
> -/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */
> -#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL)
> -
> -int pcie_host_init(PCIExpressHost *e)
> -{
> - e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
> -
> - return 0;
> -}
> -
> -void pcie_host_mmcfg_unmap(PCIExpressHost *e)
> -{
> - if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
> - memory_region_del_subregion(get_system_memory(), &e->mmio);
> - memory_region_destroy(&e->mmio);
> - e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
> - }
> -}
> -
> -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr,
> - uint32_t size)
> -{
> - assert(!(size & (size - 1))); /* power of 2 */
> - assert(size >= PCIE_MMCFG_SIZE_MIN);
> - assert(size <= PCIE_MMCFG_SIZE_MAX);
> - e->size = size;
> - memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg",
> e->size);
> - e->base_addr = addr;
> - memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
> -}
> -
> -void pcie_host_mmcfg_update(PCIExpressHost *e,
> - int enable,
> - hwaddr addr,
> - uint32_t size)
> -{
> - pcie_host_mmcfg_unmap(e);
> - if (enable) {
> - pcie_host_mmcfg_map(e, addr, size);
> - }
> -}
> -
> -static const TypeInfo pcie_host_type_info = {
> - .name = TYPE_PCIE_HOST_BRIDGE,
> - .parent = TYPE_PCI_HOST_BRIDGE,
> - .abstract = true,
> - .instance_size = sizeof(PCIExpressHost),
> -};
> -
> -static void pcie_host_register_types(void)
> -{
> - type_register_static(&pcie_host_type_info);
> -}
> -
> -type_init(pcie_host_register_types)
> diff --git a/hw/pcie_host.h b/hw/pcie_host.h
> deleted file mode 100644
> index 3921935..0000000
> --- a/hw/pcie_host.h
> +++ /dev/null
> @@ -1,54 +0,0 @@
> -/*
> - * pcie_host.h
> - *
> - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef PCIE_HOST_H
> -#define PCIE_HOST_H
> -
> -#include "pci_host.h"
> -#include "memory.h"
> -
> -#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge"
> -#define PCIE_HOST_BRIDGE(obj) \
> - OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE)
> -
> -struct PCIExpressHost {
> - PCIHostState pci;
> -
> - /* express part */
> -
> - /* base address where MMCONFIG area is mapped. */
> - hwaddr base_addr;
> -
> - /* the size of MMCONFIG area. It's host bridge dependent */
> - hwaddr size;
> -
> - /* MMCONFIG mmio area */
> - MemoryRegion mmio;
> -};
> -
> -int pcie_host_init(PCIExpressHost *e);
> -void pcie_host_mmcfg_unmap(PCIExpressHost *e);
> -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size);
> -void pcie_host_mmcfg_update(PCIExpressHost *e,
> - int enable,
> - hwaddr addr,
> - uint32_t size);
> -
> -#endif /* PCIE_HOST_H */
> diff --git a/hw/pcie_port.c b/hw/pcie_port.c
> deleted file mode 100644
> index d6350e5..0000000
> --- a/hw/pcie_port.c
> +++ /dev/null
> @@ -1,114 +0,0 @@
> -/*
> - * pcie_port.c
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "pcie_port.h"
> -
> -void pcie_port_init_reg(PCIDevice *d)
> -{
> - /* Unlike pci bridge,
> - 66MHz and fast back to back don't apply to pci express port. */
> - pci_set_word(d->config + PCI_STATUS, 0);
> - pci_set_word(d->config + PCI_SEC_STATUS, 0);
> -
> - /* Unlike conventional pci bridge, some bits are hardwired to 0. */
> - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
> - PCI_BRIDGE_CTL_PARITY |
> - PCI_BRIDGE_CTL_ISA |
> - PCI_BRIDGE_CTL_VGA |
> - PCI_BRIDGE_CTL_SERR |
> - PCI_BRIDGE_CTL_BUS_RESET);
> -}
> -
> -/**************************************************************************
> - * (chassis number, pcie physical slot number) -> pcie slot conversion
> - */
> -struct PCIEChassis {
> - uint8_t number;
> -
> - QLIST_HEAD(, PCIESlot) slots;
> - QLIST_ENTRY(PCIEChassis) next;
> -};
> -
> -static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
> -
> -static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
> -{
> - struct PCIEChassis *c;
> - QLIST_FOREACH(c, &chassis, next) {
> - if (c->number == chassis_number) {
> - break;
> - }
> - }
> - return c;
> -}
> -
> -void pcie_chassis_create(uint8_t chassis_number)
> -{
> - struct PCIEChassis *c;
> - c = pcie_chassis_find(chassis_number);
> - if (c) {
> - return;
> - }
> - c = g_malloc0(sizeof(*c));
> - c->number = chassis_number;
> - QLIST_INIT(&c->slots);
> - QLIST_INSERT_HEAD(&chassis, c, next);
> -}
> -
> -static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
> - uint8_t slot)
> -{
> - PCIESlot *s;
> - QLIST_FOREACH(s, &c->slots, next) {
> - if (s->slot == slot) {
> - break;
> - }
> - }
> - return s;
> -}
> -
> -PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
> -{
> - struct PCIEChassis *c;
> - c = pcie_chassis_find(chassis_number);
> - if (!c) {
> - return NULL;
> - }
> - return pcie_chassis_find_slot_with_chassis(c, slot);
> -}
> -
> -int pcie_chassis_add_slot(struct PCIESlot *slot)
> -{
> - struct PCIEChassis *c;
> - c = pcie_chassis_find(slot->chassis);
> - if (!c) {
> - return -ENODEV;
> - }
> - if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
> - return -EBUSY;
> - }
> - QLIST_INSERT_HEAD(&c->slots, slot, next);
> - return 0;
> -}
> -
> -void pcie_chassis_del_slot(PCIESlot *s)
> -{
> - QLIST_REMOVE(s, next);
> -}
> diff --git a/hw/pcie_port.h b/hw/pcie_port.h
> deleted file mode 100644
> index 3709583..0000000
> --- a/hw/pcie_port.h
> +++ /dev/null
> @@ -1,51 +0,0 @@
> -/*
> - * pcie_port.h
> - *
> - * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
> - * 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, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef QEMU_PCIE_PORT_H
> -#define QEMU_PCIE_PORT_H
> -
> -#include "pci_bridge.h"
> -#include "pci_internals.h"
> -
> -struct PCIEPort {
> - PCIBridge br;
> -
> - /* pci express switch port */
> - uint8_t port;
> -};
> -
> -void pcie_port_init_reg(PCIDevice *d);
> -
> -struct PCIESlot {
> - PCIEPort port;
> -
> - /* pci express switch port with slot */
> - uint8_t chassis;
> - uint16_t slot;
> - QLIST_ENTRY(PCIESlot) next;
> -};
> -
> -void pcie_chassis_create(uint8_t chassis_number);
> -void pcie_main_chassis_create(void);
> -PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
> -int pcie_chassis_add_slot(struct PCIESlot *slot);
> -void pcie_chassis_del_slot(PCIESlot *s);
> -
> -#endif /* QEMU_PCIE_PORT_H */
> diff --git a/hw/pcie_regs.h b/hw/pcie_regs.h
> deleted file mode 100644
> index 4d123d9..0000000
> --- a/hw/pcie_regs.h
> +++ /dev/null
> @@ -1,156 +0,0 @@
> -/*
> - * constants for pcie configurations space from pci express spec.
> - *
> - * TODO:
> - * Those constants and macros should go to Linux pci_regs.h
> - * Once they're merged, they will go away.
> - */
> -#ifndef QEMU_PCIE_REGS_H
> -#define QEMU_PCIE_REGS_H
> -
> -
> -/* express capability */
> -
> -#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2
> */
> -#define PCI_EXT_CAP_VER_SHIFT 16
> -#define PCI_EXT_CAP_NEXT_SHIFT 20
> -#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT)
> -
> -#define PCI_EXT_CAP(id, ver, next) \
> - ((id) | \
> - ((ver) << PCI_EXT_CAP_VER_SHIFT) | \
> - ((next) << PCI_EXT_CAP_NEXT_SHIFT))
> -
> -#define PCI_EXT_CAP_ALIGN 4
> -#define PCI_EXT_CAP_ALIGNUP(x) \
> - (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1))
> -
> -/* PCI_EXP_FLAGS */
> -#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */
> -#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1)
> -#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1)
> -
> -
> -/* PCI_EXP_LINK{CAP, STA} */
> -/* link speed */
> -#define PCI_EXP_LNK_LS_25 1
> -
> -#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1)
> -#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT)
> -
> -/* PCI_EXP_LINKCAP */
> -#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1)
> -#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
> -
> -#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1)
> -
> -#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1)
> -
> -#define PCI_EXP_SLTCTL_IND_RESERVED 0x0
> -#define PCI_EXP_SLTCTL_IND_ON 0x1
> -#define PCI_EXP_SLTCTL_IND_BLINK 0x2
> -#define PCI_EXP_SLTCTL_IND_OFF 0x3
> -#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1)
> -#define PCI_EXP_SLTCTL_AIC_OFF \
> - (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT)
> -
> -#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1)
> -#define PCI_EXP_SLTCTL_PIC_OFF \
> - (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT)
> -
> -#define PCI_EXP_SLTCTL_SUPPORTED \
> - (PCI_EXP_SLTCTL_ABPE | \
> - PCI_EXP_SLTCTL_PDCE | \
> - PCI_EXP_SLTCTL_CCIE | \
> - PCI_EXP_SLTCTL_HPIE | \
> - PCI_EXP_SLTCTL_AIC | \
> - PCI_EXP_SLTCTL_PCC | \
> - PCI_EXP_SLTCTL_EIC)
> -
> -#define PCI_EXP_DEVCAP2_EFF 0x100000
> -#define PCI_EXP_DEVCAP2_EETLPP 0x200000
> -
> -#define PCI_EXP_DEVCTL2_EETLPPB 0x80
> -
> -/* ARI */
> -#define PCI_ARI_VER 1
> -#define PCI_ARI_SIZEOF 8
> -
> -/* AER */
> -#define PCI_ERR_VER 2
> -#define PCI_ERR_SIZEOF 0x48
> -
> -#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */
> -#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */
> -#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */
> -#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */
> -#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress
> blocked */
> -#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix
> Blocked */
> -#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory
> Non-Fatal */
> -#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected
> Internal */
> -#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long
> Overflow */
> -#define PCI_ERR_CAP_FEP_MASK 0x0000001f
> -#define PCI_ERR_CAP_MHRC 0x00000200
> -#define PCI_ERR_CAP_MHRE 0x00000400
> -#define PCI_ERR_CAP_TLP 0x00000800
> -
> -#define PCI_ERR_HEADER_LOG_SIZE 16
> -#define PCI_ERR_TLP_PREFIX_LOG 0x38
> -#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16
> -
> -#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000
> -
> -/* aer root error command/status */
> -#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \
> - PCI_ERR_ROOT_CMD_NONFATAL_EN | \
> - PCI_ERR_ROOT_CMD_FATAL_EN)
> -
> -#define PCI_ERR_ROOT_IRQ_MAX 32
> -#define PCI_ERR_ROOT_IRQ 0xf8000000
> -#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1)
> -#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \
> - PCI_ERR_ROOT_MULTI_COR_RCV | \
> - PCI_ERR_ROOT_UNCOR_RCV | \
> - PCI_ERR_ROOT_MULTI_UNCOR_RCV | \
> - PCI_ERR_ROOT_FIRST_FATAL | \
> - PCI_ERR_ROOT_NONFATAL_RCV | \
> - PCI_ERR_ROOT_FATAL_RCV)
> -
> -#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \
> - PCI_ERR_UNC_SDN | \
> - PCI_ERR_UNC_POISON_TLP | \
> - PCI_ERR_UNC_FCP | \
> - PCI_ERR_UNC_COMP_TIME | \
> - PCI_ERR_UNC_COMP_ABORT | \
> - PCI_ERR_UNC_UNX_COMP | \
> - PCI_ERR_UNC_RX_OVER | \
> - PCI_ERR_UNC_MALF_TLP | \
> - PCI_ERR_UNC_ECRC | \
> - PCI_ERR_UNC_UNSUP | \
> - PCI_ERR_UNC_ACSV | \
> - PCI_ERR_UNC_INTN | \
> - PCI_ERR_UNC_MCBTLP | \
> - PCI_ERR_UNC_ATOP_EBLOCKED | \
> - PCI_ERR_UNC_TLP_PRF_BLOCKED)
> -
> -#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \
> - PCI_ERR_UNC_SDN | \
> - PCI_ERR_UNC_FCP | \
> - PCI_ERR_UNC_RX_OVER | \
> - PCI_ERR_UNC_MALF_TLP | \
> - PCI_ERR_UNC_INTN)
> -
> -#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \
> - PCI_ERR_COR_BAD_TLP | \
> - PCI_ERR_COR_BAD_DLLP | \
> - PCI_ERR_COR_REP_ROLL | \
> - PCI_ERR_COR_REP_TIMER | \
> - PCI_ERR_COR_ADV_NONFATAL | \
> - PCI_ERR_COR_INTERNAL | \
> - PCI_ERR_COR_HL_OVERFLOW)
> -
> -#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \
> - PCI_ERR_COR_INTERNAL | \
> - PCI_ERR_COR_HL_OVERFLOW)
> -
> -#endif /* QEMU_PCIE_REGS_H */
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index 8fe2123..cb7cf8f 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -10,7 +10,7 @@ obj-y += ppc_newworld.o
> # IBM pSeries (sPAPR)
> obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
> obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
> -obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o
> +obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o
> obj-$(CONFIG_PSERIES) += spapr_events.o
> # PowerPC 4xx boards
> obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
> diff --git a/hw/shpc.c b/hw/shpc.c
> deleted file mode 100644
> index 4597bbd..0000000
> --- a/hw/shpc.c
> +++ /dev/null
> @@ -1,681 +0,0 @@
> -#include <strings.h>
> -#include <stdint.h>
> -#include "range.h"
> -#include "range.h"
> -#include "shpc.h"
> -#include "pci.h"
> -#include "pci_internals.h"
> -#include "msi.h"
> -
> -/* TODO: model power only and disabled slot states. */
> -/* TODO: handle SERR and wakeups */
> -/* TODO: consider enabling 66MHz support */
> -
> -/* TODO: remove fully only on state DISABLED and LED off.
> - * track state to properly record this. */
> -
> -/* SHPC Working Register Set */
> -#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */
> -#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */
> -#define SHPC_SLOTS_66 0x08 /* 4 bytes. */
> -#define SHPC_NSLOTS 0x0C /* 1 byte */
> -#define SHPC_FIRST_DEV 0x0D /* 1 byte */
> -#define SHPC_PHYS_SLOT 0x0E /* 2 byte */
> -#define SHPC_PHYS_NUM_MAX 0x7ff
> -#define SHPC_PHYS_NUM_UP 0x2000
> -#define SHPC_PHYS_MRL 0x4000
> -#define SHPC_PHYS_BUTTON 0x8000
> -#define SHPC_SEC_BUS 0x10 /* 2 bytes */
> -#define SHPC_SEC_BUS_33 0x0
> -#define SHPC_SEC_BUS_66 0x1 /* Unused */
> -#define SHPC_SEC_BUS_MASK 0x7
> -#define SHPC_MSI_CTL 0x12 /* 1 byte */
> -#define SHPC_PROG_IFC 0x13 /* 1 byte */
> -#define SHPC_PROG_IFC_1_0 0x1
> -#define SHPC_CMD_CODE 0x14 /* 1 byte */
> -#define SHPC_CMD_TRGT 0x15 /* 1 byte */
> -#define SHPC_CMD_TRGT_MIN 0x1
> -#define SHPC_CMD_TRGT_MAX 0x1f
> -#define SHPC_CMD_STATUS 0x16 /* 2 bytes */
> -#define SHPC_CMD_STATUS_BUSY 0x1
> -#define SHPC_CMD_STATUS_MRL_OPEN 0x2
> -#define SHPC_CMD_STATUS_INVALID_CMD 0x4
> -#define SHPC_CMD_STATUS_INVALID_MODE 0x8
> -#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */
> -#define SHPC_INT_COMMAND 0x1
> -#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */
> -#define SHPC_SERR_INT 0x20 /* 4 bytes */
> -#define SHPC_INT_DIS 0x1
> -#define SHPC_SERR_DIS 0x2
> -#define SHPC_CMD_INT_DIS 0x4
> -#define SHPC_ARB_SERR_DIS 0x8
> -#define SHPC_CMD_DETECTED 0x10000
> -#define SHPC_ARB_DETECTED 0x20000
> - /* 4 bytes * slot # (start from 0) */
> -#define SHPC_SLOT_REG(s) (0x24 + (s) * 4)
> - /* 2 bytes */
> -#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s))
> -
> -/* Same slot state masks are used for command and status registers */
> -#define SHPC_SLOT_STATE_MASK 0x03
> -#define SHPC_SLOT_STATE_SHIFT \
> - (ffs(SHPC_SLOT_STATE_MASK) - 1)
> -
> -#define SHPC_STATE_NO 0x0
> -#define SHPC_STATE_PWRONLY 0x1
> -#define SHPC_STATE_ENABLED 0x2
> -#define SHPC_STATE_DISABLED 0x3
> -
> -#define SHPC_SLOT_PWR_LED_MASK 0xC
> -#define SHPC_SLOT_PWR_LED_SHIFT \
> - (ffs(SHPC_SLOT_PWR_LED_MASK) - 1)
> -#define SHPC_SLOT_ATTN_LED_MASK 0x30
> -#define SHPC_SLOT_ATTN_LED_SHIFT \
> - (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1)
> -
> -#define SHPC_LED_NO 0x0
> -#define SHPC_LED_ON 0x1
> -#define SHPC_LED_BLINK 0x2
> -#define SHPC_LED_OFF 0x3
> -
> -#define SHPC_SLOT_STATUS_PWR_FAULT 0x40
> -#define SHPC_SLOT_STATUS_BUTTON 0x80
> -#define SHPC_SLOT_STATUS_MRL_OPEN 0x100
> -#define SHPC_SLOT_STATUS_66 0x200
> -#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00
> -#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3
> -#define SHPC_SLOT_STATUS_PRSNT_25W 0x1
> -#define SHPC_SLOT_STATUS_PRSNT_15W 0x2
> -#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0
> -
> -#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000
> -
> -
> - /* 1 byte */
> -#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s))
> - /* 1 byte */
> -#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s))
> -#define SHPC_SLOT_EVENT_PRESENCE 0x01
> -#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02
> -#define SHPC_SLOT_EVENT_BUTTON 0x04
> -#define SHPC_SLOT_EVENT_MRL 0x08
> -#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10
> -/* Bits below are used for Serr/Int disable only */
> -#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20
> -#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40
> -
> -#define SHPC_MIN_SLOTS 1
> -#define SHPC_MAX_SLOTS 31
> -#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots)
> -
> -/* SHPC Slot identifiers */
> -
> -/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0,
> - and give the rest of them physical *and* pci numbers starting from 1, so
> - they match logical numbers. Note: this means that multiple slots must
> have
> - different chassis number values, to make chassis+physical slot unique.
> - TODO: make this configurable? */
> -#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1)
> -#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1)
> -#define SHPC_IDX_TO_PCI(slot) ((slot) + 1)
> -#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1)
> -#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1)
> -
> -static int roundup_pow_of_two(int x)
> -{
> - x |= (x >> 1);
> - x |= (x >> 2);
> - x |= (x >> 4);
> - x |= (x >> 8);
> - x |= (x >> 16);
> - return x + 1;
> -}
> -
> -static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk)
> -{
> - uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
> - return (pci_get_word(status) & msk) >> (ffs(msk) - 1);
> -}
> -
> -static void shpc_set_status(SHPCDevice *shpc,
> - int slot, uint8_t value, uint16_t msk)
> -{
> - uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
> - pci_word_test_and_clear_mask(status, msk);
> - pci_word_test_and_set_mask(status, value << (ffs(msk) - 1));
> -}
> -
> -static void shpc_interrupt_update(PCIDevice *d)
> -{
> - SHPCDevice *shpc = d->shpc;
> - int slot;
> - int level = 0;
> - uint32_t serr_int;
> - uint32_t int_locator = 0;
> -
> - /* Update interrupt locator register */
> - for (slot = 0; slot < shpc->nslots; ++slot) {
> - uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)];
> - uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d,
> slot)];
> - uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot);
> - if (event & ~disable) {
> - int_locator |= mask;
> - }
> - }
> - serr_int = pci_get_long(shpc->config + SHPC_SERR_INT);
> - if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) {
> - int_locator |= SHPC_INT_COMMAND;
> - }
> - pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator);
> - level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0;
> - if (msi_enabled(d) && shpc->msi_requested != level)
> - msi_notify(d, 0);
> - else
> - qemu_set_irq(d->irq[0], level);
> - shpc->msi_requested = level;
> -}
> -
> -static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed)
> -{
> - switch (speed) {
> - case SHPC_SEC_BUS_33:
> - shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK;
> - shpc->config[SHPC_SEC_BUS] |= speed;
> - break;
> - default:
> - pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
> - SHPC_CMD_STATUS_INVALID_MODE);
> - }
> -}
> -
> -void shpc_reset(PCIDevice *d)
> -{
> - SHPCDevice *shpc = d->shpc;
> - int nslots = shpc->nslots;
> - int i;
> - memset(shpc->config, 0, SHPC_SIZEOF(d));
> - pci_set_byte(shpc->config + SHPC_NSLOTS, nslots);
> - pci_set_long(shpc->config + SHPC_SLOTS_33, nslots);
> - pci_set_long(shpc->config + SHPC_SLOTS_66, 0);
> - pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0));
> - pci_set_word(shpc->config + SHPC_PHYS_SLOT,
> - SHPC_IDX_TO_PHYSICAL(0) |
> - SHPC_PHYS_NUM_UP |
> - SHPC_PHYS_MRL |
> - SHPC_PHYS_BUTTON);
> - pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS |
> - SHPC_SERR_DIS |
> - SHPC_CMD_INT_DIS |
> - SHPC_ARB_SERR_DIS);
> - pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0);
> - pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33);
> - for (i = 0; i < shpc->nslots; ++i) {
> - pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
> - SHPC_SLOT_EVENT_PRESENCE |
> - SHPC_SLOT_EVENT_ISOLATED_FAULT |
> - SHPC_SLOT_EVENT_BUTTON |
> - SHPC_SLOT_EVENT_MRL |
> - SHPC_SLOT_EVENT_CONNECTED_FAULT |
> - SHPC_SLOT_EVENT_MRL_SERR_DIS |
> - SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
> - if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) {
> - shpc_set_status(shpc, i, SHPC_STATE_ENABLED,
> SHPC_SLOT_STATE_MASK);
> - shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN);
> - shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W,
> - SHPC_SLOT_STATUS_PRSNT_MASK);
> - shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK);
> - } else {
> - shpc_set_status(shpc, i, SHPC_STATE_DISABLED,
> SHPC_SLOT_STATE_MASK);
> - shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN);
> - shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY,
> - SHPC_SLOT_STATUS_PRSNT_MASK);
> - shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK);
> - }
> - shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66);
> - }
> - shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33);
> - shpc->msi_requested = 0;
> - shpc_interrupt_update(d);
> -}
> -
> -static void shpc_invalid_command(SHPCDevice *shpc)
> -{
> - pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
> - SHPC_CMD_STATUS_INVALID_CMD);
> -}
> -
> -static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
> -{
> - int devfn;
> - int pci_slot = SHPC_IDX_TO_PCI(slot);
> - for (devfn = PCI_DEVFN(pci_slot, 0);
> - devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1);
> - ++devfn) {
> - PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
> - if (affected_dev) {
> - qdev_free(&affected_dev->qdev);
> - }
> - }
> -}
> -
> -static void shpc_slot_command(SHPCDevice *shpc, uint8_t target,
> - uint8_t state, uint8_t power, uint8_t attn)
> -{
> - uint8_t current_state;
> - int slot = SHPC_LOGICAL_TO_IDX(target);
> - if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) {
> - shpc_invalid_command(shpc);
> - return;
> - }
> - current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
> - if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) {
> - shpc_invalid_command(shpc);
> - return;
> - }
> -
> - switch (power) {
> - case SHPC_LED_NO:
> - break;
> - default:
> - /* TODO: send event to monitor */
> - shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK);
> - }
> - switch (attn) {
> - case SHPC_LED_NO:
> - break;
> - default:
> - /* TODO: send event to monitor */
> - shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK);
> - }
> -
> - if ((current_state == SHPC_STATE_DISABLED && state ==
> SHPC_STATE_PWRONLY) ||
> - (current_state == SHPC_STATE_DISABLED && state ==
> SHPC_STATE_ENABLED)) {
> - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
> - } else if ((current_state == SHPC_STATE_ENABLED ||
> - current_state == SHPC_STATE_PWRONLY) &&
> - state == SHPC_STATE_DISABLED) {
> - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
> - power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
> - /* TODO: track what monitor requested. */
> - /* Look at LED to figure out whether it's ok to remove the device. */
> - if (power == SHPC_LED_OFF) {
> - shpc_free_devices_in_slot(shpc, slot);
> - shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
> - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
> - SHPC_SLOT_STATUS_PRSNT_MASK);
> - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
> - SHPC_SLOT_EVENT_BUTTON |
> - SHPC_SLOT_EVENT_MRL |
> - SHPC_SLOT_EVENT_PRESENCE;
> - }
> - }
> -}
> -
> -static void shpc_command(SHPCDevice *shpc)
> -{
> - uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE);
> - uint8_t speed;
> - uint8_t target;
> - uint8_t attn;
> - uint8_t power;
> - uint8_t state;
> - int i;
> -
> - /* Clear status from the previous command. */
> - pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS,
> - SHPC_CMD_STATUS_BUSY |
> - SHPC_CMD_STATUS_MRL_OPEN |
> - SHPC_CMD_STATUS_INVALID_CMD |
> - SHPC_CMD_STATUS_INVALID_MODE);
> - switch (code) {
> - case 0x00 ... 0x3f:
> - target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX;
> - state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT;
> - power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT;
> - attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT;
> - shpc_slot_command(shpc, target, state, power, attn);
> - break;
> - case 0x40 ... 0x47:
> - speed = code & SHPC_SEC_BUS_MASK;
> - shpc_set_sec_bus_speed(shpc, speed);
> - break;
> - case 0x48:
> - /* Power only all slots */
> - /* first verify no slots are enabled */
> - for (i = 0; i < shpc->nslots; ++i) {
> - state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
> - if (state == SHPC_STATE_ENABLED) {
> - shpc_invalid_command(shpc);
> - goto done;
> - }
> - }
> - for (i = 0; i < shpc->nslots; ++i) {
> - if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
> - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
> - SHPC_STATE_PWRONLY, SHPC_LED_ON,
> SHPC_LED_NO);
> - } else {
> - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
> - SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
> - }
> - }
> - break;
> - case 0x49:
> - /* Enable all slots */
> - /* TODO: Spec says this shall fail if some are already enabled.
> - * This doesn't make sense - why not? a spec bug? */
> - for (i = 0; i < shpc->nslots; ++i) {
> - state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
> - if (state == SHPC_STATE_ENABLED) {
> - shpc_invalid_command(shpc);
> - goto done;
> - }
> - }
> - for (i = 0; i < shpc->nslots; ++i) {
> - if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
> - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
> - SHPC_STATE_ENABLED, SHPC_LED_ON,
> SHPC_LED_NO);
> - } else {
> - shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
> - SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
> - }
> - }
> - break;
> - default:
> - shpc_invalid_command(shpc);
> - break;
> - }
> -done:
> - pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT,
> SHPC_CMD_DETECTED);
> -}
> -
> -static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l)
> -{
> - SHPCDevice *shpc = d->shpc;
> - int i;
> - if (addr >= SHPC_SIZEOF(d)) {
> - return;
> - }
> - l = MIN(l, SHPC_SIZEOF(d) - addr);
> -
> - /* TODO: code duplicated from pci.c */
> - for (i = 0; i < l; val >>= 8, ++i) {
> - unsigned a = addr + i;
> - uint8_t wmask = shpc->wmask[a];
> - uint8_t w1cmask = shpc->w1cmask[a];
> - assert(!(wmask & w1cmask));
> - shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask);
> - shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
> - }
> - if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) {
> - shpc_command(shpc);
> - }
> - shpc_interrupt_update(d);
> -}
> -
> -static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l)
> -{
> - uint64_t val = 0x0;
> - if (addr >= SHPC_SIZEOF(d)) {
> - return val;
> - }
> - l = MIN(l, SHPC_SIZEOF(d) - addr);
> - memcpy(&val, d->shpc->config + addr, l);
> - return val;
> -}
> -
> -/* SHPC Bridge Capability */
> -#define SHPC_CAP_LENGTH 0x08
> -#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */
> -#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */
> -#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */
> -#define SHPC_CAP_CSP_MASK 0x4
> -#define SHPC_CAP_CIP_MASK 0x8
> -
> -static uint8_t shpc_cap_dword(PCIDevice *d)
> -{
> - return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT);
> -}
> -
> -/* Update dword data capability register */
> -static void shpc_cap_update_dword(PCIDevice *d)
> -{
> - unsigned data;
> - data = shpc_read(d, shpc_cap_dword(d) * 4, 4);
> - pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data);
> -}
> -
> -/* Add SHPC capability to the config space for the device. */
> -static int shpc_cap_add_config(PCIDevice *d)
> -{
> - uint8_t *config;
> - int config_offset;
> - config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC,
> - 0, SHPC_CAP_LENGTH);
> - if (config_offset < 0) {
> - return config_offset;
> - }
> - config = d->config + config_offset;
> -
> - pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0);
> - pci_set_byte(config + SHPC_CAP_CxP, 0);
> - pci_set_long(config + SHPC_CAP_DWORD_DATA, 0);
> - d->shpc->cap = config_offset;
> - /* Make dword select and data writeable. */
> - pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
> - pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
> - return 0;
> -}
> -
> -static uint64_t shpc_mmio_read(void *opaque, hwaddr addr,
> - unsigned size)
> -{
> - return shpc_read(opaque, addr, size);
> -}
> -
> -static void shpc_mmio_write(void *opaque, hwaddr addr,
> - uint64_t val, unsigned size)
> -{
> - shpc_write(opaque, addr, val, size);
> -}
> -
> -static const MemoryRegionOps shpc_mmio_ops = {
> - .read = shpc_mmio_read,
> - .write = shpc_mmio_write,
> - .endianness = DEVICE_LITTLE_ENDIAN,
> - .valid = {
> - /* SHPC ECN requires dword accesses, but the original 1.0 spec
> doesn't.
> - * It's easier to suppport all sizes than worry about it. */
> - .min_access_size = 1,
> - .max_access_size = 4,
> - },
> -};
> -
> -static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev,
> - PCIHotplugState hotplug_state)
> -{
> - int pci_slot = PCI_SLOT(affected_dev->devfn);
> - uint8_t state;
> - uint8_t led;
> - PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
> - SHPCDevice *shpc = d->shpc;
> - int slot = SHPC_PCI_TO_IDX(pci_slot);
> - if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) {
> - error_report("Unsupported PCI slot %d for standard hotplug "
> - "controller. Valid slots are between %d and %d.",
> - pci_slot, SHPC_IDX_TO_PCI(0),
> - SHPC_IDX_TO_PCI(shpc->nslots) - 1);
> - return -1;
> - }
> - /* Don't send event when device is enabled during qemu machine creation:
> - * it is present on boot, no hotplug event is necessary. We do send an
> - * event when the device is disabled later. */
> - if (hotplug_state == PCI_COLDPLUG_ENABLED) {
> - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
> - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
> - SHPC_SLOT_STATUS_PRSNT_MASK);
> - return 0;
> - }
> - if (hotplug_state == PCI_HOTPLUG_DISABLED) {
> - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
> - state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
> - led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
> - if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
> - shpc_free_devices_in_slot(shpc, slot);
> - shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
> - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
> - SHPC_SLOT_STATUS_PRSNT_MASK);
> - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
> - SHPC_SLOT_EVENT_MRL |
> - SHPC_SLOT_EVENT_PRESENCE;
> - }
> - } else {
> - /* This could be a cancellation of the previous removal.
> - * We check MRL state to figure out. */
> - if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
> - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
> - shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
> - SHPC_SLOT_STATUS_PRSNT_MASK);
> - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
> - SHPC_SLOT_EVENT_BUTTON |
> - SHPC_SLOT_EVENT_MRL |
> - SHPC_SLOT_EVENT_PRESENCE;
> - } else {
> - /* Press attention button to cancel removal */
> - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
> - SHPC_SLOT_EVENT_BUTTON;
> - }
> - }
> - shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
> - shpc_interrupt_update(d);
> - return 0;
> -}
> -
> -/* Initialize the SHPC structure in bridge's BAR. */
> -int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned
> offset)
> -{
> - int i, ret;
> - int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */
> - SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc));
> - shpc->sec_bus = sec_bus;
> - ret = shpc_cap_add_config(d);
> - if (ret) {
> - g_free(d->shpc);
> - return ret;
> - }
> - if (nslots < SHPC_MIN_SLOTS) {
> - return 0;
> - }
> - if (nslots > SHPC_MAX_SLOTS ||
> - SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) {
> - /* TODO: report an error mesage that makes sense. */
> - return -EINVAL;
> - }
> - shpc->nslots = nslots;
> - shpc->config = g_malloc0(SHPC_SIZEOF(d));
> - shpc->cmask = g_malloc0(SHPC_SIZEOF(d));
> - shpc->wmask = g_malloc0(SHPC_SIZEOF(d));
> - shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d));
> -
> - shpc_reset(d);
> -
> - pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset);
> -
> - pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff);
> - pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
> - pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
> - pci_set_long(shpc->wmask + SHPC_SERR_INT,
> - SHPC_INT_DIS |
> - SHPC_SERR_DIS |
> - SHPC_CMD_INT_DIS |
> - SHPC_ARB_SERR_DIS);
> - pci_set_long(shpc->w1cmask + SHPC_SERR_INT,
> - SHPC_CMD_DETECTED |
> - SHPC_ARB_DETECTED);
> - for (i = 0; i < nslots; ++i) {
> - pci_set_byte(shpc->wmask +
> - SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
> - SHPC_SLOT_EVENT_PRESENCE |
> - SHPC_SLOT_EVENT_ISOLATED_FAULT |
> - SHPC_SLOT_EVENT_BUTTON |
> - SHPC_SLOT_EVENT_MRL |
> - SHPC_SLOT_EVENT_CONNECTED_FAULT |
> - SHPC_SLOT_EVENT_MRL_SERR_DIS |
> - SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
> - pci_set_byte(shpc->w1cmask +
> - SHPC_SLOT_EVENT_LATCH(i),
> - SHPC_SLOT_EVENT_PRESENCE |
> - SHPC_SLOT_EVENT_ISOLATED_FAULT |
> - SHPC_SLOT_EVENT_BUTTON |
> - SHPC_SLOT_EVENT_MRL |
> - SHPC_SLOT_EVENT_CONNECTED_FAULT);
> - }
> -
> - /* TODO: init cmask */
> - memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio",
> - SHPC_SIZEOF(d));
> - shpc_cap_update_dword(d);
> - memory_region_add_subregion(bar, offset, &shpc->mmio);
> - pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev);
> -
> - d->cap_present |= QEMU_PCI_CAP_SHPC;
> - return 0;
> -}
> -
> -int shpc_bar_size(PCIDevice *d)
> -{
> - return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS));
> -}
> -
> -void shpc_cleanup(PCIDevice *d, MemoryRegion *bar)
> -{
> - SHPCDevice *shpc = d->shpc;
> - d->cap_present &= ~QEMU_PCI_CAP_SHPC;
> - memory_region_del_subregion(bar, &shpc->mmio);
> - /* TODO: cleanup config space changes? */
> - g_free(shpc->config);
> - g_free(shpc->cmask);
> - g_free(shpc->wmask);
> - g_free(shpc->w1cmask);
> - memory_region_destroy(&shpc->mmio);
> - g_free(shpc);
> -}
> -
> -void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
> -{
> - if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) {
> - return;
> - }
> - if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) {
> - unsigned dword_data;
> - dword_data = pci_get_long(d->shpc->config + d->shpc->cap
> - + SHPC_CAP_DWORD_DATA);
> - shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4);
> - }
> - /* Update cap dword data in case guest is going to read it. */
> - shpc_cap_update_dword(d);
> -}
> -
> -static void shpc_save(QEMUFile *f, void *pv, size_t size)
> -{
> - PCIDevice *d = container_of(pv, PCIDevice, shpc);
> - qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
> -}
> -
> -static int shpc_load(QEMUFile *f, void *pv, size_t size)
> -{
> - PCIDevice *d = container_of(pv, PCIDevice, shpc);
> - int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
> - if (ret != SHPC_SIZEOF(d)) {
> - return -EINVAL;
> - }
> - /* Make sure we don't lose notifications. An extra interrupt is
> harmless. */
> - d->shpc->msi_requested = 0;
> - shpc_interrupt_update(d);
> - return 0;
> -}
> -
> -VMStateInfo shpc_vmstate_info = {
> - .name = "shpc",
> - .get = shpc_load,
> - .put = shpc_save,
> -};
> diff --git a/hw/shpc.h b/hw/shpc.h
> deleted file mode 100644
> index 130b71d..0000000
> --- a/hw/shpc.h
> +++ /dev/null
> @@ -1,48 +0,0 @@
> -#ifndef SHPC_H
> -#define SHPC_H
> -
> -#include "qemu-common.h"
> -#include "memory.h"
> -#include "vmstate.h"
> -
> -struct SHPCDevice {
> - /* Capability offset in device's config space */
> - int cap;
> -
> - /* # of hot-pluggable slots */
> - int nslots;
> -
> - /* SHPC WRS: working register set */
> - uint8_t *config;
> -
> - /* Used to enable checks on load. Note that writable bits are
> - * never checked even if set in cmask. */
> - uint8_t *cmask;
> -
> - /* Used to implement R/W bytes */
> - uint8_t *wmask;
> -
> - /* Used to implement RW1C(Write 1 to Clear) bytes */
> - uint8_t *w1cmask;
> -
> - /* MMIO for the SHPC BAR */
> - MemoryRegion mmio;
> -
> - /* Bus controlled by this SHPC */
> - PCIBus *sec_bus;
> -
> - /* MSI already requested for this event */
> - int msi_requested;
> -};
> -
> -void shpc_reset(PCIDevice *d);
> -int shpc_bar_size(PCIDevice *dev);
> -int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned
> off);
> -void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar);
> -void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int
> len);
> -
> -extern VMStateInfo shpc_vmstate_info;
> -#define SHPC_VMSTATE(_field, _type) \
> - VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0)
> -
> -#endif
> diff --git a/hw/slotid_cap.c b/hw/slotid_cap.c
> deleted file mode 100644
> index 0106452..0000000
> --- a/hw/slotid_cap.c
> +++ /dev/null
> @@ -1,44 +0,0 @@
> -#include "slotid_cap.h"
> -#include "pci.h"
> -
> -#define SLOTID_CAP_LENGTH 4
> -#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1)
> -
> -int slotid_cap_init(PCIDevice *d, int nslots,
> - uint8_t chassis,
> - unsigned offset)
> -{
> - int cap;
> - if (!chassis) {
> - error_report("Bridge chassis not specified. Each bridge is required "
> - "to be assigned a unique chassis id > 0.");
> - return -EINVAL;
> - }
> - if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) {
> - /* TODO: error report? */
> - return -EINVAL;
> - }
> -
> - cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset,
> SLOTID_CAP_LENGTH);
> - if (cap < 0) {
> - return cap;
> - }
> - /* We make each chassis unique, this way each bridge is First in Chassis
> */
> - d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC |
> - (nslots << SLOTID_NSLOTS_SHIFT);
> - d->cmask[cap + PCI_SID_ESR] = 0xff;
> - d->config[cap + PCI_SID_CHASSIS_NR] = chassis;
> - /* Note: Chassis number register is non-volatile,
> - so we don't reset it. */
> - /* TODO: store in eeprom? */
> - d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff;
> -
> - d->cap_present |= QEMU_PCI_CAP_SLOTID;
> - return 0;
> -}
> -
> -void slotid_cap_cleanup(PCIDevice *d)
> -{
> - /* TODO: cleanup config space? */
> - d->cap_present &= ~QEMU_PCI_CAP_SLOTID;
> -}
> diff --git a/hw/slotid_cap.h b/hw/slotid_cap.h
> deleted file mode 100644
> index 70db047..0000000
> --- a/hw/slotid_cap.h
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -#ifndef PCI_SLOTID_CAP_H
> -#define PCI_SLOTID_CAP_H
> -
> -#include "qemu-common.h"
> -
> -int slotid_cap_init(PCIDevice *dev, int nslots,
> - uint8_t chassis,
> - unsigned offset);
> -void slotid_cap_cleanup(PCIDevice *dev);
> -
> -#endif
> --
> MST
>
>
- [Qemu-devel] [PATCH 6/8] Revert "pci: prepare makefiles for pci code reorganization", (continued)
- [Qemu-devel] [PATCH 6/8] Revert "pci: prepare makefiles for pci code reorganization", Michael S. Tsirkin, 2012/12/12
- [Qemu-devel] [PATCH 4/8] pci: update all users to look in pci/, Michael S. Tsirkin, 2012/12/12
- [Qemu-devel] [PATCH 8/8] pci_bus: update comment, Michael S. Tsirkin, 2012/12/12
- [Qemu-devel] [PATCH 5/8] pci: make external dependencies explicit, Michael S. Tsirkin, 2012/12/12
- [Qemu-devel] [PATCH 7/8] pci: rename pci_internals.h pci_bus.h, Michael S. Tsirkin, 2012/12/12
- [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci, Michael S. Tsirkin, 2012/12/12
- Re: [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci,
Blue Swirl <=
- Re: [Qemu-devel] [PATCH 0/8] pci core reorg, Anthony Liguori, 2012/12/12
- Re: [Qemu-devel] [PATCH 0/8] pci core reorg, Blue Swirl, 2012/12/12