From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:45031) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TitK8-00013c-R0 for qemu-devel@nongnu.org; Wed, 12 Dec 2012 15:55:30 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TitJF-0004wk-6A for qemu-devel@nongnu.org; Wed, 12 Dec 2012 15:54:36 -0500 Received: from mx1.redhat.com ([209.132.183.28]:6594) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TitJD-0004wW-P2 for qemu-devel@nongnu.org; Wed, 12 Dec 2012 15:53:41 -0500 Date: Wed, 12 Dec 2012 22:56:40 +0200 From: "Michael S. Tsirkin" Message-ID: <20121212205640.GD20201@redhat.com> References: <08cf3c47501dbbe21d7f265e1de3b2b75b9f8658.1355318011.git.mst@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH 3/8] pci: move pci core code to hw/pci List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Blue Swirl Cc: qemu-devel@nongnu.org On Wed, Dec 12, 2012 at 07:53:45PM +0000, Blue Swirl wrote: > On Wed, Dec 12, 2012 at 1:14 PM, Michael S. Tsirkin wr= ote: > > Move files and modify makefiles to pick them at the > > new location. >=20 > Please fix coding style before moving. Nah I'll fix it after moving. No reason to mix multiple changes. > For easier review, please use git flag -M to detect renames. I'll note that for future thanks. I don't intend to repost this huge patchset though - it'll go in through a pull request. > > > > Signed-off-by: Michael S. Tsirkin > > --- > > 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 =3D usb/ ide/ > > +common-obj-y =3D usb/ ide/ pci/ > > common-obj-y +=3D loader.o > > common-obj-$(CONFIG_VIRTIO) +=3D virtio-console.o > > common-obj-$(CONFIG_VIRTIO) +=3D virtio-rng.o > > common-obj-$(CONFIG_VIRTIO_PCI) +=3D virtio-pci.o > > common-obj-y +=3D fw_cfg.o > > -common-obj-$(CONFIG_PCI) +=3D pci.o pci_bridge.o pci_bridge_dev.o > > -common-obj-$(CONFIG_PCI) +=3D msix.o msi.o > > -common-obj-$(CONFIG_PCI) +=3D shpc.o > > -common-obj-$(CONFIG_PCI) +=3D slotid_cap.o > > -common-obj-$(CONFIG_PCI) +=3D pci_host.o pcie_host.o > > +common-obj-$(CONFIG_PCI) +=3D pci_bridge_dev.o > > common-obj-$(CONFIG_PCI) +=3D ioh3420.o xio3130_upstream.o xio3130_d= ownstream.o > > common-obj-$(CONFIG_PCI) +=3D i82801b11.o > > common-obj-y +=3D watchdog.o > > @@ -102,8 +98,6 @@ common-obj-$(CONFIG_XGMAC) +=3D xgmac.o > > # PCI watchdog devices > > common-obj-$(CONFIG_PCI) +=3D wdt_i6300esb.o > > > > -common-obj-$(CONFIG_PCI) +=3D pcie.o pcie_aer.o pcie_port.o > > - > > # PCI network cards > > common-obj-$(CONFIG_NE2000_PCI) +=3D ne2000.o > > common-obj-$(CONFIG_EEPRO100_PCI) +=3D 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 +=3D mc146818rtc.o pc.o > > obj-y +=3D apic_common.o apic.o kvmvapic.o > > obj-y +=3D sga.o ioapic_common.o ioapic.o piix_pci.o > > obj-y +=3D vmport.o > > -obj-y +=3D pci-hotplug.o smbios.o wdt_ib700.o > > +obj-y +=3D pci/pci-hotplug.o smbios.o wdt_ib700.o > > obj-y +=3D debugcon.o multiboot.o > > obj-y +=3D pc_piix.o > > obj-y +=3D 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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_ARG= S__) > > - > > -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 msi64b= it) > > -{ > > - return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA= _32); > > -} > > - > > -static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64b= it) > > -{ > > - return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK= _32); > > -} > > - > > -static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi= 64bit) > > -{ > > - return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_P= ENDING_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 =3D pci_get_word(dev->config + msi_flags_off(dev)= ); > > - bool msi64bit =3D flags & PCI_MSI_FLAGS_64BIT; > > - > > - if (msi64bit) { > > - pci_set_quad(dev->config + msi_address_lo_off(dev), msg.addr= ess); > > - } else { > > - pci_set_long(dev->config + msi_address_lo_off(dev), msg.addr= ess); > > - } > > - pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data= ); > > -} > > - > > -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) > > -{ > > - uint16_t flags =3D pci_get_word(dev->config + msi_flags_off(dev)= ); > > - bool msi64bit =3D flags & PCI_MSI_FLAGS_64BIT; > > - unsigned int nr_vectors =3D msi_nr_vectors(flags); > > - MSIMessage msg; > > - > > - assert(vector < nr_vectors); > > - > > - if (msi64bit) { > > - msg.address =3D pci_get_quad(dev->config + msi_address_lo_of= f(dev)); > > - } else { > > - msg.address =3D pci_get_long(dev->config + msi_address_lo_of= f(dev)); > > - } > > - > > - /* upper bit 31:16 is zero */ > > - msg.data =3D pci_get_word(dev->config + msi_data_off(dev, msi64b= it)); > > - if (nr_vectors > 1) { > > - msg.data &=3D ~(nr_vectors - 1); > > - msg.data |=3D 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_ve= ctor_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 <=3D PCI_MSI_VECTORS_MAX); > > - /* the nr of MSI vectors is up to 32 */ > > - vectors_order =3D ffs(nr_vectors) - 1; > > - > > - flags =3D vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1); > > - if (msi64bit) { > > - flags |=3D PCI_MSI_FLAGS_64BIT; > > - } > > - if (msi_per_vector_mask) { > > - flags |=3D PCI_MSI_FLAGS_MASKBIT; > > - } > > - > > - cap_size =3D msi_cap_sizeof(flags); > > - config_offset =3D pci_add_capability(dev, PCI_CAP_ID_MSI, offset= , cap_size); > > - if (config_offset < 0) { > > - return config_offset; > > - } > > - > > - dev->msi_cap =3D config_offset; > > - dev->cap_present |=3D 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), 0xfffffff= f); > > - } > > - 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 =3D pci_get_word(dev->config + msi_flags_off(dev)); > > - cap_size =3D msi_cap_sizeof(flags); > > - pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); > > - dev->cap_present &=3D ~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 =3D pci_get_word(dev->config + msi_flags_off(dev)); > > - flags &=3D ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > > - msi64bit =3D 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 =3D 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 =3D pci_get_long(dev->config + > > - msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BI= T)); > > - return mask & (1U << vector); > > -} > > - > > -void msi_notify(PCIDevice *dev, unsigned int vector) > > -{ > > - uint16_t flags =3D pci_get_word(dev->config + msi_flags_off(dev)= ); > > - bool msi64bit =3D flags & PCI_MSI_FLAGS_64BIT; > > - unsigned int nr_vectors =3D 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 << vect= or); > > - MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector); > > - return; > > - } > > - > > - msg =3D 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, i= nt len) > > -{ > > - uint16_t flags =3D pci_get_word(dev->config + msi_flags_off(dev)= ); > > - bool msi64bit =3D flags & PCI_MSI_FLAGS_64BIT; > > - bool msi_per_vector_mask =3D 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(flag= s))) { > > - 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, msi64bi= t)), > > - pci_get_long(dev->config + msi_pending_off(dev, msi6= 4bit))); > > - } > > - 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 pro= hibited > > - * 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 =3D > > - (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) -= 1); > > - log_max_vecs =3D > > - (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) -= 1); > > - if (log_num_vecs > log_max_vecs) { > > - flags &=3D ~PCI_MSI_FLAGS_QSIZE; > > - flags |=3D 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 =3D msi_nr_vectors(flags); > > - > > - /* This will discard pending interrupts, if any. */ > > - pending =3D pci_get_long(dev->config + msi_pending_off(dev, msi6= 4bit)); > > - pending &=3D 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors); > > - pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pendi= ng); > > - > > - /* deliver pending interrupts which are unmasked */ > > - for (vector =3D 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 << vect= or); > > - msi_notify(dev, vector); > > - } > > -} > > - > > -unsigned int msi_nr_vectors_allocated(const PCIDevice *dev) > > -{ > > - uint16_t flags =3D 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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_ve= ctor_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, i= nt 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 > > - * > > - * Copyright (c) 2009, Red Hat Inc, Michael S. Tsirkin (mst@redhat.= com) > > - * > > - * 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 th= e > > - * 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 =3D dev->msix_table + vector * PCI_MSIX_ENT= RY_SIZE; > > - MSIMessage msg; > > - > > - msg.address =3D pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_= ADDR); > > - msg.data =3D 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 =3D dev->msix_table + vector * PCI_MSIX_ENT= RY_SIZE; > > - > > - pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.addres= s); > > - pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data); > > - table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &=3D ~PCI_MSIX_ENTRY_CTR= L_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(vecto= r); > > -} > > - > > -static void msix_set_pending(PCIDevice *dev, int vector) > > -{ > > - *msix_pending_byte(dev, vector) |=3D msix_pending_mask(vector); > > -} > > - > > -static void msix_clr_pending(PCIDevice *dev, int vector) > > -{ > > - *msix_pending_byte(dev, vector) &=3D ~msix_pending_mask(vector); > > -} > > - > > -static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmas= k) > > -{ > > - unsigned offset =3D vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTR= Y_VECTOR_CTRL; > > - return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MA= SKBIT; > > -} > > - > > -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_m= asked) > > -{ > > - MSIMessage msg; > > - int ret; > > - > > - if (!dev->msix_vector_use_notifier) { > > - return; > > - } > > - if (is_masked) { > > - dev->msix_vector_release_notifier(dev, vector); > > - } else { > > - msg =3D msix_get_message(dev, vector); > > - ret =3D dev->msix_vector_use_notifier(dev, vector, msg); > > - assert(ret >=3D 0); > > - } > > -} > > - > > -static void msix_handle_mask_update(PCIDevice *dev, int vector, bool= was_masked) > > -{ > > - bool is_masked =3D msix_is_masked(dev, vector); > > - > > - if (is_masked =3D=3D 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 =3D !msix_enabled(dev) || > > - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MAS= KALL_MASK); > > -} > > - > > -/* Handle MSI-X capability config write. */ > > -void msix_write_config(PCIDevice *dev, uint32_t addr, > > - uint32_t val, int len) > > -{ > > - unsigned enable_pos =3D dev->msix_cap + MSIX_CONTROL_OFFSET; > > - int vector; > > - bool was_masked; > > - > > - if (!msix_present(dev) || !range_covers_byte(addr, len, enable_p= os)) { > > - return; > > - } > > - > > - was_masked =3D dev->msix_function_masked; > > - msix_update_function_masked(dev); > > - > > - if (!msix_enabled(dev)) { > > - return; > > - } > > - > > - pci_device_deassert_intx(dev); > > - > > - if (dev->msix_function_masked =3D=3D was_masked) { > > - return; > > - } > > - > > - for (vector =3D 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 =3D 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 =3D opaque; > > - int vector =3D addr / PCI_MSIX_ENTRY_SIZE; > > - bool was_masked; > > - > > - was_masked =3D 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 =3D { > > - .read =3D msix_table_mmio_read, > > - .write =3D msix_table_mmio_write, > > - /* TODO: MSIX should be LITTLE_ENDIAN. */ > > - .endianness =3D DEVICE_NATIVE_ENDIAN, > > - .valid =3D { > > - .min_access_size =3D 4, > > - .max_access_size =3D 4, > > - }, > > -}; > > - > > -static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, > > - unsigned size) > > -{ > > - PCIDevice *dev =3D opaque; > > - > > - return pci_get_long(dev->msix_pba + addr); > > -} > > - > > -static const MemoryRegionOps msix_pba_mmio_ops =3D { > > - .read =3D msix_pba_mmio_read, > > - /* TODO: MSIX should be LITTLE_ENDIAN. */ > > - .endianness =3D DEVICE_NATIVE_ENDIAN, > > - .valid =3D { > > - .min_access_size =3D 4, > > - .max_access_size =3D 4, > > - }, > > -}; > > - > > -static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) > > -{ > > - int vector; > > - > > - for (vector =3D 0; vector < nentries; ++vector) { > > - unsigned offset =3D > > - vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTR= L; > > - bool was_masked =3D msix_is_masked(dev, vector); > > - > > - dev->msix_table[offset] |=3D 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_p= os) > > -{ > > - 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 =3D nentries * PCI_MSIX_ENTRY_SIZE; > > - pba_size =3D QEMU_ALIGN_UP(nentries, 64) / 8; > > - > > - /* Sanity test: table & pba don't overlap, fit within BARs, min = aligned */ > > - if ((table_bar_nr =3D=3D pba_bar_nr && > > - ranges_overlap(table_offset, table_size, pba_offset, pba_si= ze)) || > > - 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 =3D pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_C= AP_LENGTH); > > - if (cap < 0) { > > - return cap; > > - } > > - > > - dev->msix_cap =3D cap; > > - dev->cap_present |=3D QEMU_PCI_CAP_MSIX; > > - config =3D dev->config + cap; > > - > > - pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); > > - dev->msix_entries_nr =3D nentries; > > - dev->msix_function_masked =3D true; > > - > > - pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_n= r); > > - pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr); > > - > > - /* Make flags bit writable. */ > > - dev->wmask[cap + MSIX_CONTROL_OFFSET] |=3D MSIX_ENABLE_MASK | > > - MSIX_MASKALL_MASK; > > - > > - dev->msix_table =3D g_malloc0(table_size); > > - dev->msix_pba =3D g_malloc0(pba_size); > > - dev->msix_entry_used =3D g_malloc0(nentries * sizeof *dev->msix_= entry_used); > > - > > - msix_mask_all(dev, nentries); > > - > > - memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_op= s, 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, d= ev, > > - "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_OFFS= ET) { > > - return -EINVAL; > > - } > > - > > - name =3D g_strdup_printf("%s-msix", dev->name); > > - memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIV= E_BAR_SIZE); > > - g_free(name); > > - > > - ret =3D msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_n= r, > > - MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_excl= usive_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 =3D 0; vector < dev->msix_entries_nr; ++vector) { > > - dev->msix_entry_used[vector] =3D 0; > > - msix_clr_pending(dev, vector); > > - } > > -} > > - > > -static void msix_clear_all_vectors(PCIDevice *dev) > > -{ > > - int vector; > > - > > - for (vector =3D 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, MemoryRegi= on *pba_bar) > > -{ > > - if (!msix_present(dev)) { > > - return; > > - } > > - pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH); > > - dev->msix_cap =3D 0; > > - msix_free_irq_entries(dev); > > - dev->msix_entries_nr =3D 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 =3D 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 =3D NULL; > > - g_free(dev->msix_entry_used); > > - dev->msix_entry_used =3D NULL; > > - dev->cap_present &=3D ~QEMU_PCI_CAP_MSIX; > > -} > > - > > -void msix_uninit_exclusive_bar(PCIDevice *dev) > > -{ > > - if (msix_present(dev)) { > > - msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclus= ive_bar); > > - memory_region_destroy(&dev->msix_exclusive_bar); > > - } > > -} > > - > > -void msix_save(PCIDevice *dev, QEMUFile *f) > > -{ > > - unsigned n =3D 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 =3D 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 =3D 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 >=3D dev->msix_entries_nr || !dev->msix_entry_used[ve= ctor]) > > - return; > > - if (msix_is_masked(dev, vector)) { > > - msix_set_pending(dev, vector); > > - return; > > - } > > - > > - msg =3D 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] &=3D > > - ~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 c= onfigure > > - * 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 >=3D 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 >=3D dev->msix_entries_nr || !dev->msix_entry_used[ve= ctor]) { > > - 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 =3D 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_notif= ier) > > -{ > > - int vector, ret; > > - > > - assert(use_notifier && release_notifier); > > - > > - dev->msix_vector_use_notifier =3D use_notifier; > > - dev->msix_vector_release_notifier =3D release_notifier; > > - > > - if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > > - (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) =3D=3D MSIX_ENABLE_M= ASK) { > > - for (vector =3D 0; vector < dev->msix_entries_nr; vector++) = { > > - ret =3D msix_set_notifier_for_vector(dev, vector); > > - if (ret < 0) { > > - goto undo; > > - } > > - } > > - } > > - return 0; > > - > > -undo: > > - while (--vector >=3D 0) { > > - msix_unset_notifier_for_vector(dev, vector); > > - } > > - dev->msix_vector_use_notifier =3D NULL; > > - dev->msix_vector_release_notifier =3D 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)) =3D=3D MSIX_ENABLE_M= ASK) { > > - for (vector =3D 0; vector < dev->msix_entries_nr; vector++) = { > > - msix_unset_notifier_for_vector(dev, vector); > > - } > > - } > > - dev->msix_vector_use_notifier =3D NULL; > > - dev->msix_vector_release_notifier =3D 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_p= os); > > -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 va= l, 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_notif= ier); > > -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 obtai= ning a copy > > - * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > > - * furnished to do so, subject to the following conditions: > > - * > > - * The above copyright notice and this permission notice shall be in= cluded in > > - * all copies or substantial portions of the Software. > > - * > > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > > - * 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, A= RISING FROM, > > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS 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 =3D NULL; > > - QemuOpts *opts; > > - PCIBus *bus; > > - int ret, devfn; > > - > > - bus =3D pci_get_bus_devfn(&devfn, devaddr); > > - if (!bus) { > > - monitor_printf(mon, "Invalid PCI device address %s\n", devad= dr); > > - return NULL; > > - } > > - if (!((BusState*)bus)->allow_hotplug) { > > - monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > > - return NULL; > > - } > > - > > - opts =3D qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_= str : "", 0); > > - if (!opts) { > > - return NULL; > > - } > > - > > - qemu_opt_set(opts, "type", "nic"); > > - > > - ret =3D 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 =3D (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 =3D qemu_opt_get_number(dinfo->opts, "unit", -1); > > - dinfo->bus =3D scsibus->busnr; > > - scsidev =3D scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinf= o->unit, > > - false, -1); > > - if (!scsidev) { > > - return -1; > > - } > > - dinfo->unit =3D 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 =3D 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 =3D 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", p= ci_addr); > > - goto err; > > - } > > - if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) !=3D 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 =3D NULL; > > - int type =3D -1; > > - char buf[128]; > > - PCIBus *bus; > > - int devfn; > > - > > - if (get_param_value(buf, sizeof(buf), "if", opts)) { > > - if (!strcmp(buf, "scsi")) > > - type =3D IF_SCSI; > > - else if (!strcmp(buf, "virtio")) { > > - type =3D IF_VIRTIO; > > - } else { > > - monitor_printf(mon, "type %s not a hotpluggable PCI devi= ce.\n", buf); > > - return NULL; > > - } > > - } else { > > - monitor_printf(mon, "no if=3D specified\n"); > > - return NULL; > > - } > > - > > - if (get_param_value(buf, sizeof(buf), "file", opts)) { > > - dinfo =3D add_init_drive(opts); > > - if (!dinfo) > > - return NULL; > > - if (dinfo->devaddr) { > > - monitor_printf(mon, "Parameter addr not supported\n"); > > - return NULL; > > - } > > - } else { > > - dinfo =3D NULL; > > - } > > - > > - bus =3D pci_get_bus_devfn(&devfn, devaddr); > > - if (!bus) { > > - monitor_printf(mon, "Invalid PCI device address %s\n", devad= dr); > > - 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 =3D pci_create(bus, devfn, "lsi53c895a"); > > - if (qdev_init(&dev->qdev) < 0) > > - dev =3D NULL; > > - if (dev && dinfo) { > > - if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) !=3D 0) { > > - qdev_unplug(&dev->qdev, NULL); > > - dev =3D NULL; > > - } > > - } > > - break; > > - case IF_VIRTIO: > > - if (!dinfo) { > > - monitor_printf(mon, "virtio requires a backing file/devi= ce.\n"); > > - return NULL; > > - } > > - dev =3D pci_create(bus, devfn, "virtio-blk-pci"); > > - if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < = 0) { > > - qdev_free(&dev->qdev); > > - dev =3D NULL; > > - break; > > - } > > - if (qdev_init(&dev->qdev) < 0) > > - dev =3D NULL; > > - break; > > - default: > > - dev =3D NULL; > > - } > > - return dev; > > -} > > - > > -void pci_device_hot_add(Monitor *mon, const QDict *qdict) > > -{ > > - PCIDevice *dev =3D NULL; > > - const char *pci_addr =3D qdict_get_str(qdict, "pci_addr"); > > - const char *type =3D qdict_get_str(qdict, "type"); > > - const char *opts =3D qdict_get_try_str(qdict, "opts"); > > - > > - /* strip legacy tag */ > > - if (!strncmp(pci_addr, "pci_addr=3D", 9)) { > > - pci_addr +=3D 9; > > - } > > - > > - if (!opts) { > > - opts =3D ""; > > - } > > - > > - if (!strcmp(pci_addr, "auto")) > > - pci_addr =3D NULL; > > - > > - if (strcmp(type, "nic") =3D=3D 0) { > > - dev =3D qemu_pci_hot_add_nic(mon, pci_addr, opts); > > - } else if (strcmp(type, "storage") =3D=3D 0) { > > - dev =3D 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 =3D NULL; > > - > > - if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { > > - return -1; > > - } > > - > > - d =3D pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slo= t, 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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 obtai= ning a copy > > - * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > > - * furnished to do so, subject to the following conditions: > > - * > > - * The above copyright notice and this permission notice shall be in= cluded in > > - * all copies or substantial portions of the Software. > > - * > > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > > - * 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, A= RISING FROM, > > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS 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 ind= ent); > > -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[] =3D { > > - 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 =3D BUS_CLASS(klass); > > - > > - k->print_dev =3D pcibus_dev_print; > > - k->get_dev_path =3D pcibus_get_dev_path; > > - k->get_fw_dev_path =3D pcibus_get_fw_dev_path; > > - k->reset =3D pcibus_reset; > > -} > > - > > -static const TypeInfo pci_bus_info =3D { > > - .name =3D TYPE_PCI_BUS, > > - .parent =3D TYPE_BUS, > > - .instance_size =3D sizeof(PCIBus), > > - .class_init =3D 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 =3D PCI_SUBVENDOR_ID_REDHA= T_QUMRANET; > > -static uint16_t pci_default_sub_device_id =3D 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 =3D { > > - .name =3D "PCIBUS", > > - .version_id =3D 1, > > - .minimum_version_id =3D 1, > > - .minimum_version_id_old =3D 1, > > - .fields =3D (VMStateField []) { > > - VMSTATE_INT32_EQUAL(nirq, PCIBus), > > - VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_inf= o_int32, int32_t), > > - VMSTATE_END_OF_LIST() > > - } > > -}; > > -static int pci_bar(PCIDevice *d, int reg) > > -{ > > - uint8_t type; > > - > > - if (reg !=3D PCI_ROM_SLOT) > > - return PCI_BASE_ADDRESS_0 + reg * 4; > > - > > - type =3D d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUN= CTION; > > - return type =3D=3D PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : P= CI_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 &=3D ~(0x1 << irq_num); > > - d->irq_state |=3D level << irq_num; > > -} > > - > > -static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, in= t change) > > -{ > > - PCIBus *bus; > > - for (;;) { > > - bus =3D pci_dev->bus; > > - irq_num =3D bus->map_irq(pci_dev, irq_num); > > - if (bus->set_irq) > > - break; > > - pci_dev =3D bus->parent_dev; > > - } > > - bus->irq_count[irq_num] +=3D change; > > - bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != =3D 0); > > -} > > - > > -int pci_bus_get_irq_level(PCIBus *bus, int irq_num) > > -{ > > - assert(irq_num >=3D 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] |=3D PCI_STATUS_INTERRUPT; > > - } else { > > - dev->config[PCI_STATUS] &=3D ~PCI_STATUS_INTERRUPT; > > - } > > -} > > - > > -void pci_device_deassert_intx(PCIDevice *dev) > > -{ > > - int i; > > - for (i =3D 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 =3D 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_COMMA= ND) | > > - pci_get_word(dev->w1cmask + PCI_COM= MAND)); > > - pci_word_test_and_clear_mask(dev->config + PCI_STATUS, > > - pci_get_word(dev->wmask + PCI_STATU= S) | > > - pci_get_word(dev->w1cmask + PCI_STA= TUS)); > > - dev->config[PCI_CACHE_LINE_SIZE] =3D 0x0; > > - dev->config[PCI_INTERRUPT_LINE] =3D 0x0; > > - for (r =3D 0; r < PCI_NUM_REGIONS; ++r) { > > - PCIIORegion *region =3D &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 =3D 0; i < bus->nirq; i++) { > > - bus->irq_count[i] =3D 0; > > - } > > - for (i =3D 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 =3D g_malloc0(sizeof(*host)); > > - host->domain =3D domain; > > - host->bus =3D 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 =3D=3D domain) { > > - return host->bus; > > - } > > - } > > - > > - return NULL; > > -} > > - > > -int pci_find_domain(const PCIBus *bus) > > -{ > > - PCIDevice *d; > > - struct PCIHostBus *host; > > - > > - /* obtain root bus */ > > - while ((d =3D bus->parent_dev) !=3D NULL) { > > - bus =3D d->bus; > > - } > > - > > - QLIST_FOREACH(host, &host_buses, next) { > > - if (host->bus =3D=3D 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) =3D=3D 0); > > - bus->devfn_min =3D devfn_min; > > - bus->address_space_mem =3D address_space_mem; > > - bus->address_space_io =3D address_space_io; > > - > > - /* host bridge */ > > - QLIST_INIT(&bus->child); > > - pci_host_bus_register(0, bus); /* for now only pci domain 0 is s= upported */ > > - > > - 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 =3D g_malloc0(sizeof(*bus)); > > - pci_bus_new_inplace(bus, parent, name, address_space_mem, > > - address_space_io, devfn_min); > > - OBJECT(bus)->free =3D g_free; > > - return bus; > > -} > > - > > -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_f= n map_irq, > > - void *irq_opaque, int nirq) > > -{ > > - bus->set_irq =3D set_irq; > > - bus->map_irq =3D map_irq; > > - bus->irq_opaque =3D irq_opaque; > > - bus->nirq =3D nirq; > > - bus->irq_count =3D g_malloc0(nirq * sizeof(bus->irq_count[0])); > > -} > > - > > -void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceStat= e *qdev) > > -{ > > - bus->qbus.allow_hotplug =3D 1; > > - bus->hotplug =3D hotplug; > > - bus->hotplug_qdev =3D 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 =3D 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 =3D container_of(pv, PCIDevice, config); > > - uint8_t *config; > > - int i; > > - > > - assert(size =3D=3D pci_config_size(s)); > > - config =3D g_malloc(size); > > - > > - qemu_get_buffer(f, config, size); > > - for (i =3D 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 =3D pv; > > - assert(size =3D=3D pci_config_size(container_of(pv, PCIDevice, c= onfig))); > > - qemu_put_buffer(f, *v, size); > > -} > > - > > -static VMStateInfo vmstate_info_pci_config =3D { > > - .name =3D "pci config", > > - .get =3D get_pci_config_device, > > - .put =3D put_pci_config_device, > > -}; > > - > > -static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) > > -{ > > - PCIDevice *s =3D container_of(pv, PCIDevice, irq_state); > > - uint32_t irq_state[PCI_NUM_PINS]; > > - int i; > > - for (i =3D 0; i < PCI_NUM_PINS; ++i) { > > - irq_state[i] =3D qemu_get_be32(f); > > - if (irq_state[i] !=3D 0x1 && irq_state[i] !=3D 0) { > > - fprintf(stderr, "irq state %d: must be 0 or 1.\n", > > - irq_state[i]); > > - return -EINVAL; > > - } > > - } > > - > > - for (i =3D 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 =3D container_of(pv, PCIDevice, irq_state); > > - > > - for (i =3D 0; i < PCI_NUM_PINS; ++i) { > > - qemu_put_be32(f, pci_irq_state(s, i)); > > - } > > -} > > - > > -static VMStateInfo vmstate_info_pci_irq_state =3D { > > - .name =3D "pci irq state", > > - .get =3D get_pci_irq_state, > > - .put =3D put_pci_irq_state, > > -}; > > - > > -const VMStateDescription vmstate_pci_device =3D { > > - .name =3D "PCIDevice", > > - .version_id =3D 2, > > - .minimum_version_id =3D 1, > > - .minimum_version_id_old =3D 1, > > - .fields =3D (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 =3D { > > - .name =3D "PCIEDevice", > > - .version_id =3D 2, > > - .minimum_version_id =3D 1, > > - .minimum_version_id_old =3D 1, > > - .fields =3D (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_d= evice; > > -} > > - > > -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] &=3D ~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 =3D 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 [[:]:], return -1 on error if funcp =3D=3D= NULL > > - * [[:]:]., 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 =3D 0, bus =3D 0; > > - unsigned int slot =3D 0; > > - unsigned int func =3D 0; > > - > > - p =3D addr; > > - val =3D strtoul(p, &e, 16); > > - if (e =3D=3D p) > > - return -1; > > - if (*e =3D=3D ':') { > > - bus =3D val; > > - p =3D e + 1; > > - val =3D strtoul(p, &e, 16); > > - if (e =3D=3D p) > > - return -1; > > - if (*e =3D=3D ':') { > > - dom =3D bus; > > - bus =3D val; > > - p =3D e + 1; > > - val =3D strtoul(p, &e, 16); > > - if (e =3D=3D p) > > - return -1; > > - } > > - } > > - > > - slot =3D val; > > - > > - if (funcp !=3D NULL) { > > - if (*e !=3D '.') > > - return -1; > > - > > - p =3D e + 1; > > - val =3D strtoul(p, &e, 16); > > - if (e =3D=3D p) > > - return -1; > > - > > - func =3D val; > > - } > > - > > - /* if funcp =3D=3D NULL func is 0 */ > > - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) > > - return -1; > > - > > - if (*e) > > - return -1; > > - > > - *domp =3D dom; > > - *busp =3D bus; > > - *slotp =3D slot; > > - if (funcp !=3D NULL) > > - *funcp =3D 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=3D", 9)) { > > - addr +=3D 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 =3D -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 =3D 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] =3D PCI_STATUS_CAP_LIST; > > - dev->cmask[PCI_REVISION_ID] =3D 0xff; > > - dev->cmask[PCI_CLASS_PROG] =3D 0xff; > > - pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff); > > - dev->cmask[PCI_HEADER_TYPE] =3D 0xff; > > - dev->cmask[PCI_CAPABILITY_LIST] =3D 0xff; > > -} > > - > > -static void pci_init_wmask(PCIDevice *dev) > > -{ > > - int config_size =3D pci_config_size(dev); > > - > > - dev->wmask[PCI_CACHE_LINE_SIZE] =3D 0xff; > > - dev->wmask[PCI_INTERRUPT_LINE] =3D 0xff; > > - pci_set_word(dev->wmask + PCI_COMMAND, > > - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_M= ASTER | > > - PCI_COMMAND_INTX_DISABLE); > > - if (dev->cap_present & QEMU_PCI_CAP_SERR) { > > - pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COM= MAND_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_P= ARITY); > > -} > > - > > -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] =3D PCI_IO_RANGE_MASK & 0xff; > > - d->wmask[PCI_IO_LIMIT] =3D 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] |=3D PCI_IO_RANGE_TYPE_16; > > - d->config[PCI_IO_LIMIT] |=3D 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 di= scard timer */ > > -#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard = timer */ > > -#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer stat= us */ > > -#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] |=3D PCI_IO_RANGE_TYPE_MASK; > > - d->cmask[PCI_IO_LIMIT] |=3D 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 =3D PCI_SLOT(dev->devfn); > > - uint8_t func; > > - > > - if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > > - dev->config[PCI_HEADER_TYPE] |=3D PCI_HEADER_TYPE_MULTI_FUNC= TION; > > - } > > - > > - /* > > - * 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 =3D 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 popul= ated " > > - "in function %x.%x", slot, PCI_FUNC(dev->de= vfn)); > > - 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 =3D 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 =3D pci_config_size(pci_dev); > > - > > - pci_dev->config =3D g_malloc0(config_size); > > - pci_dev->cmask =3D g_malloc0(config_size); > > - pci_dev->wmask =3D g_malloc0(config_size); > > - pci_dev->w1cmask =3D g_malloc0(config_size); > > - pci_dev->used =3D 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 =3D PCI_DEVICE_GET_CLASS(pci_dev); > > - PCIConfigReadFunc *config_read =3D pc->config_read; > > - PCIConfigWriteFunc *config_write =3D pc->config_write; > > - > > - if (devfn < 0) { > > - for(devfn =3D bus->devfn_min ; devfn < ARRAY_SIZE(bus->devic= es); > > - devfn +=3D 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->de= vices[devfn]->name); > > - return NULL; > > - } > > - pci_dev->bus =3D bus; > > - if (bus->dma_context_fn) { > > - pci_dev->dma =3D bus->dma_context_fn(bus, bus->dma_context_o= paque, 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_memor= y())); > > - memory_region_set_enabled(&pci_dev->bus_master_enable_region= , false); > > - address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_ma= ster_enable_region); > > - pci_dev->dma =3D g_new(DMAContext, 1); > > - dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL= , NULL, NULL); > > - } > > - pci_dev->devfn =3D devfn; > > - pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); > > - pci_dev->irq_state =3D 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 =3D pci_default_read_config; > > - if (!config_write) > > - config_write =3D pci_default_write_config; > > - pci_dev->config_read =3D config_read; > > - pci_dev->config_write =3D config_write; > > - bus->devices[devfn] =3D pci_dev; > > - pci_dev->irq =3D qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NU= M_PINS); > > - pci_dev->version_id =3D 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] =3D 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 =3D NULL; > > - } > > -} > > - > > -static void pci_unregister_io_regions(PCIDevice *pci_dev) > > -{ > > - PCIIORegion *r; > > - int i; > > - > > - for(i =3D 0; i < PCI_NUM_REGIONS; i++) { > > - r =3D &pci_dev->io_regions[i]; > > - if (!r->size || r->addr =3D=3D PCI_BAR_UNMAPPED) > > - continue; > > - memory_region_del_subregion(r->address_space, r->memory); > > - } > > -} > > - > > -static int pci_unregister_device(DeviceState *dev) > > -{ > > - PCIDevice *pci_dev =3D PCI_DEVICE(dev); > > - PCIDeviceClass *pc =3D 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 =3D memory_region_size(memory); > > - > > - assert(region_num >=3D 0); > > - assert(region_num < PCI_NUM_REGIONS); > > - if (size & (size-1)) { > > - fprintf(stderr, "ERROR: PCI region size must be pow2 " > > - "type=3D0x%x, size=3D0x%"FMT_PCIBUS"\n", type, s= ize); > > - exit(1); > > - } > > - > > - r =3D &pci_dev->io_regions[region_num]; > > - r->addr =3D PCI_BAR_UNMAPPED; > > - r->size =3D size; > > - r->type =3D type; > > - r->memory =3D NULL; > > - > > - wmask =3D ~(size - 1); > > - addr =3D pci_bar(pci_dev, region_num); > > - if (region_num =3D=3D PCI_ROM_SLOT) { > > - /* ROM enable bit is writable */ > > - wmask |=3D 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 =3D memory; > > - pci_dev->io_regions[region_num].address_space > > - =3D 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 =3D pci_bar(d, reg); > > - uint16_t cmd =3D 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 =3D pci_get_long(d->config + bar) & ~(size - 1); > > - last_addr =3D new_addr + size - 1; > > - /* NOTE: we have only 64K ioports on PC */ > > - if (last_addr <=3D new_addr || new_addr =3D=3D 0 || last_add= r > 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 =3D pci_get_quad(d->config + bar); > > - } else { > > - new_addr =3D pci_get_long(d->config + bar); > > - } > > - /* the ROM slot has a specific enable bit */ > > - if (reg =3D=3D PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENAB= LE)) { > > - return PCI_BAR_UNMAPPED; > > - } > > - new_addr &=3D ~(size - 1); > > - last_addr =3D 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 <=3D new_addr || new_addr =3D=3D 0 || > > - last_addr =3D=3D 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 >=3D UI= NT32_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 >=3D 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 =3D 0; i < PCI_NUM_REGIONS; i++) { > > - r =3D &d->io_regions[i]; > > - > > - /* this region isn't registered */ > > - if (!r->size) > > - continue; > > - > > - new_addr =3D pci_bar_address(d, i, r->type, r->size); > > - > > - /* This bar isn't changed */ > > - if (new_addr =3D=3D r->addr) > > - continue; > > - > > - /* now do the real mapping */ > > - if (r->addr !=3D PCI_BAR_UNMAPPED) { > > - memory_region_del_subregion(r->address_space, r->memory)= ; > > - } > > - r->addr =3D new_addr; > > - if (r->addr !=3D 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_disabl= ed) > > -{ > > - int i, disabled =3D pci_irq_disabled(d); > > - if (disabled =3D=3D was_irq_disabled) > > - return; > > - for (i =3D 0; i < PCI_NUM_PINS; ++i) { > > - int state =3D 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 =3D 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 =3D pci_irq_disabled(d); > > - > > - for (i =3D 0; i < l; val >>=3D 8, ++i) { > > - uint8_t wmask =3D d->wmask[addr + i]; > > - uint8_t w1cmask =3D d->w1cmask[addr + i]; > > - assert(!(wmask & w1cmask)); > > - d->config[addr + i] =3D (d->config[addr + i] & ~wmask) | (va= l & wmask); > > - d->config[addr + i] &=3D ~(val & w1cmask); /* W1C: Write 1 t= o 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_COMMA= ND) > > - & PCI_COMMAND_MASTER); > > - } > > - > > - msi_write_config(d, addr, val, l); > > - msix_write_config(d, addr, val, l); > > -} > > - > > -/***********************************************************/ > > -/* generic PCI irq support */ > > - > > -/* 0 <=3D irq_num <=3D 3. level must be 0 or 1 */ > > -static void pci_set_irq(void *opaque, int irq_num, int level) > > -{ > > - PCIDevice *pci_dev =3D opaque; > > - int change; > > - > > - change =3D 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_in= tx_to_irq) > > -{ > > - assert(!bus->parent_dev); > > - bus->route_intx_to_irq =3D route_intx_to_irq; > > -} > > - > > -PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) > > -{ > > - PCIBus *bus; > > - > > - do { > > - bus =3D dev->bus; > > - pin =3D bus->map_irq(dev, pin); > > - dev =3D 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 !=3D new->mode || old->irq !=3D new->irq; > > -} > > - > > -void pci_bus_fire_intx_routing_notifier(PCIBus *bus) > > -{ > > - PCIDevice *dev; > > - PCIBus *sec; > > - int i; > > - > > - for (i =3D 0; i < ARRAY_SIZE(bus->devices); ++i) { > > - dev =3D 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 not= ifier) > > -{ > > - dev->intx_routing_notifier =3D 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 <=3D pin <=3D 3 0 =3D INTA, 1 =3D INTB, 2 =3D INTC, 3 =3D 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[] =3D > > -{ > > - { 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, PCID= evice *d, > > - void *opaque), > > - void *opaque) > > -{ > > - PCIDevice *d; > > - int devfn; > > - > > - for(devfn =3D 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > > - d =3D 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 *o= paque), > > - void *opaque) > > -{ > > - bus =3D 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 =3D pci_class_descriptions; > > - while (desc->desc && class !=3D desc->class) { > > - desc++; > > - } > > - > > - return desc; > > -} > > - > > -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus= _num); > > - > > -static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *d= ev) > > -{ > > - PciMemoryRegionList *head =3D NULL, *cur_item =3D NULL; > > - int i; > > - > > - for (i =3D 0; i < PCI_NUM_REGIONS; i++) { > > - const PCIIORegion *r =3D &dev->io_regions[i]; > > - PciMemoryRegionList *region; > > - > > - if (!r->size) { > > - continue; > > - } > > - > > - region =3D g_malloc0(sizeof(*region)); > > - region->value =3D g_malloc0(sizeof(*region->value)); > > - > > - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { > > - region->value->type =3D g_strdup("io"); > > - } else { > > - region->value->type =3D g_strdup("memory"); > > - region->value->has_prefetch =3D true; > > - region->value->prefetch =3D !!(r->type & PCI_BASE_ADDRES= S_MEM_PREFETCH); > > - region->value->has_mem_type_64 =3D true; > > - region->value->mem_type_64 =3D !!(r->type & PCI_BASE_ADD= RESS_MEM_TYPE_64); > > - } > > - > > - region->value->bar =3D i; > > - region->value->address =3D r->addr; > > - region->value->size =3D r->size; > > - > > - /* XXX: waiting for the qapi to support GSList */ > > - if (!cur_item) { > > - head =3D cur_item =3D region; > > - } else { > > - cur_item->next =3D region; > > - cur_item =3D region; > > - } > > - } > > - > > - return head; > > -} > > - > > -static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *b= us, > > - int bus_num) > > -{ > > - PciBridgeInfo *info; > > - > > - info =3D g_malloc0(sizeof(*info)); > > - > > - info->bus.number =3D dev->config[PCI_PRIMARY_BUS]; > > - info->bus.secondary =3D dev->config[PCI_SECONDARY_BUS]; > > - info->bus.subordinate =3D dev->config[PCI_SUBORDINATE_BUS]; > > - > > - info->bus.io_range =3D g_malloc0(sizeof(*info->bus.io_range)); > > - info->bus.io_range->base =3D pci_bridge_get_base(dev, PCI_BASE_A= DDRESS_SPACE_IO); > > - info->bus.io_range->limit =3D pci_bridge_get_limit(dev, PCI_BASE= _ADDRESS_SPACE_IO); > > - > > - info->bus.memory_range =3D g_malloc0(sizeof(*info->bus.memory_ra= nge)); > > - info->bus.memory_range->base =3D pci_bridge_get_base(dev, PCI_BA= SE_ADDRESS_SPACE_MEMORY); > > - info->bus.memory_range->limit =3D pci_bridge_get_limit(dev, PCI_= BASE_ADDRESS_SPACE_MEMORY); > > - > > - info->bus.prefetchable_range =3D g_malloc0(sizeof(*info->bus.pre= fetchable_range)); > > - info->bus.prefetchable_range->base =3D pci_bridge_get_base(dev, = PCI_BASE_ADDRESS_MEM_PREFETCH); > > - info->bus.prefetchable_range->limit =3D pci_bridge_get_limit(dev= , PCI_BASE_ADDRESS_MEM_PREFETCH); > > - > > - if (dev->config[PCI_SECONDARY_BUS] !=3D 0) { > > - PCIBus *child_bus =3D pci_find_bus_nr(bus, dev->config[PCI_S= ECONDARY_BUS]); > > - if (child_bus) { > > - info->has_devices =3D true; > > - info->devices =3D qmp_query_pci_devices(child_bus, dev->= config[PCI_SECONDARY_BUS]); > > - } > > - } > > - > > - return info; > > -} > > - > > -static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *b= us, > > - int bus_num) > > -{ > > - const pci_class_desc *desc; > > - PciDeviceInfo *info; > > - uint8_t type; > > - int class; > > - > > - info =3D g_malloc0(sizeof(*info)); > > - info->bus =3D bus_num; > > - info->slot =3D PCI_SLOT(dev->devfn); > > - info->function =3D PCI_FUNC(dev->devfn); > > - > > - class =3D pci_get_word(dev->config + PCI_CLASS_DEVICE); > > - info->class_info.class =3D class; > > - desc =3D get_class_desc(class); > > - if (desc->desc) { > > - info->class_info.has_desc =3D true; > > - info->class_info.desc =3D g_strdup(desc->desc); > > - } > > - > > - info->id.vendor =3D pci_get_word(dev->config + PCI_VENDOR_ID); > > - info->id.device =3D pci_get_word(dev->config + PCI_DEVICE_ID); > > - info->regions =3D qmp_query_pci_regions(dev); > > - info->qdev_id =3D g_strdup(dev->qdev.id ? dev->qdev.id : ""); > > - > > - if (dev->config[PCI_INTERRUPT_PIN] !=3D 0) { > > - info->has_irq =3D true; > > - info->irq =3D dev->config[PCI_INTERRUPT_LINE]; > > - } > > - > > - type =3D dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_F= UNCTION; > > - if (type =3D=3D PCI_HEADER_TYPE_BRIDGE) { > > - info->has_pci_bridge =3D true; > > - info->pci_bridge =3D qmp_query_pci_bridge(dev, bus, bus_num)= ; > > - } > > - > > - return info; > > -} > > - > > -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus= _num) > > -{ > > - PciDeviceInfoList *info, *head =3D NULL, *cur_item =3D NULL; > > - PCIDevice *dev; > > - int devfn; > > - > > - for (devfn =3D 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > > - dev =3D bus->devices[devfn]; > > - if (dev) { > > - info =3D g_malloc0(sizeof(*info)); > > - info->value =3D qmp_query_pci_device(dev, bus, bus_num); > > - > > - /* XXX: waiting for the qapi to support GSList */ > > - if (!cur_item) { > > - head =3D cur_item =3D info; > > - } else { > > - cur_item->next =3D info; > > - cur_item =3D info; > > - } > > - } > > - } > > - > > - return head; > > -} > > - > > -static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) > > -{ > > - PciInfo *info =3D NULL; > > - > > - bus =3D pci_find_bus_nr(bus, bus_num); > > - if (bus) { > > - info =3D g_malloc0(sizeof(*info)); > > - info->bus =3D bus_num; > > - info->devices =3D qmp_query_pci_devices(bus, bus_num); > > - } > > - > > - return info; > > -} > > - > > -PciInfoList *qmp_query_pci(Error **errp) > > -{ > > - PciInfoList *info, *head =3D NULL, *cur_item =3D NULL; > > - struct PCIHostBus *host; > > - > > - QLIST_FOREACH(host, &host_buses, next) { > > - info =3D g_malloc0(sizeof(*info)); > > - info->value =3D qmp_query_pci_bus(host->bus, 0); > > - > > - /* XXX: waiting for the qapi to support GSList */ > > - if (!cur_item) { > > - head =3D cur_item =3D info; > > - } else { > > - cur_item->next =3D info; > > - cur_item =3D info; > > - } > > - } > > - > > - return head; > > -} > > - > > -static const char * const pci_nic_models[] =3D { > > - "ne2k_pci", > > - "i82551", > > - "i82557b", > > - "i82559er", > > - "rtl8139", > > - "e1000", > > - "pcnet", > > - "virtio", > > - NULL > > -}; > > - > > -static const char * const pci_nic_names[] =3D { > > - "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 =3D nd->devaddr ? nd->devaddr : default_deva= ddr; > > - PCIBus *bus; > > - int devfn; > > - PCIDevice *pci_dev; > > - DeviceState *dev; > > - int i; > > - > > - i =3D qemu_find_nic_model(nd, pci_nic_models, default_model); > > - if (i < 0) > > - return NULL; > > - > > - bus =3D 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 =3D pci_create(bus, devfn, pci_nic_names[i]); > > - dev =3D &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_mode= l, > > - const char *default_devaddr) > > -{ > > - PCIDevice *res; > > - > > - if (qemu_show_nic_models(nd->model, pci_nic_models)) > > - exit(0); > > - > > - res =3D 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 <=3D 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) =3D=3D 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 =3D sec) { > > - QLIST_FOREACH(sec, &bus->child, sibling) { > > - assert(sec->parent_dev); > > - if (sec->parent_dev->config[PCI_SECONDARY_BUS] =3D=3D bu= s_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 =3D 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 =3D (PCIDevice *)qdev; > > - PCIDeviceClass *pc =3D PCI_DEVICE_GET_CLASS(pci_dev); > > - PCIBus *bus; > > - int rc; > > - bool is_default_rom; > > - > > - /* initialize cap_present for pci_is_express() and pci_config_si= ze() */ > > - if (pc->is_express) { > > - pci_dev->cap_present |=3D QEMU_PCI_CAP_EXPRESS; > > - } > > - > > - bus =3D FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); > > - pci_dev =3D do_pci_register_device(pci_dev, bus, > > - object_get_typename(OBJECT(qdev= )), > > - pci_dev->devfn); > > - if (pci_dev =3D=3D NULL) > > - return -1; > > - if (qdev->hotplugged && pc->no_hotplug) { > > - qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OB= JECT(pci_dev))); > > - do_pci_unregister_device(pci_dev); > > - return -1; > > - } > > - if (pc->init) { > > - rc =3D pc->init(pci_dev); > > - if (rc !=3D 0) { > > - do_pci_unregister_device(pci_dev); > > - return rc; > > - } > > - } > > - > > - /* rom loading */ > > - is_default_rom =3D false; > > - if (pci_dev->romfile =3D=3D NULL && pc->romfile !=3D NULL) { > > - pci_dev->romfile =3D g_strdup(pc->romfile); > > - is_default_rom =3D true; > > - } > > - pci_add_option_rom(pci_dev, is_default_rom); > > - > > - if (bus->hotplug) { > > - /* Let buses differentiate between hotplug and when device i= s > > - * enabled during qemu machine creation. */ > > - rc =3D bus->hotplug(bus->hotplug_qdev, pci_dev, > > - qdev->hotplugged ? PCI_HOTPLUG_ENABLED: > > - PCI_COLDPLUG_ENABLED); > > - if (rc !=3D 0) { > > - int r =3D pci_unregister_device(&pci_dev->qdev); > > - assert(!r); > > - return rc; > > - } > > - } > > - return 0; > > -} > > - > > -static int pci_unplug_device(DeviceState *qdev) > > -{ > > - PCIDevice *dev =3D PCI_DEVICE(qdev); > > - PCIDeviceClass *pc =3D PCI_DEVICE_GET_CLASS(dev); > > - > > - if (pc->no_hotplug) { > > - qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OB= JECT(dev))); > > - return -1; > > - } > > - return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, > > - PCI_HOTPLUG_DISABLED); > > -} > > - > > -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool mul= tifunction, > > - const char *name) > > -{ > > - DeviceState *dev; > > - > > - dev =3D 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 =3D pci_create_multifunction(bus, devfn, multifun= ction, 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 *nam= e) > > -{ > > - return pci_create_simple_multifunction(bus, devfn, false, name); > > -} > > - > > -static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) > > -{ > > - int offset =3D PCI_CONFIG_HEADER_SIZE; > > - int i; > > - for (i =3D PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++= i) { > > - if (pdev->used[i]) > > - offset =3D i + 1; > > - else if (i - offset + 1 =3D=3D 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 =3D PCI_CAPABILITY_LIST; (next =3D pdev->config[prev])= ; > > - prev =3D next + PCI_CAP_LIST_NEXT) > > - if (pdev->config[next + PCI_CAP_LIST_ID] =3D=3D cap_id) > > - break; > > - > > - if (prev_p) > > - *prev_p =3D prev; > > - return next; > > -} > > - > > -static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_= t offset) > > -{ > > - uint8_t next, prev, found =3D 0; > > - > > - if (!(pdev->used[offset])) { > > - return 0; > > - } > > - > > - assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); > > - > > - for (prev =3D PCI_CAPABILITY_LIST; (next =3D pdev->config[prev])= ; > > - prev =3D next + PCI_CAP_LIST_NEXT) { > > - if (next <=3D offset && next > found) { > > - found =3D next; > > - } > > - } > > - return found; > > -} > > - > > -/* Patch the PCI vendor and device ids in a PCI rom image if necessa= ry. > > - 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 configuratio= n), > > - so they can be read / written with pci_get_word / pci_set_wor= d. */ > > - > > - /* Only a valid rom will be patched. */ > > - rom_magic =3D pci_get_word(ptr); > > - if (rom_magic !=3D 0xaa55) { > > - PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); > > - return; > > - } > > - pcir_offset =3D pci_get_word(ptr + 0x18); > > - if (pcir_offset + 8 >=3D size || memcmp(ptr + pcir_offset, "PCIR= ", 4)) { > > - PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offs= et); > > - return; > > - } > > - > > - vendor_id =3D pci_get_word(pdev->config + PCI_VENDOR_ID); > > - device_id =3D pci_get_word(pdev->config + PCI_DEVICE_ID); > > - rom_vendor_id =3D pci_get_word(ptr + pcir_offset + 4); > > - rom_device_id =3D pci_get_word(ptr + pcir_offset + 6); > > - > > - PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->rom= file, > > - vendor_id, device_id, rom_vendor_id, rom_device_id); > > - > > - checksum =3D ptr[6]; > > - > > - if (vendor_id !=3D rom_vendor_id) { > > - /* Patch vendor id and checksum (at offset 6 for etherboot r= oms). */ > > - checksum +=3D (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_= id >> 8); > > - checksum -=3D (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8)= ; > > - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > > - ptr[6] =3D checksum; > > - pci_set_word(ptr + pcir_offset + 4, vendor_id); > > - } > > - > > - if (device_id !=3D rom_device_id) { > > - /* Patch device id and checksum (at offset 6 for etherboot r= oms). */ > > - checksum +=3D (uint8_t)rom_device_id + (uint8_t)(rom_device_= id >> 8); > > - checksum -=3D (uint8_t)device_id + (uint8_t)(device_id >> 8)= ; > > - PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > > - ptr[6] =3D 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) =3D=3D 0) > > - return 0; > > - > > - if (!pdev->rom_bar) { > > - /* > > - * Load rom via fw_cfg instead of creating a rom bar, > > - * for 0.11 compatibility. > > - */ > > - int class =3D pci_get_word(pdev->config + PCI_CLASS_DEVICE); > > - if (class =3D=3D 0x0300) { > > - rom_add_vga(pdev->romfile); > > - } else { > > - rom_add_option(pdev->romfile, -1); > > - } > > - return 0; > > - } > > - > > - path =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); > > - if (path =3D=3D NULL) { > > - path =3D g_strdup(pdev->romfile); > > - } > > - > > - size =3D 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 =3D 1 << qemu_fls(size); > > - } > > - > > - vmsd =3D 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(O= BJECT(pdev))); > > - } > > - pdev->has_rom =3D true; > > - memory_region_init_ram(&pdev->rom, name, size); > > - vmstate_register_ram(&pdev->rom, &pdev->qdev); > > - ptr =3D 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 =3D false; > > -} > > - > > -/* > > - * if !offset > > - * Reserve space and add capability to the linked list in pci config= space > > - * > > - * if offset =3D 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 =3D pci_find_space(pdev, size); > > - if (!offset) { > > - return -ENOSPC; > > - } > > - } else { > > - /* Verify that capabilities don't overlap. Note: device ass= ignment > > - * depends on this check to verify that the device is not br= oken. > > - * Should never trigger for emulated devices, but it's helpf= ul > > - * for debugging these. */ > > - for (i =3D offset; i < offset + size; i++) { > > - overlapping_cap =3D 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 offse= t %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 =3D pdev->config + offset; > > - config[PCI_CAP_LIST_ID] =3D cap_id; > > - config[PCI_CAP_LIST_NEXT] =3D pdev->config[PCI_CAPABILITY_LIST]; > > - pdev->config[PCI_CAPABILITY_LIST] =3D offset; > > - pdev->config[PCI_STATUS] |=3D 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 siz= e) > > -{ > > - uint8_t prev, offset =3D pci_find_capability_list(pdev, cap_id, = &prev); > > - if (!offset) > > - return; > > - pdev->config[prev] =3D 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] &=3D ~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 ind= ent) > > -{ > > - PCIDevice *d =3D (PCIDevice *)dev; > > - const pci_class_desc *desc; > > - char ctxt[64]; > > - PCIIORegion *r; > > - int i, class; > > - > > - class =3D pci_get_word(d->config + PCI_CLASS_DEVICE); > > - desc =3D pci_class_descriptions; > > - while (desc->desc && class !=3D 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 =3D 0; i < PCI_NUM_REGIONS; i++) { > > - r =3D &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 =3D (PCIDevice *)dev; > > - const char *name =3D NULL; > > - const pci_class_desc *desc =3D pci_class_descriptions; > > - int class =3D pci_get_word(d->config + PCI_CLASS_DEVICE); > > - > > - while (desc->desc && > > - (class & ~desc->fw_ign_bits) !=3D > > - (desc->class & ~desc->fw_ign_bits)) { > > - desc++; > > - } > > - > > - if (desc->desc) { > > - name =3D 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 =3D (PCIDevice *)dev; > > - char path[50], name[33]; > > - int off; > > - > > - off =3D snprintf(path, sizeof(path), "%s@%x", > > - 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 =3D container_of(dev, PCIDevice, qdev); > > - PCIDevice *t; > > - int slot_depth; > > - /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.F= unction. > > - * 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 fo= r all > > - * devices on the path from root to the specific device. */ > > - char domain[] =3D "DDDD:00"; > > - char slot[] =3D ":SS.F"; > > - int domain_len =3D sizeof domain - 1 /* For '\0' */; > > - int slot_len =3D sizeof slot - 1 /* For '\0' */; > > - int path_len; > > - char *path, *p; > > - int s; > > - > > - /* Calculate # of slots on path between device and root. */; > > - slot_depth =3D 0; > > - for (t =3D d; t; t =3D t->bus->parent_dev) { > > - ++slot_depth; > > - } > > - > > - path_len =3D domain_len + slot_len * slot_depth; > > - > > - /* Allocate memory, fill in the terminating null byte. */ > > - path =3D g_malloc(path_len + 1 /* For '\0' */); > > - path[path_len] =3D '\0'; > > - > > - /* First field is the domain. */ > > - s =3D snprintf(domain, sizeof domain, "%04x:00", pci_find_domain= (d->bus)); > > - assert(s =3D=3D 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 =3D path + path_len; > > - for (t =3D d; t; t =3D t->bus->parent_dev) { > > - p -=3D slot_len; > > - s =3D snprintf(slot, sizeof slot, ":%02x.%x", > > - PCI_SLOT(t->devfn), PCI_FUNC(t->devfn)); > > - assert(s =3D=3D slot_len); > > - memcpy(p, slot, slot_len); > > - } > > - > > - return path; > > -} > > - > > -static int pci_qdev_find_recursive(PCIBus *bus, > > - const char *id, PCIDevice **pdev) > > -{ > > - DeviceState *qdev =3D 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 =3D PCI_DEVICE(qdev); > > - return 0; > > - } > > - return -EINVAL; > > -} > > - > > -int pci_qdev_find_device(const char *id, PCIDevice **pdev) > > -{ > > - struct PCIHostBus *host; > > - int rc =3D -ENODEV; > > - > > - QLIST_FOREACH(host, &host_buses, next) { > > - int tmp =3D pci_qdev_find_recursive(host->bus, id, pdev); > > - if (!tmp) { > > - rc =3D 0; > > - break; > > - } > > - if (tmp !=3D -ENODEV) { > > - rc =3D 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 =3D DEVICE_CLASS(klass); > > - k->init =3D pci_qdev_init; > > - k->unplug =3D pci_unplug_device; > > - k->exit =3D pci_unregister_device; > > - k->bus_type =3D TYPE_PCI_BUS; > > - k->props =3D pci_props; > > -} > > - > > -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque= ) > > -{ > > - bus->dma_context_fn =3D fn; > > - bus->dma_context_opaque =3D opaque; > > -} > > - > > -static TypeInfo pci_device_type_info =3D { > > - .name =3D TYPE_PCI_DEVICE, > > - .parent =3D TYPE_DEVICE, > > - .instance_size =3D sizeof(PCIDevice), > > - .abstract =3D true, > > - .class_size =3D sizeof(PCIDeviceClass), > > - .class_init =3D 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 ty= pe); > > -typedef void PCIUnregisterFunc(PCIDevice *pci_dev); > > - > > -typedef struct PCIIORegion { > > - pcibus_t addr; /* current PCI mapping address. -1 means not mapp= ed */ > > -#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 =3D 0x1, > > - QEMU_PCI_CAP_MSIX =3D 0x2, > > - QEMU_PCI_CAP_EXPRESS =3D 0x4, > > - > > - /* multifunction capable device */ > > -#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3 > > - QEMU_PCI_CAP_MULTIFUNCTION =3D (1 << QEMU_PCI_CAP_MULTIFUNCTION_= BITNR), > > - > > - /* command register SERR bit enabled */ > > -#define QEMU_PCI_CAP_SERR_BITNR 4 > > - QEMU_PCI_CAP_SERR =3D (1 << QEMU_PCI_CAP_SERR_BITNR), > > - /* Standard hot plug controller. */ > > -#define QEMU_PCI_SHPC_BITNR 5 > > - QEMU_PCI_CAP_SHPC =3D (1 << QEMU_PCI_SHPC_BITNR), > > -#define QEMU_PCI_SLOTID_BITNR 6 > > - QEMU_PCI_CAP_SLOTID =3D (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 =3D = 0 */ > > - uint16_t subsystem_id; /* only for header type =3D = 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 vec= tor, > > - MSIMessage msg); > > -typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned in= t 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 le= n); > > -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_f= n 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, DeviceStat= e *dev); > > -/* 0 <=3D pin <=3D 3 0 =3D INTA, 1 =3D INTB, 2 =3D INTC, 3 =3D 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 not= ifier); > > -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_mode= l, > > - 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D pci_get_byte(config); > > - uint8_t rval =3D 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 =3D 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 =3D pci_get_word(config); > > - uint16_t rval =3D 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 =3D 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 =3D pci_get_long(config); > > - uint32_t rval =3D 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 =3D 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 =3D pci_get_quad(config); > > - uint64_t rval =3D 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 =3D pci_get_quad(config); > > - return (val & mask) >> (ffs(mask) - 1); > > -} > > - > > -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool mul= tifunction, > > - 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 *nam= e); > > - > > -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_S= PACE_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_FR= OM_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 =3D dma_memory_map(pci_dma_context(dev), addr, plen, dir); > > - return buf; > > -} > > - > > -static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_a= ddr_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 *d= ev, > > - 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 =3D (stringify(_field)), = \ > > - .size =3D sizeof(PCIDevice), = \ > > - .vmsd =3D &vmstate_pci_device, = \ > > - .flags =3D VMS_STRUCT, = \ > > - .offset =3D vmstate_offset_value(_state, _field, PCIDevice),= \ > > -} > > - > > -#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { = \ > > - .name =3D (stringify(_field)), = \ > > - .size =3D sizeof(PCIDevice), = \ > > - .vmsd =3D &vmstate_pci_device, = \ > > - .flags =3D VMS_STRUCT|VMS_POINTER, = \ > > - .offset =3D 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) +=3D pci.o pci_bridge.o > > +common-obj-$(CONFIG_PCI) +=3D msix.o msi.o > > +common-obj-$(CONFIG_PCI) +=3D shpc.o > > +common-obj-$(CONFIG_PCI) +=3D slotid_cap.o > > +common-obj-$(CONFIG_PCI) +=3D pci_host.o pcie_host.o > > +common-obj-$(CONFIG_PCI) +=3D 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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_ARG= S__) > > + > > +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 msi64b= it) > > +{ > > + return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA= _32); > > +} > > + > > +static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64b= it) > > +{ > > + return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK= _32); > > +} > > + > > +static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi= 64bit) > > +{ > > + return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_P= ENDING_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 =3D pci_get_word(dev->config + msi_flags_off(dev)= ); > > + bool msi64bit =3D flags & PCI_MSI_FLAGS_64BIT; > > + > > + if (msi64bit) { > > + pci_set_quad(dev->config + msi_address_lo_off(dev), msg.addr= ess); > > + } else { > > + pci_set_long(dev->config + msi_address_lo_off(dev), msg.addr= ess); > > + } > > + pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data= ); > > +} > > + > > +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) > > +{ > > + uint16_t flags =3D pci_get_word(dev->config + msi_flags_off(dev)= ); > > + bool msi64bit =3D flags & PCI_MSI_FLAGS_64BIT; > > + unsigned int nr_vectors =3D msi_nr_vectors(flags); > > + MSIMessage msg; > > + > > + assert(vector < nr_vectors); > > + > > + if (msi64bit) { > > + msg.address =3D pci_get_quad(dev->config + msi_address_lo_of= f(dev)); > > + } else { > > + msg.address =3D pci_get_long(dev->config + msi_address_lo_of= f(dev)); > > + } > > + > > + /* upper bit 31:16 is zero */ > > + msg.data =3D pci_get_word(dev->config + msi_data_off(dev, msi64b= it)); > > + if (nr_vectors > 1) { > > + msg.data &=3D ~(nr_vectors - 1); > > + msg.data |=3D 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_ve= ctor_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 <=3D PCI_MSI_VECTORS_MAX); > > + /* the nr of MSI vectors is up to 32 */ > > + vectors_order =3D ffs(nr_vectors) - 1; > > + > > + flags =3D vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1); > > + if (msi64bit) { > > + flags |=3D PCI_MSI_FLAGS_64BIT; > > + } > > + if (msi_per_vector_mask) { > > + flags |=3D PCI_MSI_FLAGS_MASKBIT; > > + } > > + > > + cap_size =3D msi_cap_sizeof(flags); > > + config_offset =3D pci_add_capability(dev, PCI_CAP_ID_MSI, offset= , cap_size); > > + if (config_offset < 0) { > > + return config_offset; > > + } > > + > > + dev->msi_cap =3D config_offset; > > + dev->cap_present |=3D 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), 0xfffffff= f); > > + } > > + 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 =3D pci_get_word(dev->config + msi_flags_off(dev)); > > + cap_size =3D msi_cap_sizeof(flags); > > + pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); > > + dev->cap_present &=3D ~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 =3D pci_get_word(dev->config + msi_flags_off(dev)); > > + flags &=3D ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); > > + msi64bit =3D 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 =3D 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 =3D pci_get_long(dev->config + > > + msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BI= T)); > > + return mask & (1U << vector); > > +} > > + > > +void msi_notify(PCIDevice *dev, unsigned int vector) > > +{ > > + uint16_t flags =3D pci_get_word(dev->config + msi_flags_off(dev)= ); > > + bool msi64bit =3D flags & PCI_MSI_FLAGS_64BIT; > > + unsigned int nr_vectors =3D 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 << vect= or); > > + MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector); > > + return; > > + } > > + > > + msg =3D 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, i= nt len) > > +{ > > + uint16_t flags =3D pci_get_word(dev->config + msi_flags_off(dev)= ); > > + bool msi64bit =3D flags & PCI_MSI_FLAGS_64BIT; > > + bool msi_per_vector_mask =3D 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(flag= s))) { > > + 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, msi64bi= t)), > > + pci_get_long(dev->config + msi_pending_off(dev, msi6= 4bit))); > > + } > > + 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 pro= hibited > > + * 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 =3D > > + (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) -= 1); > > + log_max_vecs =3D > > + (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) -= 1); > > + if (log_num_vecs > log_max_vecs) { > > + flags &=3D ~PCI_MSI_FLAGS_QSIZE; > > + flags |=3D 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 =3D msi_nr_vectors(flags); > > + > > + /* This will discard pending interrupts, if any. */ > > + pending =3D pci_get_long(dev->config + msi_pending_off(dev, msi6= 4bit)); > > + pending &=3D 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors); > > + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pendi= ng); > > + > > + /* deliver pending interrupts which are unmasked */ > > + for (vector =3D 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 << vect= or); > > + msi_notify(dev, vector); > > + } > > +} > > + > > +unsigned int msi_nr_vectors_allocated(const PCIDevice *dev) > > +{ > > + uint16_t flags =3D 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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_ve= ctor_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, i= nt 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 > > + * > > + * Copyright (c) 2009, Red Hat Inc, Michael S. Tsirkin (mst@redhat.= com) > > + * > > + * 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 th= e > > + * 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 =3D dev->msix_table + vector * PCI_MSIX_ENT= RY_SIZE; > > + MSIMessage msg; > > + > > + msg.address =3D pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_= ADDR); > > + msg.data =3D 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 =3D dev->msix_table + vector * PCI_MSIX_ENT= RY_SIZE; > > + > > + pci_set_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR, msg.addres= s); > > + pci_set_long(table_entry + PCI_MSIX_ENTRY_DATA, msg.data); > > + table_entry[PCI_MSIX_ENTRY_VECTOR_CTRL] &=3D ~PCI_MSIX_ENTRY_CTR= L_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(vecto= r); > > +} > > + > > +static void msix_set_pending(PCIDevice *dev, int vector) > > +{ > > + *msix_pending_byte(dev, vector) |=3D msix_pending_mask(vector); > > +} > > + > > +static void msix_clr_pending(PCIDevice *dev, int vector) > > +{ > > + *msix_pending_byte(dev, vector) &=3D ~msix_pending_mask(vector); > > +} > > + > > +static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmas= k) > > +{ > > + unsigned offset =3D vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTR= Y_VECTOR_CTRL; > > + return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MA= SKBIT; > > +} > > + > > +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_m= asked) > > +{ > > + MSIMessage msg; > > + int ret; > > + > > + if (!dev->msix_vector_use_notifier) { > > + return; > > + } > > + if (is_masked) { > > + dev->msix_vector_release_notifier(dev, vector); > > + } else { > > + msg =3D msix_get_message(dev, vector); > > + ret =3D dev->msix_vector_use_notifier(dev, vector, msg); > > + assert(ret >=3D 0); > > + } > > +} > > + > > +static void msix_handle_mask_update(PCIDevice *dev, int vector, bool= was_masked) > > +{ > > + bool is_masked =3D msix_is_masked(dev, vector); > > + > > + if (is_masked =3D=3D 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 =3D !msix_enabled(dev) || > > + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MAS= KALL_MASK); > > +} > > + > > +/* Handle MSI-X capability config write. */ > > +void msix_write_config(PCIDevice *dev, uint32_t addr, > > + uint32_t val, int len) > > +{ > > + unsigned enable_pos =3D dev->msix_cap + MSIX_CONTROL_OFFSET; > > + int vector; > > + bool was_masked; > > + > > + if (!msix_present(dev) || !range_covers_byte(addr, len, enable_p= os)) { > > + return; > > + } > > + > > + was_masked =3D dev->msix_function_masked; > > + msix_update_function_masked(dev); > > + > > + if (!msix_enabled(dev)) { > > + return; > > + } > > + > > + pci_device_deassert_intx(dev); > > + > > + if (dev->msix_function_masked =3D=3D was_masked) { > > + return; > > + } > > + > > + for (vector =3D 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 =3D 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 =3D opaque; > > + int vector =3D addr / PCI_MSIX_ENTRY_SIZE; > > + bool was_masked; > > + > > + was_masked =3D 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 =3D { > > + .read =3D msix_table_mmio_read, > > + .write =3D msix_table_mmio_write, > > + /* TODO: MSIX should be LITTLE_ENDIAN. */ > > + .endianness =3D DEVICE_NATIVE_ENDIAN, > > + .valid =3D { > > + .min_access_size =3D 4, > > + .max_access_size =3D 4, > > + }, > > +}; > > + > > +static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, > > + unsigned size) > > +{ > > + PCIDevice *dev =3D opaque; > > + > > + return pci_get_long(dev->msix_pba + addr); > > +} > > + > > +static const MemoryRegionOps msix_pba_mmio_ops =3D { > > + .read =3D msix_pba_mmio_read, > > + /* TODO: MSIX should be LITTLE_ENDIAN. */ > > + .endianness =3D DEVICE_NATIVE_ENDIAN, > > + .valid =3D { > > + .min_access_size =3D 4, > > + .max_access_size =3D 4, > > + }, > > +}; > > + > > +static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) > > +{ > > + int vector; > > + > > + for (vector =3D 0; vector < nentries; ++vector) { > > + unsigned offset =3D > > + vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTR= L; > > + bool was_masked =3D msix_is_masked(dev, vector); > > + > > + dev->msix_table[offset] |=3D 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_p= os) > > +{ > > + 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 =3D nentries * PCI_MSIX_ENTRY_SIZE; > > + pba_size =3D QEMU_ALIGN_UP(nentries, 64) / 8; > > + > > + /* Sanity test: table & pba don't overlap, fit within BARs, min = aligned */ > > + if ((table_bar_nr =3D=3D pba_bar_nr && > > + ranges_overlap(table_offset, table_size, pba_offset, pba_si= ze)) || > > + 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 =3D pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_C= AP_LENGTH); > > + if (cap < 0) { > > + return cap; > > + } > > + > > + dev->msix_cap =3D cap; > > + dev->cap_present |=3D QEMU_PCI_CAP_MSIX; > > + config =3D dev->config + cap; > > + > > + pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); > > + dev->msix_entries_nr =3D nentries; > > + dev->msix_function_masked =3D true; > > + > > + pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_n= r); > > + pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr); > > + > > + /* Make flags bit writable. */ > > + dev->wmask[cap + MSIX_CONTROL_OFFSET] |=3D MSIX_ENABLE_MASK | > > + MSIX_MASKALL_MASK; > > + > > + dev->msix_table =3D g_malloc0(table_size); > > + dev->msix_pba =3D g_malloc0(pba_size); > > + dev->msix_entry_used =3D g_malloc0(nentries * sizeof *dev->msix_= entry_used); > > + > > + msix_mask_all(dev, nentries); > > + > > + memory_region_init_io(&dev->msix_table_mmio, &msix_table_mmio_op= s, 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, d= ev, > > + "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_OFFS= ET) { > > + return -EINVAL; > > + } > > + > > + name =3D g_strdup_printf("%s-msix", dev->name); > > + memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIV= E_BAR_SIZE); > > + g_free(name); > > + > > + ret =3D msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_n= r, > > + MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_excl= usive_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 =3D 0; vector < dev->msix_entries_nr; ++vector) { > > + dev->msix_entry_used[vector] =3D 0; > > + msix_clr_pending(dev, vector); > > + } > > +} > > + > > +static void msix_clear_all_vectors(PCIDevice *dev) > > +{ > > + int vector; > > + > > + for (vector =3D 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, MemoryRegi= on *pba_bar) > > +{ > > + if (!msix_present(dev)) { > > + return; > > + } > > + pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH); > > + dev->msix_cap =3D 0; > > + msix_free_irq_entries(dev); > > + dev->msix_entries_nr =3D 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 =3D 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 =3D NULL; > > + g_free(dev->msix_entry_used); > > + dev->msix_entry_used =3D NULL; > > + dev->cap_present &=3D ~QEMU_PCI_CAP_MSIX; > > +} > > + > > +void msix_uninit_exclusive_bar(PCIDevice *dev) > > +{ > > + if (msix_present(dev)) { > > + msix_uninit(dev, &dev->msix_exclusive_bar, &dev->msix_exclus= ive_bar); > > + memory_region_destroy(&dev->msix_exclusive_bar); > > + } > > +} > > + > > +void msix_save(PCIDevice *dev, QEMUFile *f) > > +{ > > + unsigned n =3D 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 =3D 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 =3D 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 >=3D dev->msix_entries_nr || !dev->msix_entry_used[ve= ctor]) > > + return; > > + if (msix_is_masked(dev, vector)) { > > + msix_set_pending(dev, vector); > > + return; > > + } > > + > > + msg =3D 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] &=3D > > + ~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 c= onfigure > > + * 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 >=3D 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 >=3D dev->msix_entries_nr || !dev->msix_entry_used[ve= ctor]) { > > + 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 =3D 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_notif= ier) > > +{ > > + int vector, ret; > > + > > + assert(use_notifier && release_notifier); > > + > > + dev->msix_vector_use_notifier =3D use_notifier; > > + dev->msix_vector_release_notifier =3D release_notifier; > > + > > + if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & > > + (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) =3D=3D MSIX_ENABLE_M= ASK) { > > + for (vector =3D 0; vector < dev->msix_entries_nr; vector++) = { > > + ret =3D msix_set_notifier_for_vector(dev, vector); > > + if (ret < 0) { > > + goto undo; > > + } > > + } > > + } > > + return 0; > > + > > +undo: > > + while (--vector >=3D 0) { > > + msix_unset_notifier_for_vector(dev, vector); > > + } > > + dev->msix_vector_use_notifier =3D NULL; > > + dev->msix_vector_release_notifier =3D 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)) =3D=3D MSIX_ENABLE_M= ASK) { > > + for (vector =3D 0; vector < dev->msix_entries_nr; vector++) = { > > + msix_unset_notifier_for_vector(dev, vector); > > + } > > + } > > + dev->msix_vector_use_notifier =3D NULL; > > + dev->msix_vector_release_notifier =3D 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_p= os); > > +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 va= l, 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_notif= ier); > > +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 obtai= ning a copy > > + * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be in= cluded in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > > + * 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, A= RISING FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS 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 =3D NULL; > > + QemuOpts *opts; > > + PCIBus *bus; > > + int ret, devfn; > > + > > + bus =3D pci_get_bus_devfn(&devfn, devaddr); > > + if (!bus) { > > + monitor_printf(mon, "Invalid PCI device address %s\n", devad= dr); > > + return NULL; > > + } > > + if (!((BusState*)bus)->allow_hotplug) { > > + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); > > + return NULL; > > + } > > + > > + opts =3D qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_= str : "", 0); > > + if (!opts) { > > + return NULL; > > + } > > + > > + qemu_opt_set(opts, "type", "nic"); > > + > > + ret =3D 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 =3D (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 =3D qemu_opt_get_number(dinfo->opts, "unit", -1); > > + dinfo->bus =3D scsibus->busnr; > > + scsidev =3D scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinf= o->unit, > > + false, -1); > > + if (!scsidev) { > > + return -1; > > + } > > + dinfo->unit =3D 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 =3D 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 =3D 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", p= ci_addr); > > + goto err; > > + } > > + if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) !=3D 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 =3D NULL; > > + int type =3D -1; > > + char buf[128]; > > + PCIBus *bus; > > + int devfn; > > + > > + if (get_param_value(buf, sizeof(buf), "if", opts)) { > > + if (!strcmp(buf, "scsi")) > > + type =3D IF_SCSI; > > + else if (!strcmp(buf, "virtio")) { > > + type =3D IF_VIRTIO; > > + } else { > > + monitor_printf(mon, "type %s not a hotpluggable PCI devi= ce.\n", buf); > > + return NULL; > > + } > > + } else { > > + monitor_printf(mon, "no if=3D specified\n"); > > + return NULL; > > + } > > + > > + if (get_param_value(buf, sizeof(buf), "file", opts)) { > > + dinfo =3D add_init_drive(opts); > > + if (!dinfo) > > + return NULL; > > + if (dinfo->devaddr) { > > + monitor_printf(mon, "Parameter addr not supported\n"); > > + return NULL; > > + } > > + } else { > > + dinfo =3D NULL; > > + } > > + > > + bus =3D pci_get_bus_devfn(&devfn, devaddr); > > + if (!bus) { > > + monitor_printf(mon, "Invalid PCI device address %s\n", devad= dr); > > + 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 =3D pci_create(bus, devfn, "lsi53c895a"); > > + if (qdev_init(&dev->qdev) < 0) > > + dev =3D NULL; > > + if (dev && dinfo) { > > + if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) !=3D 0) { > > + qdev_unplug(&dev->qdev, NULL); > > + dev =3D NULL; > > + } > > + } > > + break; > > + case IF_VIRTIO: > > + if (!dinfo) { > > + monitor_printf(mon, "virtio requires a backing file/devi= ce.\n"); > > + return NULL; > > + } > > + dev =3D pci_create(bus, devfn, "virtio-blk-pci"); > > + if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < = 0) { > > + qdev_free(&dev->qdev); > > + dev =3D NULL; > > + break; > > + } > > + if (qdev_init(&dev->qdev) < 0) > > + dev =3D NULL; > > + break; > > + default: > > + dev =3D NULL; > > + } > > + return dev; > > +} > > + > > +void pci_device_hot_add(Monitor *mon, const QDict *qdict) > > +{ > > + PCIDevice *dev =3D NULL; > > + const char *pci_addr =3D qdict_get_str(qdict, "pci_addr"); > > + const char *type =3D qdict_get_str(qdict, "type"); > > + const char *opts =3D qdict_get_try_str(qdict, "opts"); > > + > > + /* strip legacy tag */ > > + if (!strncmp(pci_addr, "pci_addr=3D", 9)) { > > + pci_addr +=3D 9; > > + } > > + > > + if (!opts) { > > + opts =3D ""; > > + } > > + > > + if (!strcmp(pci_addr, "auto")) > > + pci_addr =3D NULL; > > + > > + if (strcmp(type, "nic") =3D=3D 0) { > > + dev =3D qemu_pci_hot_add_nic(mon, pci_addr, opts); > > + } else if (strcmp(type, "storage") =3D=3D 0) { > > + dev =3D 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 =3D NULL; > > + > > + if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { > > + return -1; > > + } > > + > > + d =3D pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slo= t, 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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 obtai= ning a copy > > + * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be in= cluded in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > > + * 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, A= RISING FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS 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 ind= ent); > > +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[] =3D { > > + 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 =3D BUS_CLASS(klass); > > + > > + k->print_dev =3D pcibus_dev_print; > > + k->get_dev_path =3D pcibus_get_dev_path; > > + k->get_fw_dev_path =3D pcibus_get_fw_dev_path; > > + k->reset =3D pcibus_reset; > > +} > > + > > +static const TypeInfo pci_bus_info =3D { > > + .name =3D TYPE_PCI_BUS, > > + .parent =3D TYPE_BUS, > > + .instance_size =3D sizeof(PCIBus), > > + .class_init =3D 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 =3D PCI_SUBVENDOR_ID_REDHA= T_QUMRANET; > > +static uint16_t pci_default_sub_device_id =3D 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 =3D { > > + .name =3D "PCIBUS", > > + .version_id =3D 1, > > + .minimum_version_id =3D 1, > > + .minimum_version_id_old =3D 1, > > + .fields =3D (VMStateField []) { > > + VMSTATE_INT32_EQUAL(nirq, PCIBus), > > + VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_inf= o_int32, int32_t), > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > +static int pci_bar(PCIDevice *d, int reg) > > +{ > > + uint8_t type; > > + > > + if (reg !=3D PCI_ROM_SLOT) > > + return PCI_BASE_ADDRESS_0 + reg * 4; > > + > > + type =3D d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUN= CTION; > > + return type =3D=3D PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : P= CI_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 &=3D ~(0x1 << irq_num); > > + d->irq_state |=3D level << irq_num; > > +} > > + > > +static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, in= t change) > > +{ > > + PCIBus *bus; > > + for (;;) { > > + bus =3D pci_dev->bus; > > + irq_num =3D bus->map_irq(pci_dev, irq_num); > > + if (bus->set_irq) > > + break; > > + pci_dev =3D bus->parent_dev; > > + } > > + bus->irq_count[irq_num] +=3D change; > > + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != =3D 0); > > +} > > + > > +int pci_bus_get_irq_level(PCIBus *bus, int irq_num) > > +{ > > + assert(irq_num >=3D 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] |=3D PCI_STATUS_INTERRUPT; > > + } else { > > + dev->config[PCI_STATUS] &=3D ~PCI_STATUS_INTERRUPT; > > + } > > +} > > + > > +void pci_device_deassert_intx(PCIDevice *dev) > > +{ > > + int i; > > + for (i =3D 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 =3D 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_COMMA= ND) | > > + pci_get_word(dev->w1cmask + PCI_COM= MAND)); > > + pci_word_test_and_clear_mask(dev->config + PCI_STATUS, > > + pci_get_word(dev->wmask + PCI_STATU= S) | > > + pci_get_word(dev->w1cmask + PCI_STA= TUS)); > > + dev->config[PCI_CACHE_LINE_SIZE] =3D 0x0; > > + dev->config[PCI_INTERRUPT_LINE] =3D 0x0; > > + for (r =3D 0; r < PCI_NUM_REGIONS; ++r) { > > + PCIIORegion *region =3D &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 =3D 0; i < bus->nirq; i++) { > > + bus->irq_count[i] =3D 0; > > + } > > + for (i =3D 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 =3D g_malloc0(sizeof(*host)); > > + host->domain =3D domain; > > + host->bus =3D 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 =3D=3D domain) { > > + return host->bus; > > + } > > + } > > + > > + return NULL; > > +} > > + > > +int pci_find_domain(const PCIBus *bus) > > +{ > > + PCIDevice *d; > > + struct PCIHostBus *host; > > + > > + /* obtain root bus */ > > + while ((d =3D bus->parent_dev) !=3D NULL) { > > + bus =3D d->bus; > > + } > > + > > + QLIST_FOREACH(host, &host_buses, next) { > > + if (host->bus =3D=3D 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) =3D=3D 0); > > + bus->devfn_min =3D devfn_min; > > + bus->address_space_mem =3D address_space_mem; > > + bus->address_space_io =3D address_space_io; > > + > > + /* host bridge */ > > + QLIST_INIT(&bus->child); > > + pci_host_bus_register(0, bus); /* for now only pci domain 0 is s= upported */ > > + > > + 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 =3D g_malloc0(sizeof(*bus)); > > + pci_bus_new_inplace(bus, parent, name, address_space_mem, > > + address_space_io, devfn_min); > > + OBJECT(bus)->free =3D g_free; > > + return bus; > > +} > > + > > +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_f= n map_irq, > > + void *irq_opaque, int nirq) > > +{ > > + bus->set_irq =3D set_irq; > > + bus->map_irq =3D map_irq; > > + bus->irq_opaque =3D irq_opaque; > > + bus->nirq =3D nirq; > > + bus->irq_count =3D g_malloc0(nirq * sizeof(bus->irq_count[0])); > > +} > > + > > +void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceStat= e *qdev) > > +{ > > + bus->qbus.allow_hotplug =3D 1; > > + bus->hotplug =3D hotplug; > > + bus->hotplug_qdev =3D 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 =3D 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 =3D container_of(pv, PCIDevice, config); > > + uint8_t *config; > > + int i; > > + > > + assert(size =3D=3D pci_config_size(s)); > > + config =3D g_malloc(size); > > + > > + qemu_get_buffer(f, config, size); > > + for (i =3D 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 =3D pv; > > + assert(size =3D=3D pci_config_size(container_of(pv, PCIDevice, c= onfig))); > > + qemu_put_buffer(f, *v, size); > > +} > > + > > +static VMStateInfo vmstate_info_pci_config =3D { > > + .name =3D "pci config", > > + .get =3D get_pci_config_device, > > + .put =3D put_pci_config_device, > > +}; > > + > > +static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) > > +{ > > + PCIDevice *s =3D container_of(pv, PCIDevice, irq_state); > > + uint32_t irq_state[PCI_NUM_PINS]; > > + int i; > > + for (i =3D 0; i < PCI_NUM_PINS; ++i) { > > + irq_state[i] =3D qemu_get_be32(f); > > + if (irq_state[i] !=3D 0x1 && irq_state[i] !=3D 0) { > > + fprintf(stderr, "irq state %d: must be 0 or 1.\n", > > + irq_state[i]); > > + return -EINVAL; > > + } > > + } > > + > > + for (i =3D 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 =3D container_of(pv, PCIDevice, irq_state); > > + > > + for (i =3D 0; i < PCI_NUM_PINS; ++i) { > > + qemu_put_be32(f, pci_irq_state(s, i)); > > + } > > +} > > + > > +static VMStateInfo vmstate_info_pci_irq_state =3D { > > + .name =3D "pci irq state", > > + .get =3D get_pci_irq_state, > > + .put =3D put_pci_irq_state, > > +}; > > + > > +const VMStateDescription vmstate_pci_device =3D { > > + .name =3D "PCIDevice", > > + .version_id =3D 2, > > + .minimum_version_id =3D 1, > > + .minimum_version_id_old =3D 1, > > + .fields =3D (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 =3D { > > + .name =3D "PCIEDevice", > > + .version_id =3D 2, > > + .minimum_version_id =3D 1, > > + .minimum_version_id_old =3D 1, > > + .fields =3D (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_d= evice; > > +} > > + > > +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] &=3D ~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 =3D 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 [[:]:], return -1 on error if funcp =3D=3D= NULL > > + * [[:]:]., 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 =3D 0, bus =3D 0; > > + unsigned int slot =3D 0; > > + unsigned int func =3D 0; > > + > > + p =3D addr; > > + val =3D strtoul(p, &e, 16); > > + if (e =3D=3D p) > > + return -1; > > + if (*e =3D=3D ':') { > > + bus =3D val; > > + p =3D e + 1; > > + val =3D strtoul(p, &e, 16); > > + if (e =3D=3D p) > > + return -1; > > + if (*e =3D=3D ':') { > > + dom =3D bus; > > + bus =3D val; > > + p =3D e + 1; > > + val =3D strtoul(p, &e, 16); > > + if (e =3D=3D p) > > + return -1; > > + } > > + } > > + > > + slot =3D val; > > + > > + if (funcp !=3D NULL) { > > + if (*e !=3D '.') > > + return -1; > > + > > + p =3D e + 1; > > + val =3D strtoul(p, &e, 16); > > + if (e =3D=3D p) > > + return -1; > > + > > + func =3D val; > > + } > > + > > + /* if funcp =3D=3D NULL func is 0 */ > > + if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) > > + return -1; > > + > > + if (*e) > > + return -1; > > + > > + *domp =3D dom; > > + *busp =3D bus; > > + *slotp =3D slot; > > + if (funcp !=3D NULL) > > + *funcp =3D 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=3D", 9)) { > > + addr +=3D 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 =3D -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 =3D 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] =3D PCI_STATUS_CAP_LIST; > > + dev->cmask[PCI_REVISION_ID] =3D 0xff; > > + dev->cmask[PCI_CLASS_PROG] =3D 0xff; > > + pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff); > > + dev->cmask[PCI_HEADER_TYPE] =3D 0xff; > > + dev->cmask[PCI_CAPABILITY_LIST] =3D 0xff; > > +} > > + > > +static void pci_init_wmask(PCIDevice *dev) > > +{ > > + int config_size =3D pci_config_size(dev); > > + > > + dev->wmask[PCI_CACHE_LINE_SIZE] =3D 0xff; > > + dev->wmask[PCI_INTERRUPT_LINE] =3D 0xff; > > + pci_set_word(dev->wmask + PCI_COMMAND, > > + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_M= ASTER | > > + PCI_COMMAND_INTX_DISABLE); > > + if (dev->cap_present & QEMU_PCI_CAP_SERR) { > > + pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COM= MAND_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_P= ARITY); > > +} > > + > > +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] =3D PCI_IO_RANGE_MASK & 0xff; > > + d->wmask[PCI_IO_LIMIT] =3D 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] |=3D PCI_IO_RANGE_TYPE_16; > > + d->config[PCI_IO_LIMIT] |=3D 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 di= scard timer */ > > +#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard = timer */ > > +#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer stat= us */ > > +#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] |=3D PCI_IO_RANGE_TYPE_MASK; > > + d->cmask[PCI_IO_LIMIT] |=3D 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 =3D PCI_SLOT(dev->devfn); > > + uint8_t func; > > + > > + if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { > > + dev->config[PCI_HEADER_TYPE] |=3D PCI_HEADER_TYPE_MULTI_FUNC= TION; > > + } > > + > > + /* > > + * 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 =3D 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 popul= ated " > > + "in function %x.%x", slot, PCI_FUNC(dev->de= vfn)); > > + 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 =3D 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 =3D pci_config_size(pci_dev); > > + > > + pci_dev->config =3D g_malloc0(config_size); > > + pci_dev->cmask =3D g_malloc0(config_size); > > + pci_dev->wmask =3D g_malloc0(config_size); > > + pci_dev->w1cmask =3D g_malloc0(config_size); > > + pci_dev->used =3D 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 =3D PCI_DEVICE_GET_CLASS(pci_dev); > > + PCIConfigReadFunc *config_read =3D pc->config_read; > > + PCIConfigWriteFunc *config_write =3D pc->config_write; > > + > > + if (devfn < 0) { > > + for(devfn =3D bus->devfn_min ; devfn < ARRAY_SIZE(bus->devic= es); > > + devfn +=3D 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->de= vices[devfn]->name); > > + return NULL; > > + } > > + pci_dev->bus =3D bus; > > + if (bus->dma_context_fn) { > > + pci_dev->dma =3D bus->dma_context_fn(bus, bus->dma_context_o= paque, 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_memor= y())); > > + memory_region_set_enabled(&pci_dev->bus_master_enable_region= , false); > > + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_ma= ster_enable_region); > > + pci_dev->dma =3D g_new(DMAContext, 1); > > + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL= , NULL, NULL); > > + } > > + pci_dev->devfn =3D devfn; > > + pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); > > + pci_dev->irq_state =3D 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 =3D pci_default_read_config; > > + if (!config_write) > > + config_write =3D pci_default_write_config; > > + pci_dev->config_read =3D config_read; > > + pci_dev->config_write =3D config_write; > > + bus->devices[devfn] =3D pci_dev; > > + pci_dev->irq =3D qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NU= M_PINS); > > + pci_dev->version_id =3D 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] =3D 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 =3D NULL; > > + } > > +} > > + > > +static void pci_unregister_io_regions(PCIDevice *pci_dev) > > +{ > > + PCIIORegion *r; > > + int i; > > + > > + for(i =3D 0; i < PCI_NUM_REGIONS; i++) { > > + r =3D &pci_dev->io_regions[i]; > > + if (!r->size || r->addr =3D=3D PCI_BAR_UNMAPPED) > > + continue; > > + memory_region_del_subregion(r->address_space, r->memory); > > + } > > +} > > + > > +static int pci_unregister_device(DeviceState *dev) > > +{ > > + PCIDevice *pci_dev =3D PCI_DEVICE(dev); > > + PCIDeviceClass *pc =3D 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 =3D memory_region_size(memory); > > + > > + assert(region_num >=3D 0); > > + assert(region_num < PCI_NUM_REGIONS); > > + if (size & (size-1)) { > > + fprintf(stderr, "ERROR: PCI region size must be pow2 " > > + "type=3D0x%x, size=3D0x%"FMT_PCIBUS"\n", type, s= ize); > > + exit(1); > > + } > > + > > + r =3D &pci_dev->io_regions[region_num]; > > + r->addr =3D PCI_BAR_UNMAPPED; > > + r->size =3D size; > > + r->type =3D type; > > + r->memory =3D NULL; > > + > > + wmask =3D ~(size - 1); > > + addr =3D pci_bar(pci_dev, region_num); > > + if (region_num =3D=3D PCI_ROM_SLOT) { > > + /* ROM enable bit is writable */ > > + wmask |=3D 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 =3D memory; > > + pci_dev->io_regions[region_num].address_space > > + =3D 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 =3D pci_bar(d, reg); > > + uint16_t cmd =3D 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 =3D pci_get_long(d->config + bar) & ~(size - 1); > > + last_addr =3D new_addr + size - 1; > > + /* NOTE: we have only 64K ioports on PC */ > > + if (last_addr <=3D new_addr || new_addr =3D=3D 0 || last_add= r > 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 =3D pci_get_quad(d->config + bar); > > + } else { > > + new_addr =3D pci_get_long(d->config + bar); > > + } > > + /* the ROM slot has a specific enable bit */ > > + if (reg =3D=3D PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENAB= LE)) { > > + return PCI_BAR_UNMAPPED; > > + } > > + new_addr &=3D ~(size - 1); > > + last_addr =3D 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 <=3D new_addr || new_addr =3D=3D 0 || > > + last_addr =3D=3D 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 >=3D UI= NT32_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 >=3D 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 =3D 0; i < PCI_NUM_REGIONS; i++) { > > + r =3D &d->io_regions[i]; > > + > > + /* this region isn't registered */ > > + if (!r->size) > > + continue; > > + > > + new_addr =3D pci_bar_address(d, i, r->type, r->size); > > + > > + /* This bar isn't changed */ > > + if (new_addr =3D=3D r->addr) > > + continue; > > + > > + /* now do the real mapping */ > > + if (r->addr !=3D PCI_BAR_UNMAPPED) { > > + memory_region_del_subregion(r->address_space, r->memory)= ; > > + } > > + r->addr =3D new_addr; > > + if (r->addr !=3D 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_disabl= ed) > > +{ > > + int i, disabled =3D pci_irq_disabled(d); > > + if (disabled =3D=3D was_irq_disabled) > > + return; > > + for (i =3D 0; i < PCI_NUM_PINS; ++i) { > > + int state =3D 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 =3D 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 =3D pci_irq_disabled(d); > > + > > + for (i =3D 0; i < l; val >>=3D 8, ++i) { > > + uint8_t wmask =3D d->wmask[addr + i]; > > + uint8_t w1cmask =3D d->w1cmask[addr + i]; > > + assert(!(wmask & w1cmask)); > > + d->config[addr + i] =3D (d->config[addr + i] & ~wmask) | (va= l & wmask); > > + d->config[addr + i] &=3D ~(val & w1cmask); /* W1C: Write 1 t= o 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_COMMA= ND) > > + & PCI_COMMAND_MASTER); > > + } > > + > > + msi_write_config(d, addr, val, l); > > + msix_write_config(d, addr, val, l); > > +} > > + > > +/***********************************************************/ > > +/* generic PCI irq support */ > > + > > +/* 0 <=3D irq_num <=3D 3. level must be 0 or 1 */ > > +static void pci_set_irq(void *opaque, int irq_num, int level) > > +{ > > + PCIDevice *pci_dev =3D opaque; > > + int change; > > + > > + change =3D 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_in= tx_to_irq) > > +{ > > + assert(!bus->parent_dev); > > + bus->route_intx_to_irq =3D route_intx_to_irq; > > +} > > + > > +PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) > > +{ > > + PCIBus *bus; > > + > > + do { > > + bus =3D dev->bus; > > + pin =3D bus->map_irq(dev, pin); > > + dev =3D 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 !=3D new->mode || old->irq !=3D new->irq; > > +} > > + > > +void pci_bus_fire_intx_routing_notifier(PCIBus *bus) > > +{ > > + PCIDevice *dev; > > + PCIBus *sec; > > + int i; > > + > > + for (i =3D 0; i < ARRAY_SIZE(bus->devices); ++i) { > > + dev =3D 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 not= ifier) > > +{ > > + dev->intx_routing_notifier =3D 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 <=3D pin <=3D 3 0 =3D INTA, 1 =3D INTB, 2 =3D INTC, 3 =3D 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[] =3D > > +{ > > + { 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, PCID= evice *d, > > + void *opaque), > > + void *opaque) > > +{ > > + PCIDevice *d; > > + int devfn; > > + > > + for(devfn =3D 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > > + d =3D 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 *o= paque), > > + void *opaque) > > +{ > > + bus =3D 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 =3D pci_class_descriptions; > > + while (desc->desc && class !=3D desc->class) { > > + desc++; > > + } > > + > > + return desc; > > +} > > + > > +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus= _num); > > + > > +static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *d= ev) > > +{ > > + PciMemoryRegionList *head =3D NULL, *cur_item =3D NULL; > > + int i; > > + > > + for (i =3D 0; i < PCI_NUM_REGIONS; i++) { > > + const PCIIORegion *r =3D &dev->io_regions[i]; > > + PciMemoryRegionList *region; > > + > > + if (!r->size) { > > + continue; > > + } > > + > > + region =3D g_malloc0(sizeof(*region)); > > + region->value =3D g_malloc0(sizeof(*region->value)); > > + > > + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { > > + region->value->type =3D g_strdup("io"); > > + } else { > > + region->value->type =3D g_strdup("memory"); > > + region->value->has_prefetch =3D true; > > + region->value->prefetch =3D !!(r->type & PCI_BASE_ADDRES= S_MEM_PREFETCH); > > + region->value->has_mem_type_64 =3D true; > > + region->value->mem_type_64 =3D !!(r->type & PCI_BASE_ADD= RESS_MEM_TYPE_64); > > + } > > + > > + region->value->bar =3D i; > > + region->value->address =3D r->addr; > > + region->value->size =3D r->size; > > + > > + /* XXX: waiting for the qapi to support GSList */ > > + if (!cur_item) { > > + head =3D cur_item =3D region; > > + } else { > > + cur_item->next =3D region; > > + cur_item =3D region; > > + } > > + } > > + > > + return head; > > +} > > + > > +static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *b= us, > > + int bus_num) > > +{ > > + PciBridgeInfo *info; > > + > > + info =3D g_malloc0(sizeof(*info)); > > + > > + info->bus.number =3D dev->config[PCI_PRIMARY_BUS]; > > + info->bus.secondary =3D dev->config[PCI_SECONDARY_BUS]; > > + info->bus.subordinate =3D dev->config[PCI_SUBORDINATE_BUS]; > > + > > + info->bus.io_range =3D g_malloc0(sizeof(*info->bus.io_range)); > > + info->bus.io_range->base =3D pci_bridge_get_base(dev, PCI_BASE_A= DDRESS_SPACE_IO); > > + info->bus.io_range->limit =3D pci_bridge_get_limit(dev, PCI_BASE= _ADDRESS_SPACE_IO); > > + > > + info->bus.memory_range =3D g_malloc0(sizeof(*info->bus.memory_ra= nge)); > > + info->bus.memory_range->base =3D pci_bridge_get_base(dev, PCI_BA= SE_ADDRESS_SPACE_MEMORY); > > + info->bus.memory_range->limit =3D pci_bridge_get_limit(dev, PCI_= BASE_ADDRESS_SPACE_MEMORY); > > + > > + info->bus.prefetchable_range =3D g_malloc0(sizeof(*info->bus.pre= fetchable_range)); > > + info->bus.prefetchable_range->base =3D pci_bridge_get_base(dev, = PCI_BASE_ADDRESS_MEM_PREFETCH); > > + info->bus.prefetchable_range->limit =3D pci_bridge_get_limit(dev= , PCI_BASE_ADDRESS_MEM_PREFETCH); > > + > > + if (dev->config[PCI_SECONDARY_BUS] !=3D 0) { > > + PCIBus *child_bus =3D pci_find_bus_nr(bus, dev->config[PCI_S= ECONDARY_BUS]); > > + if (child_bus) { > > + info->has_devices =3D true; > > + info->devices =3D qmp_query_pci_devices(child_bus, dev->= config[PCI_SECONDARY_BUS]); > > + } > > + } > > + > > + return info; > > +} > > + > > +static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *b= us, > > + int bus_num) > > +{ > > + const pci_class_desc *desc; > > + PciDeviceInfo *info; > > + uint8_t type; > > + int class; > > + > > + info =3D g_malloc0(sizeof(*info)); > > + info->bus =3D bus_num; > > + info->slot =3D PCI_SLOT(dev->devfn); > > + info->function =3D PCI_FUNC(dev->devfn); > > + > > + class =3D pci_get_word(dev->config + PCI_CLASS_DEVICE); > > + info->class_info.class =3D class; > > + desc =3D get_class_desc(class); > > + if (desc->desc) { > > + info->class_info.has_desc =3D true; > > + info->class_info.desc =3D g_strdup(desc->desc); > > + } > > + > > + info->id.vendor =3D pci_get_word(dev->config + PCI_VENDOR_ID); > > + info->id.device =3D pci_get_word(dev->config + PCI_DEVICE_ID); > > + info->regions =3D qmp_query_pci_regions(dev); > > + info->qdev_id =3D g_strdup(dev->qdev.id ? dev->qdev.id : ""); > > + > > + if (dev->config[PCI_INTERRUPT_PIN] !=3D 0) { > > + info->has_irq =3D true; > > + info->irq =3D dev->config[PCI_INTERRUPT_LINE]; > > + } > > + > > + type =3D dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_F= UNCTION; > > + if (type =3D=3D PCI_HEADER_TYPE_BRIDGE) { > > + info->has_pci_bridge =3D true; > > + info->pci_bridge =3D qmp_query_pci_bridge(dev, bus, bus_num)= ; > > + } > > + > > + return info; > > +} > > + > > +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus= _num) > > +{ > > + PciDeviceInfoList *info, *head =3D NULL, *cur_item =3D NULL; > > + PCIDevice *dev; > > + int devfn; > > + > > + for (devfn =3D 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { > > + dev =3D bus->devices[devfn]; > > + if (dev) { > > + info =3D g_malloc0(sizeof(*info)); > > + info->value =3D qmp_query_pci_device(dev, bus, bus_num); > > + > > + /* XXX: waiting for the qapi to support GSList */ > > + if (!cur_item) { > > + head =3D cur_item =3D info; > > + } else { > > + cur_item->next =3D info; > > + cur_item =3D info; > > + } > > + } > > + } > > + > > + return head; > > +} > > + > > +static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) > > +{ > > + PciInfo *info =3D NULL; > > + > > + bus =3D pci_find_bus_nr(bus, bus_num); > > + if (bus) { > > + info =3D g_malloc0(sizeof(*info)); > > + info->bus =3D bus_num; > > + info->devices =3D qmp_query_pci_devices(bus, bus_num); > > + } > > + > > + return info; > > +} > > + > > +PciInfoList *qmp_query_pci(Error **errp) > > +{ > > + PciInfoList *info, *head =3D NULL, *cur_item =3D NULL; > > + struct PCIHostBus *host; > > + > > + QLIST_FOREACH(host, &host_buses, next) { > > + info =3D g_malloc0(sizeof(*info)); > > + info->value =3D qmp_query_pci_bus(host->bus, 0); > > + > > + /* XXX: waiting for the qapi to support GSList */ > > + if (!cur_item) { > > + head =3D cur_item =3D info; > > + } else { > > + cur_item->next =3D info; > > + cur_item =3D info; > > + } > > + } > > + > > + return head; > > +} > > + > > +static const char * const pci_nic_models[] =3D { > > + "ne2k_pci", > > + "i82551", > > + "i82557b", > > + "i82559er", > > + "rtl8139", > > + "e1000", > > + "pcnet", > > + "virtio", > > + NULL > > +}; > > + > > +static const char * const pci_nic_names[] =3D { > > + "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 =3D nd->devaddr ? nd->devaddr : default_deva= ddr; > > + PCIBus *bus; > > + int devfn; > > + PCIDevice *pci_dev; > > + DeviceState *dev; > > + int i; > > + > > + i =3D qemu_find_nic_model(nd, pci_nic_models, default_model); > > + if (i < 0) > > + return NULL; > > + > > + bus =3D 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 =3D pci_create(bus, devfn, pci_nic_names[i]); > > + dev =3D &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_mode= l, > > + const char *default_devaddr) > > +{ > > + PCIDevice *res; > > + > > + if (qemu_show_nic_models(nd->model, pci_nic_models)) > > + exit(0); > > + > > + res =3D 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 <=3D 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) =3D=3D 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 =3D sec) { > > + QLIST_FOREACH(sec, &bus->child, sibling) { > > + assert(sec->parent_dev); > > + if (sec->parent_dev->config[PCI_SECONDARY_BUS] =3D=3D bu= s_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 =3D 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 =3D (PCIDevice *)qdev; > > + PCIDeviceClass *pc =3D PCI_DEVICE_GET_CLASS(pci_dev); > > + PCIBus *bus; > > + int rc; > > + bool is_default_rom; > > + > > + /* initialize cap_present for pci_is_express() and pci_config_si= ze() */ > > + if (pc->is_express) { > > + pci_dev->cap_present |=3D QEMU_PCI_CAP_EXPRESS; > > + } > > + > > + bus =3D FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); > > + pci_dev =3D do_pci_register_device(pci_dev, bus, > > + object_get_typename(OBJECT(qdev= )), > > + pci_dev->devfn); > > + if (pci_dev =3D=3D NULL) > > + return -1; > > + if (qdev->hotplugged && pc->no_hotplug) { > > + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OB= JECT(pci_dev))); > > + do_pci_unregister_device(pci_dev); > > + return -1; > > + } > > + if (pc->init) { > > + rc =3D pc->init(pci_dev); > > + if (rc !=3D 0) { > > + do_pci_unregister_device(pci_dev); > > + return rc; > > + } > > + } > > + > > + /* rom loading */ > > + is_default_rom =3D false; > > + if (pci_dev->romfile =3D=3D NULL && pc->romfile !=3D NULL) { > > + pci_dev->romfile =3D g_strdup(pc->romfile); > > + is_default_rom =3D true; > > + } > > + pci_add_option_rom(pci_dev, is_default_rom); > > + > > + if (bus->hotplug) { > > + /* Let buses differentiate between hotplug and when device i= s > > + * enabled during qemu machine creation. */ > > + rc =3D bus->hotplug(bus->hotplug_qdev, pci_dev, > > + qdev->hotplugged ? PCI_HOTPLUG_ENABLED: > > + PCI_COLDPLUG_ENABLED); > > + if (rc !=3D 0) { > > + int r =3D pci_unregister_device(&pci_dev->qdev); > > + assert(!r); > > + return rc; > > + } > > + } > > + return 0; > > +} > > + > > +static int pci_unplug_device(DeviceState *qdev) > > +{ > > + PCIDevice *dev =3D PCI_DEVICE(qdev); > > + PCIDeviceClass *pc =3D PCI_DEVICE_GET_CLASS(dev); > > + > > + if (pc->no_hotplug) { > > + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OB= JECT(dev))); > > + return -1; > > + } > > + return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, > > + PCI_HOTPLUG_DISABLED); > > +} > > + > > +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool mul= tifunction, > > + const char *name) > > +{ > > + DeviceState *dev; > > + > > + dev =3D 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 =3D pci_create_multifunction(bus, devfn, multifun= ction, 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 *nam= e) > > +{ > > + return pci_create_simple_multifunction(bus, devfn, false, name); > > +} > > + > > +static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) > > +{ > > + int offset =3D PCI_CONFIG_HEADER_SIZE; > > + int i; > > + for (i =3D PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++= i) { > > + if (pdev->used[i]) > > + offset =3D i + 1; > > + else if (i - offset + 1 =3D=3D 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 =3D PCI_CAPABILITY_LIST; (next =3D pdev->config[prev])= ; > > + prev =3D next + PCI_CAP_LIST_NEXT) > > + if (pdev->config[next + PCI_CAP_LIST_ID] =3D=3D cap_id) > > + break; > > + > > + if (prev_p) > > + *prev_p =3D prev; > > + return next; > > +} > > + > > +static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_= t offset) > > +{ > > + uint8_t next, prev, found =3D 0; > > + > > + if (!(pdev->used[offset])) { > > + return 0; > > + } > > + > > + assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST); > > + > > + for (prev =3D PCI_CAPABILITY_LIST; (next =3D pdev->config[prev])= ; > > + prev =3D next + PCI_CAP_LIST_NEXT) { > > + if (next <=3D offset && next > found) { > > + found =3D next; > > + } > > + } > > + return found; > > +} > > + > > +/* Patch the PCI vendor and device ids in a PCI rom image if necessa= ry. > > + 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 configuratio= n), > > + so they can be read / written with pci_get_word / pci_set_wor= d. */ > > + > > + /* Only a valid rom will be patched. */ > > + rom_magic =3D pci_get_word(ptr); > > + if (rom_magic !=3D 0xaa55) { > > + PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); > > + return; > > + } > > + pcir_offset =3D pci_get_word(ptr + 0x18); > > + if (pcir_offset + 8 >=3D size || memcmp(ptr + pcir_offset, "PCIR= ", 4)) { > > + PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offs= et); > > + return; > > + } > > + > > + vendor_id =3D pci_get_word(pdev->config + PCI_VENDOR_ID); > > + device_id =3D pci_get_word(pdev->config + PCI_DEVICE_ID); > > + rom_vendor_id =3D pci_get_word(ptr + pcir_offset + 4); > > + rom_device_id =3D pci_get_word(ptr + pcir_offset + 6); > > + > > + PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->rom= file, > > + vendor_id, device_id, rom_vendor_id, rom_device_id); > > + > > + checksum =3D ptr[6]; > > + > > + if (vendor_id !=3D rom_vendor_id) { > > + /* Patch vendor id and checksum (at offset 6 for etherboot r= oms). */ > > + checksum +=3D (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_= id >> 8); > > + checksum -=3D (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8)= ; > > + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > > + ptr[6] =3D checksum; > > + pci_set_word(ptr + pcir_offset + 4, vendor_id); > > + } > > + > > + if (device_id !=3D rom_device_id) { > > + /* Patch device id and checksum (at offset 6 for etherboot r= oms). */ > > + checksum +=3D (uint8_t)rom_device_id + (uint8_t)(rom_device_= id >> 8); > > + checksum -=3D (uint8_t)device_id + (uint8_t)(device_id >> 8)= ; > > + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); > > + ptr[6] =3D 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) =3D=3D 0) > > + return 0; > > + > > + if (!pdev->rom_bar) { > > + /* > > + * Load rom via fw_cfg instead of creating a rom bar, > > + * for 0.11 compatibility. > > + */ > > + int class =3D pci_get_word(pdev->config + PCI_CLASS_DEVICE); > > + if (class =3D=3D 0x0300) { > > + rom_add_vga(pdev->romfile); > > + } else { > > + rom_add_option(pdev->romfile, -1); > > + } > > + return 0; > > + } > > + > > + path =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); > > + if (path =3D=3D NULL) { > > + path =3D g_strdup(pdev->romfile); > > + } > > + > > + size =3D 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 =3D 1 << qemu_fls(size); > > + } > > + > > + vmsd =3D 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(O= BJECT(pdev))); > > + } > > + pdev->has_rom =3D true; > > + memory_region_init_ram(&pdev->rom, name, size); > > + vmstate_register_ram(&pdev->rom, &pdev->qdev); > > + ptr =3D 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 =3D false; > > +} > > + > > +/* > > + * if !offset > > + * Reserve space and add capability to the linked list in pci config= space > > + * > > + * if offset =3D 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 =3D pci_find_space(pdev, size); > > + if (!offset) { > > + return -ENOSPC; > > + } > > + } else { > > + /* Verify that capabilities don't overlap. Note: device ass= ignment > > + * depends on this check to verify that the device is not br= oken. > > + * Should never trigger for emulated devices, but it's helpf= ul > > + * for debugging these. */ > > + for (i =3D offset; i < offset + size; i++) { > > + overlapping_cap =3D 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 offse= t %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 =3D pdev->config + offset; > > + config[PCI_CAP_LIST_ID] =3D cap_id; > > + config[PCI_CAP_LIST_NEXT] =3D pdev->config[PCI_CAPABILITY_LIST]; > > + pdev->config[PCI_CAPABILITY_LIST] =3D offset; > > + pdev->config[PCI_STATUS] |=3D 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 siz= e) > > +{ > > + uint8_t prev, offset =3D pci_find_capability_list(pdev, cap_id, = &prev); > > + if (!offset) > > + return; > > + pdev->config[prev] =3D 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] &=3D ~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 ind= ent) > > +{ > > + PCIDevice *d =3D (PCIDevice *)dev; > > + const pci_class_desc *desc; > > + char ctxt[64]; > > + PCIIORegion *r; > > + int i, class; > > + > > + class =3D pci_get_word(d->config + PCI_CLASS_DEVICE); > > + desc =3D pci_class_descriptions; > > + while (desc->desc && class !=3D 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 =3D 0; i < PCI_NUM_REGIONS; i++) { > > + r =3D &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 =3D (PCIDevice *)dev; > > + const char *name =3D NULL; > > + const pci_class_desc *desc =3D pci_class_descriptions; > > + int class =3D pci_get_word(d->config + PCI_CLASS_DEVICE); > > + > > + while (desc->desc && > > + (class & ~desc->fw_ign_bits) !=3D > > + (desc->class & ~desc->fw_ign_bits)) { > > + desc++; > > + } > > + > > + if (desc->desc) { > > + name =3D 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 =3D (PCIDevice *)dev; > > + char path[50], name[33]; > > + int off; > > + > > + off =3D snprintf(path, sizeof(path), "%s@%x", > > + 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 =3D container_of(dev, PCIDevice, qdev); > > + PCIDevice *t; > > + int slot_depth; > > + /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.F= unction. > > + * 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 fo= r all > > + * devices on the path from root to the specific device. */ > > + char domain[] =3D "DDDD:00"; > > + char slot[] =3D ":SS.F"; > > + int domain_len =3D sizeof domain - 1 /* For '\0' */; > > + int slot_len =3D sizeof slot - 1 /* For '\0' */; > > + int path_len; > > + char *path, *p; > > + int s; > > + > > + /* Calculate # of slots on path between device and root. */; > > + slot_depth =3D 0; > > + for (t =3D d; t; t =3D t->bus->parent_dev) { > > + ++slot_depth; > > + } > > + > > + path_len =3D domain_len + slot_len * slot_depth; > > + > > + /* Allocate memory, fill in the terminating null byte. */ > > + path =3D g_malloc(path_len + 1 /* For '\0' */); > > + path[path_len] =3D '\0'; > > + > > + /* First field is the domain. */ > > + s =3D snprintf(domain, sizeof domain, "%04x:00", pci_find_domain= (d->bus)); > > + assert(s =3D=3D 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 =3D path + path_len; > > + for (t =3D d; t; t =3D t->bus->parent_dev) { > > + p -=3D slot_len; > > + s =3D snprintf(slot, sizeof slot, ":%02x.%x", > > + PCI_SLOT(t->devfn), PCI_FUNC(t->devfn)); > > + assert(s =3D=3D slot_len); > > + memcpy(p, slot, slot_len); > > + } > > + > > + return path; > > +} > > + > > +static int pci_qdev_find_recursive(PCIBus *bus, > > + const char *id, PCIDevice **pdev) > > +{ > > + DeviceState *qdev =3D 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 =3D PCI_DEVICE(qdev); > > + return 0; > > + } > > + return -EINVAL; > > +} > > + > > +int pci_qdev_find_device(const char *id, PCIDevice **pdev) > > +{ > > + struct PCIHostBus *host; > > + int rc =3D -ENODEV; > > + > > + QLIST_FOREACH(host, &host_buses, next) { > > + int tmp =3D pci_qdev_find_recursive(host->bus, id, pdev); > > + if (!tmp) { > > + rc =3D 0; > > + break; > > + } > > + if (tmp !=3D -ENODEV) { > > + rc =3D 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 =3D DEVICE_CLASS(klass); > > + k->init =3D pci_qdev_init; > > + k->unplug =3D pci_unplug_device; > > + k->exit =3D pci_unregister_device; > > + k->bus_type =3D TYPE_PCI_BUS; > > + k->props =3D pci_props; > > +} > > + > > +void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque= ) > > +{ > > + bus->dma_context_fn =3D fn; > > + bus->dma_context_opaque =3D opaque; > > +} > > + > > +static TypeInfo pci_device_type_info =3D { > > + .name =3D TYPE_PCI_DEVICE, > > + .parent =3D TYPE_DEVICE, > > + .instance_size =3D sizeof(PCIDevice), > > + .abstract =3D true, > > + .class_size =3D sizeof(PCIDeviceClass), > > + .class_init =3D 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 ty= pe); > > +typedef void PCIUnregisterFunc(PCIDevice *pci_dev); > > + > > +typedef struct PCIIORegion { > > + pcibus_t addr; /* current PCI mapping address. -1 means not mapp= ed */ > > +#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 =3D 0x1, > > + QEMU_PCI_CAP_MSIX =3D 0x2, > > + QEMU_PCI_CAP_EXPRESS =3D 0x4, > > + > > + /* multifunction capable device */ > > +#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3 > > + QEMU_PCI_CAP_MULTIFUNCTION =3D (1 << QEMU_PCI_CAP_MULTIFUNCTION_= BITNR), > > + > > + /* command register SERR bit enabled */ > > +#define QEMU_PCI_CAP_SERR_BITNR 4 > > + QEMU_PCI_CAP_SERR =3D (1 << QEMU_PCI_CAP_SERR_BITNR), > > + /* Standard hot plug controller. */ > > +#define QEMU_PCI_SHPC_BITNR 5 > > + QEMU_PCI_CAP_SHPC =3D (1 << QEMU_PCI_SHPC_BITNR), > > +#define QEMU_PCI_SLOTID_BITNR 6 > > + QEMU_PCI_CAP_SLOTID =3D (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 =3D = 0 */ > > + uint16_t subsystem_id; /* only for header type =3D = 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 vec= tor, > > + MSIMessage msg); > > +typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned in= t 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 le= n); > > +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_f= n 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, DeviceStat= e *dev); > > +/* 0 <=3D pin <=3D 3 0 =3D INTA, 1 =3D INTB, 2 =3D INTC, 3 =3D 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 not= ifier); > > +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_mode= l, > > + 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D pci_get_byte(config); > > + uint8_t rval =3D 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 =3D 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 =3D pci_get_word(config); > > + uint16_t rval =3D 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 =3D 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 =3D pci_get_long(config); > > + uint32_t rval =3D 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 =3D 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 =3D pci_get_quad(config); > > + uint64_t rval =3D 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 =3D pci_get_quad(config); > > + return (val & mask) >> (ffs(mask) - 1); > > +} > > + > > +PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool mul= tifunction, > > + 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 *nam= e); > > + > > +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_S= PACE_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_FR= OM_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 =3D dma_memory_map(pci_dma_context(dev), addr, plen, dir); > > + return buf; > > +} > > + > > +static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_a= ddr_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 *d= ev, > > + 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 =3D (stringify(_field)), = \ > > + .size =3D sizeof(PCIDevice), = \ > > + .vmsd =3D &vmstate_pci_device, = \ > > + .flags =3D VMS_STRUCT, = \ > > + .offset =3D vmstate_offset_value(_state, _field, PCIDevice),= \ > > +} > > + > > +#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { = \ > > + .name =3D (stringify(_field)), = \ > > + .size =3D sizeof(PCIDevice), = \ > > + .vmsd =3D &vmstate_pci_device, = \ > > + .flags =3D VMS_STRUCT|VMS_POINTER, = \ > > + .offset =3D 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 obtai= ning a copy > > + * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be in= cluded in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > > + * 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, A= RISING FROM > > + > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS IN > > + * THE SOFTWARE. > > + */ > > +/* > > + * split out from pci.c > > + * Copyright (c) 2010 Isaku Yamahata > > + * 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 =3D pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SS= VID_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 dev= ice */ > > +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 =3D ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; > > + if (d->config[base] & PCI_IO_RANGE_TYPE_32) { > > + val |=3D (uint32_t)pci_get_word(d->config + base_upper16) <<= 16; > > + } > > + return val; > > +} > > + > > +static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint3= 2_t base) > > +{ > > + return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RA= NGE_MASK) > > + << 16; > > +} > > + > > +static pcibus_t pci_config_get_pref_base(const PCIDevice *d, > > + uint32_t base, uint32_t upp= er) > > +{ > > + pcibus_t tmp; > > + pcibus_t val; > > + > > + tmp =3D (pcibus_t)pci_get_word(d->config + base); > > + val =3D (tmp & PCI_PREF_RANGE_MASK) << 16; > > + if (tmp & PCI_PREF_RANGE_TYPE_64) { > > + val |=3D (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 =3D pci_config_get_io_base(bridge, > > + PCI_IO_BASE, PCI_IO_BASE_UPPER= 16); > > + } else { > > + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > > + base =3D pci_config_get_pref_base( > > + bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32)= ; > > + } else { > > + base =3D pci_config_get_memory_base(bridge, PCI_MEMORY_B= ASE); > > + } > > + } > > + > > + 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 =3D pci_config_get_io_base(bridge, > > + PCI_IO_LIMIT, PCI_IO_LIMIT_UPP= ER16); > > + limit |=3D 0xfff; /* PCI bridge spec 3.2.5.6. */ > > + } else { > > + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > > + limit =3D pci_config_get_pref_base( > > + bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER3= 2); > > + } else { > > + limit =3D pci_config_get_memory_base(bridge, PCI_MEMORY_= LIMIT); > > + } > > + limit |=3D 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. *= / > > + } > > + return limit; > > +} > > + > > +static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *a= lias, > > + uint8_t type, const char *name, > > + MemoryRegion *space, > > + MemoryRegion *parent_space, > > + bool enabled) > > +{ > > + pcibus_t base =3D pci_bridge_get_base(&bridge->dev, type); > > + pcibus_t limit =3D pci_bridge_get_limit(&bridge->dev, type); > > + /* TODO: this doesn't handle base =3D 0 limit =3D 2^64 - 1 corre= ctly. > > + * Apparently no way to do this with existing memory APIs. */ > > + pcibus_t size =3D enabled && limit >=3D 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 =3D br->dev.bus; > > + PCIBridgeWindows *w =3D g_new(PCIBridgeWindows, 1); > > + uint16_t cmd =3D 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 =3D 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, PCIBridgeWindow= s *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 =3D 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 =3D 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 =3D container_of(d, PCIBridge, dev); > > + uint16_t oldctl =3D 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 =3D 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 =3D 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 =3D PCI_DEVICE(qdev); > > + uint8_t *conf =3D dev->config; > > + > > + conf[PCI_PRIMARY_BUS] =3D 0; > > + conf[PCI_SECONDARY_BUS] =3D 0; > > + conf[PCI_SUBORDINATE_BUS] =3D 0; > > + conf[PCI_SEC_LATENCY_TIMER] =3D 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 =3D dev->bus; > > + PCIBridge *br =3D DO_UPCAST(PCIBridge, dev, dev); > > + PCIBus *sec_bus =3D &br->sec_bus; > > + > > + pci_word_test_and_set_mask(dev->config + PCI_STATUS, > > + PCI_STATUS_66MHZ | PCI_STATUS_FAST_BA= CK); > > + pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); > > + dev->config[PCI_HEADER_TYPE] =3D > > + (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTI= ON) | > > + 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 .0, where > > + * id is the device id. > > + * Since PCI Bridge devices have a single bus each, we don't nee= d the index: > > + * let users address the bus using the device name. > > + */ > > + if (!br->bus_name && dev->qdev.id && *dev->qdev.id) { > > + br->bus_name =3D dev->qdev.id; > > + } > > + > > + qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, > > + br->bus_name); > > + sec_bus->parent_dev =3D dev; > > + sec_bus->map_irq =3D br->map_irq; > > + sec_bus->address_space_mem =3D &br->address_space_mem; > > + memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT= 64_MAX); > > + sec_bus->address_space_io =3D &br->address_space_io; > > + memory_region_init(&br->address_space_io, "pci_bridge_io", 65536= ); > > + br->windows =3D 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 =3D 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_n= ame 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 =3D map_irq; > > + br->bus_name =3D 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 mod= ify > > + * 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-13= 01, USA. > > + * > > + * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc] > > + * Copyright (c) 2009 Isaku Yamahata > > + * 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_n= ame 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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 =3D addr >> 16; > > + uint8_t devfn =3D 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, uint= 32_t len) > > +{ > > + assert(len <=3D 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 ad= dr, > > + uint32_t limit, uint32_t len) > > +{ > > + assert(len <=3D 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 =3D pci_dev_find_by_addr(s, addr); > > + uint32_t config_addr =3D addr & (PCI_CONFIG_SPACE_SIZE - 1); > > + > > + if (!pci_dev) { > > + return; > > + } > > + > > + PCI_DPRINTF("%s: %s: addr=3D%02" PRIx32 " val=3D%08" PRIx32 " le= n=3D%d\n", > > + __func__, pci_dev->name, config_addr, val, len); > > + pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SP= ACE_SIZE, > > + val, len); > > +} > > + > > +uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) > > +{ > > + PCIDevice *pci_dev =3D pci_dev_find_by_addr(s, addr); > > + uint32_t config_addr =3D addr & (PCI_CONFIG_SPACE_SIZE - 1); > > + uint32_t val; > > + > > + if (!pci_dev) { > > + return ~0x0; > > + } > > + > > + val =3D pci_host_config_read_common(pci_dev, config_addr, > > + PCI_CONFIG_SPACE_SIZE, len); > > + PCI_DPRINTF("%s: %s: addr=3D%02"PRIx32" val=3D%08"PRIx32" len=3D= %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 =3D opaque; > > + > > + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", > > + __func__, addr, len, val); > > + if (addr !=3D 0 || len !=3D 4) { > > + return; > > + } > > + s->config_reg =3D val; > > +} > > + > > +static uint64_t pci_host_config_read(void *opaque, hwaddr addr, > > + unsigned len) > > +{ > > + PCIHostState *s =3D opaque; > > + uint32_t val =3D 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 =3D 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 =3D opaque; > > + uint32_t val; > > + if (!(s->config_reg & (1 << 31))) > > + return 0xffffffff; > > + val =3D 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 =3D { > > + .read =3D pci_host_config_read, > > + .write =3D pci_host_config_write, > > + .endianness =3D DEVICE_LITTLE_ENDIAN, > > +}; > > + > > +const MemoryRegionOps pci_host_conf_be_ops =3D { > > + .read =3D pci_host_config_read, > > + .write =3D pci_host_config_write, > > + .endianness =3D DEVICE_BIG_ENDIAN, > > +}; > > + > > +const MemoryRegionOps pci_host_data_le_ops =3D { > > + .read =3D pci_host_data_read, > > + .write =3D pci_host_data_write, > > + .endianness =3D DEVICE_LITTLE_ENDIAN, > > +}; > > + > > +const MemoryRegionOps pci_host_data_be_ops =3D { > > + .read =3D pci_host_data_read, > > + .write =3D pci_host_data_write, > > + .endianness =3D DEVICE_BIG_ENDIAN, > > +}; > > + > > +static const TypeInfo pci_host_type_info =3D { > > + .name =3D TYPE_PCI_HOST_BRIDGE, > > + .parent =3D TYPE_SYS_BUS_DEVICE, > > + .abstract =3D true, > > + .instance_size =3D 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 routi= nes. > > + * > > + * Copyright (c) 2006 Fabrice Bellard > > + * > > + * Permission is hereby granted, free of charge, to any person obtai= ning a copy > > + * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be in= cluded in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > > + * 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, A= RISING FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS IN > > + * THE SOFTWARE. > > + */ > > + > > +/* Worker routines for a PCI host controller that uses an {address,d= ata} > > + 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, uint= 32_t len); > > +uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t ad= dr, > > + 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 lat= er */ > > + QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev lat= er */ > > + > > + /* 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 region= s 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 > > + * > > + * For more information, please consult the following manuals (l= ook 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 spa= ce, > > + * 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 a= nd 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 steppi= ng */ > > +#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 Defin= able 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 S= ERR */ > > +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error= */ > > + > > +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, lo= w 8 revision */ > > +#define PCI_REVISION_ID 0x08 /* Revision ID */ > > +#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Int= erface */ > > +#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 =3D memo= ry, 1 =3D 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 =3D 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 ad= dress, 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 secondar= y interface */ > > +#define PCI_IO_BASE 0x1c /* I/O range behind the bridg= e */ > > +#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 behin= d */ > > +#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 addresse= s */ > > +#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, b= ut 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 forwardi= ng */ > > +#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 rese= t */ > > +#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back ena= bled 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 standar= d 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 f= or 16-bit cards */ > > +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable fo= r 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 Graphi= cs 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 Resourc= e Control */ > > +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Cont= roller */ > > +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/de= vice 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 lis= t */ > > +#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 in= itialization */ > > +#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support ma= sk */ > > +#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 P= MC */ > > +#define PCI_PM_CTRL 4 /* PM control and status regi= ster */ > > +#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power stat= e (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 en= able (??) */ > > +#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 nu= mber of requests - 1 */ > > +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing suppor= ted */ > > +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supporte= d */ > > +#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 numb= er of requests */ > > +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enable= d */ > > +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP tr= ansactions */ > > +#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 indicat= es completion */ > > +#define PCI_VPD_DATA 4 /* 32-bits of data returned h= ere */ > > + > > +/* 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 configu= red */ > > +#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size availab= le */ > > +#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 fo= r 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 fo= r 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 Registe= r */ > > +#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 c= ount */ > > +#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte c= ount */ > > +#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte c= ount */ > > +#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count= */ > > + /* Max # of outstanding split transac= tions */ > > +#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 Tran= sactions */ > > +#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 D= iscarded */ > > +#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split C= ompletion */ > > +#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity = */ > > +#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memor= y Read Count */ > > +#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed M= ax Outstanding Split Transactions */ > > +#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumul= ative Read Size */ > > +#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Complet= ion 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 vendo= r id register */ > > +#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem devic= e 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 En= dpoint */ > > +#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collec= tor */ > > +#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 P= resent */ > > +#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicato= r Present */ > > +#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Pr= esent */ > > +#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 Reportin= g En. */ > > +#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting = Enable */ > > +#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enab= le */ > > +#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Report= ing 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 Retr= y / 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 Detect= ed */ > > +#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 Manageme= nt */ > > +#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Rep= orting Capable */ > > +#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer= Link Active Reporting Capable */ > > +#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notifica= tion 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 I= nterrupt 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 Activ= e */ > > +#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 Presen= t */ > > +#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Presen= t */ > > +#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ > > +#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Pre= sent */ > > +#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 Inter= lock Present */ > > +#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Su= pport */ > > +#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 E= nable */ > > +#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enabl= e */ > > +#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable = */ > > +#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed En= able */ > > +#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrup= t Enable */ > > +#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable = */ > > +#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Contro= l */ > > +#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 Interloc= k Control */ > > +#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Chan= ged 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 Interloc= k Status */ > > +#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Chan= ged */ > > +#define PCI_EXP_RTCTL 28 /* Root Control */ > > +#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctabl= e Error */ > > +#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal = Error */ > > +#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Erro= r */ > > +#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ > > +#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility En= able */ > > +#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 Capabilitie= s 2 */ > > +#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ > > +#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reportin= g */ > > +#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 completi= on enable */ > > +#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance = reporting */ > > +#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message t= ype A */ > > +#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message t= ype 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 T= LP */ > > +#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Proto= col */ > > +#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 Complet= ion */ > > +#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 Reques= t */ > > +#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask *= / > > + /* Same bits as above */ > > +#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severi= ty */ > > + /* Same bits as above */ > > +#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status *= / > > +#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Sta= tus */ > > +#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 Rollove= r */ > > +#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeo= ut */ > > +#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ > > + /* Same bits as above */ > > +#define PCI_ERR_CAP 24 /* Advanced Error Capabilitie= s */ > > +#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointe= r */ > > +#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Ca= pable */ > > +#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation En= able */ > > +#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 by= tes) */ > > +#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 Re= ceived */ > > +/* 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 Fata= l */ > > +#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal = Received */ > > +#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Rece= ived */ > > +#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identificatio= n */ > > + > > +/* 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 def= ined > > + * 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 configu= ration */ > > +#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary lin= k configuration */ > > + > > +#define HT_5BIT_CAP_MASK 0xF8 > > +#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ > > +#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address rem= apping */ > > +#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 Spa= ce 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 ma= sk */ > > +#define HT_MSI_ADDR_HI 0x08 /* Offset to = high addr bits */ > > +#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing con= figuration */ > > +#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configurat= ion */ > > +#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configurati= on */ > > +#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hyper= transport configuration */ > > +#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanage= ment configuration */ > > + > > +/* Alternative Routing-ID Interpretation */ > > +#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ > > +#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capab= ility */ > > +#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capabi= lity */ > > +#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 Enabl= e */ > > +#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 D= epth */ > > +#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 Translati= on 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 Numb= er */ > > +#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 Ena= ble */ > > +#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 O= ffset*/ > > +#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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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_ARG= S__) > > + > > + > > +/*******************************************************************= ******** > > + * pci express capability helper functions > > + */ > > +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint= 8_t port) > > +{ > > + int pos; > > + uint8_t *exp_cap; > > + > > + assert(pci_is_express(dev)); > > + > > + pos =3D pci_add_capability(dev, PCI_CAP_ID_EXP, offset, > > + PCI_EXP_VER2_SIZEOF); > > + if (pos < 0) { > > + return pos; > > + } > > + dev->exp.exp_cap =3D pos; > > + exp_cap =3D 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 =3D 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 =3D dev->config + dev->exp.exp_cap; > > + assert(vector < 32); > > + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FL= AGS_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_FL= AGS) & > > + PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; > > +} > > + > > +void pcie_cap_deverr_init(PCIDevice *dev) > > +{ > > + uint32_t pos =3D 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_N= FED | > > + PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_U= RD); > > +} > > + > > +void pcie_cap_deverr_reset(PCIDevice *dev) > > +{ > > + uint8_t *devctl =3D dev->config + dev->exp.exp_cap + PCI_EXP_DEV= CTL; > > + pci_long_test_and_clear_mask(devctl, > > + PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCT= L_NFERE | > > + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCT= L_URRE); > > +} > > + > > +static void hotplug_event_update_event_status(PCIDevice *dev) > > +{ > > + uint32_t pos =3D dev->exp.exp_cap; > > + uint8_t *exp_cap =3D dev->config + pos; > > + uint16_t sltctl =3D pci_get_word(exp_cap + PCI_EXP_SLTCTL); > > + uint16_t sltsta =3D pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > + > > + dev->exp.hpev_notified =3D (sltctl & PCI_EXP_SLTCTL_HPIE) && > > + (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); > > +} > > + > > +static void hotplug_event_notify(PCIDevice *dev) > > +{ > > + bool prev =3D dev->exp.hpev_notified; > > + > > + hotplug_event_update_event_status(dev); > > + > > + if (prev =3D=3D dev->exp.hpev_notified) { > > + return; > > + } > > + > > + /* Note: the logic above does not take into account whether inte= rrupts > > + * 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 e= vents that > > + * occur while interrupt generation is disabled, and interrupt g= eneration 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_not= ified); > > + } > > +} > > + > > +static void hotplug_event_clear(PCIDevice *dev) > > +{ > > + hotplug_event_update_event_status(dev); > > + if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_no= tified) { > > + 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, PCIExpressHotPlugEve= nt 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 =3D PCI_DEVICE(qdev); > > + uint8_t *exp_cap =3D d->config + d->exp.exp_cap; > > + uint16_t sltsta =3D pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > + > > + /* Don't send event when device is enabled during qemu machine c= reation: > > + * it is present on boot, no hotplug event is necessary. We do s= end an > > + * event when the device is disabled later. */ > > + if (state =3D=3D 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 =3D 0 is allowed to be > > + * hot plugged/unplugged. > > + */ > > + assert(PCI_FUNC(pci_dev->devfn) =3D=3D 0); > > + > > + if (state =3D=3D 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 =3D 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 =3D 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 =3D 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 =3D dev->exp.exp_cap; > > + uint8_t *exp_cap =3D dev->config + pos; > > + uint16_t sltsta =3D 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 ^=3D 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 Po= rt by > > + * issuing a write transaction that targets any portion of the P= ort=E2=80=99s 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 t= ransaction, > > + * the Port must carry out the requested actions and then set th= e > > + * associated status field for the command completed event. */ > > + > > + /* Real hardware might take a while to complete requested comman= d because > > + * physical movement would be involved like locking the electrom= echanical > > + * lock. However in our case, command is completed instantaneou= sly 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 =3D 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 wr= itten > > + * 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_E= XP_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 =3D dev->config + dev->exp.exp_cap + PCI_EXP_DEV= CTL; > > + if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { > > + /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset han= dler > > + 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 =3D 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 =3D dev->config + dev->exp.exp_cap + PCI_EXP_DE= VCTL2; > > + 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_DEV= CTL2) & > > + 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 c= ap_id, > > + uint16_t *prev_p) > > +{ > > + uint16_t prev =3D 0; > > + uint16_t next; > > + uint32_t header =3D pci_get_long(dev->config + PCI_CONFIG_SPACE_= SIZE); > > + > > + if (!header) { > > + /* no extended capability */ > > + next =3D 0; > > + goto out; > > + } > > + for (next =3D PCI_CONFIG_SPACE_SIZE; next; > > + prev =3D next, next =3D PCI_EXT_CAP_NEXT(header)) { > > + > > + assert(next >=3D PCI_CONFIG_SPACE_SIZE); > > + assert(next <=3D PCIE_CONFIG_SPACE_SIZE - 8); > > + > > + header =3D pci_get_long(dev->config + next); > > + if (PCI_EXT_CAP_ID(header) =3D=3D cap_id) { > > + break; > > + } > > + } > > + > > +out: > > + if (prev_p) { > > + *prev_p =3D 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, uint= 16_t next) > > +{ > > + uint16_t header =3D pci_get_long(dev->config + pos); > > + assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); > > + header =3D (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 sho= uldn'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 >=3D PCI_CONFIG_SPACE_SIZE); > > + assert(offset < offset + size); > > + assert(offset + size < PCIE_CONFIG_SPACE_SIZE); > > + assert(size >=3D 8); > > + assert(pci_is_express(dev)); > > + > > + if (offset =3D=3D PCI_CONFIG_SPACE_SIZE) { > > + header =3D pci_get_long(dev->config + offset); > > + next =3D PCI_EXT_CAP_NEXT(header); > > + } else { > > + uint16_t prev; > > + > > + /* 0 is reserved cap id. use internally to find the last cap= ability > > + in the linked list */ > > + next =3D pcie_find_capability_list(dev, 0, &prev); > > + > > + assert(prev >=3D PCI_CONFIG_SPACE_SIZE); > > + assert(next =3D=3D 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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 =3D PCI_EXP_SLTCTL_IND_RESERVED, > > + PCI_EXP_HP_IND_ON =3D PCI_EXP_SLTCTL_IND_ON, > > + PCI_EXP_HP_IND_BLINK =3D PCI_EXP_SLTCTL_IND_BLINK, > > + PCI_EXP_HP_IND_OFF =3D PCI_EXP_SLTCTL_IND_OFF, > > +} PCIExpressIndicator; > > + > > +typedef enum { > > + /* these bits must match the bits in Slot Control/Status registe= rs. > > + * PCI_EXP_HP_EV_xxx =3D PCI_EXP_SLTCTL_xxxE =3D 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 =3D PCI_EXP_SLTCTL_ABPE, > > + /* attention button pressed = */ > > + PCI_EXP_HP_EV_PDC =3D PCI_EXP_SLTCTL_PDCE, > > + /* presence detect changed *= / > > + PCI_EXP_HP_EV_CCI =3D PCI_EXP_SLTCTL_CCIE, > > + /* command completed */ > > + > > + PCI_EXP_HP_EV_SUPPORTED =3D PCI_EXP_HP_EV_ABP | > > + PCI_EXP_HP_EV_PDC | > > + PCI_EXP_HP_EV_CCI, > > + /* supported event m= ask */ > > + > > + /* 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 =3D INTA# > > + * If the chip wants to use other in= terrupt > > + * line, initialize this member with= the > > + * desired number. > > + * If the chip dynamically changes t= his member, > > + * also initialize it when loaded as > > + * appropreately. > > + */ > > + bool hpev_notified; /* Logical AND of conditions for hot plug ev= ent. > > + Following 6.7.3.4: > > + Software Notification of Hot-Plug Events, a= n interrupt > > + is sent whenever the logical and of these c= onditions > > + transitions from false to true. */ > > + > > + /* AER */ > > + uint16_t aer_cap; > > + PCIEAERLog aer_log; > > + unsigned int aer_intx; /* INTx for error reporting > > + * default is 0 =3D INTA# > > + * If the chip wants to use other in= terrupt > > + * line, initialize this member with= the > > + * desired number. > > + * If the chip dynamically changes t= his 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, uint= 8_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 =3D (stringify(_field)), = \ > > + .size =3D sizeof(PCIDevice), = \ > > + .vmsd =3D &vmstate_pcie_device, = \ > > + .flags =3D VMS_STRUCT, = \ > > + .offset =3D 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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_ARG= S__) > > + > > +#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 *er= r) > > +{ > > + if (aer_log->log_num =3D=3D 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 =3D 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 =3D 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 =3D &dev->exp; > > + exp->aer_cap =3D offset; > > + > > + /* log_max is property */ > > + if (dev->exp.aer_log.log_max =3D=3D PCIE_AER_LOG_MAX_UNSET) { > > + dev->exp.aer_log.log_max =3D 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 =3D 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_S= TATUS, > > + 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 supporte= d */ > > + 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 =3D dev->config + dev->exp.aer_cap; > > + PCIEAERLog *aer_log =3D &dev->exp.aer_log; > > + > > + uint16_t i; > > + for (i =3D 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_SER= R))) { > > + 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 tha= t > > + * errors are reported if enabled either through this bit or thr= ough > > + * 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_DEVC= TL))) { > > + 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 *m= sg) > > +{ > > + uint16_t bridge_control =3D pci_get_word(dev->config + PCI_BRIDG= E_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 =3D 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 =3D dev->config + dev->exp.aer_cap; > > + uint32_t root_status =3D pci_get_long(aer_cap + PCI_ERR_ROOT_STA= TUS); > > + return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIF= T; > > +} > > + > > +/* Given a status register, get corresponding bits in the command re= gister */ > > +static uint32_t pcie_aer_status_to_cmd(uint32_t status) > > +{ > > + uint32_t cmd =3D 0; > > + if (status & PCI_ERR_ROOT_COR_RCV) { > > + cmd |=3D PCI_ERR_ROOT_CMD_COR_EN; > > + } > > + if (status & PCI_ERR_ROOT_NONFATAL_RCV) { > > + cmd |=3D PCI_ERR_ROOT_CMD_NONFATAL_EN; > > + } > > + if (status & PCI_ERR_ROOT_FATAL_RCV) { > > + cmd |=3D 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 =3D pci_get_word(dev->config + PCI_COMMAND); > > + aer_cap =3D dev->config + dev->exp.aer_cap; > > + root_cmd =3D pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > > + prev_status =3D root_status =3D pci_get_long(aer_cap + PCI_ERR_R= OOT_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 |=3D PCI_ERR_ROOT_MULTI_COR_RCV; > > + } else { > > + pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SR= C_COR_OFFS, > > + msg->source_id); > > + } > > + root_status |=3D PCI_ERR_ROOT_COR_RCV; > > + break; > > + case PCI_ERR_ROOT_CMD_NONFATAL_EN: > > + root_status |=3D PCI_ERR_ROOT_NONFATAL_RCV; > > + break; > > + case PCI_ERR_ROOT_CMD_FATAL_EN: > > + if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { > > + root_status |=3D PCI_ERR_ROOT_FIRST_FATAL; > > + } > > + root_status |=3D 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 |=3D 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 |=3D 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 =3D pcie_cap_get_type(dev); > > + if ((type =3D=3D PCI_EXP_TYPE_ROOT_PORT || > > + type =3D=3D PCI_EXP_TYPE_UPSTREAM || > > + type =3D=3D PCI_EXP_TYPE_DOWNSTREAM) && > > + !pcie_aer_msg_vbridge(dev, msg)) { > > + return; > > + } > > + if (!pcie_aer_msg_alldev(dev, msg)) { > > + return; > > + } > > + if (type =3D=3D 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 colle= ctor. */ > > + /* > > + * 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 =3D pci_bridge_get_device(dev->bus); > > + } > > +} > > + > > +static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *er= r) > > +{ > > + uint8_t *aer_cap =3D dev->config + dev->exp.aer_cap; > > + uint8_t first_bit =3D ffs(err->status) - 1; > > + uint32_t errcap =3D pci_get_long(aer_cap + PCI_ERR_CAP); > > + int i; > > + > > + assert(err->status); > > + assert(!(err->status & (err->status - 1))); > > + > > + errcap &=3D ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > > + errcap |=3D PCI_ERR_CAP_FEP(first_bit); > > + > > + if (err->flags & PCIE_AER_ERR_HEADER_VALID) { > > + for (i =3D 0; i < ARRAY_SIZE(err->header); ++i) { > > + /* 7.10.8 Header Log Register */ > > + uint8_t *header_log =3D > > + aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->heade= r[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_S= IZE); > > + } > > + > > + if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && > > + (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCT= L2) & > > + PCI_EXP_DEVCAP2_EETLPP)) { > > + for (i =3D 0; i < ARRAY_SIZE(err->prefix); ++i) { > > + /* 7.10.12 tlp prefix log register */ > > + uint8_t *prefix_log =3D > > + aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->p= refix[0]; > > + cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); > > + } > > + errcap |=3D 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 =3D 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_L= OG_SIZE); > > +} > > + > > +static void pcie_aer_clear_error(PCIDevice *dev) > > +{ > > + uint8_t *aer_cap =3D dev->config + dev->exp.aer_cap; > > + uint32_t errcap =3D pci_get_long(aer_cap + PCI_ERR_CAP); > > + PCIEAERLog *aer_log =3D &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 uncorrec= table > > + * error status. > > + * We emulate uncorrectable error status register as W1CS. > > + * So set bit in uncorrectable error status here again for multi= ple > > + * error recording support. > > + * > > + * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capa= bility) > > + */ > > + 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 =3D dev->config + dev->exp.aer_cap; > > + uint32_t errcap =3D pci_get_long(aer_cap + PCI_ERR_CAP); > > + int fep =3D 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 =3D inj->dev; > > + > > + inj->devsta |=3D PCI_EXP_DEVSTA_CED; > > + if (inj->unsupported_request) { > > + inj->devsta |=3D PCI_EXP_DEVSTA_URD; > > + } > > + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, in= j->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 =3D 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 =3D > > + pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > > + if (!(uncor_mask & uncor_status)) { > > + inj->log_overflow =3D !!pcie_aer_record_error(dev, i= nj->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_U= RRE)) { > > + return false; > > + } > > + if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { > > + return false; > > + } > > + > > + inj->msg.severity =3D PCI_ERR_ROOT_CMD_COR_EN; > > + return true; > > +} > > + > > +static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_= fatal) > > +{ > > + PCIDevice *dev =3D inj->dev; > > + uint16_t cmd; > > + > > + if (is_fatal) { > > + inj->devsta |=3D PCI_EXP_DEVSTA_FED; > > + } else { > > + inj->devsta |=3D PCI_EXP_DEVSTA_NFED; > > + } > > + if (inj->unsupported_request) { > > + inj->devsta |=3D PCI_EXP_DEVSTA_URD; > > + } > > + pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, in= j->devsta); > > + > > + if (inj->aer_cap) { > > + uint32_t mask =3D 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 =3D !!pcie_aer_record_error(dev, inj->err)= ; > > + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STAT= US, > > + inj->error_status); > > + } > > + > > + cmd =3D 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 =3D PCI_ERR_ROOT_CMD_FATAL_EN; > > + } else { > > + if (!((cmd & PCI_COMMAND_SERR) || > > + (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { > > + return false; > > + } > > + inj->msg.severity =3D 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 sh= ould > > + * 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 a= nd Logging > > + * Operations > > + */ > > +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) > > +{ > > + uint8_t *aer_cap =3D NULL; > > + uint16_t devctl =3D 0; > > + uint16_t devsta =3D 0; > > + uint32_t error_status =3D err->status; > > + PCIEAERInject inj; > > + > > + if (!pci_is_express(dev)) { > > + return -ENOSYS; > > + } > > + > > + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > > + error_status &=3D PCI_ERR_COR_SUPPORTED; > > + } else { > > + error_status &=3D 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 =3D dev->config + dev->exp.exp_cap; > > + aer_cap =3D dev->config + dev->exp.aer_cap; > > + devctl =3D pci_get_long(exp_cap + PCI_EXP_DEVCTL); > > + devsta =3D pci_get_long(exp_cap + PCI_EXP_DEVSTA); > > + } > > + > > + inj.dev =3D dev; > > + inj.aer_cap =3D aer_cap; > > + inj.err =3D err; > > + inj.devctl =3D devctl; > > + inj.devsta =3D devsta; > > + inj.error_status =3D error_status; > > + inj.unsupported_request =3D !(err->flags & PCIE_AER_ERR_IS_CORRE= CTABLE) && > > + err->status =3D=3D PCI_ERR_UNC_UNSUP; > > + inj.log_overflow =3D false; > > + > > + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > > + if (!pcie_aer_inject_cor_error(&inj, 0, false)) { > > + return 0; > > + } > > + } else { > > + bool is_fatal =3D > > + pcie_aer_uncor_default_severity(error_status) =3D=3D > > + PCI_ERR_ROOT_CMD_FATAL_EN; > > + if (aer_cap) { > > + is_fatal =3D > > + error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_= SEVER); > > + } > > + if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY))= { > > + inj.error_status =3D 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 =3D err->source_id; > > + pcie_aer_msg(dev, &inj.msg); > > + > > + if (inj.log_overflow) { > > + PCIEAERErr header_log_overflow =3D { > > + .status =3D PCI_ERR_COR_HL_OVERFLOW, > > + .flags =3D PCIE_AER_ERR_IS_CORRECTABLE, > > + }; > > + int ret =3D 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 =3D dev->config + dev->exp.aer_cap; > > + uint32_t errcap =3D pci_get_long(aer_cap + PCI_ERR_CAP); > > + uint32_t first_error =3D 1U << PCI_ERR_CAP_FEP(errcap); > > + uint32_t uncorsta =3D pci_get_long(aer_cap + PCI_ERR_UNCOR_STATU= S); > > + > > + /* 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 modificat= ion 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 =3D 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 =3D 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 depe= ndent > > + * 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 =3D dev->config + dev->exp.aer_cap; > > + uint32_t root_status =3D pci_get_long(aer_cap + PCI_ERR_ROOT_STA= TUS); > > + uint32_t enabled_cmd =3D pcie_aer_status_to_cmd(root_status); > > + uint32_t root_cmd =3D pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAN= D); > > + /* 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 & enab= led_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 =3D { > > + .name =3D "PCIE_AER_ERROR", > > + .version_id =3D 1, > > + .minimum_version_id =3D 1, > > + .minimum_version_id_old =3D 1, > > + .fields =3D (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 =3D { > > + .name =3D "PCIE_AER_ERROR_LOG", > > + .version_id =3D 1, > > + .minimum_version_id =3D 1, > > + .minimum_version_id_old =3D 1, > > + .fields =3D (VMStateField[]) { > > + VMSTATE_UINT16(log_num, PCIEAERLog), > > + VMSTATE_UINT16(log_max, PCIEAERLog), > > + VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_nu= m, > > + 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) =3D=3D QTYPE_QDICT); > > + qdict =3D qobject_to_qdict(data); > > + > > + devfn =3D (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[] =3D { > > + { > > + .name =3D "TRAIN", > > + .val =3D PCI_ERR_UNC_TRAIN, > > + .correctable =3D false, > > + }, { > > + .name =3D "DLP", > > + .val =3D PCI_ERR_UNC_DLP, > > + .correctable =3D false, > > + }, { > > + .name =3D "SDN", > > + .val =3D PCI_ERR_UNC_SDN, > > + .correctable =3D false, > > + }, { > > + .name =3D "POISON_TLP", > > + .val =3D PCI_ERR_UNC_POISON_TLP, > > + .correctable =3D false, > > + }, { > > + .name =3D "FCP", > > + .val =3D PCI_ERR_UNC_FCP, > > + .correctable =3D false, > > + }, { > > + .name =3D "COMP_TIME", > > + .val =3D PCI_ERR_UNC_COMP_TIME, > > + .correctable =3D false, > > + }, { > > + .name =3D "COMP_ABORT", > > + .val =3D PCI_ERR_UNC_COMP_ABORT, > > + .correctable =3D false, > > + }, { > > + .name =3D "UNX_COMP", > > + .val =3D PCI_ERR_UNC_UNX_COMP, > > + .correctable =3D false, > > + }, { > > + .name =3D "RX_OVER", > > + .val =3D PCI_ERR_UNC_RX_OVER, > > + .correctable =3D false, > > + }, { > > + .name =3D "MALF_TLP", > > + .val =3D PCI_ERR_UNC_MALF_TLP, > > + .correctable =3D false, > > + }, { > > + .name =3D "ECRC", > > + .val =3D PCI_ERR_UNC_ECRC, > > + .correctable =3D false, > > + }, { > > + .name =3D "UNSUP", > > + .val =3D PCI_ERR_UNC_UNSUP, > > + .correctable =3D false, > > + }, { > > + .name =3D "ACSV", > > + .val =3D PCI_ERR_UNC_ACSV, > > + .correctable =3D false, > > + }, { > > + .name =3D "INTN", > > + .val =3D PCI_ERR_UNC_INTN, > > + .correctable =3D false, > > + }, { > > + .name =3D "MCBTLP", > > + .val =3D PCI_ERR_UNC_MCBTLP, > > + .correctable =3D false, > > + }, { > > + .name =3D "ATOP_EBLOCKED", > > + .val =3D PCI_ERR_UNC_ATOP_EBLOCKED, > > + .correctable =3D false, > > + }, { > > + .name =3D "TLP_PRF_BLOCKED", > > + .val =3D PCI_ERR_UNC_TLP_PRF_BLOCKED, > > + .correctable =3D false, > > + }, { > > + .name =3D "RCVR", > > + .val =3D PCI_ERR_COR_RCVR, > > + .correctable =3D true, > > + }, { > > + .name =3D "BAD_TLP", > > + .val =3D PCI_ERR_COR_BAD_TLP, > > + .correctable =3D true, > > + }, { > > + .name =3D "BAD_DLLP", > > + .val =3D PCI_ERR_COR_BAD_DLLP, > > + .correctable =3D true, > > + }, { > > + .name =3D "REP_ROLL", > > + .val =3D PCI_ERR_COR_REP_ROLL, > > + .correctable =3D true, > > + }, { > > + .name =3D "REP_TIMER", > > + .val =3D PCI_ERR_COR_REP_TIMER, > > + .correctable =3D true, > > + }, { > > + .name =3D "ADV_NONFATAL", > > + .val =3D PCI_ERR_COR_ADV_NONFATAL, > > + .correctable =3D true, > > + }, { > > + .name =3D "INTERNAL", > > + .val =3D PCI_ERR_COR_INTERNAL, > > + .correctable =3D true, > > + }, { > > + .name =3D "HL_OVERFLOW", > > + .val =3D PCI_ERR_COR_HL_OVERFLOW, > > + .correctable =3D true, > > + }, > > +}; > > + > > +static int pcie_aer_parse_error_string(const char *error_name, > > + uint32_t *status, bool *corre= ctable) > > +{ > > + int i; > > + > > + for (i =3D 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) { > > + const PCIEAERErrorName *e =3D &pcie_aer_error_list[i]; > > + if (strcmp(error_name, e->name)) { > > + continue; > > + } > > + > > + *status =3D e->val; > > + *correctable =3D e->correctable; > > + return 0; > > + } > > + return -EINVAL; > > +} > > + > > +int do_pcie_aer_inject_error(Monitor *mon, > > + const QDict *qdict, QObject **ret_data) > > +{ > > + const char *id =3D qdict_get_str(qdict, "id"); > > + const char *error_name; > > + uint32_t error_status; > > + bool correctable; > > + PCIDevice *dev; > > + PCIEAERErr err; > > + int ret; > > + > > + ret =3D pci_qdev_find_device(id, &dev); > > + if (ret < 0) { > > + monitor_printf(mon, > > + "id or pci device path is invalid or device n= ot " > > + "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 =3D qdict_get_str(qdict, "error_status"); > > + if (pcie_aer_parse_error_string(error_name, &error_status, &corr= ectable)) { > > + char *e =3D NULL; > > + error_status =3D strtoul(error_name, &e, 0); > > + correctable =3D qdict_get_try_bool(qdict, "correctable", 0); > > + if (!e || *e !=3D '\0') { > > + monitor_printf(mon, "invalid error status value. \"%s\""= , > > + error_name); > > + return -EINVAL; > > + } > > + } > > + err.status =3D error_status; > > + err.source_id =3D (pci_bus_num(dev->bus) << 8) | dev->devfn; > > + > > + err.flags =3D 0; > > + if (correctable) { > > + err.flags |=3D PCIE_AER_ERR_IS_CORRECTABLE; > > + } > > + if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) { > > + err.flags |=3D PCIE_AER_ERR_MAYBE_ADVISORY; > > + } > > + if (qdict_haskey(qdict, "header0")) { > > + err.flags |=3D PCIE_AER_ERR_HEADER_VALID; > > + } > > + if (qdict_haskey(qdict, "prefix0")) { > > + err.flags |=3D PCIE_AER_ERR_TLP_PREFIX_PRESENT; > > + } > > + > > + err.header[0] =3D qdict_get_try_int(qdict, "header0", 0); > > + err.header[1] =3D qdict_get_try_int(qdict, "header1", 0); > > + err.header[2] =3D qdict_get_try_int(qdict, "header2", 0); > > + err.header[3] =3D qdict_get_try_int(qdict, "header3", 0); > > + > > + err.prefix[0] =3D qdict_get_try_int(qdict, "prefix0", 0); > > + err.prefix[1] =3D qdict_get_try_int(qdict, "prefix1", 0); > > + err.prefix[2] =3D qdict_get_try_int(qdict, "prefix2", 0); > > + err.prefix[3] =3D qdict_get_try_int(qdict, "prefix3", 0); > > + > > + ret =3D pcie_aer_inject_error(dev, &err); > > + *ret_data =3D 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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 thi= s. > > + * > > + * 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 ma= ny 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 sevirit= y and > > + source id. See 2.2.8.3 error signaling messages */ > > +struct PCIEAERMsg { > > + /* > > + * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN > > + * =3D 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 =3D=3D PCI_ERR_ROOT_CMD_NONFATAL_EN || > > + msg->severity =3D=3D 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/uncor= rectable */ > > +#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory no= n-fatal */ > > +#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is log= ged */ > > +#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is log= ged */ > > + 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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_B= IT) & \ > > + 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_CONFOFF= SET_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 =3D opaque; > > + PCIBus *s =3D e->pci.bus; > > + PCIDevice *pci_dev =3D pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr= ); > > + uint32_t addr; > > + uint32_t limit; > > + > > + if (!pci_dev) { > > + return; > > + } > > + addr =3D PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > > + limit =3D pci_config_size(pci_dev); > > + if (limit <=3D addr) { > > + /* conventional pci device can be behind pcie-to-pci bridge. > > + 256 <=3D 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 =3D opaque; > > + PCIBus *s =3D e->pci.bus; > > + PCIDevice *pci_dev =3D pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr= ); > > + uint32_t addr; > > + uint32_t limit; > > + > > + if (!pci_dev) { > > + return ~0x0; > > + } > > + addr =3D PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > > + limit =3D pci_config_size(pci_dev); > > + if (limit <=3D addr) { > > + /* conventional pci device can be behind pcie-to-pci bridge. > > + 256 <=3D addr < 4K has no effects. */ > > + return ~0x0; > > + } > > + return pci_host_config_read_common(pci_dev, addr, limit, len); > > +} > > + > > +static const MemoryRegionOps pcie_mmcfg_ops =3D { > > + .read =3D pcie_mmcfg_data_read, > > + .write =3D pcie_mmcfg_data_write, > > + .endianness =3D DEVICE_NATIVE_ENDIAN, > > +}; > > + > > +/* pcie_host::base_addr =3D=3D 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 =3D PCIE_BASE_ADDR_UNMAPPED; > > + > > + return 0; > > +} > > + > > +void pcie_host_mmcfg_unmap(PCIExpressHost *e) > > +{ > > + if (e->base_addr !=3D PCIE_BASE_ADDR_UNMAPPED) { > > + memory_region_del_subregion(get_system_memory(), &e->mmio); > > + memory_region_destroy(&e->mmio); > > + e->base_addr =3D 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 >=3D PCIE_MMCFG_SIZE_MIN); > > + assert(size <=3D PCIE_MMCFG_SIZE_MAX); > > + e->size =3D size; > > + memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg"= , e->size); > > + e->base_addr =3D 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 =3D { > > + .name =3D TYPE_PCIE_HOST_BRIDGE, > > + .parent =3D TYPE_PCI_HOST_BRIDGE, > > + .abstract =3D true, > > + .instance_size =3D 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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 si= ze); > > +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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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 conversi= on > > + */ > > +struct PCIEChassis { > > + uint8_t number; > > + > > + QLIST_HEAD(, PCIESlot) slots; > > + QLIST_ENTRY(PCIEChassis) next; > > +}; > > + > > +static QLIST_HEAD(, PCIEChassis) chassis =3D 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 =3D=3D chassis_number) { > > + break; > > + } > > + } > > + return c; > > +} > > + > > +void pcie_chassis_create(uint8_t chassis_number) > > +{ > > + struct PCIEChassis *c; > > + c =3D pcie_chassis_find(chassis_number); > > + if (c) { > > + return; > > + } > > + c =3D g_malloc0(sizeof(*c)); > > + c->number =3D chassis_number; > > + QLIST_INIT(&c->slots); > > + QLIST_INSERT_HEAD(&chassis, c, next); > > +} > > + > > +static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChas= sis *c, > > + uint8_t slot) > > +{ > > + PCIESlot *s; > > + QLIST_FOREACH(s, &c->slots, next) { > > + if (s->slot =3D=3D slot) { > > + break; > > + } > > + } > > + return s; > > +} > > + > > +PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t sl= ot) > > +{ > > + struct PCIEChassis *c; > > + c =3D 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 =3D 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 > > + * VA Linux Systems Japan K.K. > > + * > > + * This program is free software; you can redistribute it and/or mod= ify > > + * 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 . > > + */ > > + > > +#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 o= f 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_S= HIFT) > > + > > +#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_S= HIFT) > > + > > +#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 Viola= tion */ > > +#define PCI_ERR_UNC_INTN 0x00400000 /* Internal = Error */ > > +#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoke= d TLP */ > > +#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op= egress blocked */ > > +#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefi= x 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 Lo= ng 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_E= N | \ > > + 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_RC= V | \ > > + 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 > > +#include > > +#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 sl= ot 0, > > + and give the rest of them physical *and* pci numbers starting fro= m 1, so > > + they match logical numbers. Note: this means that multiple slots= must have > > + different chassis number values, to make chassis+physical slot un= ique. > > + 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 |=3D (x >> 1); > > + x |=3D (x >> 2); > > + x |=3D (x >> 4); > > + x |=3D (x >> 8); > > + x |=3D (x >> 16); > > + return x + 1; > > +} > > + > > +static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t= msk) > > +{ > > + uint8_t *status =3D 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 =3D 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 =3D d->shpc; > > + int slot; > > + int level =3D 0; > > + uint32_t serr_int; > > + uint32_t int_locator =3D 0; > > + > > + /* Update interrupt locator register */ > > + for (slot =3D 0; slot < shpc->nslots; ++slot) { > > + uint8_t event =3D shpc->config[SHPC_SLOT_EVENT_LATCH(slot)]; > > + uint8_t disable =3D shpc->config[SHPC_SLOT_EVENT_SERR_INT_DI= S(d, slot)]; > > + uint32_t mask =3D 1 << SHPC_IDX_TO_LOGICAL(slot); > > + if (event & ~disable) { > > + int_locator |=3D mask; > > + } > > + } > > + serr_int =3D pci_get_long(shpc->config + SHPC_SERR_INT); > > + if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_= DIS)) { > > + int_locator |=3D SHPC_INT_COMMAND; > > + } > > + pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator); > > + level =3D (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0; > > + if (msi_enabled(d) && shpc->msi_requested !=3D level) > > + msi_notify(d, 0); > > + else > > + qemu_set_irq(d->irq[0], level); > > + shpc->msi_requested =3D 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] &=3D ~SHPC_SEC_BUS_MASK; > > + shpc->config[SHPC_SEC_BUS] |=3D 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 =3D d->shpc; > > + int nslots =3D 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 =3D 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_S= TATE_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 =3D 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 =3D SHPC_IDX_TO_PCI(slot); > > + for (devfn =3D PCI_DEVFN(pci_slot, 0); > > + devfn <=3D PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1); > > + ++devfn) { > > + PCIDevice *affected_dev =3D 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 =3D SHPC_LOGICAL_TO_IDX(target); > > + if (target < SHPC_CMD_TRGT_MIN || slot >=3D shpc->nslots) { > > + shpc_invalid_command(shpc); > > + return; > > + } > > + current_state =3D shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MA= SK); > > + if (current_state =3D=3D SHPC_STATE_ENABLED && state =3D=3D 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 =3D=3D SHPC_STATE_DISABLED && state =3D=3D SH= PC_STATE_PWRONLY) || > > + (current_state =3D=3D SHPC_STATE_DISABLED && state =3D=3D SH= PC_STATE_ENABLED)) { > > + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > > + } else if ((current_state =3D=3D SHPC_STATE_ENABLED || > > + current_state =3D=3D SHPC_STATE_PWRONLY) && > > + state =3D=3D SHPC_STATE_DISABLED) { > > + shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > > + power =3D 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 d= evice. */ > > + if (power =3D=3D 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)] |=3D > > + SHPC_SLOT_EVENT_BUTTON | > > + SHPC_SLOT_EVENT_MRL | > > + SHPC_SLOT_EVENT_PRESENCE; > > + } > > + } > > +} > > + > > +static void shpc_command(SHPCDevice *shpc) > > +{ > > + uint8_t code =3D 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 =3D shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX; > > + state =3D (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_S= HIFT; > > + power =3D (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_L= ED_SHIFT; > > + attn =3D (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_= LED_SHIFT; > > + shpc_slot_command(shpc, target, state, power, attn); > > + break; > > + case 0x40 ... 0x47: > > + speed =3D 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 =3D 0; i < shpc->nslots; ++i) { > > + state =3D shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK)= ; > > + if (state =3D=3D SHPC_STATE_ENABLED) { > > + shpc_invalid_command(shpc); > > + goto done; > > + } > > + } > > + for (i =3D 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, S= HPC_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 enabl= ed. > > + * This doesn't make sense - why not? a spec bug? */ > > + for (i =3D 0; i < shpc->nslots; ++i) { > > + state =3D shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK)= ; > > + if (state =3D=3D SHPC_STATE_ENABLED) { > > + shpc_invalid_command(shpc); > > + goto done; > > + } > > + } > > + for (i =3D 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, S= HPC_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_CM= D_DETECTED); > > +} > > + > > +static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, in= t l) > > +{ > > + SHPCDevice *shpc =3D d->shpc; > > + int i; > > + if (addr >=3D SHPC_SIZEOF(d)) { > > + return; > > + } > > + l =3D MIN(l, SHPC_SIZEOF(d) - addr); > > + > > + /* TODO: code duplicated from pci.c */ > > + for (i =3D 0; i < l; val >>=3D 8, ++i) { > > + unsigned a =3D addr + i; > > + uint8_t wmask =3D shpc->wmask[a]; > > + uint8_t w1cmask =3D shpc->w1cmask[a]; > > + assert(!(wmask & w1cmask)); > > + shpc->config[a] =3D (shpc->config[a] & ~wmask) | (val & wmas= k); > > + shpc->config[a] &=3D ~(val & w1cmask); /* W1C: Write 1 to Cl= ear */ > > + } > > + 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 =3D 0x0; > > + if (addr >=3D SHPC_SIZEOF(d)) { > > + return val; > > + } > > + l =3D 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_SE= LECT); > > +} > > + > > +/* Update dword data capability register */ > > +static void shpc_cap_update_dword(PCIDevice *d) > > +{ > > + unsigned data; > > + data =3D shpc_read(d, shpc_cap_dword(d) * 4, 4); > > + pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, da= ta); > > +} > > + > > +/* 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 =3D pci_add_capability(d, PCI_CAP_ID_SHPC, > > + 0, SHPC_CAP_LENGTH); > > + if (config_offset < 0) { > > + return config_offset; > > + } > > + config =3D 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 =3D config_offset; > > + /* Make dword select and data writeable. */ > > + pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0= xff); > > + pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xf= fffffff); > > + 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 =3D { > > + .read =3D shpc_mmio_read, > > + .write =3D shpc_mmio_write, > > + .endianness =3D DEVICE_LITTLE_ENDIAN, > > + .valid =3D { > > + /* SHPC ECN requires dword accesses, but the original 1.0 sp= ec doesn't. > > + * It's easier to suppport all sizes than worry about it. */ > > + .min_access_size =3D 1, > > + .max_access_size =3D 4, > > + }, > > +}; > > + > > +static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affecte= d_dev, > > + PCIHotplugState hotplug_state) > > +{ > > + int pci_slot =3D PCI_SLOT(affected_dev->devfn); > > + uint8_t state; > > + uint8_t led; > > + PCIDevice *d =3D DO_UPCAST(PCIDevice, qdev, qdev); > > + SHPCDevice *shpc =3D d->shpc; > > + int slot =3D SHPC_PCI_TO_IDX(pci_slot); > > + if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >=3D 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 c= reation: > > + * it is present on boot, no hotplug event is necessary. We do s= end an > > + * event when the device is disabled later. */ > > + if (hotplug_state =3D=3D 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 =3D=3D PCI_HOTPLUG_DISABLED) { > > + shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=3D SHPC_SLOT_EVE= NT_BUTTON; > > + state =3D shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > > + led =3D shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > > + if (state =3D=3D SHPC_STATE_DISABLED && led =3D=3D 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)] |=3D > > + 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)] |=3D > > + 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)] |=3D > > + 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, unsi= gned offset) > > +{ > > + int i, ret; > > + int nslots =3D SHPC_MAX_SLOTS; /* TODO: qdev property? */ > > + SHPCDevice *shpc =3D d->shpc =3D g_malloc0(sizeof(*d->shpc)); > > + shpc->sec_bus =3D sec_bus; > > + ret =3D 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 =3D nslots; > > + shpc->config =3D g_malloc0(SHPC_SIZEOF(d)); > > + shpc->cmask =3D g_malloc0(SHPC_SIZEOF(d)); > > + shpc->wmask =3D g_malloc0(SHPC_SIZEOF(d)); > > + shpc->w1cmask =3D 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 =3D 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 |=3D 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 =3D d->shpc; > > + d->cap_present &=3D ~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 =3D 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 =3D 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 =3D container_of(pv, PCIDevice, shpc); > > + int ret =3D qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > > + if (ret !=3D SHPC_SIZEOF(d)) { > > + return -EINVAL; > > + } > > + /* Make sure we don't lose notifications. An extra interrupt is = harmless. */ > > + d->shpc->msi_requested =3D 0; > > + shpc_interrupt_update(d); > > + return 0; > > +} > > + > > +VMStateInfo shpc_vmstate_info =3D { > > + .name =3D "shpc", > > + .get =3D shpc_load, > > + .put =3D 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, un= signed 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 r= equired " > > + "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 =3D 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] =3D PCI_SID_ESR_FIC | > > + (nslots << SLOTID_NSLOTS_SHIFT); > > + d->cmask[cap + PCI_SID_ESR] =3D 0xff; > > + d->config[cap + PCI_SID_CHASSIS_NR] =3D 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] =3D 0xff; > > + > > + d->cap_present |=3D QEMU_PCI_CAP_SLOTID; > > + return 0; > > +} > > + > > +void slotid_cap_cleanup(PCIDevice *d) > > +{ > > + /* TODO: cleanup config space? */ > > + d->cap_present &=3D ~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 obtai= ning a copy > > - * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > > - * furnished to do so, subject to the following conditions: > > - * > > - * The above copyright notice and this permission notice shall be in= cluded in > > - * all copies or substantial portions of the Software. > > - * > > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > > - * 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, A= RISING FROM > > - > > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS IN > > - * THE SOFTWARE. > > - */ > > -/* > > - * split out from pci.c > > - * Copyright (c) 2010 Isaku Yamahata > > - * 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 =3D pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SS= VID_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 dev= ice */ > > -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 =3D ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; > > - if (d->config[base] & PCI_IO_RANGE_TYPE_32) { > > - val |=3D (uint32_t)pci_get_word(d->config + base_upper16) <<= 16; > > - } > > - return val; > > -} > > - > > -static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint3= 2_t base) > > -{ > > - return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RA= NGE_MASK) > > - << 16; > > -} > > - > > -static pcibus_t pci_config_get_pref_base(const PCIDevice *d, > > - uint32_t base, uint32_t upp= er) > > -{ > > - pcibus_t tmp; > > - pcibus_t val; > > - > > - tmp =3D (pcibus_t)pci_get_word(d->config + base); > > - val =3D (tmp & PCI_PREF_RANGE_MASK) << 16; > > - if (tmp & PCI_PREF_RANGE_TYPE_64) { > > - val |=3D (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 =3D pci_config_get_io_base(bridge, > > - PCI_IO_BASE, PCI_IO_BASE_UPPER= 16); > > - } else { > > - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > > - base =3D pci_config_get_pref_base( > > - bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32)= ; > > - } else { > > - base =3D pci_config_get_memory_base(bridge, PCI_MEMORY_B= ASE); > > - } > > - } > > - > > - 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 =3D pci_config_get_io_base(bridge, > > - PCI_IO_LIMIT, PCI_IO_LIMIT_UPP= ER16); > > - limit |=3D 0xfff; /* PCI bridge spec 3.2.5.6. */ > > - } else { > > - if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { > > - limit =3D pci_config_get_pref_base( > > - bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER3= 2); > > - } else { > > - limit =3D pci_config_get_memory_base(bridge, PCI_MEMORY_= LIMIT); > > - } > > - limit |=3D 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. *= / > > - } > > - return limit; > > -} > > - > > -static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *a= lias, > > - uint8_t type, const char *name, > > - MemoryRegion *space, > > - MemoryRegion *parent_space, > > - bool enabled) > > -{ > > - pcibus_t base =3D pci_bridge_get_base(&bridge->dev, type); > > - pcibus_t limit =3D pci_bridge_get_limit(&bridge->dev, type); > > - /* TODO: this doesn't handle base =3D 0 limit =3D 2^64 - 1 corre= ctly. > > - * Apparently no way to do this with existing memory APIs. */ > > - pcibus_t size =3D enabled && limit >=3D 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 =3D br->dev.bus; > > - PCIBridgeWindows *w =3D g_new(PCIBridgeWindows, 1); > > - uint16_t cmd =3D 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 =3D 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, PCIBridgeWindow= s *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 =3D 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 =3D 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 =3D container_of(d, PCIBridge, dev); > > - uint16_t oldctl =3D 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 =3D 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 =3D 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 =3D PCI_DEVICE(qdev); > > - uint8_t *conf =3D dev->config; > > - > > - conf[PCI_PRIMARY_BUS] =3D 0; > > - conf[PCI_SECONDARY_BUS] =3D 0; > > - conf[PCI_SUBORDINATE_BUS] =3D 0; > > - conf[PCI_SEC_LATENCY_TIMER] =3D 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 =3D dev->bus; > > - PCIBridge *br =3D DO_UPCAST(PCIBridge, dev, dev); > > - PCIBus *sec_bus =3D &br->sec_bus; > > - > > - pci_word_test_and_set_mask(dev->config + PCI_STATUS, > > - PCI_STATUS_66MHZ | PCI_STATUS_FAST_BA= CK); > > - pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); > > - dev->config[PCI_HEADER_TYPE] =3D > > - (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTI= ON) | > > - 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 .0, where > > - * id is the device id. > > - * Since PCI Bridge devices have a single bus each, we don't nee= d the index: > > - * let users address the bus using the device name. > > - */ > > - if (!br->bus_name && dev->qdev.id && *dev->qdev.id) { > > - br->bus_name =3D dev->qdev.id; > > - } > > - > > - qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, > > - br->bus_name); > > - sec_bus->parent_dev =3D dev; > > - sec_bus->map_irq =3D br->map_irq; > > - sec_bus->address_space_mem =3D &br->address_space_mem; > > - memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT= 64_MAX); > > - sec_bus->address_space_io =3D &br->address_space_io; > > - memory_region_init(&br->address_space_io, "pci_bridge_io", 65536= ); > > - br->windows =3D 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 =3D 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_n= ame 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 =3D map_irq; > > - br->bus_name =3D 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 mod= ify > > - * 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-13= 01, USA. > > - * > > - * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc] > > - * Copyright (c) 2009 Isaku Yamahata > > - * 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_n= ame 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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 =3D addr >> 16; > > - uint8_t devfn =3D 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, uint= 32_t len) > > -{ > > - assert(len <=3D 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 ad= dr, > > - uint32_t limit, uint32_t len) > > -{ > > - assert(len <=3D 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 =3D pci_dev_find_by_addr(s, addr); > > - uint32_t config_addr =3D addr & (PCI_CONFIG_SPACE_SIZE - 1); > > - > > - if (!pci_dev) { > > - return; > > - } > > - > > - PCI_DPRINTF("%s: %s: addr=3D%02" PRIx32 " val=3D%08" PRIx32 " le= n=3D%d\n", > > - __func__, pci_dev->name, config_addr, val, len); > > - pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SP= ACE_SIZE, > > - val, len); > > -} > > - > > -uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) > > -{ > > - PCIDevice *pci_dev =3D pci_dev_find_by_addr(s, addr); > > - uint32_t config_addr =3D addr & (PCI_CONFIG_SPACE_SIZE - 1); > > - uint32_t val; > > - > > - if (!pci_dev) { > > - return ~0x0; > > - } > > - > > - val =3D pci_host_config_read_common(pci_dev, config_addr, > > - PCI_CONFIG_SPACE_SIZE, len); > > - PCI_DPRINTF("%s: %s: addr=3D%02"PRIx32" val=3D%08"PRIx32" len=3D= %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 =3D opaque; > > - > > - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", > > - __func__, addr, len, val); > > - if (addr !=3D 0 || len !=3D 4) { > > - return; > > - } > > - s->config_reg =3D val; > > -} > > - > > -static uint64_t pci_host_config_read(void *opaque, hwaddr addr, > > - unsigned len) > > -{ > > - PCIHostState *s =3D opaque; > > - uint32_t val =3D 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 =3D 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 =3D opaque; > > - uint32_t val; > > - if (!(s->config_reg & (1 << 31))) > > - return 0xffffffff; > > - val =3D 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 =3D { > > - .read =3D pci_host_config_read, > > - .write =3D pci_host_config_write, > > - .endianness =3D DEVICE_LITTLE_ENDIAN, > > -}; > > - > > -const MemoryRegionOps pci_host_conf_be_ops =3D { > > - .read =3D pci_host_config_read, > > - .write =3D pci_host_config_write, > > - .endianness =3D DEVICE_BIG_ENDIAN, > > -}; > > - > > -const MemoryRegionOps pci_host_data_le_ops =3D { > > - .read =3D pci_host_data_read, > > - .write =3D pci_host_data_write, > > - .endianness =3D DEVICE_LITTLE_ENDIAN, > > -}; > > - > > -const MemoryRegionOps pci_host_data_be_ops =3D { > > - .read =3D pci_host_data_read, > > - .write =3D pci_host_data_write, > > - .endianness =3D DEVICE_BIG_ENDIAN, > > -}; > > - > > -static const TypeInfo pci_host_type_info =3D { > > - .name =3D TYPE_PCI_HOST_BRIDGE, > > - .parent =3D TYPE_SYS_BUS_DEVICE, > > - .abstract =3D true, > > - .instance_size =3D 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 routi= nes. > > - * > > - * Copyright (c) 2006 Fabrice Bellard > > - * > > - * Permission is hereby granted, free of charge, to any person obtai= ning a copy > > - * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > > - * furnished to do so, subject to the following conditions: > > - * > > - * The above copyright notice and this permission notice shall be in= cluded in > > - * all copies or substantial portions of the Software. > > - * > > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > > - * 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, A= RISING FROM, > > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS IN > > - * THE SOFTWARE. > > - */ > > - > > -/* Worker routines for a PCI host controller that uses an {address,d= ata} > > - 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, uint= 32_t len); > > -uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t ad= dr, > > - 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 lat= er */ > > - QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev lat= er */ > > - > > - /* 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 region= s 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 > > - * > > - * For more information, please consult the following manuals (l= ook 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 spa= ce, > > - * 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 a= nd 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 steppi= ng */ > > -#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 Defin= able 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 S= ERR */ > > -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error= */ > > - > > -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, lo= w 8 revision */ > > -#define PCI_REVISION_ID 0x08 /* Revision ID */ > > -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Int= erface */ > > -#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 =3D memo= ry, 1 =3D 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 =3D 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 ad= dress, 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 secondar= y interface */ > > -#define PCI_IO_BASE 0x1c /* I/O range behind the bridg= e */ > > -#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 behin= d */ > > -#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 addresse= s */ > > -#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, b= ut 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 forwardi= ng */ > > -#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 rese= t */ > > -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back ena= bled 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 standar= d 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 f= or 16-bit cards */ > > -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable fo= r 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 Graphi= cs 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 Resourc= e Control */ > > -#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Cont= roller */ > > -#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/de= vice 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 lis= t */ > > -#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 in= itialization */ > > -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support ma= sk */ > > -#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 P= MC */ > > -#define PCI_PM_CTRL 4 /* PM control and status regi= ster */ > > -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power stat= e (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 en= able (??) */ > > -#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 nu= mber of requests - 1 */ > > -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing suppor= ted */ > > -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supporte= d */ > > -#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 numb= er of requests */ > > -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enable= d */ > > -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP tr= ansactions */ > > -#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 indicat= es completion */ > > -#define PCI_VPD_DATA 4 /* 32-bits of data returned h= ere */ > > - > > -/* 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 configu= red */ > > -#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size availab= le */ > > -#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 fo= r 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 fo= r 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 Registe= r */ > > -#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 c= ount */ > > -#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte c= ount */ > > -#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte c= ount */ > > -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count= */ > > - /* Max # of outstanding split transac= tions */ > > -#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 Tran= sactions */ > > -#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 D= iscarded */ > > -#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split C= ompletion */ > > -#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity = */ > > -#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memor= y Read Count */ > > -#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed M= ax Outstanding Split Transactions */ > > -#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumul= ative Read Size */ > > -#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Complet= ion 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 vendo= r id register */ > > -#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem devic= e 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 En= dpoint */ > > -#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collec= tor */ > > -#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 P= resent */ > > -#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicato= r Present */ > > -#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Pr= esent */ > > -#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 Reportin= g En. */ > > -#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting = Enable */ > > -#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enab= le */ > > -#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Report= ing 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 Retr= y / 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 Detect= ed */ > > -#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 Manageme= nt */ > > -#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Rep= orting Capable */ > > -#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer= Link Active Reporting Capable */ > > -#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notifica= tion 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 I= nterrupt 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 Activ= e */ > > -#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 Presen= t */ > > -#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Presen= t */ > > -#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ > > -#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Pre= sent */ > > -#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 Inter= lock Present */ > > -#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Su= pport */ > > -#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 E= nable */ > > -#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enabl= e */ > > -#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable = */ > > -#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed En= able */ > > -#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrup= t Enable */ > > -#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable = */ > > -#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Contro= l */ > > -#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 Interloc= k Control */ > > -#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Chan= ged 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 Interloc= k Status */ > > -#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Chan= ged */ > > -#define PCI_EXP_RTCTL 28 /* Root Control */ > > -#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctabl= e Error */ > > -#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal = Error */ > > -#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Erro= r */ > > -#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ > > -#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility En= able */ > > -#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 Capabilitie= s 2 */ > > -#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ > > -#define PCI_EXP_DEVCAP2_LTR 0x800 /* Latency tolerance reportin= g */ > > -#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 completi= on enable */ > > -#define PCI_EXP_LTR_EN 0x400 /* Latency tolerance = reporting */ > > -#define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message t= ype A */ > > -#define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message t= ype 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 T= LP */ > > -#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Proto= col */ > > -#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 Complet= ion */ > > -#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 Reques= t */ > > -#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask *= / > > - /* Same bits as above */ > > -#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severi= ty */ > > - /* Same bits as above */ > > -#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status *= / > > -#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Sta= tus */ > > -#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 Rollove= r */ > > -#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeo= ut */ > > -#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ > > - /* Same bits as above */ > > -#define PCI_ERR_CAP 24 /* Advanced Error Capabilitie= s */ > > -#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointe= r */ > > -#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Ca= pable */ > > -#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation En= able */ > > -#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 by= tes) */ > > -#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 Re= ceived */ > > -/* 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 Fata= l */ > > -#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal = Received */ > > -#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Rece= ived */ > > -#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identificatio= n */ > > - > > -/* 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 def= ined > > - * 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 configu= ration */ > > -#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary lin= k configuration */ > > - > > -#define HT_5BIT_CAP_MASK 0xF8 > > -#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ > > -#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address rem= apping */ > > -#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 Spa= ce 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 ma= sk */ > > -#define HT_MSI_ADDR_HI 0x08 /* Offset to = high addr bits */ > > -#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing con= figuration */ > > -#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configurat= ion */ > > -#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configurati= on */ > > -#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hyper= transport configuration */ > > -#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanage= ment configuration */ > > - > > -/* Alternative Routing-ID Interpretation */ > > -#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ > > -#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capab= ility */ > > -#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capabi= lity */ > > -#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 Enabl= e */ > > -#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 D= epth */ > > -#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 Translati= on 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 Numb= er */ > > -#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 Ena= ble */ > > -#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 O= ffset*/ > > -#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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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_ARG= S__) > > - > > - > > -/*******************************************************************= ******** > > - * pci express capability helper functions > > - */ > > -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint= 8_t port) > > -{ > > - int pos; > > - uint8_t *exp_cap; > > - > > - assert(pci_is_express(dev)); > > - > > - pos =3D pci_add_capability(dev, PCI_CAP_ID_EXP, offset, > > - PCI_EXP_VER2_SIZEOF); > > - if (pos < 0) { > > - return pos; > > - } > > - dev->exp.exp_cap =3D pos; > > - exp_cap =3D 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 =3D 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 =3D dev->config + dev->exp.exp_cap; > > - assert(vector < 32); > > - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FL= AGS_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_FL= AGS) & > > - PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; > > -} > > - > > -void pcie_cap_deverr_init(PCIDevice *dev) > > -{ > > - uint32_t pos =3D 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_N= FED | > > - PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_U= RD); > > -} > > - > > -void pcie_cap_deverr_reset(PCIDevice *dev) > > -{ > > - uint8_t *devctl =3D dev->config + dev->exp.exp_cap + PCI_EXP_DEV= CTL; > > - pci_long_test_and_clear_mask(devctl, > > - PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCT= L_NFERE | > > - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCT= L_URRE); > > -} > > - > > -static void hotplug_event_update_event_status(PCIDevice *dev) > > -{ > > - uint32_t pos =3D dev->exp.exp_cap; > > - uint8_t *exp_cap =3D dev->config + pos; > > - uint16_t sltctl =3D pci_get_word(exp_cap + PCI_EXP_SLTCTL); > > - uint16_t sltsta =3D pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > - > > - dev->exp.hpev_notified =3D (sltctl & PCI_EXP_SLTCTL_HPIE) && > > - (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); > > -} > > - > > -static void hotplug_event_notify(PCIDevice *dev) > > -{ > > - bool prev =3D dev->exp.hpev_notified; > > - > > - hotplug_event_update_event_status(dev); > > - > > - if (prev =3D=3D dev->exp.hpev_notified) { > > - return; > > - } > > - > > - /* Note: the logic above does not take into account whether inte= rrupts > > - * 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 e= vents that > > - * occur while interrupt generation is disabled, and interrupt g= eneration 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_not= ified); > > - } > > -} > > - > > -static void hotplug_event_clear(PCIDevice *dev) > > -{ > > - hotplug_event_update_event_status(dev); > > - if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_no= tified) { > > - 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, PCIExpressHotPlugEve= nt 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 =3D PCI_DEVICE(qdev); > > - uint8_t *exp_cap =3D d->config + d->exp.exp_cap; > > - uint16_t sltsta =3D pci_get_word(exp_cap + PCI_EXP_SLTSTA); > > - > > - /* Don't send event when device is enabled during qemu machine c= reation: > > - * it is present on boot, no hotplug event is necessary. We do s= end an > > - * event when the device is disabled later. */ > > - if (state =3D=3D 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 =3D 0 is allowed to be > > - * hot plugged/unplugged. > > - */ > > - assert(PCI_FUNC(pci_dev->devfn) =3D=3D 0); > > - > > - if (state =3D=3D 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 =3D 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 =3D 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 =3D 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 =3D dev->exp.exp_cap; > > - uint8_t *exp_cap =3D dev->config + pos; > > - uint16_t sltsta =3D 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 ^=3D 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 Po= rt by > > - * issuing a write transaction that targets any portion of the P= ort=E2=80=99s 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 t= ransaction, > > - * the Port must carry out the requested actions and then set th= e > > - * associated status field for the command completed event. */ > > - > > - /* Real hardware might take a while to complete requested comman= d because > > - * physical movement would be involved like locking the electrom= echanical > > - * lock. However in our case, command is completed instantaneou= sly 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 =3D 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 wr= itten > > - * 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_E= XP_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 =3D dev->config + dev->exp.exp_cap + PCI_EXP_DEV= CTL; > > - if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { > > - /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset han= dler > > - 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 =3D 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 =3D dev->config + dev->exp.exp_cap + PCI_EXP_DE= VCTL2; > > - 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_DEV= CTL2) & > > - 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 c= ap_id, > > - uint16_t *prev_p) > > -{ > > - uint16_t prev =3D 0; > > - uint16_t next; > > - uint32_t header =3D pci_get_long(dev->config + PCI_CONFIG_SPACE_= SIZE); > > - > > - if (!header) { > > - /* no extended capability */ > > - next =3D 0; > > - goto out; > > - } > > - for (next =3D PCI_CONFIG_SPACE_SIZE; next; > > - prev =3D next, next =3D PCI_EXT_CAP_NEXT(header)) { > > - > > - assert(next >=3D PCI_CONFIG_SPACE_SIZE); > > - assert(next <=3D PCIE_CONFIG_SPACE_SIZE - 8); > > - > > - header =3D pci_get_long(dev->config + next); > > - if (PCI_EXT_CAP_ID(header) =3D=3D cap_id) { > > - break; > > - } > > - } > > - > > -out: > > - if (prev_p) { > > - *prev_p =3D 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, uint= 16_t next) > > -{ > > - uint16_t header =3D pci_get_long(dev->config + pos); > > - assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); > > - header =3D (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 sho= uldn'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 >=3D PCI_CONFIG_SPACE_SIZE); > > - assert(offset < offset + size); > > - assert(offset + size < PCIE_CONFIG_SPACE_SIZE); > > - assert(size >=3D 8); > > - assert(pci_is_express(dev)); > > - > > - if (offset =3D=3D PCI_CONFIG_SPACE_SIZE) { > > - header =3D pci_get_long(dev->config + offset); > > - next =3D PCI_EXT_CAP_NEXT(header); > > - } else { > > - uint16_t prev; > > - > > - /* 0 is reserved cap id. use internally to find the last cap= ability > > - in the linked list */ > > - next =3D pcie_find_capability_list(dev, 0, &prev); > > - > > - assert(prev >=3D PCI_CONFIG_SPACE_SIZE); > > - assert(next =3D=3D 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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 =3D PCI_EXP_SLTCTL_IND_RESERVED, > > - PCI_EXP_HP_IND_ON =3D PCI_EXP_SLTCTL_IND_ON, > > - PCI_EXP_HP_IND_BLINK =3D PCI_EXP_SLTCTL_IND_BLINK, > > - PCI_EXP_HP_IND_OFF =3D PCI_EXP_SLTCTL_IND_OFF, > > -} PCIExpressIndicator; > > - > > -typedef enum { > > - /* these bits must match the bits in Slot Control/Status registe= rs. > > - * PCI_EXP_HP_EV_xxx =3D PCI_EXP_SLTCTL_xxxE =3D 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 =3D PCI_EXP_SLTCTL_ABPE, > > - /* attention button pressed = */ > > - PCI_EXP_HP_EV_PDC =3D PCI_EXP_SLTCTL_PDCE, > > - /* presence detect changed *= / > > - PCI_EXP_HP_EV_CCI =3D PCI_EXP_SLTCTL_CCIE, > > - /* command completed */ > > - > > - PCI_EXP_HP_EV_SUPPORTED =3D PCI_EXP_HP_EV_ABP | > > - PCI_EXP_HP_EV_PDC | > > - PCI_EXP_HP_EV_CCI, > > - /* supported event m= ask */ > > - > > - /* 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 =3D INTA# > > - * If the chip wants to use other in= terrupt > > - * line, initialize this member with= the > > - * desired number. > > - * If the chip dynamically changes t= his member, > > - * also initialize it when loaded as > > - * appropreately. > > - */ > > - bool hpev_notified; /* Logical AND of conditions for hot plug ev= ent. > > - Following 6.7.3.4: > > - Software Notification of Hot-Plug Events, a= n interrupt > > - is sent whenever the logical and of these c= onditions > > - transitions from false to true. */ > > - > > - /* AER */ > > - uint16_t aer_cap; > > - PCIEAERLog aer_log; > > - unsigned int aer_intx; /* INTx for error reporting > > - * default is 0 =3D INTA# > > - * If the chip wants to use other in= terrupt > > - * line, initialize this member with= the > > - * desired number. > > - * If the chip dynamically changes t= his 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, uint= 8_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 =3D (stringify(_field)), = \ > > - .size =3D sizeof(PCIDevice), = \ > > - .vmsd =3D &vmstate_pcie_device, = \ > > - .flags =3D VMS_STRUCT, = \ > > - .offset =3D 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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_ARG= S__) > > - > > -#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 *er= r) > > -{ > > - if (aer_log->log_num =3D=3D 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 =3D 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 =3D 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 =3D &dev->exp; > > - exp->aer_cap =3D offset; > > - > > - /* log_max is property */ > > - if (dev->exp.aer_log.log_max =3D=3D PCIE_AER_LOG_MAX_UNSET) { > > - dev->exp.aer_log.log_max =3D 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 =3D 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_S= TATUS, > > - 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 supporte= d */ > > - 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 =3D dev->config + dev->exp.aer_cap; > > - PCIEAERLog *aer_log =3D &dev->exp.aer_log; > > - > > - uint16_t i; > > - for (i =3D 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_SER= R))) { > > - 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 tha= t > > - * errors are reported if enabled either through this bit or thr= ough > > - * 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_DEVC= TL))) { > > - 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 *m= sg) > > -{ > > - uint16_t bridge_control =3D pci_get_word(dev->config + PCI_BRIDG= E_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 =3D 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 =3D dev->config + dev->exp.aer_cap; > > - uint32_t root_status =3D pci_get_long(aer_cap + PCI_ERR_ROOT_STA= TUS); > > - return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIF= T; > > -} > > - > > -/* Given a status register, get corresponding bits in the command re= gister */ > > -static uint32_t pcie_aer_status_to_cmd(uint32_t status) > > -{ > > - uint32_t cmd =3D 0; > > - if (status & PCI_ERR_ROOT_COR_RCV) { > > - cmd |=3D PCI_ERR_ROOT_CMD_COR_EN; > > - } > > - if (status & PCI_ERR_ROOT_NONFATAL_RCV) { > > - cmd |=3D PCI_ERR_ROOT_CMD_NONFATAL_EN; > > - } > > - if (status & PCI_ERR_ROOT_FATAL_RCV) { > > - cmd |=3D 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 =3D pci_get_word(dev->config + PCI_COMMAND); > > - aer_cap =3D dev->config + dev->exp.aer_cap; > > - root_cmd =3D pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); > > - prev_status =3D root_status =3D pci_get_long(aer_cap + PCI_ERR_R= OOT_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 |=3D PCI_ERR_ROOT_MULTI_COR_RCV; > > - } else { > > - pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SR= C_COR_OFFS, > > - msg->source_id); > > - } > > - root_status |=3D PCI_ERR_ROOT_COR_RCV; > > - break; > > - case PCI_ERR_ROOT_CMD_NONFATAL_EN: > > - root_status |=3D PCI_ERR_ROOT_NONFATAL_RCV; > > - break; > > - case PCI_ERR_ROOT_CMD_FATAL_EN: > > - if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { > > - root_status |=3D PCI_ERR_ROOT_FIRST_FATAL; > > - } > > - root_status |=3D 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 |=3D 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 |=3D 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 =3D pcie_cap_get_type(dev); > > - if ((type =3D=3D PCI_EXP_TYPE_ROOT_PORT || > > - type =3D=3D PCI_EXP_TYPE_UPSTREAM || > > - type =3D=3D PCI_EXP_TYPE_DOWNSTREAM) && > > - !pcie_aer_msg_vbridge(dev, msg)) { > > - return; > > - } > > - if (!pcie_aer_msg_alldev(dev, msg)) { > > - return; > > - } > > - if (type =3D=3D 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 colle= ctor. */ > > - /* > > - * 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 =3D pci_bridge_get_device(dev->bus); > > - } > > -} > > - > > -static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *er= r) > > -{ > > - uint8_t *aer_cap =3D dev->config + dev->exp.aer_cap; > > - uint8_t first_bit =3D ffs(err->status) - 1; > > - uint32_t errcap =3D pci_get_long(aer_cap + PCI_ERR_CAP); > > - int i; > > - > > - assert(err->status); > > - assert(!(err->status & (err->status - 1))); > > - > > - errcap &=3D ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); > > - errcap |=3D PCI_ERR_CAP_FEP(first_bit); > > - > > - if (err->flags & PCIE_AER_ERR_HEADER_VALID) { > > - for (i =3D 0; i < ARRAY_SIZE(err->header); ++i) { > > - /* 7.10.8 Header Log Register */ > > - uint8_t *header_log =3D > > - aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->heade= r[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_S= IZE); > > - } > > - > > - if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && > > - (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCT= L2) & > > - PCI_EXP_DEVCAP2_EETLPP)) { > > - for (i =3D 0; i < ARRAY_SIZE(err->prefix); ++i) { > > - /* 7.10.12 tlp prefix log register */ > > - uint8_t *prefix_log =3D > > - aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->p= refix[0]; > > - cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); > > - } > > - errcap |=3D 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 =3D 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_L= OG_SIZE); > > -} > > - > > -static void pcie_aer_clear_error(PCIDevice *dev) > > -{ > > - uint8_t *aer_cap =3D dev->config + dev->exp.aer_cap; > > - uint32_t errcap =3D pci_get_long(aer_cap + PCI_ERR_CAP); > > - PCIEAERLog *aer_log =3D &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 uncorrec= table > > - * error status. > > - * We emulate uncorrectable error status register as W1CS. > > - * So set bit in uncorrectable error status here again for multi= ple > > - * error recording support. > > - * > > - * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capa= bility) > > - */ > > - 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 =3D dev->config + dev->exp.aer_cap; > > - uint32_t errcap =3D pci_get_long(aer_cap + PCI_ERR_CAP); > > - int fep =3D 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 =3D inj->dev; > > - > > - inj->devsta |=3D PCI_EXP_DEVSTA_CED; > > - if (inj->unsupported_request) { > > - inj->devsta |=3D PCI_EXP_DEVSTA_URD; > > - } > > - pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, in= j->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 =3D 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 =3D > > - pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); > > - if (!(uncor_mask & uncor_status)) { > > - inj->log_overflow =3D !!pcie_aer_record_error(dev, i= nj->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_U= RRE)) { > > - return false; > > - } > > - if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { > > - return false; > > - } > > - > > - inj->msg.severity =3D PCI_ERR_ROOT_CMD_COR_EN; > > - return true; > > -} > > - > > -static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_= fatal) > > -{ > > - PCIDevice *dev =3D inj->dev; > > - uint16_t cmd; > > - > > - if (is_fatal) { > > - inj->devsta |=3D PCI_EXP_DEVSTA_FED; > > - } else { > > - inj->devsta |=3D PCI_EXP_DEVSTA_NFED; > > - } > > - if (inj->unsupported_request) { > > - inj->devsta |=3D PCI_EXP_DEVSTA_URD; > > - } > > - pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, in= j->devsta); > > - > > - if (inj->aer_cap) { > > - uint32_t mask =3D 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 =3D !!pcie_aer_record_error(dev, inj->err)= ; > > - pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STAT= US, > > - inj->error_status); > > - } > > - > > - cmd =3D 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 =3D PCI_ERR_ROOT_CMD_FATAL_EN; > > - } else { > > - if (!((cmd & PCI_COMMAND_SERR) || > > - (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { > > - return false; > > - } > > - inj->msg.severity =3D 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 sh= ould > > - * 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 a= nd Logging > > - * Operations > > - */ > > -int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) > > -{ > > - uint8_t *aer_cap =3D NULL; > > - uint16_t devctl =3D 0; > > - uint16_t devsta =3D 0; > > - uint32_t error_status =3D err->status; > > - PCIEAERInject inj; > > - > > - if (!pci_is_express(dev)) { > > - return -ENOSYS; > > - } > > - > > - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > > - error_status &=3D PCI_ERR_COR_SUPPORTED; > > - } else { > > - error_status &=3D 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 =3D dev->config + dev->exp.exp_cap; > > - aer_cap =3D dev->config + dev->exp.aer_cap; > > - devctl =3D pci_get_long(exp_cap + PCI_EXP_DEVCTL); > > - devsta =3D pci_get_long(exp_cap + PCI_EXP_DEVSTA); > > - } > > - > > - inj.dev =3D dev; > > - inj.aer_cap =3D aer_cap; > > - inj.err =3D err; > > - inj.devctl =3D devctl; > > - inj.devsta =3D devsta; > > - inj.error_status =3D error_status; > > - inj.unsupported_request =3D !(err->flags & PCIE_AER_ERR_IS_CORRE= CTABLE) && > > - err->status =3D=3D PCI_ERR_UNC_UNSUP; > > - inj.log_overflow =3D false; > > - > > - if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { > > - if (!pcie_aer_inject_cor_error(&inj, 0, false)) { > > - return 0; > > - } > > - } else { > > - bool is_fatal =3D > > - pcie_aer_uncor_default_severity(error_status) =3D=3D > > - PCI_ERR_ROOT_CMD_FATAL_EN; > > - if (aer_cap) { > > - is_fatal =3D > > - error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_= SEVER); > > - } > > - if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY))= { > > - inj.error_status =3D 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 =3D err->source_id; > > - pcie_aer_msg(dev, &inj.msg); > > - > > - if (inj.log_overflow) { > > - PCIEAERErr header_log_overflow =3D { > > - .status =3D PCI_ERR_COR_HL_OVERFLOW, > > - .flags =3D PCIE_AER_ERR_IS_CORRECTABLE, > > - }; > > - int ret =3D 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 =3D dev->config + dev->exp.aer_cap; > > - uint32_t errcap =3D pci_get_long(aer_cap + PCI_ERR_CAP); > > - uint32_t first_error =3D 1U << PCI_ERR_CAP_FEP(errcap); > > - uint32_t uncorsta =3D pci_get_long(aer_cap + PCI_ERR_UNCOR_STATU= S); > > - > > - /* 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 modificat= ion 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 =3D 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 =3D 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 depe= ndent > > - * 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 =3D dev->config + dev->exp.aer_cap; > > - uint32_t root_status =3D pci_get_long(aer_cap + PCI_ERR_ROOT_STA= TUS); > > - uint32_t enabled_cmd =3D pcie_aer_status_to_cmd(root_status); > > - uint32_t root_cmd =3D pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAN= D); > > - /* 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 & enab= led_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 =3D { > > - .name =3D "PCIE_AER_ERROR", > > - .version_id =3D 1, > > - .minimum_version_id =3D 1, > > - .minimum_version_id_old =3D 1, > > - .fields =3D (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 =3D { > > - .name =3D "PCIE_AER_ERROR_LOG", > > - .version_id =3D 1, > > - .minimum_version_id =3D 1, > > - .minimum_version_id_old =3D 1, > > - .fields =3D (VMStateField[]) { > > - VMSTATE_UINT16(log_num, PCIEAERLog), > > - VMSTATE_UINT16(log_max, PCIEAERLog), > > - VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_nu= m, > > - 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) =3D=3D QTYPE_QDICT); > > - qdict =3D qobject_to_qdict(data); > > - > > - devfn =3D (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[] =3D { > > - { > > - .name =3D "TRAIN", > > - .val =3D PCI_ERR_UNC_TRAIN, > > - .correctable =3D false, > > - }, { > > - .name =3D "DLP", > > - .val =3D PCI_ERR_UNC_DLP, > > - .correctable =3D false, > > - }, { > > - .name =3D "SDN", > > - .val =3D PCI_ERR_UNC_SDN, > > - .correctable =3D false, > > - }, { > > - .name =3D "POISON_TLP", > > - .val =3D PCI_ERR_UNC_POISON_TLP, > > - .correctable =3D false, > > - }, { > > - .name =3D "FCP", > > - .val =3D PCI_ERR_UNC_FCP, > > - .correctable =3D false, > > - }, { > > - .name =3D "COMP_TIME", > > - .val =3D PCI_ERR_UNC_COMP_TIME, > > - .correctable =3D false, > > - }, { > > - .name =3D "COMP_ABORT", > > - .val =3D PCI_ERR_UNC_COMP_ABORT, > > - .correctable =3D false, > > - }, { > > - .name =3D "UNX_COMP", > > - .val =3D PCI_ERR_UNC_UNX_COMP, > > - .correctable =3D false, > > - }, { > > - .name =3D "RX_OVER", > > - .val =3D PCI_ERR_UNC_RX_OVER, > > - .correctable =3D false, > > - }, { > > - .name =3D "MALF_TLP", > > - .val =3D PCI_ERR_UNC_MALF_TLP, > > - .correctable =3D false, > > - }, { > > - .name =3D "ECRC", > > - .val =3D PCI_ERR_UNC_ECRC, > > - .correctable =3D false, > > - }, { > > - .name =3D "UNSUP", > > - .val =3D PCI_ERR_UNC_UNSUP, > > - .correctable =3D false, > > - }, { > > - .name =3D "ACSV", > > - .val =3D PCI_ERR_UNC_ACSV, > > - .correctable =3D false, > > - }, { > > - .name =3D "INTN", > > - .val =3D PCI_ERR_UNC_INTN, > > - .correctable =3D false, > > - }, { > > - .name =3D "MCBTLP", > > - .val =3D PCI_ERR_UNC_MCBTLP, > > - .correctable =3D false, > > - }, { > > - .name =3D "ATOP_EBLOCKED", > > - .val =3D PCI_ERR_UNC_ATOP_EBLOCKED, > > - .correctable =3D false, > > - }, { > > - .name =3D "TLP_PRF_BLOCKED", > > - .val =3D PCI_ERR_UNC_TLP_PRF_BLOCKED, > > - .correctable =3D false, > > - }, { > > - .name =3D "RCVR", > > - .val =3D PCI_ERR_COR_RCVR, > > - .correctable =3D true, > > - }, { > > - .name =3D "BAD_TLP", > > - .val =3D PCI_ERR_COR_BAD_TLP, > > - .correctable =3D true, > > - }, { > > - .name =3D "BAD_DLLP", > > - .val =3D PCI_ERR_COR_BAD_DLLP, > > - .correctable =3D true, > > - }, { > > - .name =3D "REP_ROLL", > > - .val =3D PCI_ERR_COR_REP_ROLL, > > - .correctable =3D true, > > - }, { > > - .name =3D "REP_TIMER", > > - .val =3D PCI_ERR_COR_REP_TIMER, > > - .correctable =3D true, > > - }, { > > - .name =3D "ADV_NONFATAL", > > - .val =3D PCI_ERR_COR_ADV_NONFATAL, > > - .correctable =3D true, > > - }, { > > - .name =3D "INTERNAL", > > - .val =3D PCI_ERR_COR_INTERNAL, > > - .correctable =3D true, > > - }, { > > - .name =3D "HL_OVERFLOW", > > - .val =3D PCI_ERR_COR_HL_OVERFLOW, > > - .correctable =3D true, > > - }, > > -}; > > - > > -static int pcie_aer_parse_error_string(const char *error_name, > > - uint32_t *status, bool *corre= ctable) > > -{ > > - int i; > > - > > - for (i =3D 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) { > > - const PCIEAERErrorName *e =3D &pcie_aer_error_list[i]; > > - if (strcmp(error_name, e->name)) { > > - continue; > > - } > > - > > - *status =3D e->val; > > - *correctable =3D e->correctable; > > - return 0; > > - } > > - return -EINVAL; > > -} > > - > > -int do_pcie_aer_inject_error(Monitor *mon, > > - const QDict *qdict, QObject **ret_data) > > -{ > > - const char *id =3D qdict_get_str(qdict, "id"); > > - const char *error_name; > > - uint32_t error_status; > > - bool correctable; > > - PCIDevice *dev; > > - PCIEAERErr err; > > - int ret; > > - > > - ret =3D pci_qdev_find_device(id, &dev); > > - if (ret < 0) { > > - monitor_printf(mon, > > - "id or pci device path is invalid or device n= ot " > > - "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 =3D qdict_get_str(qdict, "error_status"); > > - if (pcie_aer_parse_error_string(error_name, &error_status, &corr= ectable)) { > > - char *e =3D NULL; > > - error_status =3D strtoul(error_name, &e, 0); > > - correctable =3D qdict_get_try_bool(qdict, "correctable", 0); > > - if (!e || *e !=3D '\0') { > > - monitor_printf(mon, "invalid error status value. \"%s\""= , > > - error_name); > > - return -EINVAL; > > - } > > - } > > - err.status =3D error_status; > > - err.source_id =3D (pci_bus_num(dev->bus) << 8) | dev->devfn; > > - > > - err.flags =3D 0; > > - if (correctable) { > > - err.flags |=3D PCIE_AER_ERR_IS_CORRECTABLE; > > - } > > - if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) { > > - err.flags |=3D PCIE_AER_ERR_MAYBE_ADVISORY; > > - } > > - if (qdict_haskey(qdict, "header0")) { > > - err.flags |=3D PCIE_AER_ERR_HEADER_VALID; > > - } > > - if (qdict_haskey(qdict, "prefix0")) { > > - err.flags |=3D PCIE_AER_ERR_TLP_PREFIX_PRESENT; > > - } > > - > > - err.header[0] =3D qdict_get_try_int(qdict, "header0", 0); > > - err.header[1] =3D qdict_get_try_int(qdict, "header1", 0); > > - err.header[2] =3D qdict_get_try_int(qdict, "header2", 0); > > - err.header[3] =3D qdict_get_try_int(qdict, "header3", 0); > > - > > - err.prefix[0] =3D qdict_get_try_int(qdict, "prefix0", 0); > > - err.prefix[1] =3D qdict_get_try_int(qdict, "prefix1", 0); > > - err.prefix[2] =3D qdict_get_try_int(qdict, "prefix2", 0); > > - err.prefix[3] =3D qdict_get_try_int(qdict, "prefix3", 0); > > - > > - ret =3D pcie_aer_inject_error(dev, &err); > > - *ret_data =3D 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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 thi= s. > > - * > > - * 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 ma= ny 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 sevirit= y and > > - source id. See 2.2.8.3 error signaling messages */ > > -struct PCIEAERMsg { > > - /* > > - * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN > > - * =3D 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 =3D=3D PCI_ERR_ROOT_CMD_NONFATAL_EN || > > - msg->severity =3D=3D 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/uncor= rectable */ > > -#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory no= n-fatal */ > > -#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is log= ged */ > > -#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is log= ged */ > > - 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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_B= IT) & \ > > - 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_CONFOFF= SET_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 =3D opaque; > > - PCIBus *s =3D e->pci.bus; > > - PCIDevice *pci_dev =3D pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr= ); > > - uint32_t addr; > > - uint32_t limit; > > - > > - if (!pci_dev) { > > - return; > > - } > > - addr =3D PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > > - limit =3D pci_config_size(pci_dev); > > - if (limit <=3D addr) { > > - /* conventional pci device can be behind pcie-to-pci bridge. > > - 256 <=3D 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 =3D opaque; > > - PCIBus *s =3D e->pci.bus; > > - PCIDevice *pci_dev =3D pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr= ); > > - uint32_t addr; > > - uint32_t limit; > > - > > - if (!pci_dev) { > > - return ~0x0; > > - } > > - addr =3D PCIE_MMCFG_CONFOFFSET(mmcfg_addr); > > - limit =3D pci_config_size(pci_dev); > > - if (limit <=3D addr) { > > - /* conventional pci device can be behind pcie-to-pci bridge. > > - 256 <=3D addr < 4K has no effects. */ > > - return ~0x0; > > - } > > - return pci_host_config_read_common(pci_dev, addr, limit, len); > > -} > > - > > -static const MemoryRegionOps pcie_mmcfg_ops =3D { > > - .read =3D pcie_mmcfg_data_read, > > - .write =3D pcie_mmcfg_data_write, > > - .endianness =3D DEVICE_NATIVE_ENDIAN, > > -}; > > - > > -/* pcie_host::base_addr =3D=3D 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 =3D PCIE_BASE_ADDR_UNMAPPED; > > - > > - return 0; > > -} > > - > > -void pcie_host_mmcfg_unmap(PCIExpressHost *e) > > -{ > > - if (e->base_addr !=3D PCIE_BASE_ADDR_UNMAPPED) { > > - memory_region_del_subregion(get_system_memory(), &e->mmio); > > - memory_region_destroy(&e->mmio); > > - e->base_addr =3D 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 >=3D PCIE_MMCFG_SIZE_MIN); > > - assert(size <=3D PCIE_MMCFG_SIZE_MAX); > > - e->size =3D size; > > - memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg"= , e->size); > > - e->base_addr =3D 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 =3D { > > - .name =3D TYPE_PCIE_HOST_BRIDGE, > > - .parent =3D TYPE_PCI_HOST_BRIDGE, > > - .abstract =3D true, > > - .instance_size =3D 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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 si= ze); > > -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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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 conversi= on > > - */ > > -struct PCIEChassis { > > - uint8_t number; > > - > > - QLIST_HEAD(, PCIESlot) slots; > > - QLIST_ENTRY(PCIEChassis) next; > > -}; > > - > > -static QLIST_HEAD(, PCIEChassis) chassis =3D 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 =3D=3D chassis_number) { > > - break; > > - } > > - } > > - return c; > > -} > > - > > -void pcie_chassis_create(uint8_t chassis_number) > > -{ > > - struct PCIEChassis *c; > > - c =3D pcie_chassis_find(chassis_number); > > - if (c) { > > - return; > > - } > > - c =3D g_malloc0(sizeof(*c)); > > - c->number =3D chassis_number; > > - QLIST_INIT(&c->slots); > > - QLIST_INSERT_HEAD(&chassis, c, next); > > -} > > - > > -static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChas= sis *c, > > - uint8_t slot) > > -{ > > - PCIESlot *s; > > - QLIST_FOREACH(s, &c->slots, next) { > > - if (s->slot =3D=3D slot) { > > - break; > > - } > > - } > > - return s; > > -} > > - > > -PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t sl= ot) > > -{ > > - struct PCIEChassis *c; > > - c =3D 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 =3D 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 > > - * VA Linux Systems Japan K.K. > > - * > > - * This program is free software; you can redistribute it and/or mod= ify > > - * 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 . > > - */ > > - > > -#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 o= f 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_S= HIFT) > > - > > -#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_S= HIFT) > > - > > -#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 Viola= tion */ > > -#define PCI_ERR_UNC_INTN 0x00400000 /* Internal = Error */ > > -#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoke= d TLP */ > > -#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op= egress blocked */ > > -#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefi= x 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 Lo= ng 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_E= N | \ > > - 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_RC= V | \ > > - 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 +=3D ppc_newworld.o > > # IBM pSeries (sPAPR) > > obj-$(CONFIG_PSERIES) +=3D spapr.o spapr_hcall.o spapr_rtas.o spapr_= vio.o > > obj-$(CONFIG_PSERIES) +=3D xics.o spapr_vty.o spapr_llan.o spapr_vsc= si.o > > -obj-$(CONFIG_PSERIES) +=3D spapr_pci.o pci-hotplug.o spapr_iommu.o > > +obj-$(CONFIG_PSERIES) +=3D spapr_pci.o pci/pci-hotplug.o spapr_iommu= .o > > obj-$(CONFIG_PSERIES) +=3D spapr_events.o > > # PowerPC 4xx boards > > obj-y +=3D 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 > > -#include > > -#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 sl= ot 0, > > - and give the rest of them physical *and* pci numbers starting fro= m 1, so > > - they match logical numbers. Note: this means that multiple slots= must have > > - different chassis number values, to make chassis+physical slot un= ique. > > - 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 |=3D (x >> 1); > > - x |=3D (x >> 2); > > - x |=3D (x >> 4); > > - x |=3D (x >> 8); > > - x |=3D (x >> 16); > > - return x + 1; > > -} > > - > > -static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t= msk) > > -{ > > - uint8_t *status =3D 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 =3D 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 =3D d->shpc; > > - int slot; > > - int level =3D 0; > > - uint32_t serr_int; > > - uint32_t int_locator =3D 0; > > - > > - /* Update interrupt locator register */ > > - for (slot =3D 0; slot < shpc->nslots; ++slot) { > > - uint8_t event =3D shpc->config[SHPC_SLOT_EVENT_LATCH(slot)]; > > - uint8_t disable =3D shpc->config[SHPC_SLOT_EVENT_SERR_INT_DI= S(d, slot)]; > > - uint32_t mask =3D 1 << SHPC_IDX_TO_LOGICAL(slot); > > - if (event & ~disable) { > > - int_locator |=3D mask; > > - } > > - } > > - serr_int =3D pci_get_long(shpc->config + SHPC_SERR_INT); > > - if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_= DIS)) { > > - int_locator |=3D SHPC_INT_COMMAND; > > - } > > - pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator); > > - level =3D (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0; > > - if (msi_enabled(d) && shpc->msi_requested !=3D level) > > - msi_notify(d, 0); > > - else > > - qemu_set_irq(d->irq[0], level); > > - shpc->msi_requested =3D 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] &=3D ~SHPC_SEC_BUS_MASK; > > - shpc->config[SHPC_SEC_BUS] |=3D 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 =3D d->shpc; > > - int nslots =3D 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 =3D 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_S= TATE_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 =3D 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 =3D SHPC_IDX_TO_PCI(slot); > > - for (devfn =3D PCI_DEVFN(pci_slot, 0); > > - devfn <=3D PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1); > > - ++devfn) { > > - PCIDevice *affected_dev =3D 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 =3D SHPC_LOGICAL_TO_IDX(target); > > - if (target < SHPC_CMD_TRGT_MIN || slot >=3D shpc->nslots) { > > - shpc_invalid_command(shpc); > > - return; > > - } > > - current_state =3D shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MA= SK); > > - if (current_state =3D=3D SHPC_STATE_ENABLED && state =3D=3D 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 =3D=3D SHPC_STATE_DISABLED && state =3D=3D SH= PC_STATE_PWRONLY) || > > - (current_state =3D=3D SHPC_STATE_DISABLED && state =3D=3D SH= PC_STATE_ENABLED)) { > > - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > > - } else if ((current_state =3D=3D SHPC_STATE_ENABLED || > > - current_state =3D=3D SHPC_STATE_PWRONLY) && > > - state =3D=3D SHPC_STATE_DISABLED) { > > - shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK); > > - power =3D 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 d= evice. */ > > - if (power =3D=3D 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)] |=3D > > - SHPC_SLOT_EVENT_BUTTON | > > - SHPC_SLOT_EVENT_MRL | > > - SHPC_SLOT_EVENT_PRESENCE; > > - } > > - } > > -} > > - > > -static void shpc_command(SHPCDevice *shpc) > > -{ > > - uint8_t code =3D 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 =3D shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX; > > - state =3D (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_S= HIFT; > > - power =3D (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_L= ED_SHIFT; > > - attn =3D (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_= LED_SHIFT; > > - shpc_slot_command(shpc, target, state, power, attn); > > - break; > > - case 0x40 ... 0x47: > > - speed =3D 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 =3D 0; i < shpc->nslots; ++i) { > > - state =3D shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK)= ; > > - if (state =3D=3D SHPC_STATE_ENABLED) { > > - shpc_invalid_command(shpc); > > - goto done; > > - } > > - } > > - for (i =3D 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, S= HPC_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 enabl= ed. > > - * This doesn't make sense - why not? a spec bug? */ > > - for (i =3D 0; i < shpc->nslots; ++i) { > > - state =3D shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK)= ; > > - if (state =3D=3D SHPC_STATE_ENABLED) { > > - shpc_invalid_command(shpc); > > - goto done; > > - } > > - } > > - for (i =3D 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, S= HPC_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_CM= D_DETECTED); > > -} > > - > > -static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, in= t l) > > -{ > > - SHPCDevice *shpc =3D d->shpc; > > - int i; > > - if (addr >=3D SHPC_SIZEOF(d)) { > > - return; > > - } > > - l =3D MIN(l, SHPC_SIZEOF(d) - addr); > > - > > - /* TODO: code duplicated from pci.c */ > > - for (i =3D 0; i < l; val >>=3D 8, ++i) { > > - unsigned a =3D addr + i; > > - uint8_t wmask =3D shpc->wmask[a]; > > - uint8_t w1cmask =3D shpc->w1cmask[a]; > > - assert(!(wmask & w1cmask)); > > - shpc->config[a] =3D (shpc->config[a] & ~wmask) | (val & wmas= k); > > - shpc->config[a] &=3D ~(val & w1cmask); /* W1C: Write 1 to Cl= ear */ > > - } > > - 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 =3D 0x0; > > - if (addr >=3D SHPC_SIZEOF(d)) { > > - return val; > > - } > > - l =3D 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_SE= LECT); > > -} > > - > > -/* Update dword data capability register */ > > -static void shpc_cap_update_dword(PCIDevice *d) > > -{ > > - unsigned data; > > - data =3D shpc_read(d, shpc_cap_dword(d) * 4, 4); > > - pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, da= ta); > > -} > > - > > -/* 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 =3D pci_add_capability(d, PCI_CAP_ID_SHPC, > > - 0, SHPC_CAP_LENGTH); > > - if (config_offset < 0) { > > - return config_offset; > > - } > > - config =3D 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 =3D config_offset; > > - /* Make dword select and data writeable. */ > > - pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0= xff); > > - pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xf= fffffff); > > - 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 =3D { > > - .read =3D shpc_mmio_read, > > - .write =3D shpc_mmio_write, > > - .endianness =3D DEVICE_LITTLE_ENDIAN, > > - .valid =3D { > > - /* SHPC ECN requires dword accesses, but the original 1.0 sp= ec doesn't. > > - * It's easier to suppport all sizes than worry about it. */ > > - .min_access_size =3D 1, > > - .max_access_size =3D 4, > > - }, > > -}; > > - > > -static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affecte= d_dev, > > - PCIHotplugState hotplug_state) > > -{ > > - int pci_slot =3D PCI_SLOT(affected_dev->devfn); > > - uint8_t state; > > - uint8_t led; > > - PCIDevice *d =3D DO_UPCAST(PCIDevice, qdev, qdev); > > - SHPCDevice *shpc =3D d->shpc; > > - int slot =3D SHPC_PCI_TO_IDX(pci_slot); > > - if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >=3D 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 c= reation: > > - * it is present on boot, no hotplug event is necessary. We do s= end an > > - * event when the device is disabled later. */ > > - if (hotplug_state =3D=3D 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 =3D=3D PCI_HOTPLUG_DISABLED) { > > - shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=3D SHPC_SLOT_EVE= NT_BUTTON; > > - state =3D shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); > > - led =3D shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); > > - if (state =3D=3D SHPC_STATE_DISABLED && led =3D=3D 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)] |=3D > > - 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)] |=3D > > - 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)] |=3D > > - 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, unsi= gned offset) > > -{ > > - int i, ret; > > - int nslots =3D SHPC_MAX_SLOTS; /* TODO: qdev property? */ > > - SHPCDevice *shpc =3D d->shpc =3D g_malloc0(sizeof(*d->shpc)); > > - shpc->sec_bus =3D sec_bus; > > - ret =3D 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 =3D nslots; > > - shpc->config =3D g_malloc0(SHPC_SIZEOF(d)); > > - shpc->cmask =3D g_malloc0(SHPC_SIZEOF(d)); > > - shpc->wmask =3D g_malloc0(SHPC_SIZEOF(d)); > > - shpc->w1cmask =3D 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 =3D 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 |=3D 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 =3D d->shpc; > > - d->cap_present &=3D ~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 =3D 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 =3D 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 =3D container_of(pv, PCIDevice, shpc); > > - int ret =3D qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); > > - if (ret !=3D SHPC_SIZEOF(d)) { > > - return -EINVAL; > > - } > > - /* Make sure we don't lose notifications. An extra interrupt is = harmless. */ > > - d->shpc->msi_requested =3D 0; > > - shpc_interrupt_update(d); > > - return 0; > > -} > > - > > -VMStateInfo shpc_vmstate_info =3D { > > - .name =3D "shpc", > > - .get =3D shpc_load, > > - .put =3D 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, un= signed 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 r= equired " > > - "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 =3D 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] =3D PCI_SID_ESR_FIC | > > - (nslots << SLOTID_NSLOTS_SHIFT); > > - d->cmask[cap + PCI_SID_ESR] =3D 0xff; > > - d->config[cap + PCI_SID_CHASSIS_NR] =3D 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] =3D 0xff; > > - > > - d->cap_present |=3D QEMU_PCI_CAP_SLOTID; > > - return 0; > > -} > > - > > -void slotid_cap_cleanup(PCIDevice *d) > > -{ > > - /* TODO: cleanup config space? */ > > - d->cap_present &=3D ~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 > > > >